Fine adjustment of the scalebar position.
altanir84 opened this issue · 6 comments
Is there a way to fine adjust the scalebar position? I need to place the scalebar at the lower right of a image, but there is a label that also needs to be there and I´d like to raise the scalebar a few pixels, so both will be on the lower right but not overlapping each other.
Hi @altanir84, you could perhaps pass border_pad
?
>>> import matplotlib.pyplot as plt
>>> from matplotlib_scalebar.scalebar import ScaleBar
>>> import numpy as np
>>> a = np.random.normal(size=100).reshape((10, 10))
>>> legend_kwds = dict(x=8, y=9, s="legend", bbox=dict(facecolor="w"))
>>> fig, ax = plt.subplots(ncols=2, figsize=(10, 5))
>>> ax[0].imshow(a)
>>> ax[0].text(**legend_kwds)
>>> ax[0].add_artist(ScaleBar(1, "px", dimension="pixel-length", location="lower right"))
>>> ax[1].imshow(a)
>>> ax[1].text(**legend_kwds)
>>> ax[1].add_artist(ScaleBar(1, "px", dimension="pixel-length", location="lower right", border_pad=3))
Horizontal and vertical padding will be the same, which isn't optimal, but you can at least move it diagonally away from the lower right corner. Actually, I think you might be better off changing the legend position.
Thank you for the quick reply.
I´ve tried passing the border_pad argument, but the problem is that I´m working on generating thousands of images with a strict layout and I can´t change that because of the company´s layout standards for such images. I was looking for something like tkinter´s pady and padx.
So, I managed to get it working by downloading the scalebar.py and dimensions.py to my working folder and changed it a little bit to enable the bbox_to_anchor argument to be passed. I guess it could be a future update to the module!
What I did:
Open scalebar.py
class ScaleBar(Artist):
def init(
...
add this after rotation=None :
bbox_to_anchor=None, # bbox that the legend will be anchored.
bbox_transform=None, # transform for the bbox
add this after self.rotation = rotation :
self.bbox_to_anchor = bbox_to_anchor
...
def draw(self,renderer,*args,**kwargs):
add this after label = self.label :
bbox_to_anchor = self.bbox_to_anchor
now scroll down to # Create final offset box :
We need to insert a if-else statement, to verify if the argument bbox_to_anchor was passed. Place
it just before the box = AnchoredOffsetbox( and mind the indentation.
if bbox_to_anchor != None:
box = AnchoredOffsetbox(loc=location, pad=pad, child=child, frameon=frameon,
bbox_to_anchor=bbox_to_anchor, bbox_transform=ax.transAxes)
else:
save it and place both py files on the work dir and import it using
from scalebar import ScaleBar
Now the ScaleBar can take a tuple to define where the scalebar will be placed.
example:
scalebar = ScaleBar(resolution, length_fraction=0.3, units='mm', color='red',
box_color='black',bbox_to_anchor=(1,0.1))
Great! I suppose passing bbox_to_anchor
overrides location
?
Oops, sorry! I forgot to remove the location argument. When using both, weird stuff happens. It´s better to use only one of them.
If the module gets updated to use bbox_to_anchor in the future, great. If not, this workaround can be used.