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 -*-
|
# -*- 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 initExample ## Add path to library (just for examples; you do not need this)
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from pyqtgraph.Qt import QtGui, QtCore
|
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
|
|
||||||
|
|
||||||
app = pg.mkQApp("Log Axis Example")
|
app = pg.mkQApp("Log Axis Example")
|
||||||
|
|
||||||
w = pg.GraphicsLayoutWidget(show=True)
|
w = pg.GraphicsLayoutWidget(show=True)
|
||||||
w.setWindowTitle('pyqtgraph example: logAxis')
|
w.resize(800,800)
|
||||||
p1 = w.addPlot(0,0, title="X Semilog")
|
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")
|
p2 = w.addPlot(1,0, title="Y Semilog")
|
||||||
p3 = w.addPlot(2,0, title="XY Log")
|
p3 = w.addPlot(1,1, title="XY Log")
|
||||||
p1.showGrid(True, True)
|
# configure logarithmic axis scaling:
|
||||||
p2.showGrid(True, True)
|
|
||||||
p3.showGrid(True, True)
|
|
||||||
p1.setLogMode(True, False)
|
p1.setLogMode(True, False)
|
||||||
p2.setLogMode(False, True)
|
p2.setLogMode(False, True)
|
||||||
p3.setLogMode(True, 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()
|
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__':
|
if __name__ == '__main__':
|
||||||
pg.exec()
|
pg.exec()
|
||||||
|
@ -1123,7 +1123,10 @@ def transformCoordinates(tr, coords, transpose=False):
|
|||||||
m = m[:, :-1]
|
m = m[:, :-1]
|
||||||
|
|
||||||
## map coordinates and return
|
## 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
|
mapped += translate
|
||||||
|
|
||||||
if transpose:
|
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
|
only values with 1 will connect to the previous point. Def
|
||||||
finiteCheck : bool, default Ture
|
finiteCheck : bool, default Ture
|
||||||
When false, the check for finite values will be skipped, which can
|
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.
|
an empty QPainterPath will be generated.
|
||||||
|
|
||||||
Returns
|
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])
|
bounds = QtCore.QRectF(range[0][0], range[1][0], range[0][1]-range[0][0], range[1][1]-range[1][0])
|
||||||
return bounds
|
return bounds
|
||||||
|
|
||||||
|
def update(self, *args, **kwargs):
|
||||||
|
self.prepareForPaint()
|
||||||
|
GraphicsWidget.update(self, *args, **kwargs)
|
||||||
|
|
||||||
def updateViewRange(self, forceX=False, forceY=False):
|
def updateViewRange(self, forceX=False, forceY=False):
|
||||||
## Update viewRange to match targetRange as closely as possible, given
|
## Update viewRange to match targetRange as closely as possible, given
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import warnings
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from pyqtgraph.Qt import QtGui
|
from pyqtgraph.Qt import QtGui
|
||||||
|
|
||||||
@ -71,6 +72,31 @@ def test_setData():
|
|||||||
pdi.setData([],[])
|
pdi.setData([],[])
|
||||||
assert pdi.xData is None
|
assert pdi.xData is None
|
||||||
assert pdi.yData 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():
|
def test_opts():
|
||||||
# test that curve and scatter plot properties get updated from PlotDataItem methods
|
# test that curve and scatter plot properties get updated from PlotDataItem methods
|
||||||
|
Loading…
x
Reference in New Issue
Block a user