Skip to content

Commit

Permalink
use matplotlib ScalarFormatter to get tick labels and order&offset text
Browse files Browse the repository at this point in the history
  • Loading branch information
t20100 committed Dec 15, 2023
1 parent dba4b32 commit 2181492
Showing 1 changed file with 75 additions and 10 deletions.
85 changes: 75 additions & 10 deletions src/silx/gui/plot/backends/glutils/GLPlotFrame.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@

from .... import qt
from ...._glutils import gl, Program
from ....utils.matplotlib import DefaultTickFormatter
from ..._utils import checkAxisLimits, FLOAT32_MINPOS
from .GLSupport import mat4Ortho
from .GLText import Text2D, CENTER, BOTTOM, TOP, LEFT, RIGHT, ROTATE_270
Expand Down Expand Up @@ -78,10 +79,14 @@ def __init__(
labelVAlign=CENTER,
titleAlign=CENTER,
titleVAlign=CENTER,
orderOffsetAlign=CENTER,
orderOffsetVAlign=CENTER,
titleRotate=0,
titleOffset=(0.0, 0.0),
):
self._tickFormatter = DefaultTickFormatter()
self._ticks = None
self._orderAndOffsetText = ""

self._plotFrameRef = weakref.ref(plotFrame)

Expand All @@ -96,6 +101,9 @@ def __init__(
self._foregroundColor = foregroundColor
self._labelAlign = labelAlign
self._labelVAlign = labelVAlign
self._orderOffetAnchor = (1.0, 0.0)
self._orderOffsetAlign = orderOffsetAlign
self._orderOffsetVAlign = orderOffsetVAlign
self._titleAlign = titleAlign
self._titleVAlign = titleVAlign
self._titleRotate = titleRotate
Expand Down Expand Up @@ -193,6 +201,17 @@ def title(self, title):
self._title = title
self._dirtyPlotFrame()

@property
def orderOffetAnchor(self) -> tuple[float, float]:
"""Anchor position for the tick order&offset text"""
return self._orderOffetAnchor

@orderOffetAnchor.setter
def orderOffetAnchor(self, position: tuple[float, float]):
if position != self._orderOffetAnchor:
self._orderOffetAnchor = position
self._dirtyTicks()

@property
def titleOffset(self):
"""Title offset in pixels (x: int, y: int)"""
Expand Down Expand Up @@ -296,6 +315,20 @@ def getVerticesAndLabels(self):
)
labels.append(axisTitle)

if self._orderAndOffsetText:
xOrderOffset, yOrderOffet = self.orderOffetAnchor
labels.append(
Text2D(
text=self._orderAndOffsetText,
font=font,
color=self._foregroundColor,
x=xOrderOffset,
y=yOrderOffet,
align=self._orderOffsetAlign,
valign=self._orderOffsetVAlign,
devicePixelRatio=self.devicePixelRatio,
)
)
return vertices, labels

def _dirtyPlotFrame(self):
Expand All @@ -320,6 +353,8 @@ def _ticksGenerator(self):
"""Generator of ticks as tuples:
((x, y) in display, dataPos, textLabel).
"""
self._orderAndOffsetText = ""

dataMin, dataMax = self.dataRange
if self.isLog and dataMin <= 0.0:
_logger.warning("Getting ticks while isLog=True and dataRange[0]<=0.")
Expand Down Expand Up @@ -373,20 +408,25 @@ def _ticksGenerator(self):
tickDensity = 1.3 * self.devicePixelRatio / self.dotsPerInch

if not self.isTimeSeries:
tickMin, tickMax, step, nbFrac = niceNumbersAdaptative(
tickMin, tickMax, step, _ = niceNumbersAdaptative(
dataMin, dataMax, nbPixels, tickDensity
)

for dataPos in self._frange(tickMin, tickMax, step):
if dataMin <= dataPos <= dataMax:
xPixel = x0 + (dataPos - dataMin) * xScale
yPixel = y0 + (dataPos - dataMin) * yScale
visibleTickPositions = [
pos
for pos in self._frange(tickMin, tickMax, step)
if dataMin <= pos <= dataMax
]
self._tickFormatter.axis.set_view_interval(dataMin, dataMax)
self._tickFormatter.axis.set_data_interval(dataMin, dataMax)
texts = self._tickFormatter.format_ticks(visibleTickPositions)
self._orderAndOffsetText = self._tickFormatter.get_offset()

for dataPos, text in zip(visibleTickPositions, texts):
xPixel = x0 + (dataPos - dataMin) * xScale
yPixel = y0 + (dataPos - dataMin) * yScale
yield ((xPixel, yPixel), dataPos, text)

if nbFrac == 0:
text = "%g" % dataPos
else:
text = ("%." + str(nbFrac) + "f") % dataPos
yield ((xPixel, yPixel), dataPos, text)
else:
# Time series
try:
Expand Down Expand Up @@ -795,6 +835,8 @@ def __init__(self, marginRatios, foregroundColor, gridColor):
foregroundColor=self._foregroundColor,
labelAlign=CENTER,
labelVAlign=TOP,
orderOffsetAlign=RIGHT,
orderOffsetVAlign=TOP,
titleAlign=CENTER,
titleVAlign=TOP,
titleRotate=0,
Expand All @@ -810,6 +852,8 @@ def __init__(self, marginRatios, foregroundColor, gridColor):
foregroundColor=self._foregroundColor,
labelAlign=RIGHT,
labelVAlign=CENTER,
orderOffsetAlign=LEFT,
orderOffsetVAlign=BOTTOM,
titleAlign=CENTER,
titleVAlign=BOTTOM,
titleRotate=ROTATE_270,
Expand All @@ -822,6 +866,8 @@ def __init__(self, marginRatios, foregroundColor, gridColor):
foregroundColor=self._foregroundColor,
labelAlign=LEFT,
labelVAlign=CENTER,
orderOffsetAlign=RIGHT,
orderOffsetVAlign=BOTTOM,
titleAlign=CENTER,
titleVAlign=TOP,
titleRotate=ROTATE_270,
Expand Down Expand Up @@ -1281,6 +1327,25 @@ def _buildVerticesAndLabels(self):

self._x2AxisCoords = ((xCoords[0], yCoords[1]), (xCoords[1], yCoords[1]))

# Set order&offset anchor **before** handling Y axis inversion
font = qt.QApplication.instance().font()
fontPixelSize = font.pixelSize()
if fontPixelSize == -1:
fontPixelSize = font.pointSizeF() / 72.0 * self.dotsPerInch

self.axes[0].orderOffetAnchor = (
xCoords[1],
yCoords[0] + fontPixelSize * 1.2,
)
self.axes[1].orderOffetAnchor = (
xCoords[0],
yCoords[1] - 4 * self.devicePixelRatio,
)
self._y2Axis.orderOffetAnchor = (
xCoords[1],
yCoords[1] - 4 * self.devicePixelRatio,
)

if self.isYAxisInverted:
# Y axes are inverted, axes coordinates are inverted
yCoords = yCoords[1], yCoords[0]
Expand Down

0 comments on commit 2181492

Please sign in to comment.