+
+class DrawCmd:
+ """Represent a "draw" command, i.e. the one given in call to
+ PlotCanvas.Draw(). The axis specs are not saved to preserve
+ backward compatibility: they could be specified before the
+ first Draw() command."""
+ def __init__(self, graphics, xAxis, yAxis, xSpec, ySpec, xTicks, yTicks):
+ """Same args as PlotCanvas.Draw(), plus axis specs."""
+ self.graphics = graphics
+ self.xTickGen = xTicks
+ self.yTickGen = yTicks
+ self.xAxisInit, self.yAxisInit = xAxis, yAxis
+
+ self.xAxis = None
+ self.yAxis = None
+ self.changeAxisX(xAxis, xSpec)
+ self.changeAxisY(yAxis, ySpec)
+ assert self.xAxis is not None
+ assert self.yAxis is not None
+
+ def isEmpty(self):
+ """Return true if either axis has 0 size."""
+ if self.xAxis[0] == self.xAxis[1]:
+ return True
+ if self.yAxis[0] == self.yAxis[1]:
+ return True
+
+ return False
+
+ def resetAxes(self, xSpec, ySpec):
+ """Reset the axes to what they were initially, using axes specs given."""
+ self.changeAxisX(self.xAxisInit, xSpec)
+ self.changeAxisY(self.yAxisInit, ySpec)
+
+ def getBoundingBox(self):
+ """Returns p1, p2 (two pairs)"""
+ p1 = _Numeric.array((self.xAxis[0], self.yAxis[0]))
+ p2 = _Numeric.array((self.xAxis[1], self.yAxis[1]))
+ return p1, p2
+
+ def getClosestPoints(self, pntXY, pointScaled=True):
+ ll = []
+ for curveNum,obj in enumerate(self.graphics):
+ #check there are points in the curve
+ if len(obj.points) == 0:
+ continue #go to next obj
+ #[curveNumber, legend, index of closest point, pointXY, scaledXY, distance]
+ cn = [curveNum, obj.getLegend()]+\
+ obj.getClosestPoint( pntXY, pointScaled)
+ ll.append(cn)
+ return ll
+
+ def scrollAxisX(self, units, xSpec):
+ """Scroll y axis by units, using ySpec for axis spec."""
+ self.changeAxisX((self.xAxis[0]+units, self.xAxis[1]+units), xSpec)
+
+ def scrollAxisY(self, units, ySpec):
+ """Scroll y axis by units, using ySpec for axis spec."""
+ self.changeAxisY((self.yAxis[0]+units, self.yAxis[1]+units), ySpec)
+
+ def changeAxisX(self, xAxis=None, xSpec=None):
+ """Change the x axis to new given, or if None use ySpec to get it. """
+ assert type(xAxis) in [type(None),tuple]
+ if xAxis is None:
+ p1, p2 = self.graphics.boundingBox() #min, max points of graphics
+ self.xAxis = self._axisInterval(xSpec, p1[0], p2[0]) #in user units
+ else:
+ self.xAxis = xAxis
+
+ def changeAxisY(self, yAxis=None, ySpec=None):
+ """Change the y axis to new given, or if None use ySpec to get it. """
+ assert type(yAxis) in [type(None),tuple]
+ if yAxis is None:
+ p1, p2 = self.graphics.boundingBox() #min, max points of graphics
+ self.yAxis = self._axisInterval(ySpec, p1[1], p2[1])
+ else:
+ self.yAxis = yAxis
+
+ def zoom(self, center, ratio):
+ """Zoom to center and ratio."""
+ x,y = Center
+ w = (self.xAxis[1] - self.xAxis[0]) * Ratio[0]
+ h = (self.yAxis[1] - self.yAxis[0]) * Ratio[1]
+ self.xAxis = ( x - w/2, x + w/2 )
+ self.yAxis = ( y - h/2, y + h/2 )
+
+ def getXMaxRange(self):
+ p1, p2 = self.graphics.boundingBox() #min, max points of graphics
+ return self._axisInterval(self._xSpec, p1[0], p2[0]) #in user units
+
+ def getYMaxRange(self):
+ p1, p2 = self.graphics.boundingBox() #min, max points of graphics
+ return self._axisInterval(self._ySpec, p1[1], p2[1]) #in user units
+
+ def getTicksX(self):
+ """Get the ticks along y axis. Actually pairs of (t, str)."""
+ xticks = self._ticks(self.xAxis[0], self.xAxis[1], self.xTickGen)
+ if xticks == []: # try without the generator
+ xticks = self._ticks(self.xAxis[0], self.xAxis[1])
+ return xticks
+
+ def getTicksY(self):
+ """Get the ticks along y axis. Actually pairs of (t, str)."""
+ yticks = self._ticks(self.yAxis[0], self.yAxis[1], self.yTickGen)
+ if yticks == []: # try without the generator
+ yticks = self._ticks(self.yAxis[0], self.yAxis[1])
+ return yticks
+
+ def _axisInterval(self, spec, lower, upper):
+ """Returns sensible axis range for given spec."""
+ if spec == 'none' or spec == 'min':
+ if lower == upper:
+ return lower-0.5, upper+0.5
+ else:
+ return lower, upper
+ elif spec == 'auto':
+ range = upper-lower
+ if range == 0.:
+ return lower-0.5, upper+0.5
+ log = _Numeric.log10(range)
+ power = _Numeric.floor(log)
+ fraction = log-power
+ if fraction <= 0.05:
+ power = power-1
+ grid = 10.**power
+ lower = lower - lower % grid
+ mod = upper % grid
+ if mod != 0:
+ upper = upper - mod + grid
+ return lower, upper
+ elif type(spec) == type(()):
+ lower, upper = spec
+ if lower <= upper:
+ return lower, upper
+ else:
+ return upper, lower
+ else:
+ raise ValueError, str(spec) + ': illegal axis specification'
+
+ def _ticks(self, lower, upper, generator=None):
+ """Get ticks between lower and upper, using generator if given. """