Traditional log10 mode for PlotDataItem (by adding "mapped data" stage) (#1992)
* make PlotDataItem aware of mapped data * inf suppression, metadata storage and refactor of data structures * cleanup, test, and documentation pass * re-added prepareForPaint, added PlotDataset to sphinx index * strip more print statements * indicate (internal) PlotDataset documentation as orphaned to avoid sphinx error * Do not export PlotDataset * replacement example * example comments
This commit is contained in:
parent
bc542ae1c4
commit
0cc3580687
@ -1,38 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Test programmatically setting log transformation modes.
|
||||
Demonstrate programmatic setting of log transformation modes.
|
||||
"""
|
||||
import initExample ## Add path to library (just for examples; you do not need this)
|
||||
|
||||
import numpy as np
|
||||
from pyqtgraph.Qt import QtGui, QtCore
|
||||
import pyqtgraph as pg
|
||||
|
||||
|
||||
app = pg.mkQApp("Log Axis Example")
|
||||
|
||||
w = pg.GraphicsLayoutWidget(show=True)
|
||||
w.setWindowTitle('pyqtgraph example: logAxis')
|
||||
p1 = w.addPlot(0,0, title="X Semilog")
|
||||
w.resize(800,800)
|
||||
w.setWindowTitle('pyqtgraph example: Log Axis, or How to Recognise Different Types of Curves from Quite a Long Way Away')
|
||||
|
||||
p0 = w.addPlot(0,0, title="Linear")
|
||||
p1 = w.addPlot(0,1, title="X Semilog")
|
||||
p2 = w.addPlot(1,0, title="Y Semilog")
|
||||
p3 = w.addPlot(2,0, title="XY Log")
|
||||
p1.showGrid(True, True)
|
||||
p2.showGrid(True, True)
|
||||
p3.showGrid(True, True)
|
||||
p3 = w.addPlot(1,1, title="XY Log")
|
||||
# configure logarithmic axis scaling:
|
||||
p1.setLogMode(True, False)
|
||||
p2.setLogMode(False, True)
|
||||
p3.setLogMode(True, True)
|
||||
|
||||
# 1000 points from 0.1 to 10, chosen to give a compatible range of values across curves:
|
||||
x = np.logspace(-1, 1, 1000)
|
||||
plotdata = ( # legend entry, color, and plotted equation:
|
||||
('1 / 3x' , '#ff9d47', 1./(3*x) ),
|
||||
('sqrt x' , '#b3cf00', 1/np.sqrt(x) ),
|
||||
('exp. decay', '#00a0b5', 5 * np.exp(-x/1) ),
|
||||
('-log x' , '#a54dff', - np.log10(x) )
|
||||
)
|
||||
p0.addLegend(offset=(-20,20)) # include legend only in top left plot
|
||||
for p in (p0, p1, p2, p3): # draw identical numerical data in all four plots
|
||||
p.showGrid(True, True) # turn on grid for all four plots
|
||||
p.showAxes(True, size=(40,None)) # show a full frame, and reserve identical room for y labels
|
||||
for name, color, y in plotdata: # draw all four curves as defined in plotdata
|
||||
pen = pg.mkPen(color, width=2)
|
||||
p.plot( x,y, pen=pen, name=name )
|
||||
|
||||
w.show()
|
||||
|
||||
y = np.random.normal(size=1000)
|
||||
x = np.linspace(0, 1, 1000)
|
||||
p1.plot(x, y)
|
||||
p2.plot(x, y)
|
||||
p3.plot(x, y)
|
||||
|
||||
|
||||
|
||||
#p.getAxis('bottom').setLogMode(True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pg.exec()
|
||||
|
@ -1123,7 +1123,10 @@ def transformCoordinates(tr, coords, transpose=False):
|
||||
m = m[:, :-1]
|
||||
|
||||
## map coordinates and return
|
||||
mapped = (m*coords).sum(axis=1) ## apply scale/rotate
|
||||
# nan or inf points will not plot, but should not generate warnings
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", RuntimeWarning)
|
||||
mapped = (m*coords).sum(axis=1) ## apply scale/rotate
|
||||
mapped += translate
|
||||
|
||||
if transpose:
|
||||
@ -2042,7 +2045,7 @@ def arrayToQPath(x, y, connect='all', finiteCheck=True):
|
||||
only values with 1 will connect to the previous point. Def
|
||||
finiteCheck : bool, default Ture
|
||||
When false, the check for finite values will be skipped, which can
|
||||
improve performance. If finite values are present in `x` or `y`,
|
||||
improve performance. If nonfinite values are present in `x` or `y`,
|
||||
an empty QPainterPath will be generated.
|
||||
|
||||
Returns
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1468,6 +1468,10 @@ class ViewBox(GraphicsWidget):
|
||||
|
||||
bounds = QtCore.QRectF(range[0][0], range[1][0], range[0][1]-range[0][0], range[1][1]-range[1][0])
|
||||
return bounds
|
||||
|
||||
def update(self, *args, **kwargs):
|
||||
self.prepareForPaint()
|
||||
GraphicsWidget.update(self, *args, **kwargs)
|
||||
|
||||
def updateViewRange(self, forceX=False, forceY=False):
|
||||
## Update viewRange to match targetRange as closely as possible, given
|
||||
|
@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import numpy as np
|
||||
import warnings
|
||||
import pyqtgraph as pg
|
||||
from pyqtgraph.Qt import QtGui
|
||||
|
||||
@ -71,6 +72,31 @@ def test_setData():
|
||||
pdi.setData([],[])
|
||||
assert pdi.xData is None
|
||||
assert pdi.yData is None
|
||||
|
||||
def test_nonfinite():
|
||||
def _assert_equal_arrays(a1, a2):
|
||||
assert a1.shape == a2.shape
|
||||
for ( xtest, xgood ) in zip( a1, a2 ):
|
||||
assert( (xtest == xgood) or (np.isnan(xtest) and np.isnan(xgood) ) )
|
||||
|
||||
x = np.array([-np.inf, 0.0, 1.0, 2.0 , np.nan, 4.0 , np.inf])
|
||||
y = np.array([ 1.0, 0.0,-1.0, np.inf, 2.0 , np.nan, 0.0 ])
|
||||
pdi = pg.PlotDataItem(x, y)
|
||||
dataset = pdi.getDisplayDataset()
|
||||
_assert_equal_arrays( dataset.x, x )
|
||||
_assert_equal_arrays( dataset.y, y )
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
x_log = np.log10(x)
|
||||
y_log = np.log10(y)
|
||||
x_log[ ~np.isfinite(x_log) ] = np.nan
|
||||
y_log[ ~np.isfinite(y_log) ] = np.nan
|
||||
|
||||
pdi.setLogMode(True, True)
|
||||
dataset = pdi.getDisplayDataset()
|
||||
_assert_equal_arrays( dataset.x, x_log )
|
||||
_assert_equal_arrays( dataset.y, y_log )
|
||||
|
||||
def test_opts():
|
||||
# test that curve and scatter plot properties get updated from PlotDataItem methods
|
||||
|
Loading…
x
Reference in New Issue
Block a user