Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,35 @@ ax.add_artist(scalebar)
fig.savefig("original_resolution.png", dpi=dpi)
```

### Information about the drawn scale bar

After the scale bar has been drawn, the `info` property returns the following dataclass.

```python
@dataclasses.dataclass
class ScaleBarInfo:
length_px: int
value: float
units: str
scale_text: str
window_extent: matplotlib.transforms.Bbox
```

Note that the `info` property returns a `ValueError` exception if the scale bar has not been drawn.

```python
fig, ax = plt.subplots()

scalebar = ScaleBar(0.08, "cm", length_fraction=0.25)
ax.add_artist(scalebar)

print(scalebar.info) # raises a ValueError exception

fig.canvas.draw()

print(scalebar.info) # works
```

## ScaleBar arguments

Here are arguments of the **ScaleBar** class constructor and examples how to use them.
Expand Down
23 changes: 23 additions & 0 deletions matplotlib_scalebar/scalebar.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
# Standard library modules.
import bisect
import warnings
import dataclasses

# Third party modules.
import matplotlib
Expand Down Expand Up @@ -142,6 +143,15 @@ def _validate_legend_loc(loc):
}


@dataclasses.dataclass
class ScaleBarInfo:
length_px: int
value: float
units: str
scale_text: str
window_extent: matplotlib.transforms.Bbox


class ScaleBar(Artist):
zorder = 6

Expand Down Expand Up @@ -368,6 +378,7 @@ def __init__(
self.rotation = rotation
self.bbox_to_anchor = bbox_to_anchor
self.bbox_transform = bbox_transform
self._info = None

def _calculate_best_length(self, length_px):
dx = self.dx
Expand All @@ -393,6 +404,8 @@ def _calculate_exact_length(self, value, units):
return newvalue / self.dx

def draw(self, renderer, *args, **kwargs):
self._info = None

if not self.get_visible():
return
if self.dx == 0:
Expand Down Expand Up @@ -555,6 +568,10 @@ def _get_value(attr, default):
box.patch.set_alpha(box_alpha)
box.draw(renderer)

self._info = ScaleBarInfo(
length_px, value, units, scale_text, box.get_window_extent(renderer)
)

def get_dx(self):
return self._dx

Expand Down Expand Up @@ -841,3 +858,9 @@ def set_bbox_transform(self, bbox_transform):
self._bbox_transform = bbox_transform

bbox_transform = property(get_bbox_transform, set_bbox_transform)

@property
def info(self):
if self._info is None:
raise ValueError("Scale bar has not been drawn. Call figure.canvas.draw()")
return self._info
29 changes: 29 additions & 0 deletions tests/test_scalebar.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,3 +369,32 @@ def test_bbox_transform(scalebar):
scalebar.bbox_transform = scalebar.axes.transAxes
assert scalebar.get_bbox_transform() == scalebar.axes.transAxes
assert scalebar.bbox_transform == scalebar.axes.transAxes


def test_info():
fig = plt.figure()
ax = fig.add_subplot(111)

data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
ax.imshow(data)

scalebar = ScaleBar(0.5)
ax.add_artist(scalebar)

with pytest.raises(ValueError):
scalebar.info

plt.draw()

info = scalebar.info
assert info.length_px == pytest.approx(0.4, 1e-4)
assert info.value == pytest.approx(2, 1e-4)
assert info.units == "dm"
assert info.scale_text == "2 dm"
assert info.window_extent.x0 == pytest.approx(456.5755555555555, 1e-4)
assert info.window_extent.y0 == pytest.approx(390.81511111111104, 1e-4)
assert info.window_extent.x1 == pytest.approx(511.4111111111111, 1e-4)
assert info.window_extent.y1 == pytest.approx(421.01111111111106, 1e-4)

plt.close()
del fig
Loading