-
-
Notifications
You must be signed in to change notification settings - Fork 132
Fitting of Spectrum1D #210
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
Conversation
docs/fitting.rst
Outdated
|
|
||
| Original spectrum (blue) and fitted spectrum (orange). | ||
|
|
||
| .. automodpai:: specuilts.fitting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
argh.. darn fingers :). Thanks! Will fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, wait, not just 1 but 2 typos in one line! coffee, need more coffee
|
I'm a bit confused by this approach. Why have the user provide a list of separate models? Why not have the user provide a single compound model? It seems that the Also, the docs seem to give the impression that the returned object is a list of models matching those that were put in, but that's a bit of an over simplification, yeah? The result is a model -- a compound model, which the user can query for a list of the composing sub models, or use directly as a simple model representation of the spectrum, or even use as an input into a more complex spectrum model. From my understanding, this approach feels a little more complicated than simply asking the user to look at the astropy docs for how to compose a compound model, and feed that, along with some spectrum data, into a fitter. I think I might just be missing the bigger picture? |
|
@nmearl This is a work in progress. @eteq and I had a long discussion about the steps to fitting spectra and how to make it as modular as possible. This is the last of the fitting steps in that framework he and I discussed. He is firming up the framework and interface from our discussion. Once that is completed, I will come back to this work. cc @eteq |
|
Great! Sorry to jump the gun. |
|
@eteq In the https://github.com/spacetelescope/dat_pyinthesky/blob/master/pyinthesky_specutils_fitting.ipynb you have the Given the analysis work and discussion of region, I wonder if it is better to rename |
|
@brechmos-stsci - it seems that this will need a rebase as many unrelated changes has been merged in from master. |
|
Going down a rabbit hole and need some guidance. For fitting one could potentially pass in a compound astropy model, but astropy fitting currently can not fit a compound model that has sub-models that has parameters with astropy units. So, my plan was to convert the compound model and spectral data to a common set of units, strip the units, do the fitting, add the units back onto the fitted model and then convert fitted model units back to the original units. So, going down this rabbit hole: Attempt 1) I originally was just going take each sub-model of the compound model, create a new sub-model of the same type, then convert and set its parameters. The problem is for models such as Chebyshev1D one needs to know the 'order' to create a new instance. So, not easy to do model creation in simple, general way given some models have input that define the number of parameters. Attempt 2) So, rather than create a new sub-model I was going to do a So, basically, I have gone down this rabbit hole and there has to be a better way to do this. It all comes down to the fact that astropy fitting does not like compound models that have units. @eteq @stscicrawford @nmearl @bsipocz Any ideas on something a little cleaner I could do? [Update: I figured out a way to do it with stripping units, but I still wonder if there is a better way to do it] |
|
This has been an on going issue, I have a couple of open issues with this. I tackled the same thing when developing spectacle. To avoid this issue, I had to ensure that every model used provided a Finally, for some reason with a long winded explanation, I had to create defined classes for the compound models. This may or may not be necessary, but it seemed to alleviate some issues with astropy dealing directly with fitting a compound model as opposed to just what it thinks is a custom model. I'll certainly comb through your PR and see if I can't offer some extra help if I can. |
|
compound models are also due to be refactored, but I don't exactly know the timescale and extent of it though, you may want to check it with Nadia and Perry. |
|
After numerous discussion with Nadia, Tom, etc etc, I now have a working set of code (ie it fits compound models with units). @bsipocz, understood, but not sure how long that will be to get into astropy. This PR is not quite ready, but it passes tests on my machine and I plotted the data and fitted model/compound model and it looks decent: I will need to clean up this PR a bit. So, as a summary, astropy fitting will not fit a CompoundModel that has units. So, I stripped the units off the compound model and created a new model. After discussions with several people, it seems the only way to get a representation of the submodels with operators is to use Tomorrow, I might clean up this entry but I wanted to get all my thoughts down before I go for the day. |
a212ac9 to
c9b77eb
Compare
|
Ok. after long last, many discussions with people about astropy modeling, compound models and the idiosyncrasies I finally have a version of spectra fitting that works (for at least the test cases :) ). @stscicrawford @eteq @bsipocz and anyone else, please take a look through it. Here are the caveats:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of inline comments, most pretty straightforward typos and the like. A few that didn't fit inline:
- Should have a section on continuum fitting in the docs. For now this could just be a quick stub that shows a call to the generic fitter (and a few words on what "generic" means here), to be later expanded if/when there are cleverer continuum-fitting functions.
- I'm confused why the exciser is in
utilsrather than a method onSpectrum1DorSpectralRegion. Or is it that #289 is effectively replacing this anyway and it's just a parallel-PR's issue? - I really like the examples you showed in your comment #210 (comment) . Am I right that's from the tests? I think it would be neat to turn that into a "gallery" in the docs - you could use the
.. plot::directive to implement all of them by just importing the test functions and plotting the result?
docs/fitting.rst
Outdated
| >>> np.random.seed(42) | ||
|
|
||
|
|
||
| For the purpose of the example, build a ``spectrum1d`` variable that will be used in the fitting: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"variable" -> "object"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
k
docs/fitting.rst
Outdated
| >>> spectrum1d = Spectrum1D(spectral_axis=wave_um, flux=flux_e1) | ||
|
|
||
|
|
||
| .. figure:: img/fitting_original.jpg |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the result of the above, right? If you use the plot sphinx directive, it will automatically do this instead of you having to manage the image files.
See e.g. http://docs.astropy.org/en/stable/visualization/normalization.html#matplotlib-normalization
and the corresponding rst at
https://github.com/astropy/astropy/blob/master/docs/visualization/normalization.rst
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take a look at this.
docs/fitting.rst
Outdated
|
|
||
| Spectrum to be fit. | ||
|
|
||
| Now that there is a ``spectrum1d`` to fit, the real fitting setup must happen. First create |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
``spectrum1d``
->
`~specutils.Spectrum1D`
(to make it a live link)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
k
|
|
||
| # In this case the window defines the area around the center of each model | ||
| if window is not None and isinstance(window, (float, int)): | ||
| center = model.mean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not all models have the same definition of "center". My instinct is to right a heuristic function to determine the center - it should work for Gaussian, Lorentzian, and Voigt, and also try some obvious ones like "mean" or "center", but other than that just give up and tell the user "sorry, you've used too weird of a model for me to know what you mean".
That said, a valid response is "won't do in this PR, make an issue to track it for later"!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| # Make a new instance of the class. | ||
| # | ||
|
|
||
| if isinstance(sub_model, models.PolynomialModel): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternative solution to this that's a bit more general:
if any([p.default == p.empty for p in inspect.signature(sub_model.__class__).parameters.values() if p.kind==p.POSITIONAL_OR_KEYWORD])
You might want to unpack that into multiple lines (😉 ), but it looks to me like it does the job: if a model class has a keyword without a default, it will be treated like Polynomial. I think that's basically the key thing here, right? That there's no default?
You'd probably then have to programatically pick out the parameter name using the signature to replace the sub_model.degree in the next line, but that should work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Also falls under "you can assign this to @eteq since it's his crazy idea, though 😉)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. I would like to suggest this goes into a new PR once this PR is merged.
They are from the tests. I added them into the docs using |
|
Current test failures are unrelated and need to be addressed upstream in https://github.com/astropy/ci-helpers. A workaround in the meantime would be setting |
|
I made some doc updates in 3273b62 as promised, but other than that (and a series of issues I'll create for enhancements), looks good, and will merge as soon as tests pass. |

This PR enables the ability to fit a Spectrum1D object based on a list of
astropy.modeling.modelswhere each model in the list is set with a initial conditions. There is the ability to choose differentastropy.modeling.fittersas well.Not mergable. Just a WIP PR.