# Virus Data Analysis Tool: a data reduction GUI for HETDEX/VIRUS data
# Copyright (C) 2016, 2017, 2018 "The HETDEX collaboration"
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""This module implements all the entry points shipped with vdat"""
import copy
import vdat.database as db
from . import tab_widget
[docs]def exp_fits(target_dir, tab_dict, step_name, cache, parent_widget):
'''Create or retrieve and return tabs of type
:class:`.tab_widget.FitsFplanePanel`. Each tab represent one
exposure in one of the types in ``target_dir``.
This tab type accepts the following configuration options:
* ``tab_type`` (mandatory): name of the type.
* ``file_name`` (mandatory): name of the file(s) to show. It is possible to
format the file name using the `python formatting syntax
<https://docs.python.org/3/library/string.html#formatspec>`_.
* ``cols``, ``rows`` (optional): list of objects, typically strings. The
thumbnail gets divided into len(cols)*len(rows) quadrants and each one
shows one file.
* ``title`` (optional): title to use for the tab; if absent ``'{step}
{orig_type} {exp}'`` is used. It is possible to format the title
similarly to the ``file_name``.
* ``tool_tip`` (optional): tooltip to show when hovering on the tab name;
it is possible to format the tool_tip similarly to the ``file_name``.
* ``header_keys`` (optional): list of strings. Header keywords to show on
top of the others in the fits viewer window.
Available formatting names:
* ``ifuslot``, ``ifuid``, ``specid`` (``file_name`` only): ID of the slot,
of the IFU bundle and of the spectrograph it is connected to.
* ``basename``: date-time part of the file name.
* ``col``, ``row`` (``file_name`` only): replaced with each of the elements
in the ``cols`` and ``rows`` configuration options.
* ``step``: name of the step at hand
* ``type``: type of the file(s) in the target directory, i.e. the name
shown in the GUI.
* ``orig_type``: original type of the file(s) in the target directory.
* ``object``: value of the OBJECT header keyword.
* ``exp``: exposure number.
See :func:`.interface.plugin_interface` for the signature of this function.
'''
return _exp_tabs(tab_widget.FitsFplanePanel, target_dir, tab_dict,
step_name, cache, parent_widget)
[docs]def exp_combined(target_dir, tab_dict, step_name, cache, parent_widget):
'''Same as :func:`exp_fits`, but using tabs of type
:class:`.tab_widget.FitsAndReconFplanePanel`.
'''
return _exp_tabs(tab_widget.FitsAndReconFplanePanel, target_dir,
tab_dict, step_name, cache, parent_widget)
[docs]def _exp_tabs(cls, target_dir, tab_dict, step_name, cache, parent_widget):
'''Implementation of :func:`exp_fits` and :func:`fits_combined` types.
Parameters
----------
cls : :class:`.tab_widget.BaseFplanePanel` or child
class to initialize if not found in cache
others :
same as :func:`fits_combined`
'''
tab_dict = copy.deepcopy(tab_dict)
tab_type = tab_dict['tab_type']
with db.connect():
entries = (db.VDATExposures.select()
.where(db.VDATExposures.path == target_dir)
.order_by(db.VDATExposures.original_type,
db.VDATExposures.expname))
tabs = []
if 'title' not in tab_dict:
tab_dict['title'] = '{step} {orig_type} {exp}'
for entry in entries:
format_dict = {'type': entry.exptype,
'orig_type': entry.original_type,
'object': entry.object_, 'exp': entry.expname,
'basename': entry.basename, 'step': step_name}
# try to get one object from the cache
tab_obj = cache.from_cache(tab_type)
if not tab_obj:
tab_obj = cls(tab_type)
# Re-set the parent. It is not strictly necessary but, hey, better
# safe that sorrow
tab_obj.setParent(parent_widget)
# pass all the relevant pieces to the object to be able to show the
# target directory
tab_obj.setup(target_dir, tab_dict, format_dict)
tabs.append(tab_obj)
return tabs
[docs]def fits(target_dir, tab_dict, step_name, cache, parent_widget):
'''Create or retrieve and return one or more tabs of type
:class:`.tab_widget.FitsFplanePanel`. Each tab represents one file type
chosen by the user.
This tab type accepts the following configuration options:
* ``tab_type`` (mandatory): name of the type.
* ``file_name`` (mandatory): name of the file(s) to show. It is possible to
format the file name using the `python formatting syntax
<https://docs.python.org/3/library/string.html#formatspec>`_.
* ``file_types`` (optional): can be ``'type'``, ``'orig_type'``,
``'object'`` or a user defined string. This entry is used in the
following way:
* If the value of ``file_types`` is any of ``'type'``, ``'orig_type'``,
``'object'``: the corresponding information is extracted from the
internal database and interpreted as a list. If e.g. the
``'orig_type'`` is used and the database contains for the entry the
following ``'cmp, flt'`` value, two tabs will be created and the
``{orig_type}`` formatting key will be replaced with ``'cmp'`` in one
tab and ``'flt'`` in the other.
* If the value of ``file_types`` is any of ``'type'``, ``'orig_type'``,
``'object'`` **and** if it present as a keyword in the tab
configuration: the content of the keyword is used, instead of the
internal information. The value of the keyword must be a list. If e.g.
the ``'orig_type'`` is used and there is one keyword whose value is
``['flat', 'arc']``, two tabs will be created and the ``{orig_type}``
formatting key will be replaced with ``'flat'`` in one tab and
``'arc'`` in the other.
* If the value is a custom string: this string must be present in the
tab configuration and its value must be a list. It is also added in the
list of available formatting names to allow substitutions. If e.g. the
``'custom'`` string is used, there must be one such key. If its value
is ``['my', 'tab']``, two tabs will be created and the ``{custom}``
formatting key will be replaced with ``'my'`` in one tab and
``'tab'`` in the other.
Default: ``'orig_type'``.
* ``cols``, ``rows`` (optional): list of objects, typically strings. The
thumbnail gets divided into len(cols)*len(rows) quadrants and each one
shows one file.
* ``title`` (optional): title to use for the tab; if absent ``'{step}
{orig_type}'`` is used. It is possible to format the title similarly to
the ``file_name``.
* ``tool_tip`` (optional): tooltip to show when hovering on the tab name;
it is possible to format the tool_tip similarly to the ``file_name``.
* ``header_keys`` (optional): list of strings. Header keywords to show on
top of the others in the fits viewer window.
Available formatting names:
* ``ifuslot``, ``ifuid``, ``specid`` (``file_name`` only): ID of the slot,
of the IFU bundle and of the spectrograph it is connected to.
* ``col``, ``row`` (``file_name`` only): replaced with each of the elements
in the ``cols`` and ``rows`` configuration options.
* ``step``: name of the step at hand
* ``type``: type of the file(s) in the target directory, i.e. the name
shown in the GUI.
* ``orig_type``: original type of the file(s) in the target directory.
* ``object``: value of the OBJECT header keyword.
See :func:`.interface.plugin_interface` for the signature of this function.
'''
return _fits_tabs(tab_widget.FitsFplanePanel, target_dir,
tab_dict, step_name, cache, parent_widget)
[docs]def fits_combined(target_dir, tab_dict, step_name, cache, parent_widget):
'''Same as :func:`fits`, but using tabs of type
:class:`.tab_widget.FitsAndReconFplanePanel`. '''
return _fits_tabs(tab_widget.FitsAndReconFplanePanel, target_dir,
tab_dict, step_name, cache, parent_widget)
[docs]def fits_cube(target_dir, tab_dict, step_name, cache, parent_widget):
'''Same as :func:`fits`, but using tabs of type
:class:`.tab_widget.CubeFplanePanel`.
On top of the configuration options described in :func:`fits`, this tab
type accepts the following options:
* ``z_indx`` (optional): before creating the thumbnail for the data cubes,
the image is compressed along the z-dimension using the median; if
``z_indx`` is not given or is ``[null, null]``, it uses the whole range,
otherwise it uses only the part of the cube in the range [z_indx[0],
z_indx[1])
'''
return _fits_tabs(tab_widget.CubeFplanePanel, target_dir,
tab_dict, step_name, cache, parent_widget)
[docs]def fits_multiext(target_dir, tab_dict, step_name, cache, parent_widget):
'''Same as :func:`fits`, but using tabs of type
:class:`.tab_widget.MultiExtFplanePanel`.
On top of the configuration options described in :func:`fits`, this tab
type accepts the following options:
* ``extensions`` (list of ints or strings): indices or names of the
fits extensions to display in the IFU.
On top of the formatting names described in :func:`fits`, this tab
type has this additional formatting name:
* ``ext``: index or name of the extension displayed
'''
extensions = tab_dict['extensions']
tabs = []
for ext in extensions:
ext_dict = copy.deepcopy(tab_dict)
ext_dict['ext'] = ext
_tabs = _fits_tabs(tab_widget.MultiExtFplanePanel, target_dir,
ext_dict, step_name, cache, parent_widget,
extra_format={'ext': ext})
tabs.extend(_tabs)
return tabs
[docs]def _fits_tabs(cls, target_dir, tab_dict, step_name, cache, parent_widget,
extra_format=None):
'''Implementation of :func:`fits` and :func:`fits_combined`.
Parameters
----------
cls : :class:`.tab_widget.BaseFplanePanel` or child
class to initialize if not found in cache
extra_format : dict, optional
extra formatting values to add to the ``format_dict`` passed to the
``cls``
others :
same as :func:`fits_combined`
'''
tab_dict = copy.deepcopy(tab_dict)
tab_type = tab_dict['tab_type']
with db.connect():
entry = (db.VDATDir.select()
.where(db.VDATDir.path == target_dir)).get()
file_types = tab_dict.get('file_types', 'orig_type')
entry_attr = {'type': 'type_', 'orig_type': 'original_type_',
'object': 'object_'}
if file_types in tab_dict:
file_types_list = tab_dict[file_types]
elif file_types in entry_attr:
file_types_list = getattr(entry, entry_attr[file_types])
file_types_list = [i.strip() for i in file_types_list.split(',')]
else:
raise KeyError('The value "{}" of ``file_type`` exist neither'
' in the database nor in the tab configuration.'
' Make sure that the configuration file complies'
' with the specifications.'.format(file_types))
if 'title' not in tab_dict:
tab_dict['title'] = '{step} {orig_type}'
tabs = []
for ft in file_types_list:
format_dict = {'type': entry.type_, 'orig_type': entry.original_type_,
'object': entry.object_, 'step': step_name,
file_types: ft}
if extra_format is not None:
format_dict.update(extra_format)
# try to get one object from the cache
tab_obj = cache.from_cache(tab_type)
if not tab_obj:
tab_obj = cls(tab_type)
# Re-set the parent. It is not strictly necessary but, hey, better safe
# that sorrow
tab_obj.setParent(parent_widget)
# pass all the relevant pieces to the object to be able to show the
# target directory
tab_obj.setup(target_dir, tab_dict, format_dict)
tabs.append(tab_obj)
return tabs
[docs]def reconstruct(target_dir, tab_dict, step_name, cache, parent_widget):
'''Create or retrieve and return a tab of type
:class:`.tab_widget.QuickReconFplanePanel`. It collects all the exposures
for the ``target_dir`` and combine all of them in a single reconstructed
image.
This tab type accepts the following configuration options:
* ``tab_type`` (mandatory): name of the type.
* ``file_name`` (mandatory): name of the file(s) to show. It is possible to
format the file name using the `python formatting syntax
<https://docs.python.org/3/library/string.html#formatspec>`_.
* ``cols``, ``rows`` (optional): list of objects, typically strings. The
thumbnail gets divided into len(cols)*len(rows) quadrants and each one
shows one file.
* ``title`` (optional): title to use for the tab; if absent ``'{step}
{orig_type}'`` is used. It is possible to format the title
similarly to the ``file_name``.
* ``tool_tip`` (optional): tooltip to show when hovering on the tab name;
it is possible to format the tool_tip similarly to the ``file_name``.
* ``header_keys`` (optional): list of strings. Header keywords to show on
top of the others in the fits viewer window.
Available formatting names:
* ``ifuslot``, ``ifuid``, ``specid`` (``file_name`` only): ID of the slot,
of the IFU bundle and of the spectrograph it is connected to.
* ``col``, ``row`` (``file_name`` only): replaced with each of the elements
in the ``cols`` and ``rows`` configuration options.
* ``basename`` (``file_name`` only): date-time part of the file name.
* ``step``: name of the step at hand
* ``type``: type of the file(s) in the target directory, i.e. the name
shown in the GUI.
* ``orig_type``: original type(s) of the file(s) in the target directory.
* ``object``: value(s) of the OBJECT header keyword.
See :func:`.interface.plugin_interface` for the signature of this function.
'''
tab_dict = copy.deepcopy(tab_dict)
tab_type = tab_dict['tab_type']
with db.connect():
entries = (db.VDATExposures.select()
.where(db.VDATExposures.path == target_dir)
.order_by(db.VDATExposures.original_type,
db.VDATExposures.expname))
basenames = [e.basename for e in entries]
orig_type = ', '.join({e.original_type for e in entries})
object_ = ', '.join({e.object_ for e in entries})
if 'title' not in tab_dict:
tab_dict['title'] = '{step} {orig_type}'
format_dict = {'type': entries[0].exptype, 'orig_type': orig_type,
'object': object_, 'step': step_name}
# try to get one object from the cache
tab_obj = cache.from_cache(tab_type)
if not tab_obj:
tab_obj = tab_widget.QuickReconFplanePanel(tab_type)
# Re-set the parent. It is not strictly necessary but, hey, better safe
# that sorrow
tab_obj.basenames(basenames)
tab_obj.setParent(parent_widget)
# pass all the relevant pieces to the object to be able to show the
# target directory
tab_obj.setup(target_dir, tab_dict, format_dict)
return [tab_obj, ]
[docs]def text_file(target_dir, tab_dict, step_name, cache, parent_widget):
'''Create or retrieve and return one tab of type
:class:`.tab_widget.TextFileWidget`.
This tab type accepts the following configuration options:
* ``tab_type`` (mandatory): name of the type.
* ``file_name`` (mandatory): name of the file(s) to show. It is possible to
format the file name using the `python formatting syntax
<https://docs.python.org/3/library/string.html#formatspec>`_.
* ``title`` (optional): title to use for the tab; if absent ``'{step}'`` is
used. It is possible to format the title similarly to the ``file_name``.
* ``tool_tip`` (optional): tooltip to show when hovering on the tab name;
it is possible to format the tool_tip similarly to the ``file_name``.
Available formatting names:
* ``ifuslot``, ``ifuid``, ``specid`` (``file_name`` only): ID of the slot,
of the IFU bundle and of the spectrograph it is connected to.
* ``step``: name of the step at hand
* ``type``: type of the file(s) in the target directory, i.e. the name
shown in the GUI.
* ``orig_type``: original type(s) of the file(s) in the target directory.
* ``object``: value(s) of the OBJECT header keyword.
See :func:`.interface.plugin_interface` for the signature of this function.
'''
tab_dict = copy.deepcopy(tab_dict)
tab_type = tab_dict['tab_type']
with db.connect():
entries = (db.VDATExposures.select()
.where(db.VDATExposures.path == target_dir)
.order_by(db.VDATExposures.original_type,
db.VDATExposures.expname))
orig_type = ', '.join({e.original_type for e in entries})
object_ = ', '.join({e.object_ for e in entries})
format_dict = {'type': entries[0].exptype, 'orig_type': orig_type,
'object': object_, 'step': step_name}
if 'title' not in tab_dict:
tab_dict['title'] = '{step}'
# try to get one object from the cache
tab_obj = cache.from_cache(tab_type)
if not tab_obj:
tab_obj = tab_widget.TextFilesPanel(tab_type)
# Re-set the parent. It is not strictly necessary but, hey, better safe
# that sorrow
tab_obj.setParent(parent_widget)
# pass all the relevant pieces to the object to be able to show the
# target directory
tab_obj.setup(target_dir, tab_dict, format_dict)
return [tab_obj, ]
[docs]def dist(target_dir, tab_dict, step_name, cache, parent_widget):
'''Create or retrieve and return one tabs of type
:class:`.tab_widget.DistPanel`.
This tab type accepts the following configuration options:
* ``tab_type`` (mandatory): name of the type.
* ``file_name`` (mandatory): name of the distortion file(s) to show. It is
possible to format the file name using the `python formatting syntax
<https://docs.python.org/3/library/string.html#formatspec>`_.
* ``fits_names`` (mandatory): list of names of the fits files to use then
displaying the distortion in DS9. If the list is empty, it is not
possible to display the data on DS9.
* ``cols``, ``rows`` (optional): list of objects, typically strings. The
thumbnail gets divided into len(cols)*len(rows) quadrants and each one
shows one file.
* ``title`` (optional): title to use for the tab; if absent ``'{step}
{orig_type}'`` is used. It is possible to format the title similarly to
the ``file_name``.
* ``tool_tip`` (optional): tooltip to show when hovering on the tab name;
it is possible to format the tool_tip similarly to the ``file_name``.
Available formatting names:
* ``ifuslot``, ``ifuid``, ``specid`` (``file_name`` and ``fits_names``
only): ID of the slot, of the IFU bundle and of the spectrograph it is
connected to.
* ``col``, ``row`` (``file_name`` and ``fits_names`` only): replaced with
each of the elements in the ``cols`` and ``rows`` configuration options.
* ``step``: name of the step at hand
* ``type``: type of the file(s) in the target directory, i.e. the name
shown in the GUI.
* ``orig_type``: original type of the file(s) in the target directory.
* ``object``: value of the OBJECT header keyword.
See :func:`.interface.plugin_interface` for the signature of this function.
'''
tab_dict = copy.deepcopy(tab_dict)
tab_type = tab_dict['tab_type']
with db.connect():
entry = (db.VDATDir.select()
.where(db.VDATDir.path == target_dir)).get()
if 'title' not in tab_dict:
tab_dict['title'] = '{step} {orig_type}'
tabs = []
format_dict = {'type': entry.type_, 'orig_type': entry.original_type_,
'object': entry.object_, 'step': step_name}
# try to get one object from the cache
tab_obj = cache.from_cache(tab_type)
if not tab_obj:
tab_obj = tab_widget.DistPanel(tab_type)
# Re-set the parent. It is not strictly necessary but, hey, better safe
# that sorrow
tab_obj.setParent(parent_widget)
# pass all the relevant pieces to the object to be able to show the
# target directory
tab_obj.setup(target_dir, tab_dict, format_dict)
tabs.append(tab_obj)
return tabs
# entry points used for testing/debugging
[docs]def _empty_fplane(target_dir, tab_dict, step_name,
cache, parent_widget): # pragma: no cover
'''Create or retrieve and return one tab of type
:class:`.tab_widget.BaseFplanePanel`.
This entry point has been created for testing purposes but can be used to
display the focal plane and be able to select/deselect IFUs when no plugin
is available to display data for a step
See :func:`.interface.plugin_interface` for the signature of this function.
'''
tab_type = tab_dict['tab_type']
# try to get one object from the cache.
tab_obj = cache.from_cache(tab_type)
if not tab_obj:
tab_obj = tab_widget.BaseFplanePanel(tab_type)
tab_obj.title = 'Empty fplane'
# reset the parent. It is not strictly necessary but, hey, better safe
# that sorrow
tab_obj.setParent(parent_widget)
# pass all the relevant pieces to the object to be able to show the target
# directory
# tab_obj.setup(...)
return [tab_obj, ]