@@ -370,6 +370,80 @@ def view_limits(self, vmin, vmax):
370
370
return mtransforms .nonsingular (min (0 , vmin ), vmax )
371
371
372
372
373
+ class RadialTick (maxis .YTick ):
374
+ """
375
+ A radial-axis tick.
376
+
377
+ This subclass of `YTick` provides radial ticks with some small modification
378
+ to their re-positioning such that ticks are rotated based on axes limits.
379
+ This results in ticks that are correctly perpendicular to the spine. Labels
380
+ are also rotated to be perpendicular to the spine.
381
+ """
382
+ def _get_text1 (self ):
383
+ t = maxis .YTick ._get_text1 (self )
384
+ t .set_rotation_mode ('anchor' )
385
+ return t
386
+
387
+ def _get_text2 (self ):
388
+ t = maxis .YTick ._get_text2 (self )
389
+ t .set_rotation_mode ('anchor' )
390
+ return t
391
+
392
+ def update_position (self , loc ):
393
+ maxis .YTick .update_position (self , loc )
394
+ axes = self .axes
395
+ thetamin = axes .get_thetamin ()
396
+ thetamax = axes .get_thetamax ()
397
+ direction = axes .get_theta_direction ()
398
+ offset_rad = axes .get_theta_offset ()
399
+ offset = np .rad2deg (offset_rad )
400
+ full = _is_full_circle_deg (thetamin , thetamax )
401
+
402
+ if full :
403
+ angle = axes .get_rlabel_position () * direction + offset - 90
404
+ tick_angle = np .deg2rad (angle )
405
+ else :
406
+ angle = thetamin * direction + offset - 90
407
+ if direction > 0 :
408
+ tick_angle = np .deg2rad (angle )
409
+ else :
410
+ tick_angle = np .deg2rad (angle + 180 )
411
+ if self .label1On :
412
+ self .label1 .set_rotation (angle + self ._labelrotation )
413
+ if self .tick1On :
414
+ marker = self .tick1line .get_marker ()
415
+ if marker in (mmarkers .TICKLEFT , mmarkers .TICKRIGHT , '_' ):
416
+ trans = (mtransforms .Affine2D ()
417
+ .scale (1.0 , 1.0 )
418
+ .rotate (tick_angle ))
419
+ else :
420
+ # Don't modify custom tick line markers.
421
+ trans = self .tick1line ._marker ._transform
422
+ self .tick1line ._marker ._transform = trans
423
+
424
+ if full :
425
+ self .label2On = False
426
+ self .tick2On = False
427
+ else :
428
+ angle = thetamax * direction + offset - 90
429
+ if direction > 0 :
430
+ tick_angle = np .deg2rad (angle + 180 )
431
+ else :
432
+ tick_angle = np .deg2rad (angle )
433
+ if self .label2On :
434
+ self .label2 .set_rotation (angle + self ._labelrotation )
435
+ if self .tick2On :
436
+ marker = self .tick2line .get_marker ()
437
+ if marker in (mmarkers .TICKLEFT , mmarkers .TICKRIGHT , '_' ):
438
+ trans = (mtransforms .Affine2D ()
439
+ .scale (1.0 , 1.0 )
440
+ .rotate (tick_angle ))
441
+ else :
442
+ # Don't modify custom tick line markers.
443
+ trans = self .tick2line ._marker ._transform
444
+ self .tick2line ._marker ._transform = trans
445
+
446
+
373
447
class RadialAxis (maxis .YAxis ):
374
448
"""
375
449
A radial Axis.
@@ -385,7 +459,7 @@ def _get_tick(self, major):
385
459
tick_kw = self ._major_tick_kw
386
460
else :
387
461
tick_kw = self ._minor_tick_kw
388
- return maxis . YTick (self .axes , 0 , '' , major = major , ** tick_kw )
462
+ return RadialTick (self .axes , 0 , '' , major = major , ** tick_kw )
389
463
390
464
def _wrap_locator_formatter (self ):
391
465
self .set_major_locator (RadialLocator (self .get_major_locator (),
@@ -657,50 +731,16 @@ def get_yaxis_transform(self, which='grid'):
657
731
def get_yaxis_text1_transform (self , pad ):
658
732
thetamin , thetamax = self ._realViewLim .intervalx
659
733
full = _is_full_circle_rad (thetamin , thetamax )
660
- if full :
661
- angle = self .get_rlabel_position ()
734
+ if self . get_theta_direction () > 0 or full :
735
+ return self ._yaxis_text_transform , 'center' , 'left'
662
736
else :
663
- angle = np .rad2deg (thetamin )
664
- if angle < 0 :
665
- angle += 360
666
- angle %= 360
667
-
668
- # NOTE: Due to a bug, previous code always used bottom left, contrary
669
- # to its original intentions here.
670
- valign = [['top' , 'bottom' , 'bottom' , 'top' ],
671
- # ['bottom', 'bottom', 'top', 'top']]
672
- ['bottom' , 'bottom' , 'bottom' , 'bottom' ]]
673
- halign = [['left' , 'left' , 'right' , 'right' ],
674
- # ['left', 'right', 'right', 'left']]
675
- ['left' , 'left' , 'left' , 'left' ]]
676
-
677
- ind = np .digitize ([angle ], np .arange (0 , 361 , 90 ))[0 ] - 1
678
-
679
- return self ._yaxis_text_transform , valign [full ][ind ], halign [full ][ind ]
737
+ return self ._yaxis_text_transform , 'center' , 'right'
680
738
681
739
def get_yaxis_text2_transform (self , pad ):
682
- thetamin , thetamax = self ._realViewLim .intervalx
683
- full = _is_full_circle_rad (thetamin , thetamax )
684
- if full :
685
- angle = self .get_rlabel_position ()
740
+ if self .get_theta_direction () > 0 :
741
+ return self ._yaxis_text_transform , 'center' , 'right'
686
742
else :
687
- angle = np .rad2deg (thetamax )
688
- if angle < 0 :
689
- angle += 360
690
- angle %= 360
691
-
692
- # NOTE: Due to a bug, previous code always used top right, contrary to
693
- # its original intentions here.
694
- valign = [['bottom' , 'top' , 'top' , 'bottom' ],
695
- # ['top', 'top', 'bottom', 'bottom']]
696
- ['top' , 'top' , 'top' , 'top' ]]
697
- halign = [['right' , 'right' , 'left' , 'left' ],
698
- # ['right', 'left', 'left', 'right']]
699
- ['right' , 'right' , 'right' , 'right' ]]
700
-
701
- ind = np .digitize ([angle ], np .arange (0 , 361 , 90 ))[0 ] - 1
702
-
703
- return self ._yaxis_text_transform , valign [full ][ind ], halign [full ][ind ]
743
+ return self ._yaxis_text_transform , 'center' , 'left'
704
744
705
745
def draw (self , * args , ** kwargs ):
706
746
thetamin , thetamax = self ._realViewLim .intervalx
@@ -845,6 +885,9 @@ def set_theta_direction(self, direction):
845
885
raise ValueError (
846
886
"direction must be 1, -1, clockwise or counterclockwise" )
847
887
self ._direction .invalidate ()
888
+ # FIXME: Why is this needed? Even though the tick label gets
889
+ # re-created, the alignment is not correctly updated without a reset.
890
+ self .yaxis .reset_ticks ()
848
891
849
892
def get_theta_direction (self ):
850
893
"""
@@ -901,6 +944,7 @@ def set_rlabel_position(self, value):
901
944
The angular position of the radius labels in degrees.
902
945
"""
903
946
self ._r_label_position .clear ().translate (np .deg2rad (value ), 0.0 )
947
+ self .yaxis .reset_ticks ()
904
948
905
949
def set_yscale (self , * args , ** kwargs ):
906
950
Axes .set_yscale (self , * args , ** kwargs )
0 commit comments