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

Model fitting: re-estimate model parameters #1952

Merged
merged 5 commits into from
Jan 3, 2023

Conversation

kecnry
Copy link
Member

@kecnry kecnry commented Dec 29, 2022

Description

This pull request implements a plugin API and UI to re-estimate the initial values of free model parameters for individual or all model components.

Screen.Recording.2022-12-29.at.8.53.51.AM.mov

TODO:

Change log entry

  • Is a change log needed? If yes, is it added to CHANGES.rst? If you want to avoid merge conflicts,
    list the proposed change log here for review and add to CHANGES.rst before merge. If no, maintainer
    should add a no-changelog-entry-needed label.

Checklist for package maintainer(s)

This checklist is meant to remind the package maintainer(s) who will review this pull request of some common things to look for. This list is not exhaustive.

  • Are two approvals required? Branch protection rule does not check for the second approval. If a second approval is not necessary, please apply the trivial label.
  • Do the proposed changes actually accomplish desired goals? Also manually run the affected example notebooks, if necessary.
  • Do the proposed changes follow the STScI Style Guides?
  • Are tests added/updated as required? If so, do they follow the STScI Style Guides?
  • Are docs added/updated as required? If so, do they follow the STScI Style Guides?
  • Did the CI pass? If not, are the failures related?
  • Is a milestone set? Set this to bugfix milestone if this is a bug fix and needs to be released ASAP; otherwise, set this to the next major release milestone.
  • After merge, any internal documentations need updating (e.g., JIRA, Innerspace)?

@kecnry kecnry added the plugin Label for plugins common to multiple configurations label Dec 29, 2022
@kecnry kecnry added this to the 3.2 milestone Dec 29, 2022
@kecnry kecnry force-pushed the model-fitting-reestimate branch 2 times, most recently from 8ebc617 to 0eeb211 Compare December 29, 2022 13:55
@codecov
Copy link

codecov bot commented Dec 29, 2022

Codecov Report

Base: 91.79% // Head: 91.79% // Increases project coverage by +0.00% 🎉

Coverage data is based on head (efdae47) compared to base (3e92619).
Patch coverage: 92.68% of modified lines in pull request are covered.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1952   +/-   ##
=======================================
  Coverage   91.79%   91.79%           
=======================================
  Files         140      140           
  Lines       14941    14978   +37     
=======================================
+ Hits        13715    13749   +34     
- Misses       1226     1229    +3     
Impacted Files Coverage Δ
...igs/default/plugins/model_fitting/model_fitting.py 83.77% <86.36%> (-0.03%) ⬇️
...default/plugins/model_fitting/tests/test_plugin.py 100.00% <100.00%> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@kecnry kecnry force-pushed the model-fitting-reestimate branch 2 times, most recently from 49059a6 to a63c2c7 Compare December 29, 2022 17:44
@kecnry kecnry marked this pull request as ready for review December 29, 2022 17:53
@kecnry kecnry force-pushed the model-fitting-reestimate branch 2 times, most recently from 9c8228a to d952c40 Compare December 30, 2022 16:44
Copy link
Contributor

@pllim pllim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks like code and the video is very convincing. Thanks!

new_model['parameters'] = [fixed_params.get(p['name'], p) for p in new_model['parameters']]

# reset traitlet so vue picks up on changes by adding (and then removing) an empty entry,
# this avoids resetting the open state of the accordion in the UI.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤯

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love to know of a better way to do this... or requesting/implementing traitlet.force_update() upstream...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe @mariobuikhuizen can advise but this shouldn't block merge. Just amazed you figured out this is how you make it do what you want. To me, it is like eating pizza with chopsticks. 😸

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Traitlets can't discover in-place changes to a list or dict, so you always need to use methods that produce a new instance. You could consider using:

self.component_models = self.component_models[:model_index] + [new_model] + self.component_models[model_index + 1:]

Or you could use self.send_state("component_models"), which is similar to the envisioned .force_update() function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know about send_state, that seems to do the trick and reads more clearly to me than always rebuilding from scratch, thanks!

@pllim
Copy link
Contributor

pllim commented Dec 30, 2022

Although, do you want to explain this new feature in the user doc?

@kecnry
Copy link
Member Author

kecnry commented Dec 30, 2022

Although, do you want to explain this new feature in the user doc?

The model fitting docs already says "Model Parameters are automatically initialized with a guess. These starting values can be edited by the user. They may also be fixed by selecting the checkbox, so that they are not fit or changed by the model fitting." We could add a little here ("... with a guess from the selected data/subsets. These starting values can be edited by the user or re-estimated by clicking a button..."), but I also am always weary of going in tangents for advanced functionality that is self-discoverable in the UI.

@rosteen
Copy link
Collaborator

rosteen commented Dec 30, 2022

If I click "re-estimate" under one of the model components it works, but if I click the button above the component list I get an error (this is in Cubeviz):

File ~/projects/jdaviz/jdaviz/configs/default/plugins/model_fitting/model_fitting.py:608, in ModelFitting.reestimate_model_parameters(self, model_component_label)
    607 try:
--> 608     model_index, model_comp = [(i, x) for i, x in enumerate(self.component_models)
    609                                if x["id"] == model_component_label][0]
    610 except IndexError:

IndexError: list index out of range

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
File ~/opt/anaconda3/envs/viz_dev/lib/python3.10/site-packages/ipyvue/VueTemplateWidget.py:60, in Events._handle_event(self, _, content, buffers)
     58     getattr(self, "vue_" + event)(data, buffers)
     59 else:
---> 60     getattr(self, "vue_" + event)(data)

File ~/projects/jdaviz/jdaviz/configs/default/plugins/model_fitting/model_fitting.py:590, in ModelFitting.vue_reestimate_model_parameters(self, model_component_label, **kwargs)
    589 def vue_reestimate_model_parameters(self, model_component_label=None, **kwargs):
--> 590     self.reestimate_model_parameters(model_component_label=model_component_label)

File ~/projects/jdaviz/jdaviz/configs/default/plugins/model_fitting/model_fitting.py:611, in ModelFitting.reestimate_model_parameters(self, model_component_label)
    608     model_index, model_comp = [(i, x) for i, x in enumerate(self.component_models)
    609                                if x["id"] == model_component_label][0]
    610 except IndexError:
--> 611     raise ValueError(f"'{model_component_label}' is not a label of an existing model component")  # noqa
    613 # store user-fixed parameters so we can revert after re-initializing
    614 fixed_params = {p['name']: p for p in model_comp['parameters'] if p['fixed']}

ValueError: '{'altKey': False, 'ctrlKey': False, 'metaKey': False, 'shiftKey': False, 'offsetX': 116, 'offsetY': 14, 'clientX': 1127, 'clientY': 564, 'pageX': 1127, 'pageY': 564, 'screenX': 1860, 'screenY': 679, 'x': 1127, 'y': 564}' is not a label of an existing model component

@kecnry kecnry force-pushed the model-fitting-reestimate branch from 46c2c49 to ee8b240 Compare December 30, 2022 21:03
@kecnry
Copy link
Member Author

kecnry commented Dec 30, 2022

@rosteen - should be fixed now, thanks!

@rosteen
Copy link
Collaborator

rosteen commented Dec 30, 2022

Is it known that this doesn't respect spatial subsets in Cubeviz? You can select a small spatial subset such that the collapsed spectrum's flux is much smaller than that for the full cube, and see that, for example, a constant component's estimate is based on the full cube collapse even if you select that spatial subset.

@kecnry
Copy link
Member Author

kecnry commented Jan 3, 2023

Is it known that this doesn't respect spatial subsets in Cubeviz?

This seems to have been broken by #1947... @bmorris3 and I are investigating now and I'll see if we can get the fix in this PR or if it makes more sense to address separately. Thanks for testing that case! 😬

EDIT: fixed in #1954. Hopefully we can get that tested/reviewed/merged and then I'll rebase this PR.

@rosteen
Copy link
Collaborator

rosteen commented Jan 3, 2023

Is it known that this doesn't respect spatial subsets in Cubeviz?

This seems to have been broken by #1947... @bmorris3 and I are investigating now and I'll see if we can get the fix in this PR or if it makes more sense to address separately. Thanks for testing that case! 😬

Well, sorry I didn't catch it there, but good we caught it now I guess!

@kecnry kecnry force-pushed the model-fitting-reestimate branch from c9b6525 to efdae47 Compare January 3, 2023 15:11
@kecnry
Copy link
Member Author

kecnry commented Jan 3, 2023

Re-estimation now works with spatial subsets in cubeviz (note that the estimation is done on the 1d spectrum even if doing a cube fit, which I think is the expected behavior):

Screen.Recording.2023-01-03.at.10.12.31.AM.mov


self.component_models[model_index] = new_model
# length hasn't changed, so we need to force the traitlet to update
self.send_state("component_models")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh, that's good to know about. There might be a few other places we can simplify things with this.

Copy link
Collaborator

@rosteen rosteen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now, all subset combinations are working like I'd expect. Thanks!

@kecnry kecnry merged commit a2f3ce2 into spacetelescope:main Jan 3, 2023
@kecnry kecnry deleted the model-fitting-reestimate branch January 3, 2023 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugin Label for plugins common to multiple configurations Ready for final review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants