The Spanish Virtual Observatory (SVO) Filter Profile Service is a great resource for homogenized photometric filter curves and metadata. With svo_filters, I tried to create a lightweight and flexible package to incorporate these filters into Python applications.
Filters can also be binned arbitrarily, for use with grisms. We can pass integers to the n_bins or pixels_per_bin arguments to specify the number of wavelength bins or pixels per bin, respectively:
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
208 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
--------------------------------------------------------------------------------
/docs/_build/html/searchindex.js:
--------------------------------------------------------------------------------
1 | Search.setIndex({docnames:["index","svo"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,"sphinx.ext.todo":1,"sphinx.ext.viewcode":1,sphinx:55},filenames:["index.rst","svo.rst"],objects:{"":{svo:[1,0,0,"-"]},"svo.Filter":{Band:[1,2,1,""],CalibrationReference:[1,2,1,""],FWHM:[1,2,1,""],Facility:[1,2,1,""],FilterProfileService:[1,2,1,""],MagSys:[1,2,1,""],PhotCalID:[1,2,1,""],PhotSystem:[1,2,1,""],ProfileReference:[1,2,1,""],WavelengthCen:[1,2,1,""],WavelengthEff:[1,2,1,""],WavelengthMax:[1,2,1,""],WavelengthMean:[1,2,1,""],WavelengthMin:[1,2,1,""],WavelengthPeak:[1,2,1,""],WavelengthPhot:[1,2,1,""],WavelengthPivot:[1,2,1,""],WavelengthUCD:[1,2,1,""],WavelengthUnit:[1,2,1,""],WidthEff:[1,2,1,""],ZeroPoint:[1,2,1,""],ZeroPointType:[1,2,1,""],ZeroPointUnit:[1,2,1,""],apply:[1,3,1,""],bin:[1,3,1,""],centers:[1,2,1,""],filterID:[1,2,1,""],flux_units:[1,2,1,""],info:[1,3,1,""],load_TopHat:[1,3,1,""],load_txt:[1,3,1,""],load_xml:[1,3,1,""],overlap:[1,3,1,""],path:[1,2,1,""],plot:[1,3,1,""],refs:[1,2,1,""],rsr:[1,2,1,""],throughput:[1,2,1,""],wave:[1,2,1,""],wave_units:[1,2,1,""]},svo:{Filter:[1,1,1,""],color_gen:[1,4,1,""],filters:[1,4,1,""],rebin_spec:[1,4,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","attribute","Python attribute"],"3":["py","method","Python method"],"4":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:class","2":"py:attribute","3":"py:method","4":"py:function"},terms:{"2mass":0,"break":1,"class":[0,1],"float":1,"import":0,"int":1,"new":1,"return":1,"true":0,"while":1,And:0,The:[0,1],With:0,about:[0,1],absolut:1,actual:0,also:0,altern:0,angstrom:1,ans:1,appli:1,applic:0,arbitrarili:0,argument:0,arrai:1,ascii:1,astropi:[0,1],avail:1,averag:1,band:1,bandpass:[0,1],base:1,bin:[0,1],bokeh:1,bool:1,calcul:1,calibr:1,calibrationrefer:1,can:0,center:1,channel:1,check:1,clone:0,cm2:1,color:1,color_gen:1,colormap:1,column:1,com:0,contain:1,creat:[0,1],current:1,curv:[0,1],data:1,detail:1,dice:1,directori:1,distribut:1,each:1,effect:1,erg:1,exampl:1,facil:1,fals:1,fetch:1,fig:1,file:[0,1],filepath:1,filter:1,filter_directori:1,filterid:1,filterprofileservic:1,flexibl:0,flux:1,flux_unit:1,fmt:1,format:1,from:[0,1],full:1,fwhm:1,g102:1,g141:[0,1],gener:1,get:1,getter:1,git:0,github:0,given:1,great:0,grism:1,h_band:0,hat:1,homogen:0,hover2pi:0,http:0,incorpor:0,index:[],info:[0,1],inform:0,integ:0,kei:1,kwarg:1,lightweight:0,like:[0,1],list:1,load:1,load_tophat:1,load_txt:1,load_xml:1,local:0,magnitud:1,magsi:1,main:1,map:1,max:1,maximum:1,mean:1,metadata:[0,1],method:0,min:1,minimum:1,modul:0,n_bin:[0,1],n_pixel:1,name:[0,1],ndarrai:1,none:1,number:[0,1],object:[0,1],observatori:0,option:1,origin:1,other:1,overlap:1,oversamp:1,packag:0,page:[],palett:1,paper:1,paramet:1,partial:1,pass:0,path:1,peak:1,per:[0,1],photcalid:1,photometr:1,photon:1,photsystem:1,pickl:1,pip:0,pivot:1,pixel:[0,1],pixels_per_bin:[0,1],plot:[0,1],point:1,preserv:1,print:1,profil:[0,1],profilerefer:1,python:[0,1],quantiti:1,rang:1,rebin:1,rebin_spec:1,ref:1,refer:1,rel:1,resourc:0,respect:0,respons:1,rsr:1,search:[],see:0,self:1,sequenc:[0,1],servic:[0,1],setup:0,some:0,someinform:[],sourc:1,spanish:0,spec:[0,1],specifi:0,spectral:1,spectrum:1,standard:1,statu:1,store:[0,1],str:1,svo:0,svo_filt:1,system:1,tabl:1,telescop:1,test:1,thi:1,throughput:1,top:1,total:1,tri:0,txt:1,type:1,unit:[0,1],updat:1,use:[0,1],used:1,useful:1,valu:1,view:0,viridi:1,virtual:0,wave:1,wave_max:1,wave_min:1,wave_unit:1,wavelength:[0,1],wavelengthcen:1,wavelengtheff:1,wavelengthmax:1,wavelengthmean:1,wavelengthmin:1,wavelengthpeak:1,wavelengthphot:1,wavelengthpivot:1,wavelengthucd:1,wavelengthunit:1,wavenew:1,wavnew:1,wfc3_ir:0,which:1,width:1,widtheff:1,wrapper:[0,1],xml:0,you:0,zero:1,zeropoint:1,zeropointtyp:1,zeropointunit:1},titles:["svo_filters","svo module"],titleterms:{appli:0,content:0,document:[],filter:0,grism:0,indic:[],instal:0,load:0,modul:1,photometr:0,spectrum:0,svo:1,svo_filt:0,tabl:[],welcom:[]}})
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Configuration file for the Sphinx documentation builder.
4 | #
5 | # This file does only contain a selection of the most common options. For a
6 | # full list see the documentation:
7 | # http://www.sphinx-doc.org/en/master/config
8 |
9 | # -- Path setup --------------------------------------------------------------
10 |
11 | # If extensions (or modules to document with autodoc) are in another directory,
12 | # add these directories to sys.path here. If the directory is relative to the
13 | # documentation root, use os.path.abspath to make it absolute, like shown here.
14 | #
15 | import os
16 | import sys
17 | sys.path.insert(0, os.path.abspath('.'))
18 | sys.path.append(os.path.abspath('../svo_filters/'))
19 |
20 | # -- Project information -----------------------------------------------------
21 |
22 | project = 'svo_filters'
23 | copyright = '2018, Joe Filippazzo'
24 | author = 'Joe Filippazzo'
25 |
26 | # The short X.Y version
27 | version = '0.2'
28 | # The full version, including alpha/beta/rc tags
29 | release = '0.2.16'
30 |
31 |
32 | # -- General configuration ---------------------------------------------------
33 |
34 | # If your documentation needs a minimal Sphinx version, state it here.
35 | #
36 | # needs_sphinx = '1.0'
37 |
38 | # Add any Sphinx extension module names here, as strings. They can be
39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
40 | # ones.
41 | extensions = [
42 | 'sphinx.ext.autodoc',
43 | 'sphinx.ext.doctest',
44 | 'sphinx.ext.napoleon',
45 | 'sphinx.ext.autosummary',
46 | 'sphinx.ext.intersphinx',
47 | 'sphinx.ext.todo',
48 | 'sphinx.ext.coverage',
49 | 'sphinx.ext.mathjax',
50 | 'sphinx.ext.ifconfig',
51 | 'sphinx.ext.viewcode',
52 | 'sphinx.ext.githubpages',
53 | ]
54 |
55 | # Add any paths that contain templates here, relative to this directory.
56 | templates_path = ['_templates']
57 |
58 | # The suffix(es) of source filenames.
59 | # You can specify multiple suffix as a list of string:
60 | #
61 | # source_suffix = ['.rst', '.md']
62 | source_suffix = '.rst'
63 |
64 | # The master toctree document.
65 | master_doc = 'index'
66 |
67 | # The language for content autogenerated by Sphinx. Refer to documentation
68 | # for a list of supported languages.
69 | #
70 | # This is also used if you do content translation via gettext catalogs.
71 | # Usually you set "language" from the command line for these cases.
72 | language = None
73 |
74 | # List of patterns, relative to source directory, that match files and
75 | # directories to ignore when looking for source files.
76 | # This pattern also affects html_static_path and html_extra_path.
77 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
78 |
79 | # The name of the Pygments (syntax highlighting) style to use.
80 | pygments_style = None
81 |
82 |
83 | # -- Options for HTML output -------------------------------------------------
84 |
85 | # The theme to use for HTML and HTML Help pages. See the documentation for
86 | # a list of builtin themes.
87 | #
88 | # html_theme = 'alabaster'
89 | # The theme to use for HTML and HTML Help pages. See the documentation for
90 | # a list of builtin themes.
91 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
92 | if not on_rtd: # only import and set the theme if we're building docs locally
93 | import sphinx_rtd_theme
94 | html_theme = 'sphinx_rtd_theme'
95 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
96 |
97 | # Theme options are theme-specific and customize the look and feel of a theme
98 | # further. For a list of options available for each theme, see the
99 | # documentation.
100 | #
101 | # html_theme_options = {}
102 |
103 | # Add any paths that contain custom static files (such as style sheets) here,
104 | # relative to this directory. They are copied after the builtin static files,
105 | # so a file named "default.css" will overwrite the builtin "default.css".
106 | html_static_path = ['_static']
107 |
108 | # Custom sidebar templates, must be a dictionary that maps document names
109 | # to template names.
110 | #
111 | # The default sidebars (for documents that don't match any pattern) are
112 | # defined by theme itself. Builtin themes are using these templates by
113 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
114 | # 'searchbox.html']``.
115 | #
116 | # html_sidebars = {}
117 |
118 |
119 | # -- Options for HTMLHelp output ---------------------------------------------
120 |
121 | # Output file base name for HTML help builder.
122 | htmlhelp_basename = 'svo_filtersdoc'
123 |
124 |
125 | # -- Options for LaTeX output ------------------------------------------------
126 |
127 | latex_elements = {
128 | # The paper size ('letterpaper' or 'a4paper').
129 | #
130 | # 'papersize': 'letterpaper',
131 |
132 | # The font size ('10pt', '11pt' or '12pt').
133 | #
134 | # 'pointsize': '10pt',
135 |
136 | # Additional stuff for the LaTeX preamble.
137 | #
138 | # 'preamble': '',
139 |
140 | # Latex figure (float) alignment
141 | #
142 | # 'figure_align': 'htbp',
143 | }
144 |
145 | # Grouping the document tree into LaTeX files. List of tuples
146 | # (source start file, target name, title,
147 | # author, documentclass [howto, manual, or own class]).
148 | latex_documents = [
149 | (master_doc, 'svo_filters.tex', 'svo\\_filters Documentation',
150 | 'Joe Filippazzo', 'manual'),
151 | ]
152 |
153 |
154 | # -- Options for manual page output ------------------------------------------
155 |
156 | # One entry per manual page. List of tuples
157 | # (source start file, name, description, authors, manual section).
158 | man_pages = [
159 | (master_doc, 'svo_filters', 'svo_filters Documentation',
160 | [author], 1)
161 | ]
162 |
163 |
164 | # -- Options for Texinfo output ----------------------------------------------
165 |
166 | # Grouping the document tree into Texinfo files. List of tuples
167 | # (source start file, target name, title, author,
168 | # dir menu entry, description, category)
169 | texinfo_documents = [
170 | (master_doc, 'svo_filters', 'svo_filters Documentation',
171 | author, 'svo_filters', 'A Python wrapper for the SVO Filter Profile Service',
172 | 'Miscellaneous'),
173 | ]
174 |
175 |
176 | # -- Options for Epub output -------------------------------------------------
177 |
178 | # Bibliographic Dublin Core info.
179 | epub_title = project
180 |
181 | # The unique identifier of the text. This can be a ISBN number
182 | # or the project homepage.
183 | #
184 | # epub_identifier = ''
185 |
186 | # A unique identification for the text.
187 | #
188 | # epub_uid = ''
189 |
190 | # A list of files that should not be packed into the epub file.
191 | epub_exclude_files = ['search.html']
192 |
193 |
194 | # -- Extension configuration -------------------------------------------------
195 |
196 | # -- Options for intersphinx extension ---------------------------------------
197 |
198 | # Example configuration for intersphinx: refer to the Python standard library.
199 | intersphinx_mapping = {'https://docs.python.org/': None}
200 |
201 | # -- Options for todo extension ----------------------------------------------
202 |
203 | # If true, `todo` and `todoList` produce output, else they produce nothing.
204 | todo_include_todos = True
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | svo_filters
2 | ===========
3 |
4 | The `Spanish Virtual Observatory (SVO) Filter Profile Service `_ is a great resource for homogenized photometric filter curves and metadata. With `svo_filters`, I tried to create a lightweight and flexible package to incorporate these filters into Python applications.
5 |
6 | Installation
7 | ------------
8 |
9 | To install **svo_filters**, do::
10 |
11 | pip install svo_filters
12 |
13 | Alternatively, you can clone from Github with::
14 |
15 | git clone https://github.com/hover2pi/svo_filters.git
16 | python svo_filters/setup.py install
17 |
18 | Load a Photometric Filter
19 | ----------------------------
20 |
21 | The actual filters are stored locally as XML files and can be viewed with::
22 |
23 | from svo_filters import svo
24 | svo.filters()
25 |
26 | To create a filter object, pass a bandpass name to the :py:class:`svo.Filter()` class::
27 |
28 | H_band = svo.Filter('2MASS.H')
29 |
30 | You can see some information about the filter with::
31 |
32 | H_band.info()
33 |
34 | And you can plot the bandpass like so::
35 |
36 | H_band.plot()
37 |
38 | .. image:: ../svo_filters/data/plots/H.png
39 | :align: center
40 | :height: 300px
41 | :alt: Filter bandpass
42 |
43 | Load a Grism
44 | ------------
45 |
46 | Filters can also be binned arbitrarily, for use with grisms. We can pass integers to the ``n_bins`` or ``pixels_per_bin`` arguments to specify the number of wavelength bins or pixels per bin, respectively::
47 |
48 | G141 = svo.Filter('WFC3_IR.G141', n_bins=15)
49 |
50 | .. image:: ../svo_filters/data/plots/G141.png
51 | :align: center
52 | :height: 300px
53 | :alt: Filter bandpass
54 |
55 | Apply a Filter to a Spectrum
56 | ----------------------------
57 |
58 | Filters can be applied to a spectrum by passing a sequence of [W, F] or [W, F, E] with astropy units to the :py:meth:`~svo.Filter.apply` method::
59 |
60 | filtered = G141.apply(spec, plot=True)
61 |
62 | .. image:: ../svo_filters/data/plots/filtered.png
63 | :align: center
64 | :height: 300px
65 | :alt: Filter bandpass
66 |
67 | Contents
68 | ========
69 |
70 | .. toctree::
71 | :maxdepth: 2
72 |
73 | svo
74 |
75 | .. automodule:: svo
76 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/docs/svo.rst:
--------------------------------------------------------------------------------
1 | svo module
2 | ==========
3 |
4 | This is the main module for `svo_filters`.
5 |
6 | .. automodule:: svo
7 | :members:
8 | :undoc-members:
9 | :show-inheritance:
--------------------------------------------------------------------------------
/env/environment-3.10.yml:
--------------------------------------------------------------------------------
1 | name: svo_filters-3.10
2 | channels:
3 | - defaults
4 | - http://ssb.stsci.edu/astroconda
5 | dependencies:
6 | - astropy>=5.3.1
7 | - bokeh>=3.2.1
8 | - matplotlib
9 | - numpy>=1.25.1
10 | - numpydoc=1.1.0
11 | - pytest>=7.4.0
12 | - python>=3.10
13 | - pip:
14 | - PyYAML>=5.4
15 | - sphinx_astropy==1.3
16 | - astroquery
--------------------------------------------------------------------------------
/env/environment-3.11.yml:
--------------------------------------------------------------------------------
1 | name: svo_filters-3.11
2 | channels:
3 | - defaults
4 | - http://ssb.stsci.edu/astroconda
5 | dependencies:
6 | - astropy>=5.3.1
7 | - bokeh>=3.2.1
8 | - matplotlib
9 | - numpy>=1.25.1
10 | - numpydoc=1.1.0
11 | - pytest>=7.4.0
12 | - python>=3.9
13 | - pip:
14 | - PyYAML>=5.4
15 | - sphinx_astropy==1.3
16 | - astroquery
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | from setuptools import setup, find_packages
4 |
5 | REQUIRES = ['astropy',
6 | 'bokeh',
7 | 'ipython',
8 | 'matplotlib',
9 | 'numpy',
10 | 'numpydoc',
11 | 'pytest',
12 | 'pyyaml']
13 |
14 | DEPENDENCY_LINKS = [
15 | 'git+https://github.com/astropy/astroquery.git@ccc96185beeff86f3a12a31a00a801afcebe1dbe']
16 |
17 | FILES = []
18 | for root, _, files in os.walk("svo_filters"):
19 | FILES += [os.path.join(root.replace("svo_filters/", ""), fname)
20 | for fname in files if not fname.endswith(".py") and not fname.endswith(".pyc")]
21 |
22 | setup(
23 | name='svo_filters',
24 | version='0.5.2',
25 | description='A Python wrapper for the SVO Filter Profile Service',
26 | packages=find_packages(
27 | ".",
28 | exclude=["*.tests"]),
29 | package_data={
30 | 'svo_filters': FILES},
31 | install_requires=REQUIRES,
32 | dependency_links=DEPENDENCY_LINKS,
33 | author='Joe Filippazzo',
34 | author_email='jfilippazzo@stsci.edu',
35 | license='MIT',
36 | url='https://github.com/hover2pi/svo_filters',
37 | long_description='',
38 | zip_safe=True,
39 | use_2to3=False)
40 |
--------------------------------------------------------------------------------
/svo_filters/__init__.py:
--------------------------------------------------------------------------------
1 | from .svo import Filter
--------------------------------------------------------------------------------
/svo_filters/data/filters/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hover2pi/svo_filters/ac7fe3a7c405627810ae4d35dc29c118d1b6def8/svo_filters/data/filters/.gitkeep
--------------------------------------------------------------------------------
/svo_filters/data/filters/2MASS.H:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Photometric system
13 |
14 |
15 |
16 | Observational facility
17 |
18 |
19 |
20 |
21 |
22 | Manually specified. See reference
23 |
24 |
25 | Manually specified. See reference
26 |
27 |
28 | Minimum filter wavelength. Defined as the first lambda value with a transmission at least 1% of maximum transmission
29 |
30 |
31 | Maximum filter wavelength. Defined as the last lambda value with a transmission at least 1% of maximum transmission
32 |
33 |
34 | Effective width. Defined as integ[x*filter(x) dx].\nEquivalent to the horizontal size of a rectangle with height equal to maximum transmission and with the same area that the one covered by the filter transmission curve.
35 |
36 |
37 | Central wavelength. Defined as the central wavelength between the two points defining FWMH
38 |
39 |
40 | Peak wavelength. Defined as sqrt{integ[x*filter(x) dx]/integ[filter(x) dx/x]}
41 |
42 |
43 | Peak wavelength. Defined as the lambda value with larger transmission
44 |
45 |
46 | Photon distribution based effective wavelength. Defined as integ[x^2*filter(x)*vega(x) dx]/integ[x*filter(x)*vega(x) dx]
47 |
48 |
49 | Full width at half maximum. Defined as the difference between the two wavelengths for which filter transmission is half maximum
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Photometric system
13 |
14 |
15 |
16 |
17 |
18 | Mean wavelength. Defined as integ[x*filter(x) dx]/integ[filter(x) dx]
19 |
20 |
21 | Effective wavelength. Defined as integ[x*filter(x)*vega(x) dx]/integ[filter(x)*vega(x) dx]
22 |
23 |
24 | Minimum filter wavelength. Defined as the first lambda value with a transmission at least 1% of maximum transmission
25 |
26 |
27 | Maximum filter wavelength. Defined as the last lambda value with a transmission at least 1% of maximum transmission
28 |
29 |
30 | Effective width. Defined as integ[x*filter(x) dx].\nEquivalent to the horizontal size of a rectangle with height equal to maximum transmission and with the same area that the one covered by the filter transmission curve.
31 |
32 |
33 | Central wavelength. Defined as the central wavelength between the two points defining FWMH
34 |
35 |
36 | Peak wavelength. Defined as sqrt{integ[x*filter(x) dx]/integ[filter(x) dx/x]}
37 |
38 |
39 | Peak wavelength. Defined as the lambda value with larger transmission
40 |
41 |
42 | Photon distribution based effective wavelength. Defined as integ[x^2*filter(x)*vega(x) dx]/integ[x*filter(x)*vega(x) dx]
43 |
44 |
45 | Full width at half maximum. Defined as the difference between the two wavelengths for which filter transmission is half maximum
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Photometric system
13 |
14 |
15 |
16 |
17 |
18 | Mean wavelength. Defined as integ[x*filter(x) dx]/integ[filter(x) dx]
19 |
20 |
21 | Effective wavelength. Defined as integ[x*filter(x)*vega(x) dx]/integ[filter(x)*vega(x) dx]
22 |
23 |
24 | Minimum filter wavelength. Defined as the first lambda value with a transmission at least 1% of maximum transmission
25 |
26 |
27 | Maximum filter wavelength. Defined as the last lambda value with a transmission at least 1% of maximum transmission
28 |
29 |
30 | Effective width. Defined as integ[x*filter(x) dx].\nEquivalent to the horizontal size of a rectangle with height equal to maximum transmission and with the same area that the one covered by the filter transmission curve.
31 |
32 |
33 | Central wavelength. Defined as the central wavelength between the two points defining FWMH
34 |
35 |
36 | Peak wavelength. Defined as sqrt{integ[x*filter(x) dx]/integ[filter(x) dx/x]}
37 |
38 |
39 | Peak wavelength. Defined as the lambda value with larger transmission
40 |
41 |
42 | Photon distribution based effective wavelength. Defined as integ[x^2*filter(x)*vega(x) dx]/integ[x*filter(x)*vega(x) dx]
43 |
44 |
45 | Full width at half maximum. Defined as the difference between the two wavelengths for which filter transmission is half maximum
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Photometric system
13 |
14 |
15 |
16 |
17 | Mean wavelength. Defined as integ[x*filter(x) dx]/integ[filter(x) dx]
18 |
19 |
20 | Effective wavelength. Defined as integ[x*filter(x)*vega(x) dx]/integ[filter(x)*vega(x) dx]
21 |
22 |
23 | Minimum filter wavelength. Defined as the first lambda value with a transmission at least 1% of maximum transmission
24 |
25 |
26 | Maximum filter wavelength. Defined as the last lambda value with a transmission at least 1% of maximum transmission
27 |
28 |
29 | Effective width. Defined as integ[x*filter(x) dx].\nEquivalent to the horizontal size of a rectangle with height equal to maximum transmission and with the same area that the one covered by the filter transmission curve.
30 |
31 |
32 | Central wavelength. Defined as the central wavelength between the two points defining FWMH
33 |
34 |
35 | Peak wavelength. Defined as sqrt{integ[x*filter(x) dx]/integ[filter(x) dx/x]}
36 |
37 |
38 | Peak wavelength. Defined as the lambda value with larger transmission
39 |
40 |
41 | Photon distribution based effective wavelength. Defined as integ[x^2*filter(x)*vega(x) dx]/integ[x*filter(x)*vega(x) dx]
42 |
43 |
44 | Full width at half maximum. Defined as the difference between the two wavelengths for which filter transmission is half maximum
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Photometric system
13 |
14 |
15 | Detector type
16 |
17 |
18 | Instrument
19 |
20 |
21 | Observational facility
22 |
23 |
24 |
25 |
26 |
27 | Mean wavelength. Defined as integ[x*filter(x) dx]/integ[filter(x) dx]
28 |
29 |
30 | Effective wavelength. Defined as integ[x*filter(x)*vega(x) dx]/integ[filter(x)*vega(x) dx]
31 |
32 |
33 | Minimum filter wavelength. Defined as the first lambda value with a transmission at least 1% of maximum transmission
34 |
35 |
36 | Maximum filter wavelength. Defined as the last lambda value with a transmission at least 1% of maximum transmission
37 |
38 |
39 | Effective width. Defined as integ[x*filter(x) dx].\nEquivalent to the horizontal size of a rectangle with height equal to maximum transmission and with the same area that the one covered by the filter transmission curve.
40 |
41 |
42 | Central wavelength. Defined as the central wavelength between the two points defining FWMH
43 |
44 |
45 | Peak wavelength. Defined as sqrt{integ[x*filter(x) dx]/integ[filter(x) dx/x]}
46 |
47 |
48 | Peak wavelength. Defined as the lambda value with larger transmission
49 |
50 |
51 | Photon distribution based effective wavelength. Defined as integ[x^2*filter(x)*vega(x) dx]/integ[x*filter(x)*vega(x) dx]
52 |
53 |
54 | Full width at half maximum. Defined as the difference between the two wavelengths for which filter transmission is half maximum
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Photometric system
13 |
14 |
15 | Observational facility
16 |
17 |
18 |
19 |
20 |
21 | Mean wavelength. Defined as integ[x*filter(x) dx]/integ[filter(x) dx]
22 |
23 |
24 | Effective wavelength. Defined as integ[x*filter(x)*vega(x) dx]/integ[filter(x)*vega(x) dx]
25 |
26 |
27 | Minimum filter wavelength. Defined as the first lambda value with a transmission at least 1% of maximum transmission
28 |
29 |
30 | Maximum filter wavelength. Defined as the last lambda value with a transmission at least 1% of maximum transmission
31 |
32 |
33 | Effective width. Defined as integ[x*filter(x) dx].\nEquivalent to the horizontal size of a rectangle with height equal to maximum transmission and with the same area that the one covered by the filter transmission curve.
34 |
35 |
36 | Central wavelength. Defined as the central wavelength between the two points defining FWMH
37 |
38 |
39 | Peak wavelength. Defined as sqrt{integ[x*filter(x) dx]/integ[filter(x) dx/x]}
40 |
41 |
42 | Peak wavelength. Defined as the lambda value with larger transmission
43 |
44 |
45 | Photon distribution based effective wavelength. Defined as integ[x^2*filter(x)*vega(x) dx]/integ[x*filter(x)*vega(x) dx]
46 |
47 |
48 | Full width at half maximum. Defined as the difference between the two wavelengths for which filter transmission is half maximum
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Instrument
13 |
14 |
15 | Observational facility
16 |
17 |
18 |
19 |
20 | Mean wavelength. Defined as integ[x*filter(x) dx]/integ[filter(x) dx]
21 |
22 |
23 | Effective wavelength. Defined as integ[x*filter(x)*vega(x) dx]/integ[filter(x)*vega(x) dx]
24 |
25 |
26 | Minimum filter wavelength. Defined as the first lambda value with a transmission at least 1% of maximum transmission
27 |
28 |
29 | Maximum filter wavelength. Defined as the last lambda value with a transmission at least 1% of maximum transmission
30 |
31 |
32 | Effective width. Defined as integ[x*filter(x) dx].\nEquivalent to the horizontal size of a rectangle with height equal to maximum transmission and with the same area that the one covered by the filter transmission curve.
33 |
34 |
35 | Central wavelength. Defined as the central wavelength between the two points defining FWMH
36 |
37 |
38 | Peak wavelength. Defined as sqrt{integ[x*filter(x) dx]/integ[filter(x) dx/x]}
39 |
40 |
41 | Peak wavelength. Defined as the lambda value with larger transmission
42 |
43 |
44 | Photon distribution based effective wavelength. Defined as integ[x^2*filter(x)*vega(x) dx]/integ[x*filter(x)*vega(x) dx]
45 |
46 |
47 | Full width at half maximum. Defined as the difference between the two wavelengths for which filter transmission is half maximum
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
6538.000000
60 |
0.006486
61 |
62 |
63 |
6540.000000
64 |
0.013323
65 |
66 |
67 |
6542.000000
68 |
0.027278
69 |
70 |
71 |
6544.000000
72 |
0.055361
73 |
74 |
75 |
6546.000000
76 |
0.113072
77 |
78 |
79 |
6548.000000
80 |
0.223523
81 |
82 |
83 |
6550.000000
84 |
0.400950
85 |
86 |
87 |
6552.000000
88 |
0.590489
89 |
90 |
91 |
6554.000000
92 |
0.704917
93 |
94 |
95 |
6556.000000
96 |
0.749567
97 |
98 |
99 |
6558.000000
100 |
0.767464
101 |
102 |
103 |
6560.000000
104 |
0.777044
105 |
106 |
107 |
6562.000000
108 |
0.778400
109 |
110 |
111 |
6564.000000
112 |
0.770989
113 |
114 |
115 |
6566.000000
116 |
0.755081
117 |
118 |
119 |
6568.000000
120 |
0.734563
121 |
122 |
123 |
6570.000000
124 |
0.718113
125 |
126 |
127 |
6572.000000
128 |
0.713865
129 |
130 |
131 |
6574.000000
132 |
0.709888
133 |
134 |
135 |
6576.000000
136 |
0.647160
137 |
138 |
139 |
6578.000000
140 |
0.439003
141 |
142 |
143 |
6580.000000
144 |
0.199933
145 |
146 |
147 |
6582.000000
148 |
0.076105
149 |
150 |
151 |
6584.000000
152 |
0.029448
153 |
154 |
155 |
6586.000000
156 |
0.012509
157 |
158 |
159 |
6588.000000
160 |
0.005741
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/svo_filters/data/plots/G141.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hover2pi/svo_filters/ac7fe3a7c405627810ae4d35dc29c118d1b6def8/svo_filters/data/plots/G141.png
--------------------------------------------------------------------------------
/svo_filters/data/plots/H.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hover2pi/svo_filters/ac7fe3a7c405627810ae4d35dc29c118d1b6def8/svo_filters/data/plots/H.png
--------------------------------------------------------------------------------
/svo_filters/data/plots/filtered.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hover2pi/svo_filters/ac7fe3a7c405627810ae4d35dc29c118d1b6def8/svo_filters/data/plots/filtered.png
--------------------------------------------------------------------------------
/svo_filters/setup_package.py:
--------------------------------------------------------------------------------
1 | from distutils.extension import Extension
2 |
3 | def get_package_data():
4 | return {'svo_filters': ['data/*', 'data/filters/*', 'data/plots/*', 'data/spectra/*']}
5 |
--------------------------------------------------------------------------------
/svo_filters/test_svo.py:
--------------------------------------------------------------------------------
1 | """Some tests to make sure the filters work as intended"""
2 | import unittest
3 |
4 | import astropy.units as q
5 | import astropy.table as at
6 | import numpy as np
7 | from bokeh.plotting import figure
8 |
9 | from svo_filters import svo
10 |
11 |
12 | class TestFilter(unittest.TestCase):
13 | """Tests for Filter class"""
14 | def setUp(self):
15 | pass
16 |
17 | def test_info(self):
18 | """Test that the info attr works"""
19 | filt = svo.Filter('2MASS.J')
20 | self.assertTrue(filt.info() == None)
21 | self.assertTrue(isinstance(filt.info(fetch=True), at.Table))
22 | self.assertRaises(ValueError, setattr, filt, 'wave', np.arange(10))
23 | self.assertRaises(ValueError, setattr, filt, 'throughput', np.arange(1))
24 |
25 | def test_no_filter(self):
26 | """Test if exception is raised for bogus filter"""
27 | self.assertRaises(IndexError, svo.Filter, 'BAD_FILTER')
28 |
29 | def test_filter_web(self):
30 | """Test if Filter object is created from web query"""
31 | filt = svo.Filter('Generic/Johnson.B')
32 |
33 | self.assertTrue(isinstance(filt, svo.Filter))
34 |
35 | def test_filter_xml(self):
36 | """Test if Filter object is created properly"""
37 | filt = svo.Filter('2MASS.J')
38 |
39 | self.assertTrue(isinstance(filt, svo.Filter))
40 |
41 | def test_filter_txt(self):
42 | """Test if Filter object is created properly"""
43 | filt = svo.Filter('NIRISS.GR700XD.1')
44 |
45 | self.assertTrue(isinstance(filt, svo.Filter))
46 |
47 | def test_filter_tophat(self):
48 | """Test if Filter object is created properly"""
49 | # Good tophat
50 | filt = svo.Filter('tophat', wave_min=0.8*q.um, wave_max=1.2*q.um)
51 | self.assertTrue(isinstance(filt, svo.Filter))
52 |
53 | # Bad tophat
54 | self.assertRaises(ValueError, svo.Filter, 'tophat')
55 |
56 | def test_filter_bin(self):
57 | """Test that the binning works"""
58 | # Test n_bins
59 | filt = svo.Filter('WFC3_IR.G141', n_bins=10)
60 | self.assertTrue(filt.wave.shape[0] == 10)
61 |
62 | # Test pixels_per_bin
63 | filt = svo.Filter('WFC3_IR.G141', pixels_per_bin=50)
64 | self.assertTrue(filt.wave.shape[1] == 50)
65 |
66 | # Test neither throws an error
67 | self.assertRaises(ValueError, svo.Filter, 'WFC3_IR.G141', n_bins=None,
68 | pixels_per_bin=None)
69 |
70 | def test_filter_units_bad(self):
71 | """Test that changing the wave units to non-length raises exception"""
72 | filt = svo.Filter('WFC3_IR.G141')
73 |
74 | # Fun syntax to test attribute setting
75 | self.assertRaises(ValueError, setattr, filt, 'wave_units', q.second)
76 | self.assertRaises(ValueError, setattr, filt, 'flux_units', q.second)
77 |
78 | def test_spectrum(self):
79 | """Test that the filter gets applied to a spectrum properly"""
80 | filt = svo.Filter('2MASS.J')
81 | spec = [np.linspace(0.9, 2, 1000)*q.um,
82 | np.ones(1000)*q.erg/q.s/q.cm**2/q.AA]
83 |
84 | # Apply the filter to the spectrum
85 | filtered, err_filtered = filt.apply(spec)
86 | self.assertEqual(filtered.shape, filt.wave.squeeze().shape)
87 |
88 | # Check that the propagated errors are all nans since none were given
89 | self.assertTrue(np.all([np.isnan(i) for i in err_filtered]))
90 |
91 | # Check overlap
92 | self.assertEqual(svo.Filter('2MASS.J').overlap(spec), 'full')
93 | self.assertEqual(svo.Filter('2MASS.Ks').overlap(spec), 'partial')
94 | self.assertEqual(svo.Filter('WISE.W4').overlap(spec), 'none')
95 |
96 | def test_filter_apply_binned(self):
97 | """Test that the filter gets applied to a spectrum properly"""
98 | filt = svo.Filter('2MASS.J', n_bins=4)
99 | spec = [np.linspace(0.9, 2, 1000)*q.um,
100 | np.ones(1000)*q.erg/q.s/q.cm**2/q.AA]
101 |
102 | # Apply the filter to the spectrum
103 | filtered, err_filtered = filt.apply(spec, plot=True)
104 | self.assertEqual(filtered.shape, filt.wave.squeeze().shape)
105 |
106 | def test_filter_apply_binned_err(self):
107 | """Test that the filter gets applied to a spectrum with errors properly"""
108 | filt = svo.Filter('2MASS.J', n_bins=4)
109 | funit = q.erg/q.s/q.cm**2/q.AA
110 | spec = [np.linspace(0.9, 2, 1000)*q.um,
111 | np.ones(1000)*funit,
112 | np.ones(1000)*0.05*funit]
113 |
114 | # Apply the filter to the spectrum
115 | filtered, err_filtered = filt.apply(spec)
116 |
117 | # Check that the units are still there
118 | self.assertEqual(filtered.unit,funit)
119 | self.assertEqual(err_filtered.shape, filt.wave.squeeze().shape)
120 |
121 | def test_filter_apply_no_units(self):
122 | """Test that the apply method works with and without units"""
123 | filt = svo.Filter('2MASS.J')
124 | spec = [np.linspace(0.9, 2, 1000),
125 | np.ones(1000)]
126 |
127 | # Apply the filter to the spectrum
128 | filtered, err_filtered = filt.apply(spec)
129 | self.assertFalse(hasattr(filtered, 'unit'))
130 | self.assertTrue(np.all([np.isnan(i) for i in err_filtered]))
131 |
132 | def test_plot(self):
133 | """Test that the plots are produced properly"""
134 | filt = svo.Filter('2MASS.J')
135 | filt.plot(details=True)
136 | plt = filt.plot(draw=False)
137 |
138 | self.assertTrue(type(plt) == figure)
139 |
140 | def test_filter_monotonic(self):
141 | """Test that non-monotonic filters are treated correctly"""
142 | filt = svo.Filter('Palomar/ZTF.g')
143 | self.assertFalse(np.any(np.diff(filt.wave)<=0))
144 |
145 |
146 | class TestFilterList(unittest.TestCase):
147 | """Tests for filter function"""
148 | def setUp(self):
149 | pass
150 |
151 | def test_default(self):
152 | """Test default directory"""
153 | filts = svo.filters()
154 | self.assertTrue(len(filts) > 0)
155 |
--------------------------------------------------------------------------------
/svo_filters/utils.py:
--------------------------------------------------------------------------------
1 | import astropy.units as q
2 | import numpy as np
3 |
4 |
5 | def _padded_differences(arr, pad_val=1e20):
6 | """
7 |
8 | Parameters
9 | ----------
10 | arr: array-like
11 | pad_val: astropy.units.quantity, float, int
12 | value for padding the first element of the difference array by when calculating
13 | monotonically increasing (or not) differences.
14 | """
15 | if isinstance(arr, q.Quantity):
16 | # Quantity units cannot be padded by non-quantity unless using this wrapper.
17 | diff = arr.ediff1d(to_begin=pad_val)
18 | else:
19 | diff = np.ediff1d(arr, to_begin=pad_val)
20 | return diff
21 |
22 | def incremented_monotonic(arr, increment=None, increment_step=1000):
23 | """Returns input if monotonically increasing. Otherwise
24 | increment repeated elements by `increment`, which will be set to 1/`increment_step`
25 | of the smallest difference in array if `None`, the default.
26 | If not monotonically increasing (ignoring repeated elements), raises `ValueError`.
27 |
28 | Parameters
29 | ----------
30 | arr: array-like
31 | array to check for increment. Also handles astropy.units.quantity.Quantity arrays.
32 | increment: astropy.units.quantity, float, int (optional)
33 | value to increment repeated elements by. Set to 1/`increment_step` of the smallest difference
34 | in array if `None`, the default. Unit conversion will be attempted if array is an instance
35 | of astropy.units.quantity.Quantity.
36 | increment_step: float, int
37 | The relative size difference between repeated elements if automatically determining. Only
38 | used if `increment = None`.
39 |
40 | Returns
41 | -------
42 | array-like
43 | Input array if monotonically increasing else input array where repeat values
44 | have been incremented by `increment`.
45 | """
46 | diff = _padded_differences(arr)
47 |
48 | if np.any(diff<0):
49 | raise ValueError("Input array must be monotonically increasing except for repeated values.")
50 | non_monotonic_mask = diff<=0
51 |
52 | # Exit early if monotonic
53 | if np.all(~non_monotonic_mask):
54 | return arr
55 |
56 | if increment is None:
57 | # a thousanth of the minimimum non-zero increment.
58 | increment = np.nanmin(diff[~non_monotonic_mask])/increment_step
59 | # Try to help user with unit conversion, will fail if unconvertable.
60 | elif isinstance(arr, q.Quanity):
61 | increment = increment << arr.unit
62 |
63 | #non_monotonic_mask = non_monotonic_mask.reshape(arr.shape)
64 | repeats, multiples = get_multipliers(non_monotonic_mask)
65 | if isinstance(increment, q.Quantity):
66 | multiples = multiples << q.dimensionless_unscaled
67 | multiples *= increment
68 |
69 | flatarr = arr.flatten()
70 | flatarr[repeats] += multiples
71 | return flatarr.reshape(arr.shape)
72 |
73 |
74 | def breadth_first(repeats, state, row):
75 | """somewhat convoluted 1D breadth first search
76 | for getting multiples of repeated elements.
77 | """
78 | queue = [repeats[row]]
79 | index = 1
80 | additions = [index]
81 | state.append(row)
82 | while len(queue) > 0:
83 | idx = queue.pop(0)
84 |
85 | #print(idx, idx+1, repeats)
86 | if idx+1 in repeats:
87 | neighbor = idx+1
88 | state.append(row+index)
89 | index += 1
90 | queue.append(neighbor)
91 | additions.append(index)
92 |
93 | return additions, state
94 |
95 |
96 | def get_multipliers(mask):
97 | """Get all repeats and their multiples using breadth first search
98 |
99 | Parameters
100 | ----------
101 | mask: array_like
102 | array of booleans representing repeated elements. True for repeated.
103 |
104 | Returns
105 | -------
106 | tuple
107 | tuple of array_like of repeated indexes and their multiples for use in
108 | shifting multiple repeated indexes.
109 | """
110 | repeats = np.nonzero(mask.flatten())[0]
111 | if len(repeats)==0:
112 | raise ValueError("No repeats found. Input mask all False")
113 | groups = []
114 | state = []
115 | for j,val in enumerate(repeats):
116 | if j in state:
117 | continue
118 | additions, state = breadth_first(repeats, state, j)
119 | groups.append(additions)
120 | groups = np.array([element for sublist in groups for element in sublist])
121 |
122 | return repeats, groups
123 |
--------------------------------------------------------------------------------