diff --git a/.travis.yml b/.travis.yml index 752ddce5..36cfc00b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ os: - osx # Setting sudo to false opts in to Travis-CI container-based builds. -sudo: false +sudo: true # The apt packages below are needed for sphinx builds. A full list of packages # that can be included can be found here: @@ -95,4 +95,4 @@ after_success: # If coveralls.io is set up for this package, uncomment the line # below and replace "packagename" with the name of your package. # The coveragerc file may be customized as needed for your package. - # - if [[ $SETUP_CMD == 'test --coverage' ]]; then coveralls --rcfile='packagename/tests/coveragerc'; fi +# - if [[ $SETUP_CMD == 'test --coverage' ]]; then coveralls --rcfile='packagename/tests/coveragerc'; fi \ No newline at end of file diff --git a/docs/source/_static/demo.png b/docs/source/_static/demo.png new file mode 100644 index 00000000..3222252a Binary files /dev/null and b/docs/source/_static/demo.png differ diff --git a/docs/source/_static/viewer.png b/docs/source/_static/viewer.png index cfe47da6..43b0c28b 100644 Binary files a/docs/source/_static/viewer.png and b/docs/source/_static/viewer.png differ diff --git a/docs/source/conf.py b/docs/source/conf.py index 78c20797..7913c9a7 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -68,9 +68,9 @@ # built documents. # # The short X.Y version. -version = '0.1' +version = '0.3' # The full version, including alpha/beta/rc tags. -release = '0.1.0a1' +release = '0.3.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/index.rst b/docs/source/index.rst index 1b2a758e..65447956 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -23,10 +23,10 @@ emission and absorption lines in addition to regions of flat continuua). SpecViz incorporates various methods for fitting such models to data. For more details, see :ref:`doc_model_fitting`. -Furthermore, SpecViz allows for overplotting or simple combining of spectra. +Furthermore, SpecViz allows for overplotting or combining of spectra. SpecViz will soon include the ability to - - Measure the average of multiple spectra, splice a spectrum, and apply Fourier filters. + - Measure the average of multiple spectra, detrending, and apply Fourier filters. - Interactively renormalize data from spectral templates. - Overplot spectral line lists. - And more... @@ -34,7 +34,7 @@ SpecViz will soon include the ability to Demo ---- -.. image:: https://i.vimeocdn.com/video/571749719_640.jpg +.. image:: _static/demo.png :target: https://stsci.box.com/s/6ynrfshzrix3yaxvd3c8bcs4hzltpadz @@ -45,6 +45,7 @@ Installation and Setup :maxdepth: 2 installation + launching Using SpecViz diff --git a/docs/source/installation.rst b/docs/source/installation.rst index 04364683..7c4fdc31 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -31,21 +31,13 @@ any terminal:: $ specviz -PyQt5 version (optional) -^^^^^^^^^^^^^^^^^^^^^^^^ +Uninstalling +^^^^^^^^^^^^ -While the PyQt4 version of SpecViz is currently the default distributed, it -is recommended that you upgrade to using the PyQt5 version if you know that -you do not have any system conflicts. Note that this is entirely optional, -but encouraged due to the fact that `Qt4 development and support has ended -`_. :: +To uninstall via Anaconda, simply type the following at a command line:: - $ conda install --channel https://conda.anaconda.org/spyder-ide pyqt5 - $ conda install --channel https://conda.anaconda.org/nmearl specviz + $ conda uninstall specviz -SpecViz can then be launched via the command line:: - - $ specviz Install via source ------------------ @@ -60,70 +52,58 @@ handled automatically by the setup functions, with the exception of PyQt/PySide. * Numpy * Scipy * PyQtGraph +* qtpy -Installing PyQt/PySide -^^^^^^^^^^^^^^^^^^^^^^ - -The easiest way to install PyQt/PySide is through some package manager. -Please keep in mind that PyQt5 is the recommended PyQt implementation as -`Qt4 development and support has ended `_. - -Below are instructions for installing using *either* `Homebrew `_ *or* `Anaconda `__. +Installing +^^^^^^^^^^ -PyQt5 -""""" +Clone the SpecViz repository somewhere on your system, and install locally using +``pip``. If you are using an Anaconda virtual environment, please be sure to +activate it first before installing: ``$ source activate ``. -Homebrew - `Install using Homebrew for Qt5 `_. +:: -Anaconda - Installing PyQt5 with Anaconda will require installing from the Spyder-IDE - channel as it is not currently a core package (but they're working on it). - :: + $ git clone https://github.com/spacetelescope/specviz.git + $ cd specviz + $ git checkout tags/v0.3.0 + $ pip install -r requirements.txt - $ conda install --channel https://anaconda.org/m-labs/pyqt5 pyqt5 +This uses the ``pip`` installation system, so please note that +1. You need to have ``pip`` installed (included in most Python installations). +2. You do **not** need to run ``python setup.py install``. +3. You do **not** need to install the dependencies by hand (except for PyQt). -PyQt4 -""""" +Likewise, the ``pip`` command will use your default Python to install. +You can specify by using ``pip2`` or ``pip3``, if you're not using a virtual +environment. -Homebrew - `Install using Homebrew for Qt4 `_. -Anaconda - Install using Anaconda:: +PyQt/PySide bindings +^^^^^^^^^^^^^^^^^^^^ - $ conda install pyqt +SpecViz requires PyQt. Currently, only python environments with 3.5 or higher +installed can use ``pip`` to install PyQt5, in which case simply type:: + $ pip install pyqt5 -Installing -^^^^^^^^^^ +to install it on your system. -Clone the SpecViz repository somewhere on your system, and install locally using -``pip``. If you are using an Anaconda virtual environment, please be sure to -activate it first before installing: ``$ source activate ``. +In any other case, PyQt can be installed via anaconda:: -:: + $ conda install pyqt - $ git clone https://github.com/spacetelescope/specviz.git - $ cd specviz - $ git checkout tags/v0.1.2rc3 - $ pip install -r requirements.txt +SpecViz works with with PyQt4 and PySide, but it is recommended that users use +PyQt5 if available. -.. note:: - This uses the ``pip`` installation system, so please note that +Uninstalling +^^^^^^^^^^^^ - 1. You need to have ``pip`` installed (included in most Python - installations). - 2. You do **not** need to run ``python setup.py install``. - 3. You do **not** need to install the dependencies by hand (except for PyQt). +To uninstall via ``pip``, simply type the following at a command line:: - Likewise, the ``pip`` command will use your default Python to install. - You can specify by using ``pip2`` or ``pip3``, if you're not using a virtual - environment. + $ pip uninstall specviz Known Issues @@ -154,19 +134,3 @@ This issue can be solved with the following command:: $ conda uninstall pyqt5 qt5 - -.. _doc_launching: - -Launching SpecViz -================= - -Once you've installed SpecViz, you can launch it via the command line:: - - $ specviz - - -If you only wish to inspect a single FITS or ASCII file using the default -:ref:`doc_custom_loaders` file formatting, you can also pass in the filename -as a command line argument, as follows:: - - $ specviz filename diff --git a/docs/source/launching.rst b/docs/source/launching.rst new file mode 100644 index 00000000..f07172ed --- /dev/null +++ b/docs/source/launching.rst @@ -0,0 +1,20 @@ +.. _doc_launching: + +Launching SpecViz +================= + +Once you've installed SpecViz, you can launch it via the command line:: + + $ specviz + + +If you only wish to inspect a single FITS or ASCII file using the default +:ref:`doc_custom_loaders` file formatting, you can also pass in the filename +as a command line argument, as follows:: + + $ specviz filename + + +You may also include the name of a custom loader as second optional argument:: + + $ specviz filename --format="my-custom-format" \ No newline at end of file diff --git a/docs/source/model_fitting.rst b/docs/source/model_fitting.rst index ee6a6e7e..aec42ebb 100644 --- a/docs/source/model_fitting.rst +++ b/docs/source/model_fitting.rst @@ -44,19 +44,22 @@ SLSQP `~astropy.modeling.fitting.SLSQPLSQFitter` To use a model: -#. Select the layer you wish to operate on from the LAYERS window in the upper left. -#. Create and position a region of interest (ROI) as described in the :ref:`doc_viewer` section of - the documentation.” +#. Select the layer you wish to operate on from the "Layer List" window in the + bottom left. For example, you can choose the layer containing your emission + or absorption line. +#. Create and position a region of interest (ROI) as described in the + :ref:`doc_viewer` section of the documentation. #. Select the desired model from the ``Add Model`` drop-down box and click ``Select`` to add it to ``Current Models``. #. If desired, repeat the above step to add additional models. -#. A new model layer will be created under ``Layers`` (left panel) and it is - attached to the selected data layer. +#. A new model layer will be created under your data layer in the "Layer List" + window. -To edit model parameters or enter a better first estimate of the model parameters: +To edit model parameters or enter a better first estimate of the model +parameters: -#. Select the model layer under ``Layers`` (left panel) that contains the desired - model. +#. Select the model layer in the "Layer List" window that contains the + desired model. #. If desired, double-click on the model name to rename it. When you see a blinking cursor, enter its new name and press "Enter". #. Expand the model listing under ``Current Models`` on the right of the viewer. @@ -135,7 +138,7 @@ accessed, and varied, by the fitter. Thus, the spline parameters are not fitted, they are just a convenient mechanism that enables user access to the parameter's values. -The documentation for the spline model can be seen here: +The documentation for the spline model can be found here: http://docs.scipy.org/doc/scipy-0.16.0/reference/generated/scipy.interpolate.UnivariateSpline.html @@ -152,44 +155,45 @@ value. Model arithmetic is a work in progress. -Saving and Exporting Models to File -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Saving and exporting models to a file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Selecting a model layer under "Layers" will enable the :ref:`Save ` (the "floppy disk" icon) and :ref:`doc_model_export` (the "out the door" icon) buttons under -"Current Models" on the right of the viewer. Saving a model to a file will -enable SpecViz to read back that model into a new model layer. Exporting a model +"Current Models" on the right of the viewer. When a model is saved as a file on +disk, it can later be read into SpecViz as described below. Exporting a model to a file wil create a Python script in a ``.py`` file. This file can be directly imported by Python in a command-line session. -Click on either button to get a file dialog window. Type in a file name. -If this file name does not end with the correct suffix, the suffix will -automatically be appended. Click "Save", or just the Return/Enter key. -The correct suffix for saved and exported files are ``.yaml`` and ``.py``, -respectively. +Click on either button to get a file dialog window. Provide a name for the model +file, if this file name does not end with the +correct suffix, the suffix will automatically be appended. Click "Save", or +just press the Return/Enter key. The correct suffix for saved and exported files are +``.yaml`` and ``.py``, respectively. .. _doc_model_save: -Save and Load +Save and load ^^^^^^^^^^^^^ Saving the model to a file works in the same way as :ref:`doc_model_export`. The difference is that a saved model can be later read back into SpecViz via -the "Load" button (the "folder" icon), also under "Current Models". +the "Load" button (the "folder" icon), also under "Current Models", whereas the +exported model cannot. For the "Load" button to be enabled, a data (spectrum) layer (not a model layer) -must be selected under "Layers" listing. The selected ``.yaml`` model file will -generate a model that will be attached to a new model layer associated under the -selected data layer. +must be selected in the "Layer List" window. The selected ``.yaml`` model file +will generate a model that will be attached to a new model layer associated +with the selected data layer. -The file is writen using the YAML format. Being a plain text file with a +The file is writen in the YAML format. Being a plain text file with a self-explanatory structure, it can be edited at will by the user, e.g., to add bounds, fixed flags, and ties to the model parameters. Note that these extra, user-defined attributes, won't be accessible from SpecViz's user interface. -They will however, be accessible by the fitter when a fit is run on the -model. They will also be written ou correctly, either when saving or exporting +They will however, be used by the fitter when a fit is run on the +model. They will also be written out correctly, either when saving or exporting the model. .. note:: @@ -205,8 +209,8 @@ Export This will save the model in the currently selected model layer to a file that can be directly imported by Python. The file is just a plain text -file with the model expressed recorded as a Python expression. The model -is associated to a variable named ``'model1'``. +file with the model given as a Python expression. The model +is associated a variable named ``'model1'``. The following example uses the ``'test3.py'`` file name, and a model comprised of a constant and a gaussian: @@ -228,11 +232,11 @@ of a constant and a gaussian: -------------- ------------- ------------- ------------- 0.297160787184 2.25396100263 15117.1710847 948.493577186 -The file can be edited at will by the user, e.g., to add bounds, fixed flags, +The file can be edited by the user, e.g., to add bounds, fixed flags, and ties to the model parameters. -.. note:: +.. warning:: - Security issues importing model this way into Python and usage of advanced - features like bounds and fixed flags are work in progress. + Security issues with importing model this way into Python and usage of + advanced features like bounds and fixed flags are work in progress. diff --git a/docs/source/viewer.rst b/docs/source/viewer.rst index fa728375..e70f2709 100644 --- a/docs/source/viewer.rst +++ b/docs/source/viewer.rst @@ -14,27 +14,28 @@ Viewer To open a file: -#. Click on the folder icon on top left or select ``File -> Open`` from menu. -#. Select the desired filename and data type in the file dialog and click +#. Click on the folder icon on top left corner or select ``File -> Open`` from menu. +#. Select the desired file and data type in the file dialog and click "Open". -#. The file will be listed under "Data" (top half of left panel). -#. To remove the file from "Data", click on "trash can" icon under "Data". +#. The file will be listed in the "Data List" window (top half of left panel). +#. To remove the file from "Data", click on "trash can" icon at lower right +corner of the "Data List" window. -Once a spectrum is loaded, remember to **click on the plot icon** -(left-most button right above "Layers" at the center of the left panel) -to display the spectrum. It will be plotted in the center display window. -Some basic statistics are shown on top right. -Its data layer will be listed under "Layers" (bottom half of left panel). +To plot the spectrum that is now loaded, **click on the plot icon** +(lower left corner of the Data window). It will be plotted in the central +window. Basic statistics for the displayed spectrum will be shown in the +"Statistics" window at the lower left. -If multiple files are opened, each file will have its own plot (overplotting -is not yet supported). To work on the file of interest, click on its plot -window to bring it in focus. +Each spectrum loaded will have its own layer, as shown the "Layer List" window +at the lower left. New layers are created each time a spectrum is +modified or a fit is performed, and the original spectrum is untouched. To +work on the file of interest, click on its plot window to bring it in focus. To adjust plot display: -#. If your mouse has center wheel, the wheel can be used to zoom in and out +#. If your mouse has center wheel, it can be used to zoom in and out while the cursor is over the plot. -#. Click on the "big wheel" icon on top of the plot to change top axis display +#. Click on the "big wheel" icon on top of the plot to change top axis parameters or displayed units. #. Left click on the plot to bring up a context menu. #. Select "View All" to view all available data (if zoomed in). @@ -48,9 +49,9 @@ To select a region of interest (ROI): #. Select the layer from "Layers" list (if you have multiple). #. Click on the "rectangle" icon on the top left of the plot. An adjustable rectangle will appear on plot display. -#. Click and drag the edges to adjust dispersion coverage. As the region - changes, basic statistics under "Statistic" on top right of the viewer will - also update accordingly. +#. Click and drag the edges to adjust wavelength coverage. As the region + changes, basic statistics in the "Statistics" window on bottom left of the viewer + will also update accordingly. #. Click inside the rectangle and drag to reposition it without resizing. #. Click the left-most "knife" button under "Layers" (bottom left of the left panel) to create a new layer slice from the ROI. diff --git a/requirements.txt b/requirements.txt index c436ca12..8ed5c1bf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,11 @@ --index-url https://pypi.python.org/simple/ - pyyaml cython numpy scipy astropy +sphinx sphinx_automodapi sphinx_rtd_theme -git+https://github.com/nmearl/specutils.git -git+https://github.com/nmearl/pyqtgraph.git --e . +specutils +pyqtgraph +qtpy \ No newline at end of file diff --git a/setup.py b/setup.py old mode 100755 new mode 100644 index f046a083..affe635b --- a/setup.py +++ b/setup.py @@ -46,7 +46,7 @@ builtins._ASTROPY_PACKAGE_NAME_ = PACKAGENAME # VERSION should be PEP386 compatible (http://www.python.org/dev/peps/pep-0386) -VERSION = '0.2.2rc5.dev' +VERSION = '0.3.0' # Indicates if this version is a release version RELEASE = 'dev' not in VERSION @@ -133,6 +133,11 @@ 'scipy', 'qtpy' ], + # extras_require={ + # ':python_version >= "3.5"': [ + # 'pyqt5', + # ], + # }, author=AUTHOR, author_email=AUTHOR_EMAIL, license=LICENSE, diff --git a/specviz/interfaces/registries.py b/specviz/interfaces/registries.py index 98f0780f..adc2198c 100644 --- a/specviz/interfaces/registries.py +++ b/specviz/interfaces/registries.py @@ -81,7 +81,8 @@ def __init__(self): for cls_name, cls_plugin in cls_members: self._members.append(cls_plugin()) - sys.path.pop(0) + if path != cur_path: + sys.path.pop(0) class LoaderRegistry(Registry): diff --git a/specviz/plugins/data_list_plugin.py b/specviz/plugins/data_list_plugin.py index dd469a85..dcdcaa60 100644 --- a/specviz/plugins/data_list_plugin.py +++ b/specviz/plugins/data_list_plugin.py @@ -234,6 +234,8 @@ def __init__(self, plugin): # List widget for the data sets plugin.list_widget_data_list = QListWidget(plugin) + plugin.list_widget_data_list.setMinimumHeight(50) + plugin.list_widget_data_list.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Ignored) # Allow for multiple selections plugin.list_widget_data_list.setSelectionMode( @@ -252,6 +254,8 @@ def __init__(self, plugin): border: 1px solid #faebcc; border-radius: 4px; }""") + plugin.label_unopened.setSizePolicy(QSizePolicy.Preferred, + QSizePolicy.Fixed) plugin.layout_vertical.addWidget(plugin.label_unopened) plugin.layout_vertical.addWidget(plugin.list_widget_data_list) diff --git a/specviz/plugins/layer_list_plugin.py b/specviz/plugins/layer_list_plugin.py index 73c6e0e9..7a3d7a63 100644 --- a/specviz/plugins/layer_list_plugin.py +++ b/specviz/plugins/layer_list_plugin.py @@ -426,6 +426,7 @@ def __init__(self, plugin): plugin.layout_vertical.setContentsMargins(11, 11, 11, 11) plugin.tree_widget_layer_list = QTreeWidget(plugin) + plugin.tree_widget_layer_list.setMinimumHeight(50) plugin.tree_widget_layer_list.setHeaderHidden(True) plugin.layout_vertical.addWidget(plugin.tree_widget_layer_list) diff --git a/specviz/plugins/model_fitting_plugin.py b/specviz/plugins/model_fitting_plugin.py index df90ebfb..ba07b206 100644 --- a/specviz/plugins/model_fitting_plugin.py +++ b/specviz/plugins/model_fitting_plugin.py @@ -81,6 +81,9 @@ def setup_connections(self): self.button_perform_fit.clicked.connect( self.fit_model_layer) + # Update model name when a user makes changes + self.tree_widget_current_models.itemChanged.connect(self._update_model_name) + # --- # IO # Attach the model save/read buttons @@ -213,10 +216,12 @@ def add_model_item(self, layer, unique=True): new_para_item.setText(0, para) new_para_item.setData(1, Qt.UserRole, model.parameters[i]) new_para_item.setText(1, "{:4.4g}".format(model.parameters[i])) - new_para_item.setFlags( - new_para_item.flags() | Qt.ItemIsEditable | - Qt.ItemIsUserCheckable) - new_para_item.setCheckState(0, Qt.Unchecked) + new_para_item.setFlags(new_para_item.flags() | + Qt.ItemIsEditable | + Qt.ItemIsUserCheckable) + + new_para_item.setCheckState(0, Qt.Checked if model.fixed.get(para) + else Qt.Unchecked) self.tree_widget_current_models.addTopLevelItem(new_item) self.tree_widget_current_models.expandItem(new_item) @@ -379,7 +384,21 @@ def _update_model_name(self, model_item, col=0): model = model_item.data(0, Qt.UserRole) if hasattr(model, '_name'): - model._name = model_item.text(0) + name = model_item.text(0) + all_names = self.tree_widget_current_models.findItems( + name, Qt.MatchExactly, 0) + + if len(all_names) > 1: + name = "{}{}".format(name, len(all_names) - 1) + + # Remove whitespace + name = name.replace(" ", "_") + + model._name = name + + self.tree_widget_current_models.blockSignals(True) + model_item.setText(0, name) + self.tree_widget_current_models.blockSignals(False) self._update_arithmetic_text(self.current_layer) diff --git a/specviz/ui/viewer.py b/specviz/ui/viewer.py index 79b3f190..34cb540a 100644 --- a/specviz/ui/viewer.py +++ b/specviz/ui/viewer.py @@ -61,7 +61,7 @@ def load_plugins(self, hidden=False): # Resize the widgets now that they are all present for ip in instance_plugins[::-1]: ip.setMinimumSize(ip.sizeHint()) - QApplication.processEvents() + # QApplication.processEvents() # Sort actions based on priority all_actions = [y for x in instance_plugins for y in x._actions]