astrofrog / sedfitter

Python version of the SED fitter from Robitaille et al., 2007, ApJS 169 328
http://sedfitter.readthedocs.org
BSD 2-Clause "Simplified" License
20 stars 22 forks source link

Plotter can't handle units #76

Closed keflavich closed 1 year ago

keflavich commented 3 years ago

I suspect this is a regression caused by changes in astropy, but I'm not sure.

The problem line is this in plot.py:

--> 322                 lines.append(np.column_stack([s.wav, flux]))

s.wav has units of u.um, while flux is unitless (but should be mJy). Numpy can't handle mixed units/non-unit values.

Full traceback:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/quantity.py in _to_own_unit(self, value, check_precision)
   1355         try:
-> 1356             _value = value.to_value(self.unit)
   1357         except AttributeError:

AttributeError: 'numpy.ndarray' object has no attribute 'to_value'

During handling of the above exception, another exception occurred:

UnitConversionError                       Traceback (most recent call last)
/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/quantity.py in to_value(self, unit, equivalencies)
    746             try:
--> 747                 scale = self.unit._to(unit)
    748             except Exception:

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/core.py in _to(self, other)
   1095 
-> 1096         raise UnitConversionError(
   1097             f"'{self!r}' is not a scaled version of '{other!r}'")

UnitConversionError: 'Unit(dimensionless)' is not a scaled version of 'Unit("um")'

During handling of the above exception, another exception occurred:

UnitConversionError                       Traceback (most recent call last)
<ipython-input-72-235adb40c5b3> in <module>
----> 1 sedfitter.plot(fit)

/blue/adamginsburg/adamginsburg/repos/sedfitter/sedfitter/plot.py in plot(input_fits, output_dir, select_format, plot_max, plot_mode, sed_type, show_sed, show_convolved, x_mode, y_mode, x_range, y_range, plot_name, plot_info, format, sources, memmap, dpi)
    320                     colors.append(color[color_type][j])
    321             else:
--> 322                 lines.append(np.column_stack([s.wav, flux]))
    323                 colors.append(color[color_type])
    324 

<__array_function__ internals> in column_stack(*args, **kwargs)

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/quantity.py in __array_function__(self, function, types, args, kwargs)
   1518         # implementation.
   1519         if function in SUBCLASS_SAFE_FUNCTIONS:
-> 1520             return super().__array_function__(function, types, args, kwargs)
   1521 
   1522         elif function in FUNCTION_HELPERS:

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/numpy/lib/shape_base.py in column_stack(tup)
    654             arr = array(arr, copy=False, subok=True, ndmin=2).T
    655         arrays.append(arr)
--> 656     return _nx.concatenate(arrays, 1)
    657 
    658 

<__array_function__ internals> in concatenate(*args, **kwargs)

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/quantity.py in __array_function__(self, function, types, args, kwargs)
   1523             function_helper = FUNCTION_HELPERS[function]
   1524             try:
-> 1525                 args, kwargs, unit, out = function_helper(*args, **kwargs)
   1526             except NotImplementedError:
   1527                 return self._not_implemented_or_raise(function, types)

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/quantity_helper/function_helpers.py in concatenate(arrays, axis, out)
    370     # TODO: make this smarter by creating an appropriately shaped
    371     # empty output array and just filling it.
--> 372     arrays, kwargs, unit, out = _iterable_helper(*arrays, out=out, axis=axis)
    373     return (arrays,), kwargs, unit, out
    374 

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/quantity_helper/function_helpers.py in _iterable_helper(out, *args, **kwargs)
    362             raise NotImplementedError
    363 
--> 364     arrays, unit = _quantities2arrays(*args)
    365     return arrays, kwargs, unit, out
    366 

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/quantity_helper/function_helpers.py in _quantities2arrays(unit_from_first, *args)
    343     # as we want to allow arbitrary unit for 0, inf, and nan.
    344     try:
--> 345         arrays = tuple((q._to_own_unit(arg)) for arg in args)
    346     except TypeError:
    347         raise NotImplementedError

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/quantity_helper/function_helpers.py in <genexpr>(.0)
    343     # as we want to allow arbitrary unit for 0, inf, and nan.
    344     try:
--> 345         arrays = tuple((q._to_own_unit(arg)) for arg in args)
    346     except TypeError:
    347         raise NotImplementedError

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/quantity.py in _to_own_unit(self, value, check_precision)
   1370             try:
   1371                 as_quantity = Quantity(value)
-> 1372                 _value = as_quantity.to_value(self.unit)
   1373             except UnitsError:
   1374                 # last chance: if this was not something with a unit

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/quantity.py in to_value(self, unit, equivalencies)
    748             except Exception:
    749                 # Short-cut failed; try default (maybe equivalencies help).
--> 750                 value = self._to_value(unit, equivalencies)
    751             else:
    752                 value = self.view(np.ndarray)

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/quantity.py in _to_value(self, unit, equivalencies)
    667         if equivalencies == []:
    668             equivalencies = self._equivalencies
--> 669         return self.unit.to(unit, self.view(np.ndarray),
    670                             equivalencies=equivalencies)
    671 

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/core.py in to(self, other, value, equivalencies)
   1131             return UNITY
   1132         else:
-> 1133             return self._get_converter(Unit(other),
   1134                                        equivalencies=equivalencies)(value)
   1135 

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/core.py in _get_converter(self, other, equivalencies)
   1062                             pass
   1063 
-> 1064             raise exc
   1065 
   1066     def _to(self, other):

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/core.py in _get_converter(self, other, equivalencies)
   1047         # if that doesn't work, maybe we can do it with equivalencies?
   1048         try:
-> 1049             return self._apply_equivalencies(
   1050                 self, other, self._normalize_equivalencies(equivalencies))
   1051         except UnitsError as exc:

/orange/adamginsburg/miniconda3/envs/python39/lib/python3.9/site-packages/astropy/units/core.py in _apply_equivalencies(self, unit, other, equivalencies)
   1023         other_str = get_err_str(other)
   1024 
-> 1025         raise UnitConversionError(
   1026             f"{unit_str} and {other_str} are not convertible")
   1027 

UnitConversionError: '' (dimensionless) and 'um' (length) are not convertible
stormnick commented 2 years ago

I am getting the similar issue, but my flux does have units actually (erg/cm^2 s). Instead of the original line I did a very "stupid" fix: `lines.append(np.column_stack([s.wav / u.micron, flux / u.erg u.cm * 2 u.s]))` And it actually worked. I don't think it is a real solution, but I did not see anything wrong with the fit I got in the end.

EDIT (03.12.21):

In case anyone is reading this in the future: since the units of flux seems to be indeed gone for some other models (like in the OP's example), the ugly work around that works in either case would be this:

try:
    lines.append(np.column_stack([s.wav / s.wav.unit, flux / flux.unit]))
except:
    lines.append(np.column_stack([s.wav / s.wav.unit, flux]))
keflavich commented 2 years ago

@Korboal that's a fine workaround; numpy can concatenate things that are unitless-equivalent, and you've effectively dropped the units

astrofrog commented 1 year ago

I think this should be fixed in main - I just stripped the units before stacking as they are not needed for plotting. Can someone confirm this works now?