3939
4040# Standard library modules.
4141import bisect
42- import warnings
4342import dataclasses
43+ import numbers
44+ import warnings
4445
4546# Third party modules.
4647import matplotlib
6162 AnchoredOffsetbox ,
6263)
6364from matplotlib .patches import Rectangle
65+ from matplotlib .transforms import IdentityTransform , blended_transform_factory
6466
6567# Local modules.
6668from matplotlib_scalebar .dimension import (
@@ -96,10 +98,19 @@ def _validate_legend_loc(loc):
9698 return loc
9799
98100
101+ def _validate_dim (dim ):
102+ if (len (dim ) == 2
103+ and isinstance (dim [0 ], numbers .Real )
104+ and dim [1 ] in ["saxis" , "laxis" , "font" ]):
105+ return dim
106+ else :
107+ raise ValueError ("Not a valid dimension" )
108+
109+
99110defaultParams .update (
100111 {
101112 "scalebar.length_fraction" : [0.2 , validate_float ],
102- "scalebar.width_fraction " : [0.01 , validate_float ],
113+ "scalebar.thickness " : [( 0.01 , "saxis" ), _validate_dim ],
103114 "scalebar.location" : ["upper right" , _validate_legend_loc ],
104115 "scalebar.pad" : [0.2 , validate_float ],
105116 "scalebar.border_pad" : [0.1 , validate_float ],
@@ -177,6 +188,7 @@ def __init__(
177188 dimension = "si-length" ,
178189 label = None ,
179190 length_fraction = None ,
191+ thickness = None ,
180192 height_fraction = None ,
181193 width_fraction = None ,
182194 location = None ,
@@ -242,9 +254,15 @@ def __init__(
242254 This argument is ignored if a *fixed_value* is specified.
243255 :type length_fraction: :class:`float`
244256
245- :arg width_fraction: width of the scale bar as a fraction of the
246- axes's height (default: rcParams['scalebar.width_fraction'] or ``0.01``)
247- :type width_fraction: :class:`float`
257+ :arg thickness: thickness of the scale bar, as a ``(value, unit)`` pair.
258+ Valid units are
259+ * "laxis": value is relative to the size of the parent axes in the
260+ "long" direction.
261+ * "saxis": value is relative to the size of the parent axes in the
262+ "short" direction.
263+ * "font": value is relative to the label fontsize.
264+ (default: rcParams['scalebar.thickness'] or ``(0.01, "saxis")``)
265+ :type thickness: ``tuple[float, str]``
248266
249267 :arg location: a location code (same as legend)
250268 (default: rcParams['scalebar.location'] or ``upper right``)
@@ -347,6 +365,12 @@ def __init__(
347365 )
348366 scale_formatter = scale_formatter or label_formatter
349367
368+ if width_fraction is not None :
369+ if thickness is not None :
370+ warnings .warn ("Ignoring 'width_fraction', as 'thickness' is also set" )
371+ else :
372+ thickness = (width_fraction , "saxis" )
373+
350374 if (
351375 loc is not None
352376 and location is not None
@@ -359,7 +383,7 @@ def __init__(
359383 self .units = units
360384 self .label = label
361385 self .length_fraction = length_fraction
362- self .width_fraction = width_fraction
386+ self .thickness = thickness
363387 self .location = location or loc
364388 self .pad = pad
365389 self .border_pad = border_pad
@@ -433,7 +457,7 @@ def _get_value(attr, default):
433457 return value
434458
435459 length_fraction = _get_value ("length_fraction" , 0.2 )
436- width_fraction = _get_value ("width_fraction " , 0.01 )
460+ thickness_value , thickness_unit = _get_value ("thickness " , ( 0.01 , "saxis" ) )
437461 location = _get_value ("location" , "upper right" )
438462 if isinstance (location , str ):
439463 location = self ._LOCATIONS [location .lower ()]
@@ -486,29 +510,44 @@ def _get_value(attr, default):
486510
487511 scale_text = self .scale_formatter (value , self .dimension .to_latex (units ))
488512
489- width_px = abs (ylim [1 ] - ylim [0 ]) * width_fraction
513+ if thickness_unit == "saxis" :
514+ thickness = thickness_value
515+ transform = (ax .get_xaxis_transform ()
516+ if rotation == "horizontal" else
517+ ax .get_yaxis_transform ())
518+ elif thickness_unit == "laxis" :
519+ thickness = thickness_value
520+ transform = (ax .get_yaxis_transform ()
521+ if rotation == "horizontal" else
522+ ax .get_xaxis_transform ())
523+ elif thickness_unit == "font" :
524+ thickness = (font_properties .get_size () / 72 * thickness_value )
525+ transform = (
526+ blended_transform_factory (ax .transData , ax .figure .dpi_scale_trans )
527+ if rotation == "horizontal" else
528+ blended_transform_factory (ax .figure .dpi_scale_trans , ax .transData ))
490529
491530 # Create scale bar
492531 if rotation == "horizontal" :
493532 scale_rect = Rectangle (
494533 (0 , 0 ),
495534 length_px ,
496- width_px ,
535+ thickness ,
497536 fill = True ,
498537 facecolor = color ,
499538 edgecolor = "none" ,
500539 )
501540 else :
502541 scale_rect = Rectangle (
503542 (0 , 0 ),
504- width_px ,
543+ thickness ,
505544 length_px ,
506545 fill = True ,
507546 facecolor = color ,
508547 edgecolor = "none" ,
509548 )
510549
511- scale_bar_box = AuxTransformBox (ax . transData )
550+ scale_bar_box = AuxTransformBox (transform )
512551 scale_bar_box .add_artist (scale_rect )
513552
514553 # Create scale text
@@ -627,30 +666,45 @@ def set_length_fraction(self, fraction):
627666
628667 length_fraction = property (get_length_fraction , set_length_fraction )
629668
669+ def get_thickness (self ):
670+ return self ._thickness
671+
672+ def set_thickness (self , thickness ):
673+ if thickness is not None :
674+ _validate_dim (thickness )
675+ self ._thickness = thickness
676+
677+ thickness = property (get_thickness , set_thickness )
678+
630679 def get_width_fraction (self ):
631- return self ._width_fraction
680+ if self ._thickness is None :
681+ return None
682+ elif self ._thickness [1 ] == "saxis" :
683+ return self ._thickness [0 ]
684+ else :
685+ raise ValueError (f"thickness ({ self ._thickness } ) is not a width fraction" )
632686
633687 def set_width_fraction (self , fraction ):
634688 if fraction is not None :
635689 fraction = float (fraction )
636690 if fraction <= 0.0 or fraction > 1.0 :
637691 raise ValueError ("Width fraction must be between [0.0, 1.0]" )
638- self ._width_fraction = fraction
692+ self ._thickness = ( fraction , "saxis" )
639693
640694 width_fraction = property (get_width_fraction , set_width_fraction )
641695
642696 def get_height_fraction (self ):
643697 warnings .warn (
644698 "The get_height_fraction method is deprecated. "
645- "Use get_width_fraction instead." ,
699+ "Use get_thickness instead." ,
646700 DeprecationWarning ,
647701 )
648702 return self .width_fraction
649703
650704 def set_height_fraction (self , fraction ):
651705 warnings .warn (
652706 "The set_height_fraction method is deprecated. "
653- "Use set_width_fraction instead." ,
707+ "Use set_thickness instead." ,
654708 DeprecationWarning ,
655709 )
656710 self .width_fraction = fraction
0 commit comments