-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DM-40359: Implement Butler.get for matplotlib generated png files #877
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,9 @@ | |
|
||
from typing import Any | ||
|
||
import matplotlib.pyplot as plt | ||
import numpy as np | ||
|
||
from .file import FileFormatter | ||
|
||
|
||
|
@@ -38,8 +41,22 @@ | |
|
||
def _readFile(self, path: str, pytype: type[Any] | None = None) -> Any: | ||
# docstring inherited from FileFormatter._readFile | ||
raise NotImplementedError(f"matplotlib figures cannot be read by the butler; path is {path}") | ||
return plt.imread(path) | ||
|
||
def _writeFile(self, inMemoryDataset: Any) -> None: | ||
# docstring inherited from FileFormatter._writeFile | ||
inMemoryDataset.savefig(self.fileDescriptor.location.path) | ||
|
||
@staticmethod | ||
def fromArray(cls: np.ndarray) -> plt.Figure: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not need to be a static method in the formatter class. It's okay for this to be a private function in the file that is not exported and only referenced from the yaml file. The first parameter should not be named |
||
"""Convert an array into a Figure.""" | ||
fig = plt.figure() | ||
plt.imshow(cls) | ||
return fig | ||
|
||
@staticmethod | ||
def dummyCovnerter(cls: np.ndarray) -> np.ndarray: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name has a typo in it. Also see comment about naming I make above. I am confused by the signature. Surely this should take a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, this is just what the name says, a dummy converter. This is what I was trying to get across in slack: In some cases we want to just load the png file directly, although a numpy array is fine. Yes, it is possible to convert a Figure to a numpy array, but it's messy. You basically have to create a dummy file, save the figure to the dummy file, then read the dummy file as a numpy array. 👎 I did the cursory stack overflow search, and that was the recommended solution. I also looked at the matplotlib codebase a bit and it does indeed look like it would be non-trivial to try and convert the figure to a numpy array directly. This is probably why the method wasn't implemented in the first place. The other solution that I thought of is that we could define a
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Completely untested but can something like this work? def fig_to_np(fig: pyplot.figure.Figure) -> np.ndarray:
buf = io.BytesIO()
fig.savefig(buf, format="png")
return plt.imread(buf, format="png") ? |
||
"""This converter exists to trick the Butler into allowing | ||
a numpy array on read with ``storageClass='NumpyArray'``. | ||
""" | ||
Check failure on line 61 in python/lsst/daf/butler/formatters/matplotlib.py GitHub Actions / ruffRuff (D401)
|
||
return cls | ||
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -27,6 +27,8 @@ | |||||
import unittest | ||||||
from random import Random | ||||||
|
||||||
import numpy as np | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be a protected import since numpy is not butler requirement (although effectively it is since astropy won't work without it). |
||||||
|
||||||
try: | ||||||
import matplotlib | ||||||
|
||||||
|
@@ -78,8 +80,13 @@ def testMatplotlibFormatter(self): | |||||
pyplot.gcf().savefig(file.name) | ||||||
self.assertTrue(filecmp.cmp(local.ospath, file.name, shallow=True)) | ||||||
self.assertTrue(butler.exists(ref)) | ||||||
with self.assertRaises(ValueError): | ||||||
butler.get(ref) | ||||||
|
||||||
fig = butler.get(ref) | ||||||
# Ensure that the result is a figure | ||||||
self.assertTrue(isinstance(fig, pyplot.Figure)) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
image = butler.get(ref, storageClass="NumpyArray") | ||||||
self.assertTrue(isinstance(image, np.ndarray)) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
butler.pruneDatasets([ref], unstore=True, purge=True) | ||||||
self.assertFalse(butler.exists(ref)) | ||||||
|
||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that this is returning something unexpected (and effectively backwards from expectations) please add a comment saying that it's not returning a figure.