Commit 194f90aa authored by Luke Campagnola's avatar Luke Campagnola
Browse files

AxisItem update: added setTicks method

parent ff384b80
...@@ -59,6 +59,7 @@ class AxisItem(GraphicsWidget): ...@@ -59,6 +59,7 @@ class AxisItem(GraphicsWidget):
self.textHeight = 18 self.textHeight = 18
self.tickLength = maxTickLength self.tickLength = maxTickLength
self._tickLevels = None ## used to override the automatic ticking system with explicit ticks
self.scale = 1.0 self.scale = 1.0
self.autoScale = True self.autoScale = True
...@@ -227,7 +228,8 @@ class AxisItem(GraphicsWidget): ...@@ -227,7 +228,8 @@ class AxisItem(GraphicsWidget):
self.update() self.update()
def setRange(self, mn, mx): def setRange(self, mn, mx):
"""Set the range of values displayed by the axis""" """Set the range of values displayed by the axis.
Usually this is handled automatically by linking the axis to a ViewBox with :func:`linkToView <pyqtgraph.AxisItem.linkToView>`"""
if mn in [np.nan, np.inf, -np.inf] or mx in [np.nan, np.inf, -np.inf]: if mn in [np.nan, np.inf, -np.inf] or mx in [np.nan, np.inf, -np.inf]:
raise Exception("Not setting range to [%s, %s]" % (str(mn), str(mx))) raise Exception("Not setting range to [%s, %s]" % (str(mn), str(mx)))
self.range = [mn, mx] self.range = [mn, mx]
...@@ -284,9 +286,27 @@ class AxisItem(GraphicsWidget): ...@@ -284,9 +286,27 @@ class AxisItem(GraphicsWidget):
self.drawPicture(painter) self.drawPicture(painter)
finally: finally:
painter.end() painter.end()
p.setRenderHint(p.Antialiasing, False)
p.setRenderHint(p.TextAntialiasing, True)
self.picture.play(p) self.picture.play(p)
def setTicks(self, ticks):
"""Explicitly determine which ticks to display.
This overrides the behavior specified by tickSpacing(), tickValues(), and tickStrings()
The format for *ticks* looks like::
[
[ (majorTickValue1, majorTickString1), (majorTickValue2, majorTickString2), ... ],
[ (minorTickValue1, minorTickString1), (minorTickValue2, minorTickString2), ... ],
...
]
If *ticks* is None, then the default tick system will be used instead.
"""
self._tickLevels = ticks
self.picture = None
self.update()
def tickSpacing(self, minVal, maxVal, size): def tickSpacing(self, minVal, maxVal, size):
"""Return values describing the desired spacing and offset of ticks. """Return values describing the desired spacing and offset of ticks.
...@@ -350,6 +370,7 @@ class AxisItem(GraphicsWidget): ...@@ -350,6 +370,7 @@ class AxisItem(GraphicsWidget):
ticks = [] ticks = []
tickLevels = self.tickSpacing(minVal, maxVal, size) tickLevels = self.tickSpacing(minVal, maxVal, size)
allValues = []
for i in range(len(tickLevels)): for i in range(len(tickLevels)):
spacing, offset = tickLevels[i] spacing, offset = tickLevels[i]
...@@ -358,7 +379,10 @@ class AxisItem(GraphicsWidget): ...@@ -358,7 +379,10 @@ class AxisItem(GraphicsWidget):
## determine number of ticks ## determine number of ticks
num = int((maxVal-start) / spacing) + 1 num = int((maxVal-start) / spacing) + 1
ticks.append((spacing, np.arange(num) * spacing + start)) values = np.arange(num) * spacing + start
values = filter(lambda x: x not in allValues, values) ## remove any ticks that were present in higher levels
allValues.extend(values)
ticks.append((spacing, values))
return ticks return ticks
def logTickValues(self, minVal, maxVal, size): def logTickValues(self, minVal, maxVal, size):
...@@ -408,7 +432,6 @@ class AxisItem(GraphicsWidget): ...@@ -408,7 +432,6 @@ class AxisItem(GraphicsWidget):
p.setRenderHint(p.TextAntialiasing, True) p.setRenderHint(p.TextAntialiasing, True)
prof = debug.Profiler("AxisItem.paint", disabled=True) prof = debug.Profiler("AxisItem.paint", disabled=True)
p.setPen(self.pen)
#bounds = self.boundingRect() #bounds = self.boundingRect()
bounds = self.mapRectFromParent(self.geometry()) bounds = self.mapRectFromParent(self.geometry())
...@@ -446,6 +469,7 @@ class AxisItem(GraphicsWidget): ...@@ -446,6 +469,7 @@ class AxisItem(GraphicsWidget):
#print tickStart, tickStop, span #print tickStart, tickStop, span
## draw long line along axis ## draw long line along axis
p.setPen(self.pen)
p.drawLine(*span) p.drawLine(*span)
p.translate(0.5,0) ## resolves some damn pixel ambiguity p.translate(0.5,0) ## resolves some damn pixel ambiguity
...@@ -455,8 +479,21 @@ class AxisItem(GraphicsWidget): ...@@ -455,8 +479,21 @@ class AxisItem(GraphicsWidget):
if lengthInPixels == 0: if lengthInPixels == 0:
return return
if self._tickLevels is None:
tickLevels = self.tickValues(self.range[0], self.range[1], lengthInPixels) tickLevels = self.tickValues(self.range[0], self.range[1], lengthInPixels)
tickStrings = None
else:
## parse self.tickLevels into the formats returned by tickLevels() and tickStrings()
tickLevels = []
tickStrings = []
for level in self._tickLevels:
values = []
strings = []
tickLevels.append((None, values))
tickStrings.append(strings)
for val, strn in level:
values.append(val)
strings.append(strn)
textLevel = 1 ## draw text at this scale level textLevel = 1 ## draw text at this scale level
...@@ -500,32 +537,37 @@ class AxisItem(GraphicsWidget): ...@@ -500,32 +537,37 @@ class AxisItem(GraphicsWidget):
tickPositions[i].append(x) tickPositions[i].append(x)
prof.mark('draw ticks') prof.mark('draw ticks')
## determine level to draw text ## Draw text until there is no more room (or no more text)
best = 0 textRects = []
for i in range(len(tickLevels)): for i in range(len(tickLevels)):
## take a small sample of strings and measure their rendered text ## Get the list of strings to display for this level
if tickStrings is None:
spacing, values = tickLevels[i] spacing, values = tickLevels[i]
strings = self.tickStrings(values, self.scale, spacing) strings = self.tickStrings(values, self.scale, spacing)
else:
strings = tickStrings[i]
if len(strings) == 0: if len(strings) == 0:
continue continue
textRects = [p.boundingRect(QtCore.QRectF(0, 0, 100, 100), QtCore.Qt.AlignCenter, s) for s in strings]
if i > 0: ## always draw top level
## measure all text, make sure there's enough room
textRects.extend([p.boundingRect(QtCore.QRectF(0, 0, 100, 100), QtCore.Qt.AlignCenter, s) for s in strings])
if axis == 0: if axis == 0:
textSize = np.max([r.height() for r in textRects]) textSize = np.sum([r.height() for r in textRects])
else: else:
textSize = np.max([r.width() for r in textRects]) textSize = np.sum([r.width() for r in textRects])
## If these strings are not too crowded, then this level is ok ## If the strings are too crowded, stop drawing text now
textFillRatio = float(textSize * len(values)) / lengthInPixels textFillRatio = float(textSize) / lengthInPixels
if textFillRatio < 0.7: if textFillRatio > 0.7:
best = i break
continue
prof.mark('measure text')
spacing, values = tickLevels[best] #spacing, values = tickLevels[best]
strings = self.tickStrings(values, self.scale, spacing) #strings = self.tickStrings(values, self.scale, spacing)
for j in range(len(strings)): for j in range(len(strings)):
vstr = strings[j] vstr = strings[j]
x = tickPositions[best][j] x = tickPositions[i][j]
textRect = p.boundingRect(QtCore.QRectF(0, 0, 100, 100), QtCore.Qt.AlignCenter, vstr) textRect = p.boundingRect(QtCore.QRectF(0, 0, 100, 100), QtCore.Qt.AlignCenter, vstr)
height = textRect.height() height = textRect.height()
self.textHeight = height self.textHeight = height
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment