Coverage for python/lsst/sims/photUtils/BandpassSet.py : 5%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#
2# LSST Data Management System
3# Copyright 2008, 2009, 2010, 2011, 2012 LSST Corporation.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <http://www.lsstcorp.org/LegalNotices/>.
21#
23"""
24 Questions or comments, email : ljones.uw@gmail.com
27 The point of this class is mostly for convenience when dealing with
28 sets of Seds and Bandpasses. Often this convenience is needed when
29 dealing with these sets from the python interpreter (when figuring out
30 if a group of SEDS looks appropriate, etc.)
32 So, a lot of these functions actually deal with plotting.
33 Still, particularly in SedSet.py you may find the methods to calculate
34 magnitudes or colors of a large group of seds
35 (with a set of Bandpasses, defined in this class) useful.
37 Many of the functions defined here are useful for testing the set
38 of LSST filters (i.e. do they meet the filter leak requirements?)
39 or plotting the filters (i.e. plotFilters).
40"""
41from __future__ import print_function
44from builtins import zip
45from builtins import range
46from builtins import object
47import os
48import copy
49import numpy as np
50import matplotlib.pyplot as plt
51from .Bandpass import Bandpass
52from .Sed import Sed
54# airmass of standard atmosphere
55_stdX = 1.2
57# wavelength range parameters for calculations.
58WAVELEN_MIN = 300 # minimum wavelength for transmission/source (nm)
59WAVELEN_MAX = 1200 # maximum wavelength for transmission/source (nm)
60WAVELEN_STEP = 0.1 # step size in wavelength grid (nm)
62# figure format to save output figures, if desired. (can choose 'png' or 'eps' or 'pdf' or a few others).
63figformat = 'png'
65class BandpassSet(object):
66 """ Set up a dictionary of a set of bandpasses (multi-filters).
67 Run various engineering tests or visualizations."""
69 def __init__(self):
70 """Initialize the class but don't do anything yet."""
71 return
73 def setBandpassSet(self, bpDict, bpDictlist=('u', 'g', 'r', 'i', 'z','y'), verbose=True):
74 """Simply set throughputs from a pre-made dictionary."""
75 if len(bpDictlist) != len(list(bpDict.keys())):
76 bpDictList = list(bpDict.keys())
77 self.bandpass = copy.deepcopy(bpDict)
78 self.filterlist = copy.deepcopy(bpDictlist)
79 return
81 def setThroughputs_SingleFiles(self, filterlist=('u', 'g', 'r', 'i', 'z', 'y'),
82 rootdir="./", rootname="total_", rootsuffix=".dat", verbose=True):
83 """Read bandpass set with filters in filterlist, from directory rootdir with base name rootname."""
84 # Set up dictionary to hold bandpass information.
85 bandpass = {}
86 # Loop through filters:
87 for f in filterlist:
88 # Build full filename.
89 filename = os.path.join(rootdir, rootname+f+rootsuffix)
90 # read filter throughput and set up Sb/Phi and zeropoint
91 if verbose:
92 print("Reading throughput file %s" %(filename))
93 # Initialize bandpass object.
94 bandpass[f] = Bandpass()
95 # Read the throughput curve, sampling onto grid of wavelen min/max/step.
96 bandpass[f].readThroughput(filename, wavelen_min=WAVELEN_MIN,
97 wavelen_max=WAVELEN_MAX,
98 wavelen_step=WAVELEN_STEP)
99 # Calculate phi as well.
100 bandpass[f].sbTophi()
101 # Set data in self.
102 self.bandpass = bandpass
103 self.filterlist = filterlist
104 return
106 def setThroughputs_ComponentFiles(self, filterlist=('u', 'g', 'r', 'i', 'z', 'y'),
107 all_filter_complist = ('detector.dat', 'lens1.dat', 'lens2.dat',
108 'lens3.dat', 'm1.dat', 'm2.dat', 'm3.dat',
109 'atmos_std.dat'),
110 rootdir = "./", verbose=True):
111 """Read and build bandpass set from all_filter_complist, using data from directory rootdir.
112 Note that with this method, every bandpass will be the same. The point is that then you can
113 use this method, plus set up a different BandpassSet with values that are different for each filter
114 and then multiply the two together using multiplyBandpassSets."""
115 # Set up dictionary to hold final bandpass information.
116 bandpass = {}
117 # Loop through filters.
118 # Set up full filenames in a list containing all elements of final throughput curve.
119 complist = []
120 # Join all 'all-filter' items.
121 for cp in all_filter_complist:
122 complist.append(os.path.join(rootdir, cp))
123 for f in filterlist:
124 if verbose:
125 print("Reading throughput curves ", complist, " for filter ", f)
126 # Initialize bandpass object.
127 bandpass[f] = Bandpass()
128 bandpass[f].readThroughputList(complist, wavelen_min=WAVELEN_MIN,
129 wavelen_max=WAVELEN_MAX, wavelen_step=WAVELEN_STEP)
130 bandpass[f].sbTophi()
131 self.bandpass = bandpass
132 self.filterlist = filterlist
133 return
135 def multiplyBandpassSets(self, otherBpSet):
136 """Multiply two bandpass sets together, filter by filter. Filterlists must match!
137 Returns a new bandpassSet object."""
138 if self.filterlist != otherBpSet.filterlist:
139 raise Exception("The bandpassSet filter lists must match.")
140 # Set up dictionary to hold new bandpass objects.
141 newBpDict = {}
142 for f in self.filterlist:
143 wavelen, sb = self.bandpass[f].multiplyThroughputs(otherBpSet.bandpass[f].wavelen,
144 otherBpSet.bandpass[f].sb)
145 newBpDict[f] = Bandpass(wavelen=wavelen, sb=sb)
146 newBpSet = BandpassSet()
147 newBpSet.setBandpassSet(newBpDict, self.filterlist)
148 return newBpSet
150 def writePhis(self, filename):
151 """Write all phi values and wavelength to stdout"""
152 # This is useful for getting a data file with only phi's, as requested by some science collaborations.
153 file = open(filename, "w")
154 # Print header.
155 headerline = "#Wavelen(nm) "
156 for filter in self.filterlist:
157 headerline = headerline + " phi_" + filter
158 print(headerline, file=file)
159 # print data
160 for i in range(0, len(self.bandpass[self.filterlist[0]].wavelen), 1):
161 outline = "%.2f " %(self.bandpass[self.filterlist[0]].wavelen[i])
162 for f in self.filterlist:
163 outline = outline + " %.6g " %(self.bandpass[f].phi[i])
164 print(outline, file=file)
165 file.close()
166 return
168 def writePhotozThroughputs(self, filename):
169 """Write all throughputs in format AndyC needs for photoz"""
170 file = open(filename,"w")
171 for i,filter in enumerate(self.filterlist):
172 file.write("%d NAME %d\n"%(len(filter.wavelen),i))
173 j=0
174 for lam,thru in zip(filter.wavelen,filter.sb):
175 file.write("%d %g %g\n"%(j,10.*lam,thru))
176 j=j+1
177 file.close()
178 return
180 def calcFilterEffWave(self, verbose=True):
181 """Calculate the effective wavelengths for all filters."""
182 # Set up dictionaries for effective wavelengths, as calculated for Transmission (sb) and Phi (phi).
183 effsb = {}
184 effphi = {}
185 # Calculate values for each filter.
186 for f in self.filterlist:
187 effphi[f], effsb[f] = self.bandpass[f].calcEffWavelen()
188 self.effsb = effsb
189 self.effphi = effphi
190 if verbose:
191 print("Filter Eff_Sb Eff_phi")
192 for f in self.filterlist:
193 print(" %s %.3f %.3f" %(f, self.effsb[f], effphi[f]))
194 return
196 def calcZeroPoints(self, gain=1.0, verbose=True):
197 """Calculate the theoretical zeropoints for the bandpass, in AB magnitudes."""
198 exptime = 15 # Default exposure time.
199 effarea = np.pi*(6.5*100/2.0)**2 # Default effective area of primary mirror.
200 zpt = {}
201 print("Filter Zeropoint")
202 for f in self.filterlist:
203 zpt[f] = self.bandpass[f].calcZP_t(expTime=exptime, effarea=effarea, gain=gain)
204 print(" %s %.3f" %(f, zpt[f]))
205 return
207 def calcFilterEdges(self, drop_peak=0.1, drop_percent=50, verbose=True):
208 """Calculate the edges of each filter for Sb, at values of 'drop_*'.
210 Values for drop_peak are X percent of max throughput, drop_percent is where the
211 filter throughput drops to an absolute X percent value. """
212 bandpass = self.bandpass
213 filterlist = self.filterlist
214 try:
215 effsb = self.effsb
216 effphi = self.effphi
217 except AttributeError:
218 self.calcFilterEffWave()
219 effsb = self.effsb
220 effphi = self.effphi
221 # Set up dictionary for effective wavelengths and X% peak_drop wavelengths.
222 drop_peak_blue = {}
223 drop_peak_red = {}
224 drop_perc_blue = {}
225 drop_perc_red = {}
226 maxthruput = {}
227 # Calculate values for each filter.
228 for f in filterlist:
229 # Calculate minimum and maximum wavelengths for bandpass.
230 minwavelen = bandpass[f].wavelen.min()
231 maxwavelen = bandpass[f].wavelen.max()
232 # Set defaults for dropoff points.
233 drop_peak_blue[f] = maxwavelen
234 drop_peak_red[f] = minwavelen
235 drop_perc_blue[f] = maxwavelen
236 drop_perc_red[f] = minwavelen
237 # Find out what current wavelength grid is being used.
238 wavelenstep=(bandpass[f].wavelen[1] - bandpass[f].wavelen[0])
239 # Find peak throughput.
240 maxthruput[f] = bandpass[f].sb.max()
241 # Calculate the values we're looking for (for the threshold for the 'drop')
242 d_peak = maxthruput[f] * drop_peak/100.0
243 d_perc = drop_percent/100.0 # given in %, must translate to fraction.
244 # Find the nearest spot on the wavelength grid used for filter, for edge lookup.
245 sbindex = np.where(abs(bandpass[f].wavelen - effsb[f]) < wavelenstep/2.0)
246 sbindex = sbindex[0][0]
247 # Now find where Sb drops below 'drop_peak_thruput' of max for the first time.
248 # Calculate wavelength where dropoff X percent of max level.
249 # Start at effective wavelength, and walk outwards.
250 for i in range(sbindex, len(bandpass[f].wavelen)):
251 if bandpass[f].sb[i] <= d_peak:
252 drop_peak_red[f] = bandpass[f].wavelen[i]
253 break
254 for i in range(sbindex, 0, -1):
255 if bandpass[f].sb[i] <= d_peak:
256 drop_peak_blue[f] = bandpass[f].wavelen[i]
257 break
258 # Calculate wavelength where dropoff X percent, absolute value
259 for i in range(sbindex, len(bandpass[f].wavelen)):
260 if bandpass[f].sb[i] <= d_perc:
261 drop_perc_red[f] = bandpass[f].wavelen[i]
262 break
263 for i in range(sbindex, 0, -1):
264 if bandpass[f].sb[i] <= d_perc:
265 drop_perc_blue[f] = bandpass[f].wavelen[i]
266 break
267 # Print output to screen.
268 if verbose:
269 print("Filter MaxThruput EffWavelen %.3f%s_max(blue) %.3f%s_max(red) %.3f%s_abs(blue) %.3f%s_abs(red)" \
270 %(drop_peak, "%", drop_peak, "%", drop_percent, "%", drop_percent, "%"))
271 for f in self.filterlist:
272 print("%4s %10.4f %10.4f %12.2f %12.2f %12.2f %12.2f" \
273 % (f, maxthruput[f],
274 effsb[f],
275 drop_peak_blue[f],
276 drop_peak_red[f],
277 drop_perc_blue[f],
278 drop_perc_red[f]))
279 # Set values (dictionaries keyed by filterlist).
280 self.drop_peak_red = drop_peak_red
281 self.drop_peak_blue = drop_peak_blue
282 self.drop_perc_red = drop_perc_red
283 self.drop_perc_blue = drop_perc_blue
284 return
286 def calcFilterLeaks(self, ten_nm_limit=0.01, out_of_band_limit=0.05, filter_edges=0.1,
287 extra_title=None, makeplot=True, savefig=False, figroot = "bandpass"):
288 """ Calculate throughput leaks beyond location where bandpass drops to filter_edges (%) of max throughput.
291 According to SRD these leaks must be below 0.01% of peak value in any 10nm interval,
292 and less than 0.05% of total transmission over all wavelengths beyond where thruput<0.1% of peak.
293 Assumes wavelength is in nanometers! (because of nm requirement). Uses ten_nm_limit and out_of_band_limit
294 to set specs. Note that the values given here should be in PERCENT (not fractions).
295 Generates plots for each filter, as well as calculation of fleaks. """
296 # Go through each filter, calculate filter leaks.
297 filterlist = self.filterlist
298 bandpass = self.bandpass
299 # Make sure effective wavelengths defined.
300 self.calcFilterEffWave(verbose=False)
301 effsb = self.effsb
302 # Look for the new FWHM definition for the 10nm filter leak definition
303 if filter_edges == "FWHM":
304 self.calcFilterEffWave(verbose=False)
305 self.calcFilterEdges(drop_percent=0.50, verbose=False)
306 # Calculate FWHM values.
307 fwhm = {}
308 for f in filterlist:
309 fwhm[f] = self.drop_peak_red[f] - self.drop_peak_blue[f]
310 # Adjust 'drop' edges to account for being FWHM from center.
311 for f in filterlist:
312 self.drop_peak_red[f] = self.effsb[f] + fwhm[f]
313 self.drop_peak_blue[f] = self.effsb[f] - fwhm[f]
314 # Otherwise, traditional % definition.
315 else:
316 self.calcFilterEdges(drop_peak=filter_edges, verbose=False)
317 drop_peak_red = self.drop_peak_red
318 drop_peak_blue = self.drop_peak_blue
319 # Set up plot colors.
320 colors = ('m', 'b', 'g', 'y', 'r', 'k', 'c')
321 colorindex = 0
322 for f in filterlist:
323 print("=====")
324 print("Analyzing %s filter" %(f))
325 # find wavelength range in use.
326 minwavelen = bandpass[f].wavelen.min()
327 maxwavelen = bandpass[f].wavelen.max()
328 # find out what current wavelength grid is being used
329 wavelenstep= bandpass[f].wavelen[1] - bandpass[f].wavelen[0]
330 # find the wavelength in the wavelength grid which is closest to effsb
331 condition = (abs(bandpass[f].wavelen - effsb[f]) < wavelenstep/2.0)
332 waveleneffsb = bandpass[f].wavelen[condition]
333 # calculate peak transmission
334 peaktrans = bandpass[f].sb.max()
335 # calculate total transmission withinin proper bandpass
336 condition = ((bandpass[f].wavelen>drop_peak_blue[f]) &
337 (bandpass[f].wavelen<drop_peak_red[f]))
338 temporary = bandpass[f].sb[condition]
339 totaltrans = temporary.sum()
340 # calculate total transmission outside drop_peak wavelengths of peak
341 condition = ((bandpass[f].wavelen>=drop_peak_red[f]) |
342 (bandpass[f].wavelen<=drop_peak_blue[f]))
343 temporary = bandpass[f].sb[condition]
344 sumthruput_outside_bandpass = temporary.sum()
345 print("Total transmission through filter: %s" %(totaltrans))
346 print("Transmission outside of filter edges (drop_peak): %f" %(sumthruput_outside_bandpass))
347 # Calculate percentage of out of band transmission to in-band transmission
348 out_of_band_perc = sumthruput_outside_bandpass / totaltrans * 100.0
349 print("Ratio of total out-of-band to in-band transmission: %f%s" \
350 %(out_of_band_perc, "%"))
351 infotext = "Out-of-band/in-band transmission %.3f%s" \
352 %(out_of_band_perc, '%')
353 if out_of_band_perc > out_of_band_limit:
354 print(" Does not meet SRD-This is more than %.4f%s of throughput outside the bandpass %s" \
355 %(out_of_band_limit, '%', f))
356 else:
357 print(" Meets SRD - This is less than %.4f%s of total throughput outside bandpass" \
358 %(out_of_band_limit, '%'))
359 # calculate transmission in each 10nm interval.
360 sb_10nm = np.zeros(len(bandpass[f].sb), dtype='float')
361 gapsize_10nm = 10.0 # wavelen gap in nm
362 meet_SRD=True
363 maxsb_10nm = 0.
364 maxwavelen_10nm = 0.
365 # Convert 10nm limit into actual value (and account for %)
366 ten_nm_limit_value = ten_nm_limit * peaktrans/100.0
367 for i in range(0, len(sb_10nm), 1):
368 # calculate 10 nm 'smoothed' transmission
369 wavelen = bandpass[f].wavelen[i]
370 condition = ((bandpass[f].wavelen >= wavelen-gapsize_10nm/2.0) &
371 (bandpass[f].wavelen < wavelen+gapsize_10nm/2.0) &
372 ((bandpass[f].wavelen <= drop_peak_blue[f])
373 | (bandpass[f].wavelen >= drop_peak_red[f])))
374 sb_10nm[i] = bandpass[f].sb[condition].mean()
375 condition = ((bandpass[f].wavelen > drop_peak_blue[f]) &
376 (bandpass[f].wavelen < drop_peak_red[f]))
377 sb_10nm[condition] = 0
378 # now check for violation of SRD
379 if sb_10nm.max() > ten_nm_limit_value:
380 meet_SRD = False
381 maxsb_10nm = sb_10nm.max()
382 maxwavelen_10nm = bandpass[f].wavelen[np.where(sb_10nm==sb_10nm.max())]
383 if meet_SRD==False:
384 print("Does not meet SRD - %s has at least one region not meeting the 10nm SRD filter leak requirement (max is %f%s of peak transmission at %.1f A)" %(f, maxsb_10nm, "%", maxwavelen_10nm))
385 else:
386 print("10nm limit within SRD.")
387 if makeplot:
388 # make plot for this filter
389 plt.figure()
390 # set colors for filter in plot
391 color = colors[colorindex]
392 colorindex = colorindex + 1
393 if colorindex == len(colors):
394 colorindex = 0
395 # Make lines on the plot.
396 plt.plot(bandpass[f].wavelen, bandpass[f].sb, color=color, linestyle="-")
397 plt.plot(bandpass[f].wavelen, sb_10nm, 'r-',linewidth=2)
398 plt.axvline(drop_peak_blue[f], color='b', linestyle=':')
399 plt.axvline(drop_peak_red[f], color='b', linestyle=':')
400 plt.axhline(ten_nm_limit_value, color='b', linestyle=':')
401 legendstring = f + " filter thruput, 10nm average thruput in red\n"
402 legendstring = legendstring + " Peak throughput is %.1f%s\n" \
403 %(peaktrans*100.0, '%')
404 legendstring = legendstring + " Total throughput (in band) is %.0f%s\n" \
405 %(totaltrans*100.0, '%')
406 legendstring = legendstring + " " + infotext
407 plt.figtext(0.25, 0.76, legendstring)
408 plt.xlabel("Wavelength (nm)")
409 plt.ylabel("Throughput (0-1)")
410 plt.yscale('log')
411 if extra_title != None:
412 titletext = extra_title + " " + f
413 else:
414 titletext = f
415 plt.title(titletext)
416 plt.ylim(1e-6, 1)
417 plt.xlim(xmin=300, xmax=1200)
418 if savefig:
419 figname = figroot + "_" + f + "_fleak."+ figformat
420 plt.savefig(figname, format=figformat)
421 # end of loop through filters
422 return
424 def plotFilters(self, rootdir=".", throughput=True, phi=False, atmos=True,
425 plotdropoffs=False, ploteffsb=True, compare=None, savefig=False,
426 figroot='bandpass', xlim=(300, 1100), ylimthruput=(0, 1), ylimphi=(0, 0.002),
427 filter_tags='normal', leg_tag=None, compare_tag=None, title=None,
428 linestyle='-', linewidth=2, newfig=True):
429 """ Plot the filter throughputs and phi's, with limits xlim/ylimthruput/ylimphi.
431 Optionally add comparison (another BandpassSet) throughput and phi curves.
432 and show lines for % dropoffs ; filter_tags can be side or normal. """
433 # check that all self variables are set up if needed
434 bandpass = self.bandpass
435 filterlist = self.filterlist
436 try:
437 self.effsb
438 self.effphi
439 if plotdropoffs:
440 self.drop_peak_red
441 self.drop_peak_blue
442 except AttributeError:
443 self.calcFilterEffWave(verbose=False)
444 if plotdropoffs:
445 self.calcFilterEdges(verbose=False)
446 effsb = self.effsb
447 effphi = self.effphi
448 if plotdropoffs:
449 drop_peak_red = self.drop_peak_red
450 drop_peak_blue = self.drop_peak_blue
451 # read files for atmosphere and optional comparison throughputs
452 if atmos:
453 atmosfile = os.path.join(rootdir, 'atmos_std.dat')
454 atmosphere = Bandpass()
455 atmosphere.readThroughput(atmosfile)
456 Xatm=_stdX
457 # set up colors for plot output
458 colors = ('k', 'b', 'g', 'y', 'r', 'm', 'burlywood', 'k')
459 #colors = ('r', 'b', 'r', 'b', 'r', 'b', 'r', 'b')
460 if (throughput):
461 if newfig:
462 plt.figure()
463 # plot throughputs
464 colorindex = 0
465 for f in filterlist:
466 color = colors[colorindex]
467 colorindex = colorindex+1
468 if colorindex == len(colors):
469 colorindex=0
470 plt.plot(bandpass[f].wavelen, bandpass[f].sb,
471 color=color, linestyle=linestyle, linewidth=linewidth)
472 # add effective wavelengths (optional)
473 if ploteffsb:
474 vertline = np.arange(0, 1.2, 0.1)
475 temp = vertline*0.0 + 1.0
476 colorindex = 0
477 for f in filterlist:
478 color = colors[colorindex]
479 colorindex = colorindex + 1
480 if colorindex == len(colors):
481 colorindex = 0
482 plt.plot(effsb[f]*temp, vertline, color=color, linestyle='-')
483 # add dropoff limits if desired (usually only good with reduced x/y limits) (optional)
484 if (plotdropoffs):
485 colorindex = 0
486 for filter in filterlist:
487 color = colors[colorindex]
488 colorindex = colorindex+1
489 if colorindex == len(colors):
490 colorindex = 0
491 plt.plot(drop_peak_red[f]*temp, vertline, color=color, linestyle='--')
492 plt.plot(drop_peak_blue[f]*temp, vertline, color=color, linestyle='--')
493 # plot atmosphere (optional)
494 if atmos:
495 plt.plot(atmosphere.wavelen, atmosphere.sb, 'k:')
496 # plot comparison throughputs (optional)
497 if compare!=None:
498 colorindex = 0
499 for f in compare.filterlist:
500 color = colors[colorindex]
501 colorindex = colorindex + 1
502 if colorindex == len(colors):
503 colorindex = 0
504 plt.plot(compare.bandpass[f].wavelen, compare.bandpass[f].sb,
505 color=color, linestyle='--')
506 # add line legend (type of filter curves)
507 legendtext = "%s = solid" %(leg_tag)
508 if leg_tag==None:
509 legendtext = ""
510 if compare!=None:
511 if compare_tag!=None:
512 legendtext= legendtext + "\n%s = dashed" %(compare_tag)
513 if atmos:
514 legendtext = legendtext + "\nAirmass %.1f" %(Xatm)
515 plt.figtext(0.15, 0.8, legendtext)
516 # add names to filter throughputs
517 if filter_tags == 'side':
518 xtags = np.zeros(len(filterlist), dtype=float)
519 xtags = xtags + 0.15
520 spacing = (0.8 - 0.1) / len(filterlist)
521 ytags = np.arange(0.8, 0.1, -1*spacing, dtype=float)
522 ytags = ytags
523 else: # 'normal' tagging
524 xtags = (0.16, 0.27, 0.42, 0.585, 0.68, 0.8, 0.8, 0.8)
525 ytags = (0.73, 0.73, 0.73, 0.73, 0.73, 0.73, 0.69, 0.65)
526 index= 0
527 colorindex = 0
528 for f in filterlist:
529 plt.figtext(xtags[index], ytags[index], f, color=colors[colorindex],
530 va='top', size='x-large')
531 index = index+1
532 colorindex = colorindex + 1
533 if colorindex == len(colors):
534 colorindex = 0
535 # set x/y limits
536 plt.xlim(xmin=xlim[0], xmax=xlim[1])
537 plt.ylim(ymin=ylimthruput[0], ymax=ylimthruput[1])
538 plt.xlabel("Wavelength (nm)")
539 plt.ylabel("Throughput (0-1)")
540 plt.grid()
541 if title!=None:
542 plt.title(title)
543 if savefig:
544 figname = figroot + "_thruputs." + figformat
545 plt.savefig(figname, format=figformat)
546 if (phi):
547 if newfig:
548 plt.figure()
549 # plot LSST 'phi' curves
550 colorindex = 0
551 for f in filterlist:
552 color = colors[colorindex]
553 colorindex = colorindex+1
554 if colorindex == len(colors):
555 colorindex = 0
556 plt.plot(bandpass[f].wavelen, bandpass[f].phi, color=color,
557 linestyle=linestyle, linewidth=linewidth)
558 # add effective wavelengths for main filter set (optional)
559 if ploteffsb:
560 vertline = np.arange(0, .1, 0.01)
561 temp = vertline*0.0 + 1.0
562 colorindex = 0
563 for filter in filterlist:
564 color = colors[colorindex]
565 colorindex = colorindex + 1
566 if colorindex == len(colors):
567 colorindex = 0
568 plt.plot(effphi[f]*temp, vertline, color=color, linestyle='-')
569 # plot comparison throughputs (optional)
570 if compare!=None:
571 colorindex = 0
572 for filter in compare.filterlist:
573 color = colors[colorindex]
574 colorindex = colorindex + 1
575 if colorindex == len(colors):
576 colorindex = 0
577 plt.plot(compare.bandpass[f].wavelen, compare.bandpass[f].phi,
578 color=color, linestyle='--')
579 # add line legend
580 legendtext = "%s = solid" %(leg_tag)
581 if leg_tag ==None:
582 legendtext = " "
583 if compare!=None:
584 if compare_tag!=None:
585 legendtext = legendtext + "\n%s = dashed" %(compare_tag)
586 plt.figtext(0.15, 0.78, legendtext)
587 # add name tags to filters
588 if filter_tags == 'side':
589 xtags = np.zeros(len(filterlist), dtype=float)
590 xtags = xtags + 0.15
591 ytags = np.arange(len(filterlist), 0, -1.0, dtype=float)
592 ytags = ytags*0.04 + 0.35
593 else:
594 xtags = (0.17, 0.27, 0.42, 0.585, 0.677, 0.82, 0.82, 0.82)
595 ytags = (0.63, 0.63, 0.63, 0.63, 0.63, 0.63, 0.60, 0.57)
596 index= 0
597 colorindex = 0
598 for f in filterlist:
599 plt.figtext(xtags[index], ytags[index], f, color=colors[colorindex], va='top')
600 index = index+1
601 colorindex = colorindex+1
602 if colorindex==len(colors):
603 colorindex=0
604 # set x/y limits
605 plt.xlim(xmin=xlim[0], xmax=xlim[1])
606 plt.ylim(ymin=ylimphi[0], ymax=ylimphi[1])
607 plt.xlabel("Wavelength (nm)")
608 plt.ylabel("Phi")
609 plt.grid()
610 if title!=None:
611 plt.title(title)
612 if savefig:
613 figname = figroot + "_phi." + figformat
614 plt.savefig(figname, format=figformat)
615 return