Skip to content
Empty file added __init__.py
Empty file.
46 changes: 42 additions & 4 deletions chromatic/rainbows/actions/normalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,20 @@ def normalize(self, axis="wavelength", percentile=50):
# create an empty copy
new = self._create_copy()

# shortcut for the first letter of the axis
a = axis.lower()[0]

# (ignore nan warnings)
with warnings.catch_warnings():
warnings.simplefilter("ignore")

if axis.lower()[0] == "w":
normalization = np.nanpercentile(new.flux, percentile, axis=self.timeaxis)
# get fluxes, with not-OK replaced with nans
flux_for_normalizing = new.get_ok_data()
negative_normalization_message = ""
if a == "w":
normalization = np.nanpercentile(
flux_for_normalizing, percentile, axis=self.timeaxis
)
for k in self._keys_that_respond_to_math:
new.fluxlike[k] = new.get(k) / normalization[:, np.newaxis]
try:
Expand All @@ -58,8 +66,11 @@ def normalize(self, axis="wavelength", percentile=50):
)
except ValueError:
pass
elif axis.lower()[0] == "t":
normalization = np.nanpercentile(self.flux, percentile, axis=self.waveaxis)

elif a == "t":
normalization = np.nanpercentile(
flux_for_normalizing, percentile, axis=self.waveaxis
)
for k in self._keys_that_respond_to_math:
new.fluxlike[k] = new.get(k) / normalization[np.newaxis, :]
try:
Expand All @@ -69,6 +80,33 @@ def normalize(self, axis="wavelength", percentile=50):
except ValueError:
pass

if a in "wt":
thing = {"w": "wavelengths", "t": "times"}[a]
fix = {
"w": """
ok = rainbow.get_median_spectrum() > 0
rainbow[ok, :].normalize()
""",
"t": """
ok = rainbow.get_median_lightcurve() > 0
rainbow[:, ok].normalize()
""",
}[a]
if np.any(normalization < 0):
cheerfully_suggest(
f"""
There are {np.sum(normalization < 0)} negative {thing} that
are going into the normalization of this Rainbow. If you're
not expecting negative fluxes, it may be useful to trim them
away with something like:

{fix}

Otherwise, watch out that your fluxes and uncertainties may
potentially have flipped sign!
"""
)

# append the history entry to the new Rainbow
new._record_history_entry(h)

Expand Down
1 change: 1 addition & 0 deletions chromatic/rainbows/get/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .timelike import *
from .wavelike import *
from .fluxlike import *
1 change: 1 addition & 0 deletions chromatic/rainbows/get/fluxlike/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .subset import *
41 changes: 41 additions & 0 deletions chromatic/rainbows/get/fluxlike/subset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from ....imports import *

__all__ = [
"get_ok_data",
]


def get_ok_data(
self,
y="flux",
minimum_acceptable_ok=1,
):
"""
A small wrapper to get the good data as a 2D array.

Extract fluxes as 2D array, marking data that are not `ok`
either as nan or by inflating uncertainties to infinity.

Parameters
----------
y : array
The desired quantity (default is `flux`)
minimum_acceptable_ok : float, optional
The smallest value of `ok` that will still be included.
(1 for perfect data, 1e-10 for everything but terrible data, 0 for all data)

Returns
-------
flux : array
The fluxes, but with not-OK data replaced with nan.
"""
# get 1D array of what to keep
ok = self.ok >= minimum_acceptable_ok

# create copy of flux array
y = self.get(y) * 1

# set bad values to nan
y[ok == False] = np.nan

return y
2 changes: 1 addition & 1 deletion chromatic/rainbows/get/timelike/median_lightcurve.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ def get_median_lightcurve(self):
"""
with warnings.catch_warnings():
warnings.simplefilter("ignore")
return np.nanmedian(self.flux, axis=0)
return np.nanmedian(self.get_ok_data(), axis=0)
2 changes: 1 addition & 1 deletion chromatic/rainbows/get/wavelike/median_spectrum.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ def get_median_spectrum(self):
"""
with warnings.catch_warnings():
warnings.simplefilter("ignore")
return np.nanmedian(self.flux, axis=1)
return np.nanmedian(self.get_ok_data(), axis=1)
12 changes: 9 additions & 3 deletions chromatic/rainbows/rainbow.py
Original file line number Diff line number Diff line change
Expand Up @@ -817,8 +817,9 @@ def _validate_core_dictionaries(self):

# make sure 2D arrays are uniquely named from 1D
for k in tuple(self.fluxlike.keys()):
if (k in self.wavelike) or (k in self.timelike):
self.fluxlike[f"{k}_2d"] = self.fluxlike.pop(k)
if k is not "ok":
if (k in self.wavelike) or (k in self.timelike):
self.fluxlike[f"{k}_2d"] = self.fluxlike.pop(k)

if "ok" in self.fluxlike:
is_nan = np.isnan(self.fluxlike["flux"])
Expand Down Expand Up @@ -1005,7 +1006,7 @@ def __repr__(self):
get_ok_data_for_wavelength,
)

# import summary statistics for each wavelength
# import summary statistics for each time
from .get.timelike import (
get_average_lightcurve,
get_median_lightcurve,
Expand All @@ -1015,6 +1016,11 @@ def __repr__(self):
set_times_from_astropy,
)

# import 2D summary statistics
from .get.fluxlike import (
get_ok_data,
)

# import visualizations that can act on Rainbows
from .visualizations import (
imshow,
Expand Down
1 change: 1 addition & 0 deletions chromatic/rainbows/readers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# some particular instruments
from .nres import *
from .atoca import *
from .hst import *

# some individual-ish folks
from .espinoza import *
Expand Down
Loading