46
46
47
47
from .... import qt
48
48
from ...._glutils import gl , Program
49
+ from ....utils .matplotlib import DefaultTickFormatter
49
50
from ..._utils import checkAxisLimits , FLOAT32_MINPOS
50
51
from .GLSupport import mat4Ortho
51
52
from .GLText import Text2D , CENTER , BOTTOM , TOP , LEFT , RIGHT , ROTATE_270
@@ -78,10 +79,14 @@ def __init__(
78
79
labelVAlign = CENTER ,
79
80
titleAlign = CENTER ,
80
81
titleVAlign = CENTER ,
82
+ orderOffsetAlign = CENTER ,
83
+ orderOffsetVAlign = CENTER ,
81
84
titleRotate = 0 ,
82
85
titleOffset = (0.0 , 0.0 ),
83
86
):
87
+ self ._tickFormatter = DefaultTickFormatter ()
84
88
self ._ticks = None
89
+ self ._orderAndOffsetText = ""
85
90
86
91
self ._plotFrameRef = weakref .ref (plotFrame )
87
92
@@ -96,6 +101,9 @@ def __init__(
96
101
self ._foregroundColor = foregroundColor
97
102
self ._labelAlign = labelAlign
98
103
self ._labelVAlign = labelVAlign
104
+ self ._orderOffetAnchor = (1.0 , 0.0 )
105
+ self ._orderOffsetAlign = orderOffsetAlign
106
+ self ._orderOffsetVAlign = orderOffsetVAlign
99
107
self ._titleAlign = titleAlign
100
108
self ._titleVAlign = titleVAlign
101
109
self ._titleRotate = titleRotate
@@ -193,6 +201,17 @@ def title(self, title):
193
201
self ._title = title
194
202
self ._dirtyPlotFrame ()
195
203
204
+ @property
205
+ def orderOffetAnchor (self ) -> tuple [float , float ]:
206
+ """Anchor position for the tick order&offset text"""
207
+ return self ._orderOffetAnchor
208
+
209
+ @orderOffetAnchor .setter
210
+ def orderOffetAnchor (self , position : tuple [float , float ]):
211
+ if position != self ._orderOffetAnchor :
212
+ self ._orderOffetAnchor = position
213
+ self ._dirtyTicks ()
214
+
196
215
@property
197
216
def titleOffset (self ):
198
217
"""Title offset in pixels (x: int, y: int)"""
@@ -296,6 +315,20 @@ def getVerticesAndLabels(self):
296
315
)
297
316
labels .append (axisTitle )
298
317
318
+ if self ._orderAndOffsetText :
319
+ xOrderOffset , yOrderOffet = self .orderOffetAnchor
320
+ labels .append (
321
+ Text2D (
322
+ text = self ._orderAndOffsetText ,
323
+ font = font ,
324
+ color = self ._foregroundColor ,
325
+ x = xOrderOffset ,
326
+ y = yOrderOffet ,
327
+ align = self ._orderOffsetAlign ,
328
+ valign = self ._orderOffsetVAlign ,
329
+ devicePixelRatio = self .devicePixelRatio ,
330
+ )
331
+ )
299
332
return vertices , labels
300
333
301
334
def _dirtyPlotFrame (self ):
@@ -320,6 +353,8 @@ def _ticksGenerator(self):
320
353
"""Generator of ticks as tuples:
321
354
((x, y) in display, dataPos, textLabel).
322
355
"""
356
+ self ._orderAndOffsetText = ""
357
+
323
358
dataMin , dataMax = self .dataRange
324
359
if self .isLog and dataMin <= 0.0 :
325
360
_logger .warning ("Getting ticks while isLog=True and dataRange[0]<=0." )
@@ -373,20 +408,25 @@ def _ticksGenerator(self):
373
408
tickDensity = 1.3 * self .devicePixelRatio / self .dotsPerInch
374
409
375
410
if not self .isTimeSeries :
376
- tickMin , tickMax , step , nbFrac = niceNumbersAdaptative (
411
+ tickMin , tickMax , step , _ = niceNumbersAdaptative (
377
412
dataMin , dataMax , nbPixels , tickDensity
378
413
)
379
414
380
- for dataPos in self ._frange (tickMin , tickMax , step ):
381
- if dataMin <= dataPos <= dataMax :
382
- xPixel = x0 + (dataPos - dataMin ) * xScale
383
- yPixel = y0 + (dataPos - dataMin ) * yScale
415
+ visibleTickPositions = [
416
+ pos
417
+ for pos in self ._frange (tickMin , tickMax , step )
418
+ if dataMin <= pos <= dataMax
419
+ ]
420
+ self ._tickFormatter .axis .set_view_interval (dataMin , dataMax )
421
+ self ._tickFormatter .axis .set_data_interval (dataMin , dataMax )
422
+ texts = self ._tickFormatter .format_ticks (visibleTickPositions )
423
+ self ._orderAndOffsetText = self ._tickFormatter .get_offset ()
424
+
425
+ for dataPos , text in zip (visibleTickPositions , texts ):
426
+ xPixel = x0 + (dataPos - dataMin ) * xScale
427
+ yPixel = y0 + (dataPos - dataMin ) * yScale
428
+ yield ((xPixel , yPixel ), dataPos , text )
384
429
385
- if nbFrac == 0 :
386
- text = "%g" % dataPos
387
- else :
388
- text = ("%." + str (nbFrac ) + "f" ) % dataPos
389
- yield ((xPixel , yPixel ), dataPos , text )
390
430
else :
391
431
# Time series
392
432
try :
@@ -795,6 +835,8 @@ def __init__(self, marginRatios, foregroundColor, gridColor):
795
835
foregroundColor = self ._foregroundColor ,
796
836
labelAlign = CENTER ,
797
837
labelVAlign = TOP ,
838
+ orderOffsetAlign = RIGHT ,
839
+ orderOffsetVAlign = TOP ,
798
840
titleAlign = CENTER ,
799
841
titleVAlign = TOP ,
800
842
titleRotate = 0 ,
@@ -810,6 +852,8 @@ def __init__(self, marginRatios, foregroundColor, gridColor):
810
852
foregroundColor = self ._foregroundColor ,
811
853
labelAlign = RIGHT ,
812
854
labelVAlign = CENTER ,
855
+ orderOffsetAlign = LEFT ,
856
+ orderOffsetVAlign = BOTTOM ,
813
857
titleAlign = CENTER ,
814
858
titleVAlign = BOTTOM ,
815
859
titleRotate = ROTATE_270 ,
@@ -822,6 +866,8 @@ def __init__(self, marginRatios, foregroundColor, gridColor):
822
866
foregroundColor = self ._foregroundColor ,
823
867
labelAlign = LEFT ,
824
868
labelVAlign = CENTER ,
869
+ orderOffsetAlign = RIGHT ,
870
+ orderOffsetVAlign = BOTTOM ,
825
871
titleAlign = CENTER ,
826
872
titleVAlign = TOP ,
827
873
titleRotate = ROTATE_270 ,
@@ -1281,6 +1327,25 @@ def _buildVerticesAndLabels(self):
1281
1327
1282
1328
self ._x2AxisCoords = ((xCoords [0 ], yCoords [1 ]), (xCoords [1 ], yCoords [1 ]))
1283
1329
1330
+ # Set order&offset anchor **before** handling Y axis inversion
1331
+ font = qt .QApplication .instance ().font ()
1332
+ fontPixelSize = font .pixelSize ()
1333
+ if fontPixelSize == - 1 :
1334
+ fontPixelSize = font .pointSizeF () / 72.0 * self .dotsPerInch
1335
+
1336
+ self .axes [0 ].orderOffetAnchor = (
1337
+ xCoords [1 ],
1338
+ yCoords [0 ] + fontPixelSize * 1.2 ,
1339
+ )
1340
+ self .axes [1 ].orderOffetAnchor = (
1341
+ xCoords [0 ],
1342
+ yCoords [1 ] - 4 * self .devicePixelRatio ,
1343
+ )
1344
+ self ._y2Axis .orderOffetAnchor = (
1345
+ xCoords [1 ],
1346
+ yCoords [1 ] - 4 * self .devicePixelRatio ,
1347
+ )
1348
+
1284
1349
if self .isYAxisInverted :
1285
1350
# Y axes are inverted, axes coordinates are inverted
1286
1351
yCoords = yCoords [1 ], yCoords [0 ]
0 commit comments