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
Some plotting and representation improvements #260
Some plotting and representation improvements #260
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## dev_master #260 +/- ##
==============================================
- Coverage 80.85% 80.55% -0.30%
==============================================
Files 143 143
Lines 14676 14736 +60
==============================================
+ Hits 11866 11871 +5
- Misses 2810 2865 +55
☔ View full report in Codecov by Sentry. |
if len(Gcf.figs) == 0: | ||
plt.figure(figsize=(12, 12)) | ||
if axes is None: | ||
fig, axes = plt.subplots(figsize=(12, 12)) |
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.
Should we keep the absolute figsize or should we leave that to the user? While 12in x 12in makes a nice LP cover, it is a tad too large for my computer screens.
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.
I don't know what the original motivation was for this giant plot, but I thought there might have been a good reason, so I left it in. That said, working on the .plot()
methods here motivated me to go over those in general for other classes (PR coming soon!) and the figure creation will be "outsourced" to a new function utils.figure_factory
anyway, so the explicit figsize
here will most likely go away as a result of that...
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.
Giant plots are needed to see where the spectral traces are actually positioned on the detector plane. However this should only be a default if someone hasn't already generated a figure or passed an Axes object.
Feel free to change this to something else if it's bothersome 👍
hdu = self[trace_id].rectify(hdulist, | ||
interps=interps, | ||
bin_width=bin_width, | ||
xi_min=xi_min, xi_max=xi_max, | ||
wave_min=wave_min, wave_max=wave_max) | ||
if hdu is not None: # ..todo: rectify does not do that yet | ||
outhdul.append(hdu) | ||
outhdul[0].header[f"EXTNAME{i+1}"] = trace_id | ||
outhdul[0].header[f"EXTNAME{i}"] = trace_id |
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.
i
is in the range [0, len(spec traces)]
from the enumerate call in line 302
The primary header EXTNAME0
will (should) never contain trace data.
Trace data should only be held in the additional FITS extensions 1..N, i.e. EXTNAME[1 ... len(spec traces)]
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.
If you look a few lines further up, I also changed the enumerate to enumerate(self.spectral_traces, start=1)
, which means i
is in range(1, len(self.spectral_traces) + 1)
. This (in general, not only in this example) has the benefits of more clearly marking the purpose of i
(we want values from 1, not 0) and saving to type +1
every time (which may cause bugs if forgotten once). Of course, this only makes sense if i
is only used as i+1
within that particular scope (which is the case here).
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.
Today I learned ... :)
aperture_id = self.meta["aperture_id"] | ||
lam_arr = self.table[self.meta["wave_colname"]] | ||
|
||
wave_max = np.max(lam_arr) | ||
wave_min = np.min(lam_arr) | ||
|
||
return {"wave_min": wave_min, "wave_max": wave_max, | ||
"trace_id": trace_id, "aperture_id": aperture_id} | ||
"trace_id": self.trace_id, "aperture_id": aperture_id} |
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.
Where is self.trace_id
first defined? I can't find it in __init__
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.
Or is this one of those new-fangled things that _class_param
dict entries can be accessed through self.
?
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.
It's a property that already existed anyway and is defined in (new) line 599. It should probably be a bit further up, it's somewhat "hidden in the jungle" now. I wrote that in my general list and will include it later.
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.
Apart from the question I have regarding the use of self.trace_id when this is not explicitly available from
self.or in the
_class_paramsdict, and the change back to
EXTNAME{i+1}`, it looks good to go.
Good job!
aperture_id = self.meta["aperture_id"] | ||
lam_arr = self.table[self.meta["wave_colname"]] | ||
|
||
wave_max = np.max(lam_arr) | ||
wave_min = np.min(lam_arr) | ||
|
||
return {"wave_min": wave_min, "wave_max": wave_max, | ||
"trace_id": trace_id, "aperture_id": aperture_id} | ||
"trace_id": self.trace_id, "aperture_id": aperture_id} |
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.
Or is this one of those new-fangled things that _class_param
dict entries can be accessed through self.
?
@@ -207,7 +206,7 @@ def map_spectra_to_focal_plane(self, fov): | |||
xilam = XiLamImage(fov, self.dlam_per_pix) | |||
self._xilamimg = xilam # ..todo: remove or make available with a debug flag? | |||
except ValueError: | |||
print(f" ---> {self.meta['trace_id']} gave ValueError") | |||
print(f" ---> {self.trace_id} gave ValueError") |
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.
Same as comment above
@@ -548,7 +624,7 @@ def __repr__(self): | |||
return f"{self.__class__.__name__}({self.table!r}, **{self.meta!r})" | |||
|
|||
def __str__(self): | |||
msg = (f"<SpectralTrace> \"{self.meta['trace_id']}\" : " | |||
msg = (f"<SpectralTrace> \"{self.trace_id}\" : " |
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.
Same as above with self.trace_id
SpectralTrace
,SpectralTraceList
andDetectorList
. They now usematplotlib
's "OOP mode" (i.e.fig, ax
instead of allplt.whatever
), as a first step to migrate all plotting related functions to that. This allows e.g. to easily plot the spectral traces into the detector layout plot by passing theaxes
object (this use-case was the main motivation for this modification). More configurability for the plot methods was added along the way, but the default behavior should remain the same as before._repr_pretty_
method was added to some classes, which is accessed by IPython to support a nicer human-readable representation of an object. This is currently very experimental, as there are multiple (not really compatible) ways to implement this. This will require more though, experimentation, and finally standardization. And probably a separate issue...