Merge pull request #44 from astrofrog/color-size-att

Expose options for color and size encoding of layers
This commit is contained in:
Thomas Robitaille 2019-02-22 17:24:47 +00:00 коммит произвёл GitHub
Родитель d9ae63036b c770ecf92f
Коммит b0aa1318e7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 551 добавлений и 122 удалений

Просмотреть файл

@ -16,6 +16,11 @@ from .utils import center_fov
__all__ = ['WWTLayer']
RESET_DATA_PROPERTIES = ('mode', 'frame', 'lon_att', 'lat_att', 'alt_att',
'alt_unit', 'size_att', 'cmap_att', 'size_mode',
'color_mode')
class WWTLayer(LayerArtist):
_layer_state_cls = WWTLayerState
@ -71,7 +76,7 @@ class WWTLayer(LayerArtist):
# for now we set unit to pc and scale values accordingly, so if the
# unit changes we need to refresh the data just in case
if force or 'mode' in kwargs or 'frame' in kwargs or 'lon_att' in kwargs or 'lat_att' in kwargs or 'alt_att' in kwargs or 'alt_unit' in kwargs:
if force or any(x in kwargs for x in RESET_DATA_PROPERTIES):
try:
lon = self.layer[self._viewer_state.lon_att]
@ -92,6 +97,24 @@ class WWTLayer(LayerArtist):
self.disable_invalid_attributes(self._viewer_state.alt_att)
return
if self.state.size_mode == 'Linear' and self.state.size_att is not None:
try:
size_values = self.layer[self.state.size_att]
except IncompatibleAttribute:
self.disable_invalid_attributes(self.state.size_att)
return
else:
size_values = None
if self.state.color_mode == 'Linear' and self.state.cmap_att is not None:
try:
cmap_values = self.layer[self.state.size_att]
except IncompatibleAttribute:
self.disable_invalid_attributes(self.state.size_att)
return
else:
cmap_values = None
if self.wwt_layer is not None:
self.wwt_layer.remove()
self.wwt_layer = None
@ -126,18 +149,28 @@ class WWTLayer(LayerArtist):
if self._viewer_state.alt_att is not None and self._viewer_state.alt_unit == 'kpc':
alt = alt * 1000
data_kwargs = {}
tab = Table()
tab['lon'] = lon * u.degree
tab['lat'] = lat * u.degree
if self._viewer_state.alt_att is not None:
# FIXME: allow arbitrary units
tab['alt'] = alt
alt_att = {'alt_att': 'alt'}
else:
alt_att = {}
data_kwargs['alt_att'] = 'alt'
if size_values is not None:
tab['size'] = size_values
data_kwargs['size_att'] = 'size'
if cmap_values is not None:
tab['cmap'] = cmap_values
data_kwargs['cmap_att'] = 'cmap'
self.wwt_layer = self.wwt_client.layers.add_data_layer(tab, frame=ref_frame,
lon_att='lon', lat_att='lat', **alt_att)
lon_att='lon', lat_att='lat', **data_kwargs)
self.wwt_layer.far_side_visible = self._viewer_state.mode in MODES_3D
@ -160,8 +193,11 @@ class WWTLayer(LayerArtist):
if force or 'alt_type' in kwargs:
self.wwt_layer.alt_type = self._viewer_state.alt_type.lower()
if force or 'size' in kwargs:
self.wwt_layer.size_scale = self.state.size * 5
if force or 'size' in kwargs or 'size_mode' in kwargs or 'size_scaling' in kwargs:
if self.state.size_mode == 'Linear':
self.wwt_layer.size_scale = self.state.size_scaling
else:
self.wwt_layer.size_scale = self.state.size * 5 * self.state.size_scaling
if force or 'color' in kwargs:
self.wwt_layer.color = self.state.color
@ -169,6 +205,21 @@ class WWTLayer(LayerArtist):
if force or 'alpha' in kwargs:
self.wwt_layer.opacity = self.state.alpha
if force or 'size_vmin' in kwargs:
self.wwt_layer.size_vmin = self.state.size_vmin
if force or 'size_vmax' in kwargs:
self.wwt_layer.size_vmax = self.state.size_vmax
if force or 'cmap_vmin' in kwargs:
self.wwt_layer.cmap_vmin = self.state.cmap_vmin
if force or 'cmap_vmax' in kwargs:
self.wwt_layer.cmap_vmax = self.state.cmap_vmax
if force or 'cmap' in kwargs:
self.wwt_layer.cmap = self.state.cmap
self.enable()
# TODO: deal with visible, zorder, frame

Просмотреть файл

@ -5,26 +5,66 @@ import os
from qtpy import QtWidgets
from glue.external.echo.qt import autoconnect_callbacks_to_qt
from glue.utils.qt import load_ui
from glue.utils.qt import load_ui, fix_tab_widget_fontsize
class WWTLayerStyleEditor(QtWidgets.QWidget):
def __init__(self, layer, parent=None):
def __init__(self, layer_artist):
super(WWTLayerStyleEditor, self).__init__(parent=parent)
super(WWTLayerStyleEditor, self).__init__()
self.ui = load_ui('layer_style_editor.ui', self,
directory=os.path.dirname(__file__))
connect_kwargs = {'alpha': dict(value_range=(0, 1))}
fix_tab_widget_fontsize(self.ui.tab_widget)
autoconnect_callbacks_to_qt(layer.state, self.ui, connect_kwargs)
self.state = layer_artist.state
self.ui.button_center.clicked.connect(layer.center)
self.layer_artist = layer_artist
self.layer = layer_artist.layer
self._viewer_state = layer._viewer_state
connect_kwargs = {'value_alpha': dict(value_range=(0., 1.)),
'value_size_scaling': dict(value_range=(0.1, 10), log=True)}
autoconnect_callbacks_to_qt(self.state, self.ui, connect_kwargs)
# Set initial values
self._update_size_mode()
self._update_color_mode()
self.state.add_callback('color_mode', self._update_color_mode)
self.state.add_callback('size_mode', self._update_size_mode)
self.ui.button_center.clicked.connect(layer_artist.center)
self._viewer_state = layer_artist._viewer_state
self._viewer_state.add_callback('mode', self._on_mode_changed)
def _on_mode_changed(self, *args):
self.ui.button_center.setVisible(self._viewer_state.mode == 'Sky')
def _update_size_mode(self, *args):
if self.state.size_mode == "Fixed":
self.ui.size_row_2.hide()
self.ui.combosel_size_att.hide()
self.ui.valuetext_size.show()
else:
self.ui.valuetext_size.hide()
self.ui.combosel_size_att.show()
self.ui.size_row_2.show()
def _update_color_mode(self, *args):
if self.state.color_mode == "Fixed":
self.ui.color_row_2.hide()
self.ui.color_row_3.hide()
self.ui.combosel_cmap_att.hide()
self.ui.spacer_color_label.show()
self.ui.color_color.show()
else:
self.ui.color_color.hide()
self.ui.combosel_cmap_att.show()
self.ui.spacer_color_label.hide()
self.ui.color_row_2.show()
self.ui.color_row_3.show()

Просмотреть файл

@ -6,91 +6,384 @@
<rect>
<x>0</x>
<y>0</y>
<width>333</width>
<height>232</height>
<width>200</width>
<height>202</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>5</number>
<number>3</number>
</property>
<property name="topMargin">
<number>5</number>
<number>3</number>
</property>
<property name="rightMargin">
<number>5</number>
<number>3</number>
</property>
<property name="bottomMargin">
<number>5</number>
<number>3</number>
</property>
<property name="verticalSpacing">
<number>5</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Color:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<item>
<widget class="QTabWidget" name="tab_widget">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Size</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QWidget" name="size_row_1" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>7</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="QComboBox" name="combotext_size_mode">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<item>
<property name="text">
<string>Fixed</string>
</property>
</item>
<item>
<property name="text">
<string>Linear</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QComboBox" name="combosel_size_att">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="valuetext_size"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="size_row_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>7</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="QLineEdit" name="valuetext_size_vmin"/>
</item>
<item>
<widget class="QToolButton" name="button_flip_size">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">padding: 0px</string>
</property>
<property name="text">
<string>⇄</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="valuetext_size_vmax"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="size_row_3" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>7</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="QSlider" name="value_size_scaling">
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</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>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>Color</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QWidget" name="color_row_1" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="spacing">
<number>7</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="QComboBox" name="combotext_color_mode">
<property name="maximumSize">
<size>
<width>80</width>
<height>16777215</height>
</size>
</property>
<item>
<property name="text">
<string>Fixed</string>
</property>
</item>
<item>
<property name="text">
<string>Linear</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QComboBox" name="combosel_cmap_att">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
</property>
</widget>
</item>
<item>
<widget class="QColorBox" name="color_color">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="spacer_color_label" native="true"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="color_row_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="spacing">
<number>7</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="QLineEdit" name="valuetext_cmap_vmin"/>
</item>
<item>
<widget class="QToolButton" name="button_flip_cmap">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">padding: 0px</string>
</property>
<property name="text">
<string>⇄</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="valuetext_cmap_vmax"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="color_row_3" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<property name="spacing">
<number>7</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="QColormapCombo" name="combodata_cmap">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QSlider" name="value_alpha">
<property name="maximum">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<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>
</layout>
</widget>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSlider" name="value_alpha">
<property name="maximum">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Size:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Opacity:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<spacer name="horizontalSpacer">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -110,7 +403,7 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -124,28 +417,8 @@
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="value_size">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QColorBox" name="color_color">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer">
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@ -165,6 +438,11 @@
<extends>QLabel</extends>
<header>glue.utils.qt.colors</header>
</customwidget>
<customwidget>
<class>QColormapCombo</class>
<extends>QComboBox</extends>
<header>glue.utils.qt.colors</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>

Просмотреть файл

@ -2,11 +2,14 @@ from __future__ import absolute_import, division, print_function
from astropy import units as u
from glue.config import colormaps
from glue.external.echo import (CallbackProperty, ListCallbackProperty,
SelectionCallbackProperty,
SelectionCallbackProperty, delay_callback,
keep_in_sync)
from glue.core.data_combo_helper import ComponentIDComboHelper
from glue.core.state_objects import StateAttributeLimitsHelper
from glue.viewers.common.state import ViewerState, LayerState
from pywwt.layers import VALID_FRAMES
@ -103,35 +106,92 @@ class WWTDataViewerState(ViewerState):
class WWTLayerState(LayerState):
"""
A state object for volume layers
"""
layer = CallbackProperty()
color = CallbackProperty()
size = CallbackProperty()
alpha = CallbackProperty()
zorder = CallbackProperty(0)
visible = CallbackProperty(True)
def __init__(self, viewer_state=None, **kwargs):
size_mode = CallbackProperty('Fixed')
size = CallbackProperty()
size_att = SelectionCallbackProperty()
size_vmin = CallbackProperty()
size_vmax = CallbackProperty()
size_scaling = CallbackProperty(1)
super(WWTLayerState, self).__init__()
color_mode = CallbackProperty('Fixed')
cmap_att = SelectionCallbackProperty()
cmap_vmin = CallbackProperty()
cmap_vmax = CallbackProperty()
cmap = CallbackProperty()
self.viewer_state = viewer_state
size_limits_cache = CallbackProperty({})
cmap_limits_cache = CallbackProperty({})
self.update_from_dict(kwargs)
def __init__(self, layer=None, **kwargs):
self.color = self.layer.style.color
self.alpha = self.layer.style.alpha
self.size = self.layer.style.markersize
self._sync_markersize = None
super(WWTLayerState, self).__init__(layer=layer)
self._sync_color = keep_in_sync(self, 'color', self.layer.style, 'color')
self._sync_alpha = keep_in_sync(self, 'alpha', self.layer.style, 'alpha')
self._sync_size = keep_in_sync(self, 'size', self.layer.style, 'markersize')
def _update_priority(self, name):
if name == 'layer':
return 1
else:
return 0
self.color = self.layer.style.color
self.size = self.layer.style.markersize
self.alpha = self.layer.style.alpha
def _att_changed(self, *args):
self.viewer_state._sync_all_attributes(reference=self)
self.size_att_helper = ComponentIDComboHelper(self, 'size_att')
self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_att')
self.size_lim_helper = StateAttributeLimitsHelper(self, attribute='size_att',
lower='size_vmin', upper='size_vmax',
cache=self.size_limits_cache)
self.cmap_lim_helper = StateAttributeLimitsHelper(self, attribute='cmap_att',
lower='cmap_vmin', upper='cmap_vmax',
cache=self.cmap_limits_cache)
self.add_callback('layer', self._on_layer_change)
if layer is not None:
self._on_layer_change()
self.cmap = colormaps.members[0][1]
self.update_from_dict(kwargs)
def _on_layer_change(self, layer=None):
with delay_callback(self, 'cmap_vmin', 'cmap_vmax', 'size_vmin', 'size_vmax'):
if self.layer is None:
self.cmap_att_helper.set_multiple_data([])
self.size_att_helper.set_multiple_data([])
else:
self.cmap_att_helper.set_multiple_data([self.layer])
self.size_att_helper.set_multiple_data([self.layer])
def update_priority(self, name):
return 0 if name.endswith(('vmin', 'vmax')) else 1
def _layer_changed(self):
super(WWTLayerState, self)._layer_changed()
if self._sync_markersize is not None:
self._sync_markersize.stop_syncing()
if self.layer is not None:
self.size = self.layer.style.markersize
self._sync_markersize = keep_in_sync(self, 'size', self.layer.style, 'markersize')
def flip_size(self):
self.size_lim_helper.flip_limits()
def flip_cmap(self):
self.cmap_lim_helper.flip_limits()