Skip to content
This repository has been archived by the owner on Jul 22, 2021. It is now read-only.

Commit

Permalink
Merge pull request #500 from nmearl/model-editor-ux-improvements
Browse files Browse the repository at this point in the history
Disallow interaction until user has created a model
  • Loading branch information
javerbukh committed Oct 31, 2018
2 parents bbf7ae5 + 1e8982a commit c59351f
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 66 deletions.
39 changes: 38 additions & 1 deletion specviz/core/hub.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from qtpy.QtWidgets import QApplication
import logging

from .items import DataItem


class Hub:
Expand Down Expand Up @@ -73,6 +75,41 @@ def data_items(self):
"""List of all data items held in the data item model."""
return self.model.items

def append_data_item(self, data_item):
"""
Adds a new data item object to appear in the left data list view.
Parameters
----------
data_item : :class:`~specviz.core.items.PlotDataItem`
The data item to be added to the list view.
"""
if isinstance(data_item, DataItem):
self.workspace.model.appendRow(data_item)
else:
logging.error("Data item model only accepts items of class "
"'DataItem', received '{}'.".format(type(data_item)))

def plot_data_item_from_data_item(self, data_item):
"""
Returns the PlotDataItem associated with the provided DataItem.
Parameters
----------
data_item : :class:`~specviz.core.items.PlotDataItem`
The DataItem from which the associated PlotDataItem will be
returned.
Returns
-------
plot_data_item : :class:`~specviz.core.items.PlotDataItem`
The PlotDataItem wrapping the DataItem.
"""
plot_data_item = self.workspace.proxy_model.item_from_id(
data_item.identifier)

return plot_data_item

def set_active_plugin_bar(self, name=None, index=None):
"""
Sets the currently displayed widget in the plugin side panel.
Expand Down
8 changes: 6 additions & 2 deletions specviz/plugins/model_editor/items.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import numpy as np

from ...core.items import DataItem
import astropy.units as u


class ModelDataItem(DataItem):
Expand All @@ -15,7 +16,10 @@ def flux(self):

result = self.model_editor_model.evaluate()

return result(self.spectral_axis.value) * self.data(self.DataRole).flux.unit
if result is not None:
return result(self.spectral_axis.value) * self.data(self.DataRole).flux.unit

return np.zeros(self.spectral_axis.size) * self.data(self.DataRole).flux.unit

@property
def model_editor_model(self):
Expand Down
28 changes: 25 additions & 3 deletions specviz/plugins/model_editor/model_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,15 @@ def __init__(self, *args, **kwargs):
action.triggered.connect(lambda x, m=v: self._add_fittable_model(m))
models_menu.addAction(action)

# Initially hide the model editor tools until user has selected an
# editable model spectrum object
self.editor_holder_widget.setHidden(True)
self.setup_holder_widget.setHidden(False)

self.equation_edit_button.clicked.connect(
self._on_equation_edit_button_clicked)
self.new_model_button.clicked.connect(self._on_create_new_model)
self.remove_model_button.clicked.connect(self._on_remove_model)

# When a plot data item is select, get its model editor model
# representation
Expand All @@ -51,6 +58,9 @@ def __init__(self, *args, **kwargs):

@plugin.tool_bar(name="New Model", icon=QIcon(":/icons/012-file.svg"))
def on_new_model_triggered(self):
self._on_create_new_model()

def _on_create_new_model(self):
if self.hub.data_item is None:
message_box = QMessageBox()
message_box.setText("No item selected, cannot create model.")
Expand All @@ -74,16 +84,23 @@ def on_new_model_triggered(self):
identifier=uuid.uuid4(),
data=new_spec)

self.hub.workspace.model.appendRow(model_data_item)
self.hub.append_data_item(model_data_item)

plot_data_item = self.hub.workspace.proxy_model.item_from_id(
model_data_item.identifier)
plot_data_item = self.hub.plot_data_item_from_data_item(model_data_item)

# Connect data change signals so that the plot updates when the user
# changes a parameter in the model view model
model_data_item.model_editor_model.dataChanged.connect(
lambda tl, br, r, pi=plot_data_item: self._on_model_data_changed(tl, br, pi))

def _on_remove_model(self):
"""Remove an astropy model from the model editor tree view."""
indexes = self.model_tree_view.selectionModel().selectedIndexes()

if len(indexes) > 0:
selected_idx = indexes[0]
self.model_tree_view.model().removeRow(selected_idx.row())

def _add_fittable_model(self, model):
idx = self.model_tree_view.model().add_model(model())
self.model_tree_view.setExpanded(idx, True)
Expand Down Expand Up @@ -124,8 +141,13 @@ def _on_equation_edit_button_clicked(self):
def _on_plot_item_selected(self, plot_data_item):
if not isinstance(plot_data_item.data_item, ModelDataItem):
self.model_tree_view.setModel(None)
self.editor_holder_widget.setHidden(True)
self.setup_holder_widget.setHidden(False)
return

self.editor_holder_widget.setHidden(False)
self.setup_holder_widget.setHidden(True)

model_data_item = plot_data_item.data_item

# Set the model on the tree view and expand all children initially.
Expand Down
175 changes: 124 additions & 51 deletions specviz/plugins/model_editor/model_editor.ui
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,60 @@
<number>0</number>
</property>
<item>
<widget class="QTreeView" name="model_tree_view">
<attribute name="headerCascadingSectionResizes">
<bool>true</bool>
</attribute>
<widget class="QWidget" name="setup_holder_widget" native="true">
<layout class="QVBoxLayout" name="no_model_layout">
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Create a new model-based spectrum object before adding sub models.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="new_model_button">
<property name="text">
<string>Create New Model</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<property name="autoFillBackground">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<widget class="QWidget" name="editor_holder_widget" native="true">
<layout class="QVBoxLayout" name="model_editor_layout">
<property name="spacing">
<number>0</number>
</property>
Expand All @@ -60,54 +102,85 @@
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="add_model_button">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/plus.svg</normalon>
</iconset>
</property>
<widget class="QTreeView" name="model_tree_view">
<attribute name="headerCascadingSectionResizes">
<bool>true</bool>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="remove_model_button">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/minus.svg</normalon>
</iconset>
<widget class="QWidget" name="widget" native="true">
<property name="autoFillBackground">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="add_model_button">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/plus.svg</normalon>
</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="remove_model_button">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/minus.svg</normalon>
</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="equation_edit_button">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/014-calculator.svg</normalon>
</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QToolButton" name="equation_edit_button">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/014-calculator.svg</normalon>
</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
Expand Down
9 changes: 0 additions & 9 deletions specviz/plugins/model_editor/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,6 @@ def __init__(self, *args, **kwargs):

self.setHorizontalHeaderLabels(["Name", "Value", "Unit", "Fixed"])

from astropy.modeling.models import Gaussian1D, Linear1D

a = Gaussian1D()
l = Linear1D()

self.add_model(a)
self.add_model(l)
self.add_model(Gaussian1D())

@property
def items(self):
return [self.item(idx) for idx in range(self.rowCount())]
Expand Down

0 comments on commit c59351f

Please sign in to comment.