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-34625: Add sky coverage plots of visit summary quantities to analysis_tools #51
Conversation
ed41db8
to
45f22ef
Compare
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.
A few overall comments:
- Can you add the units for the colorbars?
- From the naming, i.e.
VisitCoveragePlot
, it isn't really clear that the plots are for multiple visits, and I think users might get mixed up with the visit-level plots. Maybe something likeMultiVisitCoveragePlot
? - Can you explain the "focalPlane" vs "raDec" plots options somewhere? Without looking at the examples, it isn't obvious that the focalPlane plot will give one number per detector, while the raDec is binned in ra/Dec.
I didn't go through the big makePlot
function as closely as I would have liked to, but I wanted to get this back to you before I go on break. I would be happy to look at it again, but if you want to get this merged, I will let you make the call on that.
setupRequired(daf_butler) | ||
setupRequired(geom) |
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.
Did you end up using this or meas_algorithms
, or are these existing dependencies that should have already been included? I didn't find them anywhere in this PR.
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.
Oh, yeah. When I realized I had to update this table, I figured I might as well check if other dependencies had been omitted. I found these (both occur in catalogMatch.py
).
xNumBins : `int`, optional | ||
The number of bins in along the x-axis to use in the binning. | ||
yNumBins : `int`, optional | ||
The number of bins in along the y-axis to use in the binning. |
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.
bins in along
-> bins along
, and to use in the binning
is redundant. Same thing at ln 682.
dataId = DataCoordinate.standardize(dataId, universe=butlerQC.registry.dimensions) | ||
plotInfo = self.parsePlotInfo(inputs, dataId) | ||
data = self.loadData(inputs["data"]) | ||
if "skymap" in inputs.keys(): |
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.
Can you make the if
statements for setting skymap
, camera
, and makeWarpConfig
all be written the same way? I.e. all one-liners or all multi-line statements.
from ..interfaces import AnalysisPlot | ||
|
||
|
||
class BaseVisitCoveragePlot(AnalysisPlot): |
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.
Maybe there has been discussion of this elsewhere, but is there a strong reason to have these in their own file, instead of in analysisPlots.py? I also think it would be helpful to have the filename be distinctly different from actions/plot/coveragePlot.py, as navigating analysis_tools
is already quite difficult.
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 of any official word on this, but I am going on the assumption that making analysisPlots
a subdirectory came with the intent of having the freedom/flexibility to separate the variously flavored actions out into separate files (where here the "flavor" is an x,y-plane "coverage"). Pilling more disparate plots classes into the generically named analysisPlots.py
is more confusing to me, so I'm going stick with this for now (but will happily accept a refactor if one is more concretely defined and affected!).
Taking on your other naming suggestion, the other file is now called actions/plot/multiVisitCoveragePlot.py
, so hopefully that helps at least a bit in distinguishing the two...but I'm totally with you on the difficulties in navigating this repo!
tickFmt : `matplotlib.ticker.FormatStrFormatter` | ||
The tick formatter to use with matplotlib functions. | ||
""" | ||
if np.abs(value) >= 10000: |
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 think you could write a formula for this, maybe something like
x = 4 - np.floor(np.log(np.abs(value)))
tickFmt = FormatStrFormatter(f"%.{x}f")
but I didn't check this, and it's up to you.
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 see where you're going...but I just can't get it to work. I tried with your incantation, but it required special casing to the point that what I have (despite the mess) is actually more readable (and has been battle tested to work as desired). Given that it's a "_private" function, I'm going to leave it as is (but would be very open to adapting another incantation that is more streamlined, but still works!, if one is suggested).
Parameters | ||
---------- | ||
value : `float` | ||
The the value used to determine the apporpriate formatting. |
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.
apporpriate
-> appropriate
optional=True, | ||
) | ||
projection = Field[str]( | ||
doc="Projection to plot. Currently only raDec and focalPlane are permitted.", |
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.
raDec and focalPlane should be in quotes for clarity.
default="raDec", | ||
) | ||
nBins = Field[int]( | ||
doc="Number of bins to use for the effective plot range in the raDec projection.", |
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.
A little unclear. Maybe "Number of bins to use in the effective plot range in the spatial direction. Only used in the raDec projection."?
"(regardless if they have any data in them).", | ||
default=False, | ||
) | ||
raDecLimitsDict = DictField[str, float]( |
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.
Can you just make the default None, and not have doUseRaDecLimits
, then only use this if it's not None?
if isScalar and typ != Scalar: | ||
raise ValueError(f"Data keyed by {name} has type {colType} but action requires type {typ}.") | ||
|
||
if "medianE" in self.parametersToPlotList: |
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.
Do you need more statements like this for all the other parameters to plot? Could you remove vectorsToLoadList
and just have a dict somewhere that gives the vectors needed? I'm a little concerned by the interplay between having to set vectorsToLoad
corresponding to the parametersToPlot
.
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.
Yeah, I'm not thrilled about the interplay either, but can't think of a better way. This is the only metric (at the moment) that is computed based on two entries in the table, so they can't be kept specifically in sync, so I added this check...but I believe it's really the only one required at present. (I did add one other validation on the entries in raDecLimitsDict
if that config is overridden.)
This is to enable use of this functionality in other plot actions.
859dc3b
to
73608d8
Compare
The coverage plots are based on the data in ccdVisitTable and are thus "by collection". Each visit gets one entry per detector. Parameter values can be plotted in either RA/Dec or Focal Plane projections.
73608d8
to
5623e10
Compare
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.
Can you add the units for the colorbars?
Added (where the parameters are not unitless).
From the naming, i.e. VisitCoveragePlot, it isn't really clear that the plots are for multiple visits, and I think users might get mixed up with the visit-level plots. Maybe something like MultiVisitCoveragePlot?
Suggestion adopted and action/plot filename changed to multiVisitCoveragePlot.py
.
Can you explain the "focalPlane" vs "raDec" plots options somewhere? Without looking at the examples, it isn't obvious that the focalPlane plot will give one number per detector, while the raDec is binned in ra/Dec.
They both plot the same data, just in different "projections", which I hoped would be clear with a config name of projection
. To (hopefully) help, I added the line:
"In either case, one point is plotted per visit/detector combination."
to the docstring.
setupRequired(daf_butler) | ||
setupRequired(geom) |
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.
Oh, yeah. When I realized I had to update this table, I figured I might as well check if other dependencies had been omitted. I found these (both occur in catalogMatch.py
).
from ..interfaces import AnalysisPlot | ||
|
||
|
||
class BaseVisitCoveragePlot(AnalysisPlot): |
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 of any official word on this, but I am going on the assumption that making analysisPlots
a subdirectory came with the intent of having the freedom/flexibility to separate the variously flavored actions out into separate files (where here the "flavor" is an x,y-plane "coverage"). Pilling more disparate plots classes into the generically named analysisPlots.py
is more confusing to me, so I'm going stick with this for now (but will happily accept a refactor if one is more concretely defined and affected!).
Taking on your other naming suggestion, the other file is now called actions/plot/multiVisitCoveragePlot.py
, so hopefully that helps at least a bit in distinguishing the two...but I'm totally with you on the difficulties in navigating this repo!
tickFmt : `matplotlib.ticker.FormatStrFormatter` | ||
The tick formatter to use with matplotlib functions. | ||
""" | ||
if np.abs(value) >= 10000: |
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 see where you're going...but I just can't get it to work. I tried with your incantation, but it required special casing to the point that what I have (despite the mess) is actually more readable (and has been battle tested to work as desired). Given that it's a "_private" function, I'm going to leave it as is (but would be very open to adapting another incantation that is more streamlined, but still works!, if one is suggested).
if isScalar and typ != Scalar: | ||
raise ValueError(f"Data keyed by {name} has type {colType} but action requires type {typ}.") | ||
|
||
if "medianE" in self.parametersToPlotList: |
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.
Yeah, I'm not thrilled about the interplay either, but can't think of a better way. This is the only metric (at the moment) that is computed based on two entries in the table, so they can't be kept specifically in sync, so I added this check...but I believe it's really the only one required at present. (I did add one other validation on the entries in raDecLimitsDict
if that config is overridden.)
Coming in here super late, but I don't see |
Sigh...indeed, you are correct (and thank you very much for pointing this out!) I definitely still want the ability to make these plots, so I guess I should make a ticket to (fix any bitrot) and add a pipeline to the repo. Do you know how tasks that aren't necessarily run in the "core" pipelines get tested/CI'd? |
Oh, I definitely want to reuse this task but found that I had to comment out one line to be able to run it (hence the bitrot comment). I think having a pipeline that could be run would be a good start. If you want it CI'd, you probably need a test with made up data similar to this one: https://github.com/lsst/analysis_tools/blob/main/tests/test_catalogMatch.py |
Ah, ok, thanks! How would you like to proceed? Shall I make a ticket as I suggest above, or will your pipeline & bitrot fix(?) be suitable (modulo the ci option...)? |
I think you should add the |
Sounds good. I'll try to get to that soon...ish! |
No description provided.