Skip to content
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

New API for interactive filter lookups #14

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,53 @@ Contents
Simple example
^^^^^^^^^^^^^^

Find available filters like this:

.. code-block:: python

>>> from tynt.lookup import filters
>>> # filters.<TAB> # this works in a Jupyter environment, OR:
>>> dir(filters) # this works in any interactive environment
['CAHA',
'CHEOPS',
'CTIO',
'GAIA',
...

To see the filters available within a filter set:

.. code-block:: python

>>> from tynt.lookup import filters

>>> filters.Kepler
<FilterSet: "Kepler"
Available filters: ["Kepler_K"]>

Plot the filter transmittance curve:

.. plot::
:include-source:

from tynt.lookup import filters

filters.Kepler.Kepler_K.plot()

Compare several optical filters:

.. plot::
:include-source:

from tynt.lookup import filters

filters.Kepler.Kepler_K.plot(label='Kepler')
filters.CHEOPS.CHEOPS_band.plot(label='CHEOPS')
filters.TESS.TESS_Red.plot(label='TESS')


FilterGenerator
^^^^^^^^^^^^^^^

Let's plot the transmittance curve of the SDSS r' filter:

.. plot::
Expand Down
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ setup_requires = setuptools_scm
install_requires =
numpy
astropy
matplotlib
scipy

[options.extras_require]
all =
Expand Down
85 changes: 77 additions & 8 deletions tynt/core.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import os

import numpy as np
import matplotlib.pyplot as plt

import astropy.units as u
from astropy.io import fits
from astropy.table import Table
from astropy.utils.data import download_file
from astropy.modeling import models
from astropy.modeling.tabular import Tabular1D
from astropy.table import Table
from astropy.utils.data import download_file
from astropy.visualization import quantity_support

__all__ = ['FilterGenerator', 'Filter']

Expand All @@ -17,7 +20,7 @@ class FilterGenerator:
"""
Astronomical filter object generator.
"""
def __init__(self, path=None):
def __init__(self, path=None, name=None):
"""
Parameters
----------
Expand All @@ -28,6 +31,7 @@ def __init__(self, path=None):
path = data_path

self.path = path
self.name = name
self.table = Table(fits.getdata(path))
self.table.add_index('Filter name')

Expand Down Expand Up @@ -152,8 +156,11 @@ def fft_model(x):

astropy_model = fft_model()

filter_set, filter_name = identifier.split('/')
return Filter(
wavelength * u.Angstrom, transmittance, model=astropy_model
wavelength * u.Angstrom, transmittance,
filter_set=filter_set, filter_name=identifier,
model=astropy_model
)

def download_true_transmittance(self, identifier, **kwargs):
Expand All @@ -174,18 +181,28 @@ def download_true_transmittance(self, identifier, **kwargs):
f'theory/fps3/fps.php?ID={identifier}', **kwargs)

true_transmittance = Table.read(path, format='votable')

filter_set, filter_name = identifier.split('/')

return Filter(
true_transmittance['Wavelength'].data.data * u.Angstrom,
true_transmittance['Transmission'].data.data
true_transmittance['Transmission'].data.data,
filter_set=filter_set, filter_name=identifier
)


_filter_generator = FilterGenerator()


class Filter:
"""
Astronomical filter.
"""
@u.quantity_input(wavelength=u.m)
def __init__(self, wavelength, transmittance, model=None):
def __init__(
self, wavelength=None, transmittance=None,
model=None, filter_set=None, filter_name=None
):
"""
Parameters
----------
Expand All @@ -196,9 +213,39 @@ def __init__(self, wavelength, transmittance, model=None):
model : ~astropy.modeling.Model
Astropy model for the transmittance curve
"""
self.wavelength = wavelength
self.transmittance = transmittance
self._wavelength = wavelength
self._transmittance = transmittance
self.model = model
self.filter_set = filter_set
self.filter_name = filter_name

@property
def wavelength(self):
if self._wavelength is None:
self._get_filter_from_name()
return self._wavelength

@wavelength.setter
def wavelength(self, value):
if value is not None:
self._wavelength = value

@property
def transmittance(self):
if self._transmittance is None:
self._get_filter_from_name()
return self._transmittance

@transmittance.setter
def transmittance(self, value):
if value is not None:
self._transmittance = value

def _get_filter_from_name(self):
name = f"{self.filter_set}/{self.filter_name.replace('__', '.')}"
filt = _filter_generator.reconstruct(name)
self.wavelength = filt.wavelength
self.transmittance = filt.transmittance

@property
def table(self):
Expand All @@ -212,3 +259,25 @@ def table(self):
"""
return Tabular1D(points=self.wavelength,
lookup_table=self.transmittance)

def __repr__(self):
if None not in (self.filter_name, self.filter_set):
return f"<Filter: {self.filter_set}/{self.filter_name}>"
return "<Filter>"

def plot(self, ax=None, x_unit=u.um, y_label='Transmittance', **kwargs):

if ax is None:
ax = plt.gca()

label = kwargs.pop('label', self.filter_name)

with quantity_support():
ax.plot(
self.wavelength.to(x_unit), self.transmittance,
label=label, **kwargs
)
ax.legend()

if y_label is not None:
ax.set(ylabel=y_label)
73 changes: 73 additions & 0 deletions tynt/lookup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from collections import defaultdict
from tynt.core import Filter, _filter_generator

__all__ = ['filters']


class FilterSet:

def __init__(self, filter_set, filter_names):
self._filter_set = filter_set
self._filter_names = filter_names
self.filters = set()
for filter_name in filter_names:
fname = filter_name.replace('.', '_')
setattr(
self, fname,
Filter(filter_set=filter_set, filter_name=filter_name)
)
self.filters.add(f'"{fname}"')

def __repr__(self):
return (f"<FilterSet: \"{self._filter_set}\"\n "
f"Available filters: [{', '.join(sorted(self.filters))}]>")


def assemble_filter_sets():

filter_sets = defaultdict(list)

for name in _filter_generator.available_filters():
filter_set, filter_name = name.split('/')
filter_sets[filter_set].append(filter_name)

sets = dict()
for filter_set, filter_names in filter_sets.items():
sets[filter_set] = FilterSet(filter_set, filter_names)

return sets


class DefaultFacilities:
TWOMASS = None
SLOAN = None
Kepler = None
TESS = None
HST = None
JWST = None
LSST = None
Keck = None
WISE = None
WFIRST = None
Roman = None
Spitzer = None
GAIA = None
CHEOPS = None


class FilterLookup(DefaultFacilities):
_accessors = set()

def __init__(self):

filter_sets = assemble_filter_sets()

for name, filter_set in filter_sets.items():
if name[0].isnumeric():
name = name.replace('2', 'TWO')

setattr(self, name, filter_set)
self._accessors.add(name)


filters = FilterLookup()
14 changes: 8 additions & 6 deletions tynt/tests/test_core.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import pytest
import numpy as np
from astropy.tests.helper import assert_quantity_allclose

import astropy.units as u
from astropy.tests.helper import assert_quantity_allclose
from scipy.integrate import trapezoid

from ..core import FilterGenerator
from tynt.core import FilterGenerator

filter_generator = FilterGenerator()

Expand Down Expand Up @@ -68,11 +70,11 @@ def test_lambda_eff_w_eff(
for identifier in filters:
filt = filter_generator.reconstruct(identifier)

lambda_bar_approx = (np.trapz(filt.transmittance * filt.wavelength,
filt.wavelength) /
np.trapz(filt.transmittance, filt.wavelength))
lambda_bar_approx = (trapezoid(filt.transmittance * filt.wavelength,
filt.wavelength) /
trapezoid(filt.transmittance, filt.wavelength))

width_approx = (np.trapz(filt.transmittance, filt.wavelength) /
width_approx = (trapezoid(filt.transmittance, filt.wavelength) /
filt.transmittance.max())

w_eff_approx.append(width_approx)
Expand Down
Loading