Skip to content

Commit c70565b

Browse files
authored
Merge pull request #79 from mdecleir/refine_plotting
Refine plotting
2 parents 5be6588 + 7c20f04 commit c70565b

File tree

8 files changed

+213
-85
lines changed

8 files changed

+213
-85
lines changed
-115 KB
Binary file not shown.

measure_extinction/extdata.py

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from astropy.io import fits
88
from scipy.optimize import curve_fit
99

10-
from dust_extinction.parameter_averages import F04
1110
from astropy.modeling.powerlaws import PowerLaw1D
1211
from astropy.modeling import Parameter
1312
from astropy.modeling.fitting import LevMarLSQFitter
@@ -98,7 +97,7 @@ def _get_column_val(column):
9897
return float(column)
9998

10099

101-
def AverageExtData(extdatas):
100+
def AverageExtData(extdatas, min_number=3):
102101
"""
103102
Generate the average extinction curve from a list of ExtData objects
104103
@@ -107,6 +106,9 @@ def AverageExtData(extdatas):
107106
extdatas : list of ExtData objects
108107
list of extinction curves to average
109108
109+
min_number : int [default=3]
110+
minimum number of extinction curves that are required to measure the average extinction; if less than min_number of curves are available at certain wavelengths, the average extinction will still be calculated, but the number of points (npts) at those wavelengths will be set to zero (e.g. used in the plotting)
111+
110112
Returns
111113
-------
112114
aveext: ExtData object
@@ -117,7 +119,8 @@ def AverageExtData(extdatas):
117119
names = []
118120
bwaves = []
119121
for extdata in extdatas:
120-
# check the data type of the extinction curves, and convert if needed
122+
# check the data type of the extinction curve, and convert if needed
123+
# the average curve must be calculated from the A(lambda)/A(V) curves
121124
if extdata.type != "alav" or extdata.type != "alax":
122125
extdata.trans_elv_alav()
123126

@@ -136,7 +139,7 @@ def AverageExtData(extdatas):
136139
aveext.type = extdatas[0].type
137140
aveext.type_rel_band = extdatas[0].type_rel_band
138141

139-
# calculate the average for all spectral data
142+
# collect all the extinction data
140143
bexts = {k: [] for k in aveext.names["BAND"]}
141144
for src in keys:
142145
exts = []
@@ -149,27 +152,39 @@ def AverageExtData(extdatas):
149152
extdata.exts[src][np.where(extdata.npts[src] == 0)] = np.nan
150153
exts.append(extdata.exts[src])
151154

155+
# calculate the average and uncertainties of the band extinction data
152156
if src == "BAND":
153-
aveext.exts["BAND"] = []
154-
aveext.npts["BAND"] = []
155-
aveext.stds["BAND"] = []
156-
aveext.uncs["BAND"] = []
157-
for name in aveext.names["BAND"]:
158-
aveext.exts["BAND"].append(np.nanmean(bexts[name]))
159-
aveext.npts["BAND"].append(len(bexts[name]))
157+
aveext.exts["BAND"] = np.zeros(len(names))
158+
aveext.npts["BAND"] = np.zeros(len(names))
159+
aveext.stds["BAND"] = np.zeros(len(names))
160+
aveext.uncs["BAND"] = np.zeros(len(names))
161+
for i, name in enumerate(aveext.names["BAND"]):
162+
aveext.exts["BAND"][i] = np.nanmean(bexts[name])
163+
aveext.npts["BAND"][i] = len(bexts[name])
160164

161165
# calculation of the standard deviation (this is the spread of the sample around the population mean)
162-
aveext.stds["BAND"].append(np.nanstd(bexts[name], ddof=1))
166+
aveext.stds["BAND"][i] = np.nanstd(bexts[name], ddof=1)
163167

164168
# calculation of the standard error of the average (the standard error of the sample mean is an estimate of how far the sample mean is likely to be from the population mean)
165169
aveext.uncs["BAND"] = aveext.stds["BAND"] / np.sqrt(aveext.npts["BAND"])
166170

171+
# calculate the average and uncertainties of the spectral extinction data
167172
else:
168173
aveext.exts[src] = np.nanmean(exts, axis=0)
169174
aveext.npts[src] = np.sum(~np.isnan(exts), axis=0)
170175
aveext.stds[src] = np.nanstd(exts, axis=0, ddof=1)
171176
aveext.uncs[src] = aveext.stds[src] / np.sqrt(aveext.npts[src])
172177

178+
# take out the data points where less than a certain number of values was averaged, and give a warning
179+
if min_number > 1:
180+
aveext.npts[src][aveext.npts[src] < min_number] = 0
181+
warnings.warn(
182+
"The minimum number of "
183+
+ str(min_number)
184+
+ " extinction curves was not reached for certain wavelengths, and the number of points (npts) for those wavelengths was set to 0.",
185+
UserWarning,
186+
)
187+
173188
return aveext
174189

175190

@@ -490,14 +505,12 @@ def calc_RV(self):
490505

491506
def trans_elv_alav(self, av=None, akav=0.112):
492507
"""
493-
Transform E(lambda-V) to A(lambda)/A(V) by normalizing to
494-
A(V) and adding 1. Default is to calculate A(V) from the
495-
input elx curve. If A(V) value is passed, use that one instead.
508+
Transform E(lambda-V) to A(lambda)/A(V) by normalizing to A(V) and adding 1. If A(V) is in the columns of the extdata object, use that value. If A(V) is passed explicitly, use that value instead. If no A(V) is available, calculate A(V) from the input elx curve.
496509
497510
Parameters
498511
----------
499512
av : float [default = None]
500-
value of A(V) to use - otherwise calculate it
513+
value of A(V) to use - otherwise take it from the columns of the object or calculate it
501514
502515
akav : float [default = 0.112]
503516
Value of A(K)/A(V), only needed if A(V) has to be calculated from the K-band extinction
@@ -514,10 +527,11 @@ def trans_elv_alav(self, av=None, akav=0.112):
514527
)
515528
else:
516529
if av is None:
517-
self.calc_AV(akav=akav)
530+
if "AV" not in self.columns.keys():
531+
self.calc_AV(akav=akav)
532+
av = _get_column_val(self.columns["AV"])
518533

519534
for curname in self.exts.keys():
520-
av = _get_column_val(self.columns["AV"])
521535
self.exts[curname] = (self.exts[curname] / av) + 1
522536
self.uncs[curname] /= av
523537
# update the extinction curve type
@@ -1091,19 +1105,8 @@ def plot(
10911105
fontsize for plot
10921106
"""
10931107
if alax:
1094-
# compute A(V) if it is not available
1095-
if "AV" not in self.columns.keys():
1096-
self.trans_elv_alav()
1097-
av = _get_column_val(self.columns["AV"])
1098-
if self.type_rel_band != "V": # not sure if this works (where is RV given?)
1099-
# use F04 model to convert AV to AX
1100-
rv = _get_column_val(self.columns["RV"])
1101-
emod = F04(rv)
1102-
(indx,) = np.where(self.type_rel_band == self.names["BAND"])
1103-
axav = emod(self.waves["BAND"][indx[0]])
1104-
else:
1105-
axav = 1.0
1106-
ax = axav * av
1108+
# transform the extinctions from E(lambda-V) to A(lambda)/A(V)
1109+
self.trans_elv_alav()
11071110

11081111
for curtype in self.waves.keys():
11091112
# do not plot the excluded data type(s)
@@ -1115,13 +1118,6 @@ def plot(
11151118
y = self.exts[curtype]
11161119
yu = self.uncs[curtype]
11171120

1118-
if (
1119-
alax and self.type == "elx"
1120-
): # in the case A(V) was already available and the curve has not been transformed yet
1121-
# convert E(lambda-X) to A(lambda)/A(X)
1122-
y = (y / ax) + 1.0
1123-
yu /= ax
1124-
11251121
y = y / normval + yoffset
11261122
yu = yu / normval
11271123

@@ -1160,6 +1156,7 @@ def plot(
11601156
color=annotate_color,
11611157
horizontalalignment="left",
11621158
rotation=annotate_rotation,
1159+
rotation_mode="anchor",
11631160
fontsize=fontsize,
11641161
)
11651162

measure_extinction/plotting/plot_ext.py

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,22 @@
99
import numpy as np
1010
import astropy.units as u
1111
import pandas as pd
12+
import os
1213

1314
from measure_extinction.extdata import ExtData
14-
from measure_extinction.utils.calc_ext import calc_ave_ext
1515
from dust_extinction.parameter_averages import CCM89
1616

1717

1818
def plot_average(
19-
starpair_list,
2019
path,
20+
filename="average_ext.fits",
2121
ax=None,
2222
extmodels=False,
2323
fitmodel=False,
2424
HI_lines=False,
2525
range=None,
2626
exclude=[],
27+
log=False,
2728
spread=False,
2829
annotate_key=None,
2930
annotate_wave_range=None,
@@ -34,11 +35,11 @@ def plot_average(
3435
3536
Parameters
3637
----------
37-
starpair_list : list of strings
38-
List of star pairs for which to calculate and plot the average extinction curve, in the format "reddenedstarname_comparisonstarname" (no spaces)
39-
4038
path : string
41-
Path to the data files
39+
Path to the average extinction curve fits file
40+
41+
filename : string [default="average_ext.fits"]
42+
Name of the average extinction curve fits file
4243
4344
ax : AxesSubplot [default=None]
4445
Axes of plot on which to add the average extinction curve if pdf=False
@@ -58,14 +59,17 @@ def plot_average(
5859
exclude : list of strings [default=[]]
5960
List of data type(s) to exclude from the plot (e.g., IRS)
6061
62+
log : boolean [default=False]
63+
Whether or not to plot the wavelengths on a log-scale
64+
6165
spread : boolean [default=False]
62-
Whether or not to offset the average extinction curve from the other curves
66+
Whether or not to offset the average extinction curve from the other curves (only relevant when pdf=False and ax=None)
6367
6468
annotate_key : string [default=None]
65-
type of data for which to annotate text (e.g., SpeX_LXD)
69+
type of data for which to annotate text (e.g., SpeX_LXD) (only relevant when pdf=False and ax=None)
6670
6771
annotate_wave_range : list of 2 floats [default=None]
68-
min/max wavelength range for the annotation of the text
72+
min/max wavelength range for the annotation of the text (only relevant when pdf=False and ax=None)
6973
7074
pdf : boolean [default=False]
7175
- If False, the average extinction curve will be overplotted on the current plot (defined by ax)
@@ -75,11 +79,18 @@ def plot_average(
7579
-------
7680
Plots the average extinction curve
7781
"""
78-
# calculate the average extinction curve
79-
calc_ave_ext(starpair_list, path)
80-
81-
# read in the average extinction curve
82-
average = ExtData(path + "average_ext.fits")
82+
# read in the average extinction curve (if it exists)
83+
if os.path.isfile(path + filename):
84+
average = ExtData(path + filename)
85+
else:
86+
warnings.warn(
87+
"An average extinction curve with the name "
88+
+ filename
89+
+ " could not be found in "
90+
+ path
91+
+ ". Please calculate the average extinction curve first with the calc_ave_ext function in measure_extinction/utils/calc_ext.py.",
92+
UserWarning,
93+
)
8394

8495
# make a new plot if requested
8596
if pdf:
@@ -116,14 +127,17 @@ def plot_average(
116127
zoom(ax, range)
117128

118129
# finish configuring the plot
119-
ax.set_title("average", fontsize=50)
120-
ax.set_xscale("log")
130+
if log:
131+
ax.set_xscale("log")
121132
plt.xlabel(r"$\lambda$ [$\mu m$]", fontsize=1.5 * fontsize)
122133
ax.set_ylabel(
123134
average._get_ext_ytitle(ytype=average.type), fontsize=1.5 * fontsize
124135
)
125136
fig.savefig(path + "average_ext.pdf", bbox_inches="tight")
126137

138+
# return the figure and axes for additional manipulations
139+
return fig, ax
140+
127141
else:
128142
if spread:
129143
yoffset = -0.3
@@ -258,6 +272,7 @@ def plot_fitmodel(extdata, yoffset=0, res=False):
258272
plt.axhline(ls="--", c="k", alpha=0.5)
259273
plt.axhline(y=0.05, ls=":", c="k", alpha=0.5)
260274
plt.axhline(y=-0.05, ls=":", c="k", alpha=0.5)
275+
plt.ylim(-0.1, 0.1)
261276
plt.ylabel("residual")
262277

263278
else:
@@ -359,6 +374,9 @@ def plot_multi_extinction(
359374
range=None,
360375
spread=False,
361376
exclude=[],
377+
log=False,
378+
text_offsets=[],
379+
text_angles=[],
362380
pdf=False,
363381
):
364382
"""
@@ -396,6 +414,15 @@ def plot_multi_extinction(
396414
exclude : list of strings [default=[]]
397415
List of data type(s) to exclude from the plot (e.g., IRS)
398416
417+
log : boolean [default=False]
418+
Whether or not to plot the wavelengths on a log-scale
419+
420+
text_offsets : list of floats [default=[]]
421+
List of the same length as starpair_list with offsets for the annotated text
422+
423+
text_angles : list of integers [default=[]]
424+
List of the same length as starpair_list with rotation angles for the annotated text
425+
399426
pdf : boolean [default=False]
400427
Whether or not to save the figure as a pdf file
401428
@@ -419,13 +446,19 @@ def plot_multi_extinction(
419446
fig, ax = plt.subplots(figsize=(15, len(starpair_list) * 1.25))
420447
colors = plt.get_cmap("tab10")
421448

449+
# set default text offsets and angles
450+
if text_offsets == []:
451+
text_offsets = np.full(len(starpair_list), 0.2)
452+
if text_angles == []:
453+
text_angles = np.full(len(starpair_list), 10)
454+
422455
for i, starpair in enumerate(starpair_list):
423456
# read in the extinction curve data
424457
extdata = ExtData("%s%s_ext.fits" % (path, starpair.lower()))
425458

426459
# spread out the curves if requested
427460
if spread:
428-
yoffset = 0.3 * i
461+
yoffset = 0.25 * i
429462
else:
430463
yoffset = 0.0
431464

@@ -455,8 +488,8 @@ def plot_multi_extinction(
455488
annotate_key=ann_key,
456489
annotate_wave_range=ann_range,
457490
annotate_text=extdata.red_file.split(".")[0].upper(),
458-
annotate_yoffset=-0.1,
459-
annotate_rotation=-15,
491+
annotate_yoffset=text_offsets[i],
492+
annotate_rotation=text_angles[i],
460493
annotate_color=colors(i % 10),
461494
)
462495

@@ -477,7 +510,6 @@ def plot_multi_extinction(
477510
# plot the average extinction curve if requested
478511
if average:
479512
plot_average(
480-
starpair_list,
481513
path,
482514
ax=ax,
483515
extmodels=extmodels,
@@ -501,16 +533,23 @@ def plot_multi_extinction(
501533
outname = outname.replace(".pdf", "_zoom.pdf")
502534

503535
# finish configuring the plot
504-
ax.set_xscale("log")
536+
if log:
537+
ax.set_xscale("log")
505538
ax.set_xlabel(r"$\lambda$ [$\mu m$]", fontsize=1.5 * fontsize)
506-
ax.set_ylabel(extdata._get_ext_ytitle(ytype=extdata.type), fontsize=1.5 * fontsize)
539+
ylabel = extdata._get_ext_ytitle(ytype=extdata.type)
540+
if spread:
541+
ylabel += " + offset"
542+
ax.set_ylabel(ylabel, fontsize=1.5 * fontsize)
507543

508544
# show the figure or save it to a pdf file
509545
if pdf:
510546
fig.savefig(path + outname, bbox_inches="tight")
511547
else:
512548
plt.show()
513549

550+
# return the figure and axes for additional manipulations
551+
return fig, ax
552+
514553

515554
def plot_extinction(
516555
starpair,

0 commit comments

Comments
 (0)