Skip to content

Commit

Permalink
Skip doomed matplotlib/numpy calls
Browse files Browse the repository at this point in the history
  • Loading branch information
taranu committed May 3, 2023
1 parent 4b37866 commit a516654
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 75 deletions.
150 changes: 78 additions & 72 deletions python/lsst/analysis/tools/actions/plot/histPlot.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,74 +412,77 @@ def _makePanel(self, data, panel, ax, colors, label_font_size=9, legend_font_siz
meds.append(med)
mads.append(mad)
panel_range = self._getPanelRange(data, panel, mads=mads, meds=meds)

for i, hist in enumerate(self.panels[panel].hists):
hist_data = data[hist][np.isfinite(data[hist])]
ax.hist(
hist_data,
range=panel_range,
bins=self.panels[panel].bins,
histtype="step",
density=self.panels[panel].histDensity,
lw=2,
color=colors[i],
label=self.panels[panel].hists[hist],
)
ax.axvline(meds[i], ls=(0, (5, 3)), lw=1, c=colors[i])

ax.legend(fontsize=legend_font_size, loc="upper left", frameon=False)
ax.set_xlim(panel_range)
# The following accommodates spacing for ranges with large numbers
# but small-ish dynamic range (example use case: RA 300-301).
if ncols > 1 and max(np.abs(panel_range)) >= 100 and (panel_range[1] - panel_range[0]) < 5:
ax.xaxis.set_major_formatter("{x:.2f}")
ax.tick_params(axis="x", labelrotation=25, pad=-1)
ax.set_xlabel(self.panels[panel].label, fontsize=label_font_size)
y_label = "Normalized (PDF)" if self.panels[panel].histDensity else "Frequency"
ax.set_ylabel(y_label, fontsize=label_font_size)
ax.set_yscale(self.panels[panel].yscale)
ax.tick_params(labelsize=max(5, label_font_size - 2))
# add a buffer to the top of the plot to allow headspace for labels
ylims = list(ax.get_ylim())
if ax.get_yscale() == "log":
ylims[1] = 10 ** (np.log10(ylims[1]) * 1.1)
if all(np.isfinite(panel_range)):
for i, hist in enumerate(self.panels[panel].hists):
hist_data = data[hist][np.isfinite(data[hist])]
if len(hist_data) > 0:
ax.hist(
hist_data,
range=panel_range,
bins=self.panels[panel].bins,
histtype="step",
density=self.panels[panel].histDensity,
lw=2,
color=colors[i],
label=self.panels[panel].hists[hist],
)
ax.axvline(meds[i], ls=(0, (5, 3)), lw=1, c=colors[i])

ax.legend(fontsize=legend_font_size, loc="upper left", frameon=False)
ax.set_xlim(panel_range)
# The following accommodates spacing for ranges with large numbers
# but small-ish dynamic range (example use case: RA 300-301).
if ncols > 1 and max(np.abs(panel_range)) >= 100 and (panel_range[1] - panel_range[0]) < 5:
ax.xaxis.set_major_formatter("{x:.2f}")
ax.tick_params(axis="x", labelrotation=25, pad=-1)
ax.set_xlabel(self.panels[panel].label, fontsize=label_font_size)
y_label = "Normalized (PDF)" if self.panels[panel].histDensity else "Frequency"
ax.set_ylabel(y_label, fontsize=label_font_size)
ax.set_yscale(self.panels[panel].yscale)
ax.tick_params(labelsize=max(5, label_font_size - 2))
# add a buffer to the top of the plot to allow headspace for labels
ylims = list(ax.get_ylim())
if ax.get_yscale() == "log":
ylims[1] = 10 ** (np.log10(ylims[1]) * 1.1)
else:
ylims[1] *= 1.1
ax.set_ylim(ylims[0], ylims[1])

# Draw a vertical line at a reference value, if given.
# If histDensity is True, also plot a reference PDF with
# mean = referenceValue and sigma = 1 for reference.
if self.panels[panel].referenceValue is not None:
ax = self._addReferenceLines(ax, panel, panel_range, legend_font_size=legend_font_size)

# Check if we should use the default stats panel or if a custom one
# has been created.
statList = [
self.panels[panel].statsPanel.stat1,
self.panels[panel].statsPanel.stat2,
self.panels[panel].statsPanel.stat3,
]
if not any(statList):
stats_dict = {
"statLabels": ["N$_{{data}}$", "Med", "${{\\sigma}}_{{MAD}}$"],
"stat1": nums,
"stat2": meds,
"stat3": mads,
}
elif all(statList):
stat1 = [data[stat] for stat in self.panels[panel].statsPanel.stat1]
stat2 = [data[stat] for stat in self.panels[panel].statsPanel.stat2]
stat3 = [data[stat] for stat in self.panels[panel].statsPanel.stat3]
stats_dict = {
"statLabels": self.panels[panel].statsPanel.statsLabels,
"stat1": stat1,
"stat2": stat2,
"stat3": stat3,
}
else:
raise RuntimeError("Invalid configuration of HistStatPanel")
else:
ylims[1] *= 1.1
ax.set_ylim(ylims[0], ylims[1])

# Draw a vertical line at a reference value, if given. If histDensity
# is True, also plot a reference PDF with mean = referenceValue and
# sigma = 1 for reference.
if self.panels[panel].referenceValue is not None:
ax = self._addReferenceLines(ax, panel, panel_range, legend_font_size=legend_font_size)

# Check if we should use the default stats panel or if a custom one
# has been created.
statList = [
self.panels[panel].statsPanel.stat1,
self.panels[panel].statsPanel.stat2,
self.panels[panel].statsPanel.stat3,
]
if not any(statList):
stats_dict = {
"statLabels": ["N$_{{data}}$", "Med", "${{\\sigma}}_{{MAD}}$"],
"stat1": nums,
"stat2": meds,
"stat3": mads,
}
elif all(statList):
stat1 = [data[stat] for stat in self.panels[panel].statsPanel.stat1]
stat2 = [data[stat] for stat in self.panels[panel].statsPanel.stat2]
stat3 = [data[stat] for stat in self.panels[panel].statsPanel.stat3]
stats_dict = {
"statLabels": self.panels[panel].statsPanel.statsLabels,
"stat1": stat1,
"stat2": stat2,
"stat3": stat3,
}
else:
raise RuntimeError("Invalid configuration of HistStatPanel")

stats_dict = {key: [] for key in ("stat1", "stat2", "stat3")}
stats_dict["statLabels"] = [""] * 3
return nums, meds, mads, stats_dict

def _getPanelRange(self, data, panel, mads=None, meds=None):
Expand Down Expand Up @@ -515,11 +518,14 @@ def _getPercentilePanelRange(self, data, panel):
"""Determine panel x-axis range based on data percentile limits."""
panel_range = [np.nan, np.nan]
for hist in self.panels[panel].hists:
hist_range = np.nanpercentile(
data[hist], [self.panels[panel].lowerRange, self.panels[panel].upperRange]
)
panel_range[0] = np.nanmin([panel_range[0], hist_range[0]])
panel_range[1] = np.nanmax([panel_range[1], hist_range[1]])
data_hist = data[hist]
# TODO: Consider raising instead
if len(data_hist) > 0:
hist_range = np.nanpercentile(
data[hist], [self.panels[panel].lowerRange, self.panels[panel].upperRange]
)
panel_range[0] = np.nanmin([panel_range[0], hist_range[0]])
panel_range[1] = np.nanmax([panel_range[1], hist_range[1]])
return panel_range

def _calcStats(self, data):
Expand Down
12 changes: 9 additions & 3 deletions python/lsst/analysis/tools/actions/plot/skyPlot.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,10 +295,16 @@ def makePlot(
)

for i, (xs, ys, colorVals, cmap, label) in enumerate(toPlotList):
xs = xs[np.isfinite(xs)]
ys = ys[np.isfinite(ys)]
finite = np.isfinite(xs) & np.isfinite(ys)
xs = xs[finite]
ys = ys[finite]
n_xs = len(xs)
if (n_xs < 5) or (n_xs != len(ys)):
# colorVal column is unusable so zero it out
# This should be obvious on the plot
if not any(np.isfinite(colorVals)):
colorVals[:] = 0

if n_xs < 5:
continue
if not self.plotOutlines or "tract" not in sumStats.keys():
minRa = np.min(xs)
Expand Down

0 comments on commit a516654

Please sign in to comment.