def __init__(self, layer=None, **kwargs): self._sync_markersize = None super(ScatterLayerState, self).__init__(layer=layer) if self.layer is not None: self.color = self.layer.style.color self.size = self.layer.style.markersize self.alpha = self.layer.style.alpha self.size_att_helper = ComponentIDComboHelper(self, 'size_attribute') self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_attribute') self.size_lim_helper = StateAttributeLimitsHelper(self, attribute='size_attribute', lower='size_vmin', upper='size_vmax', cache=self.size_limits_cache) self.cmap_lim_helper = StateAttributeLimitsHelper(self, attribute='cmap_attribute', 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 __init__(self, **kwargs): super(ScatterViewerState, self).__init__() self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper(self, attribute='x_att', lower='x_min', upper='x_max', log='x_log', margin=0.05, limits_cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper(self, attribute='y_att', lower='y_min', upper='y_max', log='y_log', margin=0.05, limits_cache=self.limits_cache) self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', pixel_coord=True, world_coord=True) self.y_att_helper = ComponentIDComboHelper(self, 'y_att', pixel_coord=True, world_coord=True) self.update_from_dict(kwargs) self.add_callback('x_log', self._reset_x_limits) self.add_callback('y_log', self._reset_y_limits)
def __init__(self, **kwargs): super(Vispy3DViewerState, self).__init__(**kwargs) if self.limits_cache is None: self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper(self, attribute='x_att', lower='x_min', upper='x_max', cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper(self, attribute='y_att', lower='y_min', upper='y_max', cache=self.limits_cache) self.z_lim_helper = StateAttributeLimitsHelper(self, attribute='z_att', lower='z_min', upper='z_max', cache=self.limits_cache) # TODO: if limits_cache is re-assigned to a different object, we need to # update the attribute helpers. However if in future we make limits_cache # into a smart dictionary that can call callbacks when elements are # changed then we shouldn't always call this. It'd also be nice to # avoid this altogether and make it more clean. self.add_callback('limits_cache', nonpartial(self._update_limits_cache))
def __init__(self, **kwargs): super(ProfileViewerState, self).__init__() self.ref_data_helper = ManualDataComboHelper(self, 'reference_data') self.x_lim_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max') self.add_callback('layers', self._layers_changed) self.add_callback('reference_data', self._reference_data_changed) self.add_callback('normalize', self._reset_y_limits) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', numeric=False, categorical=False, world_coord=True, pixel_coord=True) ProfileViewerState.function.set_choices(self, list(FUNCTIONS)) ProfileViewerState.function.set_display_func(self, FUNCTIONS.get) self.update_from_dict(kwargs)
def __init__(self, **kwargs): super(HistogramViewerState, self).__init__() self.hist_helper = StateAttributeHistogramHelper( self, 'x_att', lower='hist_x_min', upper='hist_x_max', n_bin='hist_n_bin', common_n_bin='common_n_bin') self.x_lim_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max', log='x_log') self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', pixel_coord=True, world_coord=True) self.update_from_dict(kwargs) # This should be added after update_from_dict since we don't want to # influence the restoring of sessions. self.add_callback('hist_x_min', self.update_view_to_bins) self.add_callback('hist_x_max', self.update_view_to_bins) self.add_callback('x_log', self._reset_x_limits, priority=1000)
def __init__(self, **kwargs): super(ScatterViewerState, self).__init__() self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper( self, attribute='x_att', lower='x_min', upper='x_max', log='x_log', limits_cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper( self, attribute='y_att', lower='y_min', upper='y_max', log='y_log', limits_cache=self.limits_cache) self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att') self.y_att_helper = ComponentIDComboHelper(self, 'y_att') self.update_from_dict(kwargs)
def __init__(self, layer=None, viewer_state=None, **kwargs): self.uuid = str(uuid.uuid4()) super(ImageLayerState, self).__init__(layer=layer, viewer_state=viewer_state) self.attribute_lim_helper = StateAttributeLimitsHelper( self, attribute='attribute', percentile='percentile', lower='v_min', upper='v_max') self.attribute_att_helper = ComponentIDComboHelper(self, 'attribute', numeric=True, categorical=False) percentile_display = { 100: 'Min/Max', 99.5: '99.5%', 99: '99%', 95: '95%', 90: '90%', 'Custom': 'Custom' } ImageLayerState.percentile.set_choices( self, [100, 99.5, 99, 95, 90, 'Custom']) ImageLayerState.percentile.set_display_func(self, percentile_display.get) stretch_display = { 'linear': 'Linear', 'sqrt': 'Square Root', 'arcsinh': 'Arcsinh', 'log': 'Logarithmic' } ImageLayerState.stretch.set_choices( self, ['linear', 'sqrt', 'arcsinh', 'log']) ImageLayerState.stretch.set_display_func(self, stretch_display.get) self.add_callback('global_sync', self._update_syncing) self.add_callback('layer', self._update_attribute) self._update_syncing() if layer is not None: self._update_attribute() self.update_from_dict(kwargs) if self.cmap is None: self.cmap = self.layer.style.preferred_cmap or colormaps.members[ 0][1]
def __init__(self, **kwargs): super(ImageViewerState, self).__init__() self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper( self, attribute='x_att', lower='x_min', upper='x_max', limits_cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper( self, attribute='y_att', lower='y_min', upper='y_max', limits_cache=self.limits_cache) self.ref_data_helper = ManualDataComboHelper(self, 'reference_data') self.xw_att_helper = ComponentIDComboHelper(self, 'x_att_world', numeric=False, categorical=False, visible=False, world_coord=True) self.yw_att_helper = ComponentIDComboHelper(self, 'y_att_world', numeric=False, categorical=False, visible=False, world_coord=True) self.add_callback('reference_data', self._reference_data_changed, priority=1000) self.add_callback('layers', self._layers_changed, priority=1000) self.add_callback('x_att', self._on_xatt_change, priority=500) self.add_callback('y_att', self._on_yatt_change, priority=500) self.add_callback('x_att_world', self._update_att, priority=500) self.add_callback('y_att_world', self._update_att, priority=500) self.add_callback('x_att_world', self._on_xatt_world_change, priority=1000) self.add_callback('y_att_world', self._on_yatt_world_change, priority=1000) self.update_from_dict(kwargs)
def __init__(self, **kwargs): super(ScatterViewerState, self).__init__() self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper( self, attribute='x_att', lower='x_min', upper='x_max', log='x_log', margin=0.04, limits_cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper( self, attribute='y_att', lower='y_min', upper='y_max', log='y_log', margin=0.04, limits_cache=self.limits_cache) self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', pixel_coord=True, world_coord=True) self.y_att_helper = ComponentIDComboHelper(self, 'y_att', pixel_coord=True, world_coord=True) self.plot_mode_helper = ComboHelper(self, 'plot_mode') self.plot_mode_helper.choices = [ proj for proj in get_projection_names() if proj not in ['3d', 'scatter_density'] ] self.plot_mode_helper.selection = 'rectilinear' self.angle_unit_helper = ComboHelper(self, 'angle_unit') self.angle_unit_helper.choices = ['radians', 'degrees'] self.angle_unit_helper.selection = 'radians' self.update_from_dict(kwargs) self.add_callback('x_log', self._reset_x_limits) self.add_callback('y_log', self._reset_y_limits) if self.using_polar: self.full_circle()
def __init__(self, **kwargs): super(HistogramViewerState, self).__init__(**kwargs) self.x_att_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max', log='x_log') self.hist_helper = StateAttributeHistogramHelper( self, 'x_att', lower='hist_x_min', upper='hist_x_max', n_bin='hist_n_bin', common_n_bin='common_n_bin')
def __init__(self, layer=None, **kwargs): self._sync_markersize = None super(WWTTableLayerState, 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') self.color = self.layer.style.color self.size = self.layer.style.markersize self.alpha = self.layer.style.alpha self.size_att_helper = ComponentIDComboHelper(self, 'size_att', numeric=True, categorical=False) self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_att', numeric=True, categorical=False) self.img_data_att_helper = ComponentIDComboHelper(self, 'img_data_att', numeric=True, categorical=False) 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] # Color and size encoding depending on attributes is only available # in PyWWT 0.6 or later. if PYWWT_LT_06: modes = ['Fixed'] else: modes = ['Fixed', 'Linear'] WWTTableLayerState.color_mode.set_choices(self, modes) WWTTableLayerState.size_mode.set_choices(self, modes) self.update_from_dict(kwargs)
def __init__(self, viewer_state=None, layer=None, **kwargs): super(ScatterLayerState, self).__init__(viewer_state=viewer_state, layer=layer) self.limits_cache = {} self.cmap_lim_helper = StateAttributeLimitsHelper(self, attribute='cmap_att', lower='cmap_vmin', upper='cmap_vmax', limits_cache=self.limits_cache) self.size_lim_helper = StateAttributeLimitsHelper(self, attribute='size_att', lower='size_vmin', upper='size_vmax', limits_cache=self.limits_cache) self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_att', numeric=True, categorical=False) self.size_att_helper = ComponentIDComboHelper(self, 'size_att', numeric=True, categorical=False) self.xerr_att_helper = ComponentIDComboHelper(self, 'xerr_att', numeric=True, categorical=False) self.yerr_att_helper = ComponentIDComboHelper(self, 'yerr_att', numeric=True, categorical=False) ScatterLayerState.style.set_choices(self, ['Scatter', 'Line']) ScatterLayerState.cmap_mode.set_choices(self, ['Fixed', 'Linear']) ScatterLayerState.size_mode.set_choices(self, ['Fixed', 'Linear']) linestyle_display = {'solid': '–––––––', 'dashed': '– – – – –', 'dotted': '· · · · · · · ·', 'dashdot': '– · – · – ·'} ScatterLayerState.linestyle.set_choices(self, ['solid', 'dashed', 'dotted', 'dashdot']) ScatterLayerState.linestyle.set_display_func(self, linestyle_display.get) self.add_callback('layer', self._on_layer_change) if layer is not None: self._on_layer_change() self.cmap = colormaps.members[0][1] self.size = self.layer.style.markersize self._sync_size = keep_in_sync(self, 'size', self.layer.style, 'markersize') self.update_from_dict(kwargs)
def __init__(self, layer=None, **kwargs): super(VolumeLayerState, self).__init__(layer=layer) if self.layer is not None: self.color = self.layer.style.color self.alpha = self.layer.style.alpha self.att_helper = ComponentIDComboHelper(self, 'attribute') self.lim_helper = StateAttributeLimitsHelper(self, attribute='attribute', lower='vmin', upper='vmax', cache=self.limits_cache) self.add_callback('layer', self._on_layer_change) if layer is not None: self._on_layer_change() if isinstance(self.layer, Subset): self.vmin = 0 self.lim_helper.lower_frozen = True self.update_from_dict(kwargs)
def __init__(self, layer=None, **kwargs): 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') self.color = self.layer.style.color self.size = self.layer.style.markersize self.alpha = self.layer.style.alpha self.size_att_helper = ComponentIDComboHelper(self, 'size_att', numeric=True, categorical=False) self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_att', numeric=True, categorical=False) 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] # Color and size encoding depending on attributes is only available # in PyWWT 0.6 or later. if PYWWT_LT_06: modes = ['Fixed'] else: modes = ['Fixed', 'Linear'] WWTLayerState.color_mode.set_choices(self, modes) WWTLayerState.size_mode.set_choices(self, modes) self.update_from_dict(kwargs)
def __init__(self, layer=None, viewer_state=None, **kwargs): super(ImageLayerState, self).__init__(layer=layer, viewer_state=viewer_state) self.attribute_helper = StateAttributeLimitsHelper(self, attribute='attribute', percentile='percentile', lower='v_min', upper='v_max') self.add_callback('global_sync', self._update_syncing) self.add_callback('layer', self._update_attribute) self._update_syncing() if layer is not None: self._update_attribute() self.update_from_dict(kwargs) if self.cmap is None: self.cmap = colormaps.members[0][1]
def __init__(self, data_collection): super(SubsetFacetState, self).__init__() self.data_helper = DataCollectionComboHelper(self, 'data', data_collection) self.att_helper = ComponentIDComboHelper(self, 'att') self.lim_helper = StateAttributeLimitsHelper(self, attribute='att', lower='v_min', upper='v_max', log='log') self.add_callback('data', self._on_data_change) self._on_data_change()
def __init__(self, **kwargs): super(Vispy3DViewerState, self).__init__(**kwargs) if self.limits_cache is None: self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper(self, attribute='x_att', lower='x_min', upper='x_max', cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper(self, attribute='y_att', lower='y_min', upper='y_max', cache=self.limits_cache) self.z_lim_helper = StateAttributeLimitsHelper(self, attribute='z_att', lower='z_min', upper='z_max', cache=self.limits_cache) # TODO: if limits_cache is re-assigned to a different object, we need to # update the attribute helpers. However if in future we make limits_cache # into a smart dictionary that can call callbacks when elements are # changed then we shouldn't always call this. It'd also be nice to # avoid this altogether and make it more clean. self.add_callback('limits_cache', self._update_limits_cache)
def __init__(self, **kwargs): super(HistogramViewerState, self).__init__() self.hist_helper = StateAttributeHistogramHelper( self, 'x_att', lower='hist_x_min', upper='hist_x_max', n_bin='hist_n_bin', common_n_bin='common_n_bin') self.x_lim_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max', log='x_log') self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att') self.update_from_dict(kwargs)
def __init__(self, **kwargs): super(ImageViewerState, self).__init__() self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper(self, attribute='x_att', lower='x_min', upper='x_max', limits_cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper(self, attribute='y_att', lower='y_min', upper='y_max', limits_cache=self.limits_cache) self.ref_data_helper = ManualDataComboHelper(self, 'reference_data') self.xw_att_helper = ComponentIDComboHelper(self, 'x_att_world', numeric=False, categorical=False, world_coord=True) self.yw_att_helper = ComponentIDComboHelper(self, 'y_att_world', numeric=False, categorical=False, world_coord=True) self.add_callback('reference_data', self._reference_data_changed, priority=1000) self.add_callback('layers', self._layers_changed, priority=1000) self.add_callback('x_att', self._on_xatt_change, priority=500) self.add_callback('y_att', self._on_yatt_change, priority=500) self.add_callback('x_att_world', self._update_att, priority=500) self.add_callback('y_att_world', self._update_att, priority=500) self.add_callback('x_att_world', self._on_xatt_world_change, priority=1000) self.add_callback('y_att_world', self._on_yatt_world_change, priority=1000) self.update_from_dict(kwargs)
def __init__(self, layer=None, **kwargs): self._sync_markersize = None super(ScatterLayerState, self).__init__(layer=layer) if self.layer is not None: self.color = self.layer.style.color self.size = self.layer.style.markersize self.alpha = self.layer.style.alpha self.size_att_helper = ComponentIDComboHelper(self, 'size_attribute') self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_attribute') self.size_lim_helper = StateAttributeLimitsHelper( self, attribute='size_attribute', lower='size_vmin', upper='size_vmax', cache=self.size_limits_cache) self.cmap_lim_helper = StateAttributeLimitsHelper( self, attribute='cmap_attribute', 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 __init__(self, **kwargs): super(HistogramViewerState, self).__init__() self.hist_helper = StateAttributeHistogramHelper(self, 'x_att', lower='hist_x_min', upper='hist_x_max', n_bin='hist_n_bin', common_n_bin='common_n_bin') self.x_lim_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max', log='x_log') self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att') self.update_from_dict(kwargs)
def __init__(self, layer=None, **kwargs): super(IsosurfaceLayerState, self).__init__(layer=layer) self.att_helper = ComponentIDComboHelper(self, 'attribute') self.lim_helper = StateAttributeLimitsHelper(self, attribute='attribute', lower='level_low', upper='level_high') 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 __init__(self, layer=None, viewer_state=None, **kwargs): self.uuid = str(uuid.uuid4()) super(ImageLayerState, self).__init__(layer=layer, viewer_state=viewer_state) self.attribute_lim_helper = StateAttributeLimitsHelper(self, attribute='attribute', percentile='percentile', lower='v_min', upper='v_max') self.attribute_att_helper = ComponentIDComboHelper(self, 'attribute', numeric=True, categorical=False) percentile_display = {100: 'Min/Max', 99.5: '99.5%', 99: '99%', 95: '95%', 90: '90%', 'Custom': 'Custom'} ImageLayerState.percentile.set_choices(self, [100, 99.5, 99, 95, 90, 'Custom']) ImageLayerState.percentile.set_display_func(self, percentile_display.get) stretch_display = {'linear': 'Linear', 'sqrt': 'Square Root', 'arcsinh': 'Arcsinh', 'log': 'Logarithmic'} ImageLayerState.stretch.set_choices(self, ['linear', 'sqrt', 'arcsinh', 'log']) ImageLayerState.stretch.set_display_func(self, stretch_display.get) self.add_callback('global_sync', self._update_syncing) self.add_callback('layer', self._update_attribute) self._update_syncing() if layer is not None: self._update_attribute() self.update_from_dict(kwargs) if self.cmap is None: self.cmap = colormaps.members[0][1]
def __init__(self, layer=None, viewer_state=None, **kwargs): super(ImageLayerState, self).__init__(layer=layer, viewer_state=viewer_state) self.attribute_helper = StateAttributeLimitsHelper(self, attribute='attribute', percentile='percentile', lower='v_min', upper='v_max') self.add_callback('global_sync', self._update_syncing) self.add_callback('layer', self._update_attribute) self._update_syncing() if layer is not None: self._update_attribute() self.update_from_dict(kwargs) if self.cmap is None: self.cmap = colormaps.members[0][1]
def __init__(self, **kwargs): super(ProfileViewerState, self).__init__() self.ref_data_helper = ManualDataComboHelper(self, 'reference_data') self.x_lim_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max') self.add_callback('layers', self._layers_changed) self.add_callback('reference_data', self._reference_data_changed) self.add_callback('normalize', self._reset_y_limits) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', numeric=False, categorical=False, world_coord=True, pixel_coord=True) ProfileViewerState.function.set_choices(self, list(FUNCTIONS)) ProfileViewerState.function.set_display_func(self, FUNCTIONS.get) self.update_from_dict(kwargs)
def __init__(self, *args, **kwargs): super(BqplotImageLayerState, self).__init__(*args, **kwargs) BqplotImageLayerState.level_mode.set_choices(self, ['Linear', 'Custom']) percentile_display = {100: 'Min/Max', 99.5: '99.5%', 99: '99%', 95: '95%', 90: '90%', 'Custom': 'Custom'} BqplotImageLayerState.contour_percentile.set_choices(self, [100, 99.5, 99, 95, 90, 'Custom']) BqplotImageLayerState.contour_percentile.set_display_func(self, percentile_display.get) self.contour_lim_helper = StateAttributeLimitsHelper(self, attribute='attribute', percentile='contour_percentile', lower='c_min', upper='c_max') self.add_callback('n_levels', self._update_levels) self.add_callback('c_min', self._update_levels) self.add_callback('c_max', self._update_levels) self.add_callback('level_mode', self._update_levels) self.add_callback('levels', self._update_labels) self._update_levels()
def __init__(self, **kwargs): super(HistogramViewerState, self).__init__() self.hist_helper = StateAttributeHistogramHelper(self, 'x_att', lower='hist_x_min', upper='hist_x_max', n_bin='hist_n_bin', common_n_bin='common_n_bin') self.x_lim_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max', log='x_log') self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', pixel_coord=True, world_coord=True) self.update_from_dict(kwargs) # This should be added after update_from_dict since we don't want to # influence the restoring of sessions. self.add_callback('hist_x_min', self.update_view_to_bins) self.add_callback('hist_x_max', self.update_view_to_bins) self.add_callback('x_log', self._reset_x_limits, priority=1000)
def __init__(self, layer=None, **kwargs): self._sync_markersize = None super(ScatterLayerState, self).__init__(layer=layer) if self.layer is not None: self.color = self.layer.style.color self.size = self.layer.style.markersize self.alpha = self.layer.style.alpha self.size_att_helper = ComponentIDComboHelper(self, 'size_attribute') self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_attribute') self.xerr_att_helper = ComponentIDComboHelper(self, 'xerr_attribute', categorical=False) self.yerr_att_helper = ComponentIDComboHelper(self, 'yerr_attribute', categorical=False) self.zerr_att_helper = ComponentIDComboHelper(self, 'zerr_attribute', categorical=False) self.vx_att_helper = ComponentIDComboHelper(self, 'vx_attribute', categorical=False) self.vy_att_helper = ComponentIDComboHelper(self, 'vy_attribute', categorical=False) self.vz_att_helper = ComponentIDComboHelper(self, 'vz_attribute', categorical=False) self.size_lim_helper = StateAttributeLimitsHelper( self, attribute='size_attribute', lower='size_vmin', upper='size_vmax', cache=self.size_limits_cache) self.cmap_lim_helper = StateAttributeLimitsHelper( self, attribute='cmap_attribute', lower='cmap_vmin', upper='cmap_vmax', cache=self.cmap_limits_cache) vector_origin_display = { 'tail': 'Tail of vector', 'middle': 'Middle of vector', 'tip': 'Tip of vector' } ScatterLayerState.vector_origin.set_choices(self, ['tail', 'middle', 'tip']) ScatterLayerState.vector_origin.set_display_func( self, vector_origin_display.get) 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)
class Vispy3DViewerState(State): """ A common state object for all vispy 3D viewers """ x_att = SelectionCallbackProperty() x_min = CallbackProperty(0) x_max = CallbackProperty(1) x_stretch = CallbackProperty(1.) y_att = SelectionCallbackProperty() y_min = CallbackProperty(0) y_max = CallbackProperty(1) y_stretch = CallbackProperty(1.) z_att = SelectionCallbackProperty() z_min = CallbackProperty(0) z_max = CallbackProperty(1) z_stretch = CallbackProperty(1.) visible_axes = CallbackProperty(True) perspective_view = CallbackProperty(False) clip_data = CallbackProperty(False) native_aspect = CallbackProperty(False) layers = ListCallbackProperty() limits_cache = CallbackProperty() def _update_priority(self, name): if name == 'layers': return 2 elif name.endswith(('_min', '_max')): return 0 else: return 1 def __init__(self, **kwargs): super(Vispy3DViewerState, self).__init__(**kwargs) if self.limits_cache is None: self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper(self, attribute='x_att', lower='x_min', upper='x_max', cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper(self, attribute='y_att', lower='y_min', upper='y_max', cache=self.limits_cache) self.z_lim_helper = StateAttributeLimitsHelper(self, attribute='z_att', lower='z_min', upper='z_max', cache=self.limits_cache) # TODO: if limits_cache is re-assigned to a different object, we need to # update the attribute helpers. However if in future we make limits_cache # into a smart dictionary that can call callbacks when elements are # changed then we shouldn't always call this. It'd also be nice to # avoid this altogether and make it more clean. self.add_callback('limits_cache', nonpartial(self._update_limits_cache)) def _update_limits_cache(self): self.x_lim_helper._cache = self.limits_cache self.x_lim_helper._update_attribute() self.y_lim_helper._cache = self.limits_cache self.y_lim_helper._update_attribute() self.z_lim_helper._cache = self.limits_cache self.z_lim_helper._update_attribute() @property def aspect(self): # TODO: this could be cached based on the limits, but is not urgent aspect = np.array([1, 1, 1], dtype=float) if self.native_aspect: aspect[0] = 1. aspect[1] = (self.y_max - self.y_min) / (self.x_max - self.x_min) aspect[2] = (self.z_max - self.z_min) / (self.x_max - self.x_min) aspect /= aspect.max() return aspect def reset(self): pass def flip_x(self): self.x_lim_helper.flip_limits() def flip_y(self): self.y_lim_helper.flip_limits() def flip_z(self): self.z_lim_helper.flip_limits() @property def clip_limits(self): return (self.x_min, self.x_max, self.y_min, self.y_max, self.z_min, self.z_max) def set_limits(self, x_min, x_max, y_min, y_max, z_min, z_max): with delay_callback(self, 'x_min', 'x_max', 'y_min', 'y_max', 'z_min', 'z_max'): self.x_min = x_min self.x_max = x_max self.y_min = y_min self.y_max = y_max self.z_min = z_min self.z_max = z_max
class ScatterLayerState(VispyLayerState): """ A state object for volume layers """ size_mode = CallbackProperty('Fixed') size = CallbackProperty() size_attribute = SelectionCallbackProperty() size_vmin = CallbackProperty() size_vmax = CallbackProperty() size_scaling = CallbackProperty(1) color_mode = CallbackProperty('Fixed') cmap_attribute = SelectionCallbackProperty() cmap_vmin = CallbackProperty() cmap_vmax = CallbackProperty() cmap = CallbackProperty() size_limits_cache = CallbackProperty({}) cmap_limits_cache = CallbackProperty({}) def __init__(self, layer=None, **kwargs): self._sync_markersize = None super(ScatterLayerState, self).__init__(layer=layer) if self.layer is not None: self.color = self.layer.style.color self.size = self.layer.style.markersize self.alpha = self.layer.style.alpha self.size_att_helper = ComponentIDComboHelper(self, 'size_attribute') self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_attribute') self.size_lim_helper = StateAttributeLimitsHelper(self, attribute='size_attribute', lower='size_vmin', upper='size_vmax', cache=self.size_limits_cache) self.cmap_lim_helper = StateAttributeLimitsHelper(self, attribute='cmap_attribute', 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(ScatterLayerState, 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()
class ScatterViewerState(MatplotlibDataViewerState): """ A state class that includes all the attributes for a scatter viewer. """ x_att = DDSCProperty(docstring='The attribute to show on the x-axis', default_index=0) y_att = DDSCProperty(docstring='The attribute to show on the y-axis', default_index=1) dpi = DDCProperty(72, docstring='The resolution (in dots per inch) of density maps, if present') def __init__(self, **kwargs): super(ScatterViewerState, self).__init__() self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper(self, attribute='x_att', lower='x_min', upper='x_max', log='x_log', margin=0.05, limits_cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper(self, attribute='y_att', lower='y_min', upper='y_max', log='y_log', margin=0.05, limits_cache=self.limits_cache) self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', pixel_coord=True, world_coord=True) self.y_att_helper = ComponentIDComboHelper(self, 'y_att', pixel_coord=True, world_coord=True) self.update_from_dict(kwargs) self.add_callback('x_log', self._reset_x_limits) self.add_callback('y_log', self._reset_y_limits) def _reset_x_limits(self, *args): self.x_lim_helper.percentile = 100 self.x_lim_helper.update_values(force=True) def _reset_y_limits(self, *args): self.y_lim_helper.percentile = 100 self.y_lim_helper.update_values(force=True) def reset_limits(self): self._reset_x_limits() self._reset_y_limits() def flip_x(self): """ Flip the x_min/x_max limits. """ self.x_lim_helper.flip_limits() def flip_y(self): """ Flip the y_min/y_max limits. """ self.y_lim_helper.flip_limits() @property def x_categories(self): return self._categories(self.x_att) @property def y_categories(self): return self._categories(self.y_att) def _categories(self, cid): categories = [] for layer_state in self.layers: if isinstance(layer_state.layer, BaseData): layer = layer_state.layer else: layer = layer_state.layer.data try: if layer.data.get_kind(cid) == 'categorical': categories.append(layer.data.get_data(cid).categories) except IncompatibleAttribute: pass if len(categories) == 0: return None else: return np.unique(np.hstack(categories)) @property def x_kinds(self): return self._component_kinds(self.x_att) @property def y_kinds(self): return self._component_kinds(self.y_att) def _component_kinds(self, cid): # Construct list of component kinds over all layers kinds = set() for layer_state in self.layers: if isinstance(layer_state.layer, BaseData): layer = layer_state.layer else: layer = layer_state.layer.data try: kinds.add(layer.data.get_kind(cid)) except IncompatibleAttribute: pass return kinds def _layers_changed(self, *args): layers_data = self.layers_data layers_data_cache = getattr(self, '_layers_data_cache', []) if layers_data == layers_data_cache: return self.x_att_helper.set_multiple_data(self.layers_data) self.y_att_helper.set_multiple_data(self.layers_data) self._layers_data_cache = layers_data
class ScatterViewerState(MatplotlibDataViewerState): """ A state class that includes all the attributes for a scatter viewer. """ x_att = DDSCProperty(docstring='The attribute to show on the x-axis', default_index=0) y_att = DDSCProperty(docstring='The attribute to show on the y-axis', default_index=1) dpi = DDCProperty( 72, docstring= 'The resolution (in dots per inch) of density maps, if present') def __init__(self, **kwargs): super(ScatterViewerState, self).__init__() self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper( self, attribute='x_att', lower='x_min', upper='x_max', log='x_log', margin=0.05, limits_cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper( self, attribute='y_att', lower='y_min', upper='y_max', log='y_log', margin=0.05, limits_cache=self.limits_cache) self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', pixel_coord=True, world_coord=True) self.y_att_helper = ComponentIDComboHelper(self, 'y_att', pixel_coord=True, world_coord=True) self.update_from_dict(kwargs) self.add_callback('x_log', self._reset_x_limits) self.add_callback('y_log', self._reset_y_limits) def _reset_x_limits(self, *args): self.x_lim_helper.percentile = 100 self.x_lim_helper.update_values(force=True) def _reset_y_limits(self, *args): self.y_lim_helper.percentile = 100 self.y_lim_helper.update_values(force=True) def reset_limits(self): self._reset_x_limits() self._reset_y_limits() def _update_priority(self, name): if name == 'layers': return 2 elif name.endswith('_log'): return 0.5 elif name.endswith(('_min', '_max')): return 0 else: return 1 def flip_x(self): """ Flip the x_min/x_max limits. """ self.x_lim_helper.flip_limits() def flip_y(self): """ Flip the y_min/y_max limits. """ self.y_lim_helper.flip_limits() def _get_x_components(self): return self._get_components(self.x_att) def _get_y_components(self): return self._get_components(self.y_att) def _get_components(self, cid): # Construct list of components over all layers components = [] for layer_state in self.layers: if isinstance(layer_state.layer, Data): layer = layer_state.layer else: layer = layer_state.layer.data try: components.append(layer.data.get_component(cid)) except IncompatibleAttribute: pass return components def _layers_changed(self, *args): layers_data = self.layers_data layers_data_cache = getattr(self, '_layers_data_cache', []) if layers_data == layers_data_cache: return self.x_att_helper.set_multiple_data(self.layers_data) self.y_att_helper.set_multiple_data(self.layers_data) self._layers_data_cache = layers_data
class HistogramViewerState(MatplotlibDataViewerState): """ A state class that includes all the attributes for a histogram viewer. """ x_att = DDSCProperty(docstring='The attribute to compute the histograms for') cumulative = DDCProperty(False, docstring='Whether to show the histogram as ' 'a cumulative histogram') normalize = DDCProperty(False, docstring='Whether to normalize the histogram ' '(based on the total sum)') hist_x_min = DDCProperty(docstring='The minimum value used to compute the ' 'histogram') hist_x_max = DDCProperty(docstring='The maxumum value used to compute the ' 'histogram') hist_n_bin = DDCProperty(docstring='The number of bins in the histogram') common_n_bin = DDCProperty(True, docstring='The number of bins to use for ' 'all numerical components') def __init__(self, **kwargs): super(HistogramViewerState, self).__init__() self.hist_helper = StateAttributeHistogramHelper(self, 'x_att', lower='hist_x_min', upper='hist_x_max', n_bin='hist_n_bin', common_n_bin='common_n_bin') self.x_lim_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max', log='x_log') self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att') self.update_from_dict(kwargs) def _update_priority(self, name): if name == 'layers': return 2 elif name.endswith('_log'): return 0.5 elif name.endswith(('_min', '_max', '_bin')): return 0 else: return 1 def flip_x(self): """ Flip the x_min/x_max limits. """ self.x_lim_helper.flip_limits() def update_bins_to_view(self): """ Update the bins to match the current view. """ with delay_callback(self, 'hist_x_min', 'hist_x_max'): if self.x_max > self.x_min: self.hist_x_min = self.x_min self.hist_x_max = self.x_max else: self.hist_x_min = self.x_max self.hist_x_max = self.x_min def _get_x_components(self): if self.x_att is None: return [] # Construct list of components over all layers components = [] for layer_state in self.layers: if isinstance(layer_state.layer, Data): layer = layer_state.layer else: layer = layer_state.layer.data try: components.append(layer.get_component(self.x_att)) except IncompatibleAttribute: pass return components @property def bins(self): """ The position of the bins for the histogram based on the current state. """ if self.x_log: return np.logspace(np.log10(self.hist_x_min), np.log10(self.hist_x_max), self.hist_n_bin + 1) else: return np.linspace(self.hist_x_min, self.hist_x_max, self.hist_n_bin + 1) @defer_draw def _layers_changed(self, *args): self.x_att_helper.set_multiple_data(self.layers_data)
class WWTLayerState(LayerState): """ A state object for volume layers """ layer = CallbackProperty() color = CallbackProperty() size = CallbackProperty() alpha = CallbackProperty() size_mode = SelectionCallbackProperty(default_index=0) size = CallbackProperty() size_att = SelectionCallbackProperty() size_vmin = CallbackProperty() size_vmax = CallbackProperty() size_scaling = CallbackProperty(1) color_mode = SelectionCallbackProperty(default_index=0) cmap_att = SelectionCallbackProperty() cmap_vmin = CallbackProperty() cmap_vmax = CallbackProperty() cmap = CallbackProperty() size_limits_cache = CallbackProperty({}) cmap_limits_cache = CallbackProperty({}) def __init__(self, layer=None, **kwargs): 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') self.color = self.layer.style.color self.size = self.layer.style.markersize self.alpha = self.layer.style.alpha self.size_att_helper = ComponentIDComboHelper(self, 'size_att', numeric=True, categorical=False) self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_att', numeric=True, categorical=False) 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] # Color and size encoding depending on attributes is only available # in PyWWT 0.6 or later. if PYWWT_LT_06: modes = ['Fixed'] else: modes = ['Fixed', 'Linear'] WWTLayerState.color_mode.set_choices(self, modes) WWTLayerState.size_mode.set_choices(self, modes) 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()
class ViewerState3D(ViewerState): """ A common state object for all 3D viewers """ x_att = SelectionCallbackProperty() x_min = CallbackProperty(0) x_max = CallbackProperty(1) # x_stretch = CallbackProperty(1.) y_att = SelectionCallbackProperty(default_index=1) y_min = CallbackProperty(0) y_max = CallbackProperty(1) # y_stretch = CallbackProperty(1.) z_att = SelectionCallbackProperty(default_index=2) z_min = CallbackProperty(0) z_max = CallbackProperty(1) # z_stretch = CallbackProperty(1.) visible_axes = CallbackProperty(True) # perspective_view = CallbackProperty(False) # clip_data = CallbackProperty(False) # native_aspect = CallbackProperty(False) limits_cache = CallbackProperty() # def _update_priority(self, name): # if name == 'layers': # return 2 # elif name.endswith(('_min', '_max')): # return 0 # else: # return 1 def __init__(self, **kwargs): super(ViewerState3D, self).__init__(**kwargs) if self.limits_cache is None: self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper(self, attribute='x_att', lower='x_min', upper='x_max', cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper(self, attribute='y_att', lower='y_min', upper='y_max', cache=self.limits_cache) self.z_lim_helper = StateAttributeLimitsHelper(self, attribute='z_att', lower='z_min', upper='z_max', cache=self.limits_cache) # TODO: if limits_cache is re-assigned to a different object, we need to # update the attribute helpers. However if in future we make limits_cache # into a smart dictionary that can call callbacks when elements are # changed then we shouldn't always call this. It'd also be nice to # avoid this altogether and make it more clean. self.add_callback('limits_cache', nonpartial(self._update_limits_cache)) def _update_limits_cache(self): self.x_lim_helper._cache = self.limits_cache self.x_lim_helper._update_attribute() self.y_lim_helper._cache = self.limits_cache self.y_lim_helper._update_attribute() self.z_lim_helper._cache = self.limits_cache self.z_lim_helper._update_attribute() # @property # def aspect(self): # # TODO: this could be cached based on the limits, but is not urgent # aspect = np.array([1, 1, 1], dtype=float) # if self.native_aspect: # aspect[0] = 1. # aspect[1] = (self.y_max - self.y_min) / (self.x_max - self.x_min) # aspect[2] = (self.z_max - self.z_min) / (self.x_max - self.x_min) # aspect /= aspect.max() # return aspect # def reset(self): # pass def flip_x(self): self.x_lim_helper.flip_limits() def flip_y(self): self.y_lim_helper.flip_limits() def flip_z(self): self.z_lim_helper.flip_limits()
class ProfileViewerState(MatplotlibDataViewerState): """ A state class that includes all the attributes for a Profile viewer. """ reference_data = DDSCProperty( docstring='The dataset that is used to define the ' 'available pixel/world components, and ' 'which defines the coordinate frame in ' 'which the images are shown') x_att = DDSCProperty(docstring='The data component to use for the x-axis ' 'of the profile (should be a pixel component)') function = DDSCProperty( docstring='The function to use for collapsing data') normalize = DDCProperty(False, docstring='Whether to normalize all profiles ' 'to the [0:1] range') # TODO: add function to use def __init__(self, **kwargs): super(ProfileViewerState, self).__init__() self.ref_data_helper = ManualDataComboHelper(self, 'reference_data') self.x_lim_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max') self.add_callback('layers', self._layers_changed) self.add_callback('reference_data', self._reference_data_changed) self.add_callback('normalize', self._reset_y_limits) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', numeric=False, categorical=False, world_coord=True, pixel_coord=True) ProfileViewerState.function.set_choices(self, list(FUNCTIONS)) ProfileViewerState.function.set_display_func(self, FUNCTIONS.get) self.update_from_dict(kwargs) def _update_combo_ref_data(self): self.ref_data_helper.set_multiple_data(self.layers_data) def reset_limits(self): with delay_callback(self, 'x_min', 'x_max', 'y_min', 'y_max'): self.x_lim_helper.percentile = 100 self.x_lim_helper.update_values(force=True) self._reset_y_limits() def _reset_y_limits(self, *event): if self.normalize: self.y_min = -0.1 self.y_max = +1.1 def _update_priority(self, name): if name == 'layers': return 2 elif name.endswith(('_min', '_max')): return 0 else: return 1 def flip_x(self): """ Flip the x_min/x_max limits. """ self.x_lim_helper.flip_limits() @defer_draw def _layers_changed(self, *args): self._update_combo_ref_data() @defer_draw def _reference_data_changed(self, *args): if self.reference_data is None: self.x_att_helper.set_multiple_data([]) else: self.x_att_helper.set_multiple_data([self.reference_data]) if type(self.reference_data.coords) == Coordinates: self.x_att = self.reference_data.pixel_component_ids[0] else: self.x_att = self.reference_data.world_component_ids[0]
class ProfileViewerState(MatplotlibDataViewerState): """ A state class that includes all the attributes for a Profile viewer. """ reference_data = DDSCProperty(docstring='The dataset that is used to define the ' 'available pixel/world components, and ' 'which defines the coordinate frame in ' 'which the images are shown') x_att = DDSCProperty(docstring='The data component to use for the x-axis ' 'of the profile (should be a pixel component)') function = DDSCProperty(docstring='The function to use for collapsing data') normalize = DDCProperty(False, docstring='Whether to normalize all profiles ' 'to the [0:1] range') # TODO: add function to use def __init__(self, **kwargs): super(ProfileViewerState, self).__init__() self.ref_data_helper = ManualDataComboHelper(self, 'reference_data') self.x_lim_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max') self.add_callback('layers', self._layers_changed) self.add_callback('reference_data', self._reference_data_changed) self.add_callback('normalize', self._reset_y_limits) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', numeric=False, categorical=False, world_coord=True, pixel_coord=True) ProfileViewerState.function.set_choices(self, list(FUNCTIONS)) ProfileViewerState.function.set_display_func(self, FUNCTIONS.get) self.update_from_dict(kwargs) def _update_combo_ref_data(self): self.ref_data_helper.set_multiple_data(self.layers_data) def reset_limits(self): with delay_callback(self, 'x_min', 'x_max', 'y_min', 'y_max'): self.x_lim_helper.percentile = 100 self.x_lim_helper.update_values(force=True) self._reset_y_limits() def _reset_y_limits(self, *event): if self.normalize: self.y_min = -0.1 self.y_max = +1.1 def flip_x(self): """ Flip the x_min/x_max limits. """ self.x_lim_helper.flip_limits() @defer_draw def _layers_changed(self, *args): self._update_combo_ref_data() @defer_draw def _reference_data_changed(self, *args): if self.reference_data is None: self.x_att_helper.set_multiple_data([]) else: self.x_att_helper.set_multiple_data([self.reference_data]) if type(self.reference_data.coords) == Coordinates: self.x_att = self.reference_data.pixel_component_ids[0] else: self.x_att = self.reference_data.world_component_ids[0]
class ImageLayerState(BaseImageLayerState): """ A state class that includes all the attributes for data layers in an image plot. """ attribute = DDCProperty(docstring='The attribute shown in the layer') v_min = DDCProperty(docstring='The lower level shown') v_max = DDCProperty(docstring='The upper leven shown') percentile = DDCProperty(100, docstring='The percentile value used to ' 'automatically calculate levels') contrast = DDCProperty(1, docstring='The contrast of the layer') bias = DDCProperty(0.5, docstring='A constant value that is added to the ' 'layer before rendering') cmap = DDCProperty(docstring='The colormap used to render the layer') stretch = DDCProperty('linear', docstring='The stretch used to render the layer, ' 'which should be one of ``linear``, ' '``sqrt``, ``log``, or ``arcsinh``') global_sync = DDCProperty(True, docstring='Whether the color and transparency ' 'should be synced with the global ' 'color and transparency for the data') def __init__(self, layer=None, viewer_state=None, **kwargs): super(ImageLayerState, self).__init__(layer=layer, viewer_state=viewer_state) self.attribute_helper = StateAttributeLimitsHelper( self, attribute='attribute', percentile='percentile', lower='v_min', upper='v_max') self.add_callback('global_sync', self._update_syncing) self.add_callback('layer', self._update_attribute) self._update_syncing() if layer is not None: self._update_attribute() self.update_from_dict(kwargs) if self.cmap is None: self.cmap = colormaps.members[0][1] def _update_attribute(self, *args): if self.layer is not None: self.attribute = self.layer.visible_components[0] def _update_priority(self, name): if name == 'layer': return 3 elif name == 'attribute': return 2 elif name == 'global_sync': return 1.5 elif name.endswith(('_min', '_max')): return 0 else: return 1 def _update_syncing(self, *args): if self.global_sync: self._sync_color.enable_syncing() self._sync_alpha.enable_syncing() else: self._sync_color.disable_syncing() self._sync_alpha.disable_syncing() def _get_image(self, view=None): return self.layer[self.attribute, view] def flip_limits(self): """ Flip the image levels. """ self.attribute_helper.flip_limits() def reset_contrast_bias(self): with delay_callback(self, 'contrast', 'bias'): self.contrast = 1 self.bias = 0.5
class ImageViewerState(MatplotlibDataViewerState): """ A state class that includes all the attributes for an image viewer. """ x_att = DDCProperty( docstring='The component ID giving the pixel component ' 'shown on the x axis') y_att = DDCProperty( docstring='The component ID giving the pixel component ' 'shown on the y axis') x_att_world = DDSCProperty( docstring='The component ID giving the world component ' 'shown on the x axis', default_index=-1) y_att_world = DDSCProperty( docstring='The component ID giving the world component ' 'shown on the y axis', default_index=-2) aspect = DDCProperty( 'equal', docstring='Whether to enforce square pixels (``equal``) ' 'or fill the axes (``auto``)') reference_data = DDSCProperty( docstring='The dataset that is used to define the ' 'available pixel/world components, and ' 'which defines the coordinate frame in ' 'which the images are shown') slices = DDCProperty(docstring='The current slice along all dimensions') color_mode = DDCProperty('Colormaps', docstring='Whether each layer can have ' 'its own colormap (``Colormaps``) or ' 'whether each layer is assigned ' 'a single color (``One color per layer``)') def __init__(self, **kwargs): super(ImageViewerState, self).__init__() self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper( self, attribute='x_att', lower='x_min', upper='x_max', limits_cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper( self, attribute='y_att', lower='y_min', upper='y_max', limits_cache=self.limits_cache) self.ref_data_helper = ManualDataComboHelper(self, 'reference_data') self.xw_att_helper = ComponentIDComboHelper(self, 'x_att_world', numeric=False, categorical=False, visible=False, world_coord=True) self.yw_att_helper = ComponentIDComboHelper(self, 'y_att_world', numeric=False, categorical=False, visible=False, world_coord=True) self.add_callback('reference_data', self._reference_data_changed, priority=1000) self.add_callback('layers', self._layers_changed, priority=1000) self.add_callback('x_att', self._on_xatt_change, priority=500) self.add_callback('y_att', self._on_yatt_change, priority=500) self.add_callback('x_att_world', self._update_att, priority=500) self.add_callback('y_att_world', self._update_att, priority=500) self.add_callback('x_att_world', self._on_xatt_world_change, priority=1000) self.add_callback('y_att_world', self._on_yatt_world_change, priority=1000) self.update_from_dict(kwargs) def _reference_data_changed(self, *args): with delay_callback(self, 'x_att_world', 'y_att_world', 'slices'): self._update_combo_att() self._set_default_slices() def _layers_changed(self, *args): # The layers callback gets executed if anything in the layers changes, # but we only care about whether the actual set of 'layer' attributes # for all layers change. layers_data = self.layers_data layers_data_cache = getattr(self, '_layers_data_cache', []) if layers_data == layers_data_cache: return self._update_combo_ref_data() self._set_reference_data() self._update_syncing() self._layers_data_cache = layers_data def _update_syncing(self): # If there are multiple layers for a given dataset, we disable the # syncing by default. layer_state_by_data = defaultdict(list) for layer_state in self.layers: if isinstance(layer_state.layer, Data): layer_state_by_data[layer_state.layer].append(layer_state) for data, layer_states in layer_state_by_data.items(): if len(layer_states) > 1: for layer_state in layer_states: if layer_state.global_sync: layer_state.global_sync = False def _update_combo_ref_data(self): self.ref_data_helper.set_multiple_data(self.layers_data) def _update_combo_att(self): with delay_callback(self, 'x_att_world', 'y_att_world'): if self.reference_data is None: self.xw_att_helper.set_multiple_data([]) self.yw_att_helper.set_multiple_data([]) else: self.xw_att_helper.set_multiple_data([self.reference_data]) self.yw_att_helper.set_multiple_data([self.reference_data]) def _update_priority(self, name): if name == 'layers': return 3 elif name == 'reference_data': return 2 elif name.endswith(('_min', '_max')): return 0 else: return 1 @defer_draw def _update_att(self, *args): # Need to delay the callbacks here to make sure that we get a chance to # update both x_att and y_att otherwise could end up triggering image # slicing with two pixel components that are the same. with delay_callback(self, 'x_att', 'y_att'): if self.x_att_world is not None: index = self.reference_data.world_component_ids.index( self.x_att_world) self.x_att = self.reference_data.pixel_component_ids[index] if self.y_att_world is not None: index = self.reference_data.world_component_ids.index( self.y_att_world) self.y_att = self.reference_data.pixel_component_ids[index] @defer_draw def _on_xatt_change(self, *args): if self.x_att is not None: self.x_att_world = self.reference_data.world_component_ids[ self.x_att.axis] @defer_draw def _on_yatt_change(self, *args): if self.y_att is not None: self.y_att_world = self.reference_data.world_component_ids[ self.y_att.axis] @defer_draw def _on_xatt_world_change(self, *args): if self.x_att_world is not None and self.x_att_world == self.y_att_world: world_ids = self.reference_data.world_component_ids if self.x_att_world == world_ids[-1]: self.y_att_world = world_ids[-2] else: self.y_att_world = world_ids[-1] @defer_draw def _on_yatt_world_change(self, *args): if self.y_att_world is not None and self.y_att_world == self.x_att_world: world_ids = self.reference_data.world_component_ids if self.y_att_world == world_ids[-1]: self.x_att_world = world_ids[-2] else: self.x_att_world = world_ids[-1] def _set_reference_data(self): if self.reference_data is None: for layer in self.layers: if isinstance(layer.layer, Data): self.reference_data = layer.layer return def _set_default_slices(self): # Need to make sure this gets called immediately when reference_data is changed if self.reference_data is None: self.slices = () else: self.slices = (0, ) * self.reference_data.ndim @property def numpy_slice_aggregation_transpose(self): """ Returns slicing information usable by Numpy. This returns two objects: the first is an object that can be used to slice Numpy arrays and return a 2D array, and the second object is a boolean indicating whether to transpose the result. """ if self.reference_data is None: return None slices = [] agg_func = [] for i in range(self.reference_data.ndim): if i == self.x_att.axis or i == self.y_att.axis: slices.append(slice(None)) agg_func.append(None) else: if isinstance(self.slices[i], AggregateSlice): slices.append(self.slices[i].slice) agg_func.append(self.slices[i].function) else: slices.append(self.slices[i]) transpose = self.y_att.axis > self.x_att.axis return slices, agg_func, transpose @property def wcsaxes_slice(self): """ Returns slicing information usable by WCSAxes. This returns an iterable of slices, and including ``'x'`` and ``'y'`` for the dimensions along which we are not slicing. """ if self.reference_data is None: return None slices = [] for i in range(self.reference_data.ndim): if i == self.x_att.axis: slices.append('x') elif i == self.y_att.axis: slices.append('y') else: if isinstance(self.slices[i], AggregateSlice): slices.append(self.slices[i].center) else: slices.append(self.slices[i]) return slices[::-1] def flip_x(self): """ Flip the x_min/x_max limits. """ self.x_lim_helper.flip_limits() def flip_y(self): """ Flip the y_min/y_max limits. """ self.y_lim_helper.flip_limits()
class HistogramViewerState(MatplotlibDataViewerState): """ A state class that includes all the attributes for a histogram viewer. """ x_att = DDSCProperty(docstring='The attribute to compute the histograms for') cumulative = DDCProperty(False, docstring='Whether to show the histogram as ' 'a cumulative histogram') normalize = DDCProperty(False, docstring='Whether to normalize the histogram ' '(based on the total sum)') hist_x_min = DDCProperty(docstring='The minimum value used to compute the ' 'histogram') hist_x_max = DDCProperty(docstring='The maxumum value used to compute the ' 'histogram') hist_n_bin = DDCProperty(docstring='The number of bins in the histogram') common_n_bin = DDCProperty(True, docstring='The number of bins to use for ' 'all numerical components') def __init__(self, **kwargs): super(HistogramViewerState, self).__init__() self.hist_helper = StateAttributeHistogramHelper(self, 'x_att', lower='hist_x_min', upper='hist_x_max', n_bin='hist_n_bin', common_n_bin='common_n_bin') self.x_lim_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max', log='x_log') self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', pixel_coord=True, world_coord=True) self.update_from_dict(kwargs) # This should be added after update_from_dict since we don't want to # influence the restoring of sessions. self.add_callback('hist_x_min', self.update_view_to_bins) self.add_callback('hist_x_max', self.update_view_to_bins) self.add_callback('x_log', self._reset_x_limits, priority=1000) def _reset_x_limits(self, *args): with delay_callback(self, 'hist_x_min', 'hist_x_max', 'x_min', 'x_max', 'x_log'): self.x_lim_helper.percentile = 100 self.x_lim_helper.update_values(force=True) self.update_bins_to_view() def reset_limits(self): self._reset_x_limits() self.y_min = min(getattr(layer, '_y_min', np.inf) for layer in self.layers) self.y_max = max(getattr(layer, '_y_max', 0) for layer in self.layers) def _update_priority(self, name): if name == 'layers': return 2 elif name.endswith('_log'): return 0.5 elif name.endswith(('_min', '_max', '_bin')): return 0 else: return 1 def flip_x(self): """ Flip the x_min/x_max limits. """ self.x_lim_helper.flip_limits() @avoid_circular def update_bins_to_view(self, *args): """ Update the bins to match the current view. """ with delay_callback(self, 'hist_x_min', 'hist_x_max'): if self.x_max > self.x_min: self.hist_x_min = self.x_min self.hist_x_max = self.x_max else: self.hist_x_min = self.x_max self.hist_x_max = self.x_min @avoid_circular def update_view_to_bins(self, *args): """ Update the view to match the histogram interval """ with delay_callback(self, 'x_min', 'x_max'): self.x_min = self.hist_x_min self.x_max = self.hist_x_max def _get_x_components(self): if self.x_att is None: return [] # Construct list of components over all layers components = [] for layer_state in self.layers: if isinstance(layer_state.layer, Data): layer = layer_state.layer else: layer = layer_state.layer.data try: components.append(layer.get_component(self.x_att)) except IncompatibleAttribute: pass return components @property def bins(self): """ The position of the bins for the histogram based on the current state. """ if self.hist_x_min is None or self.hist_x_max is None or self.hist_n_bin is None: return None if self.x_log: return np.logspace(np.log10(self.hist_x_min), np.log10(self.hist_x_max), self.hist_n_bin + 1) elif isinstance(self.hist_x_min, np.datetime64): x_min = self.hist_x_min.astype(int) x_max = self.hist_x_max.astype(self.hist_x_min.dtype).astype(int) return np.linspace(x_min, x_max, self.hist_n_bin + 1).astype(self.hist_x_min.dtype) else: return np.linspace(self.hist_x_min, self.hist_x_max, self.hist_n_bin + 1) @defer_draw def _layers_changed(self, *args): self.x_att_helper.set_multiple_data(self.layers_data)
class ScatterLayerState(VispyLayerState): """ A state object for volume layers """ size_mode = CallbackProperty('Fixed') size = CallbackProperty() size_attribute = SelectionCallbackProperty() size_vmin = CallbackProperty() size_vmax = CallbackProperty() size_scaling = CallbackProperty(1) color_mode = CallbackProperty('Fixed') cmap_attribute = SelectionCallbackProperty() cmap_vmin = CallbackProperty() cmap_vmax = CallbackProperty() cmap = CallbackProperty() xerr_visible = CallbackProperty(False) xerr_attribute = SelectionCallbackProperty() yerr_visible = CallbackProperty(False) yerr_attribute = SelectionCallbackProperty() zerr_visible = CallbackProperty(False) zerr_attribute = SelectionCallbackProperty() vector_visible = CallbackProperty(False) vx_attribute = SelectionCallbackProperty() vy_attribute = SelectionCallbackProperty() vz_attribute = SelectionCallbackProperty() vector_scaling = CallbackProperty(1) vector_origin = SelectionCallbackProperty(default_index=1) vector_arrowhead = CallbackProperty() size_limits_cache = CallbackProperty({}) cmap_limits_cache = CallbackProperty({}) def __init__(self, layer=None, **kwargs): self._sync_markersize = None super(ScatterLayerState, self).__init__(layer=layer) if self.layer is not None: self.color = self.layer.style.color self.size = self.layer.style.markersize self.alpha = self.layer.style.alpha self.size_att_helper = ComponentIDComboHelper(self, 'size_attribute') self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_attribute') self.xerr_att_helper = ComponentIDComboHelper(self, 'xerr_attribute', categorical=False) self.yerr_att_helper = ComponentIDComboHelper(self, 'yerr_attribute', categorical=False) self.zerr_att_helper = ComponentIDComboHelper(self, 'zerr_attribute', categorical=False) self.vx_att_helper = ComponentIDComboHelper(self, 'vx_attribute', categorical=False) self.vy_att_helper = ComponentIDComboHelper(self, 'vy_attribute', categorical=False) self.vz_att_helper = ComponentIDComboHelper(self, 'vz_attribute', categorical=False) self.size_lim_helper = StateAttributeLimitsHelper( self, attribute='size_attribute', lower='size_vmin', upper='size_vmax', cache=self.size_limits_cache) self.cmap_lim_helper = StateAttributeLimitsHelper( self, attribute='cmap_attribute', lower='cmap_vmin', upper='cmap_vmax', cache=self.cmap_limits_cache) vector_origin_display = { 'tail': 'Tail of vector', 'middle': 'Middle of vector', 'tip': 'Tip of vector' } ScatterLayerState.vector_origin.set_choices(self, ['tail', 'middle', 'tip']) ScatterLayerState.vector_origin.set_display_func( self, vector_origin_display.get) 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'): helpers = [ self.size_att_helper, self.cmap_att_helper, self.xerr_att_helper, self.yerr_att_helper, self.zerr_att_helper, self.vx_att_helper, self.vy_att_helper, self.vz_att_helper ] if self.layer is None: for helper in helpers: helper.set_multiple_data([]) else: for helper in helpers: 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(ScatterLayerState, 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()
class ImageLayerState(BaseImageLayerState): """ A state class that includes all the attributes for data layers in an image plot. """ attribute = DDSCProperty(docstring='The attribute shown in the layer') v_min = DDCProperty(docstring='The lower level shown') v_max = DDCProperty(docstring='The upper level shown') percentile = DDSCProperty(docstring='The percentile value used to ' 'automatically calculate levels') contrast = DDCProperty(1, docstring='The contrast of the layer') bias = DDCProperty(0.5, docstring='A constant value that is added to the ' 'layer before rendering') cmap = DDCProperty(docstring='The colormap used to render the layer') stretch = DDSCProperty(docstring='The stretch used to render the layer, ' 'which should be one of ``linear``, ' '``sqrt``, ``log``, or ``arcsinh``') global_sync = DDCProperty(True, docstring='Whether the color and transparency ' 'should be synced with the global ' 'color and transparency for the data') def __init__(self, layer=None, viewer_state=None, **kwargs): super(ImageLayerState, self).__init__(layer=layer, viewer_state=viewer_state) self.attribute_lim_helper = StateAttributeLimitsHelper( self, attribute='attribute', percentile='percentile', lower='v_min', upper='v_max') self.attribute_att_helper = ComponentIDComboHelper(self, 'attribute', numeric=True, categorical=False) percentile_display = { 100: 'Min/Max', 99.5: '99.5%', 99: '99%', 95: '95%', 90: '90%', 'Custom': 'Custom' } ImageLayerState.percentile.set_choices( self, [100, 99.5, 99, 95, 90, 'Custom']) ImageLayerState.percentile.set_display_func(self, percentile_display.get) stretch_display = { 'linear': 'Linear', 'sqrt': 'Square Root', 'arcsinh': 'Arcsinh', 'log': 'Logarithmic' } ImageLayerState.stretch.set_choices( self, ['linear', 'sqrt', 'arcsinh', 'log']) ImageLayerState.stretch.set_display_func(self, stretch_display.get) self.add_callback('global_sync', self._update_syncing) self.add_callback('layer', self._update_attribute) self._update_syncing() if layer is not None: self._update_attribute() self.update_from_dict(kwargs) if self.cmap is None: self.cmap = colormaps.members[0][1] def _update_attribute(self, *args): if self.layer is not None: self.attribute_att_helper.set_multiple_data([self.layer]) self.attribute = self.layer.main_components[0] def _update_priority(self, name): if name == 'layer': return 3 elif name == 'attribute': return 2 elif name == 'global_sync': return 1.5 elif name.endswith(('_min', '_max')): return 0 else: return 1 def _update_syncing(self, *args): if self.global_sync: self._sync_color.enable_syncing() self._sync_alpha.enable_syncing() else: self._sync_color.disable_syncing() self._sync_alpha.disable_syncing() def _get_image(self, view=None): return self.layer[self.attribute, view] def flip_limits(self): """ Flip the image levels. """ self.attribute_lim_helper.flip_limits() def reset_contrast_bias(self): with delay_callback(self, 'contrast', 'bias'): self.contrast = 1 self.bias = 0.5
class HistogramViewerState(MatplotlibDataViewerState): """ A state class that includes all the attributes for a histogram viewer. """ x_att = DDSCProperty( docstring='The attribute to compute the histograms for') cumulative = DDCProperty(False, docstring='Whether to show the histogram as ' 'a cumulative histogram') normalize = DDCProperty(False, docstring='Whether to normalize the histogram ' '(based on the total sum)') hist_x_min = DDCProperty(docstring='The minimum value used to compute the ' 'histogram') hist_x_max = DDCProperty(docstring='The maxumum value used to compute the ' 'histogram') hist_n_bin = DDCProperty(docstring='The number of bins in the histogram') common_n_bin = DDCProperty(True, docstring='The number of bins to use for ' 'all numerical components') def __init__(self, **kwargs): super(HistogramViewerState, self).__init__() self.hist_helper = StateAttributeHistogramHelper( self, 'x_att', lower='hist_x_min', upper='hist_x_max', n_bin='hist_n_bin', common_n_bin='common_n_bin') self.x_lim_helper = StateAttributeLimitsHelper(self, 'x_att', lower='x_min', upper='x_max', log='x_log') self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', pixel_coord=True, world_coord=True) self.update_from_dict(kwargs) # This should be added after update_from_dict since we don't want to # influence the restoring of sessions. self.add_callback('hist_x_min', self.update_view_to_bins) self.add_callback('hist_x_max', self.update_view_to_bins) self.add_callback('x_log', self._reset_x_limits, priority=1000) def _reset_x_limits(self, *args): with delay_callback(self, 'hist_x_min', 'hist_x_max', 'x_min', 'x_max', 'x_log'): self.x_lim_helper.percentile = 100 self.x_lim_helper.update_values(force=True) self.update_bins_to_view() def reset_limits(self): self._reset_x_limits() self.y_min = min( getattr(layer, '_y_min', np.inf) for layer in self.layers) self.y_max = max(getattr(layer, '_y_max', 0) for layer in self.layers) def _update_priority(self, name): if name == 'layers': return 2 elif name.endswith('_log'): return 0.5 elif name.endswith(('_min', '_max', '_bin')): return 0 else: return 1 def flip_x(self): """ Flip the x_min/x_max limits. """ self.x_lim_helper.flip_limits() @avoid_circular def update_bins_to_view(self, *args): """ Update the bins to match the current view. """ with delay_callback(self, 'hist_x_min', 'hist_x_max'): if self.x_max > self.x_min: self.hist_x_min = self.x_min self.hist_x_max = self.x_max else: self.hist_x_min = self.x_max self.hist_x_max = self.x_min @avoid_circular def update_view_to_bins(self, *args): """ Update the view to match the histogram interval """ with delay_callback(self, 'x_min', 'x_max'): self.x_min = self.hist_x_min self.x_max = self.hist_x_max @property def x_categories(self): return self._categories(self.x_att) def _categories(self, cid): categories = [] for layer_state in self.layers: if isinstance(layer_state.layer, BaseData): layer = layer_state.layer else: layer = layer_state.layer.data try: if layer.data.get_kind(cid) == 'categorical': categories.append(layer.data.get_data(cid).categories) except IncompatibleAttribute: pass if len(categories) == 0: return None else: return np.unique(np.hstack(categories)) @property def x_kinds(self): return self._component_kinds(self.x_att) def _component_kinds(self, cid): # Construct list of component kinds over all layers kinds = set() for layer_state in self.layers: if isinstance(layer_state.layer, BaseData): layer = layer_state.layer else: layer = layer_state.layer.data try: kinds.add(layer.data.get_kind(cid)) except IncompatibleAttribute: pass return kinds @property def bins(self): """ The position of the bins for the histogram based on the current state. """ if self.hist_x_min is None or self.hist_x_max is None or self.hist_n_bin is None: return None if self.x_log: return np.logspace(np.log10(self.hist_x_min), np.log10(self.hist_x_max), self.hist_n_bin + 1) elif isinstance(self.hist_x_min, np.datetime64): x_min = self.hist_x_min.astype(int) x_max = self.hist_x_max.astype(self.hist_x_min.dtype).astype(int) return np.linspace(x_min, x_max, self.hist_n_bin + 1).astype( self.hist_x_min.dtype) else: return np.linspace(self.hist_x_min, self.hist_x_max, self.hist_n_bin + 1) @defer_draw def _layers_changed(self, *args): self.x_att_helper.set_multiple_data(self.layers_data)
def __init__(self, viewer_state=None, layer=None, **kwargs): super(ScatterLayerState, self).__init__(viewer_state=viewer_state, layer=layer) self.limits_cache = {} self.cmap_lim_helper = StateAttributeLimitsHelper(self, attribute='cmap_att', lower='cmap_vmin', upper='cmap_vmax', limits_cache=self.limits_cache) self.size_lim_helper = StateAttributeLimitsHelper(self, attribute='size_att', lower='size_vmin', upper='size_vmax', limits_cache=self.limits_cache) self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_att', numeric=True, categorical=False) self.size_att_helper = ComponentIDComboHelper(self, 'size_att', numeric=True, categorical=False) self.xerr_att_helper = ComponentIDComboHelper(self, 'xerr_att', numeric=True, categorical=False) self.yerr_att_helper = ComponentIDComboHelper(self, 'yerr_att', numeric=True, categorical=False) self.vx_att_helper = ComponentIDComboHelper(self, 'vx_att', numeric=True, categorical=False) self.vy_att_helper = ComponentIDComboHelper(self, 'vy_att', numeric=True, categorical=False) points_mode_display = {'auto': 'Density map or markers (auto)', 'markers': 'Markers', 'density': 'Density map'} ScatterLayerState.points_mode.set_choices(self, ['auto', 'markers', 'density']) ScatterLayerState.points_mode.set_display_func(self, points_mode_display.get) self.add_callback('points_mode', self._update_density_map_mode) ScatterLayerState.cmap_mode.set_choices(self, ['Fixed', 'Linear']) ScatterLayerState.size_mode.set_choices(self, ['Fixed', 'Linear']) linestyle_display = {'solid': '–––––––', 'dashed': '– – – – –', 'dotted': '· · · · · · · ·', 'dashdot': '– · – · – ·'} ScatterLayerState.linestyle.set_choices(self, ['solid', 'dashed', 'dotted', 'dashdot']) ScatterLayerState.linestyle.set_display_func(self, linestyle_display.get) ScatterLayerState.vector_mode.set_choices(self, ['Cartesian', 'Polar']) vector_origin_display = {'tail': 'Tail of vector', 'middle': 'Middle of vector', 'tip': 'Tip of vector'} ScatterLayerState.vector_origin.set_choices(self, ['tail', 'middle', 'tip']) ScatterLayerState.vector_origin.set_display_func(self, vector_origin_display.get) stretch_display = {'linear': 'Linear', 'sqrt': 'Square Root', 'arcsinh': 'Arcsinh', 'log': 'Logarithmic'} ScatterLayerState.stretch.set_choices(self, ['linear', 'sqrt', 'arcsinh', 'log']) ScatterLayerState.stretch.set_display_func(self, stretch_display.get) self.add_callback('layer', self._on_layer_change) if layer is not None: self._on_layer_change() self.cmap = colormaps.members[0][1] self.size = self.layer.style.markersize self._sync_size = keep_in_sync(self, 'size', self.layer.style, 'markersize') self.update_from_dict(kwargs)
class ScatterViewerState(MatplotlibDataViewerState): """ A state class that includes all the attributes for a scatter viewer. """ x_att = DDSCProperty(docstring='The attribute to show on the x-axis', default_index=0) y_att = DDSCProperty(docstring='The attribute to show on the y-axis', default_index=1) dpi = DDCProperty( 72, docstring= 'The resolution (in dots per inch) of density maps, if present') def __init__(self, **kwargs): super(ScatterViewerState, self).__init__() self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper( self, attribute='x_att', lower='x_min', upper='x_max', log='x_log', margin=0.04, limits_cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper( self, attribute='y_att', lower='y_min', upper='y_max', log='y_log', margin=0.04, limits_cache=self.limits_cache) self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att', pixel_coord=True, world_coord=True) self.y_att_helper = ComponentIDComboHelper(self, 'y_att', pixel_coord=True, world_coord=True) self.update_from_dict(kwargs) self.add_callback('x_log', self._reset_x_limits) self.add_callback('y_log', self._reset_y_limits) def _reset_x_limits(self, *args): if self.x_att is None: return self.x_lim_helper.percentile = 100 self.x_lim_helper.update_values(force=True) def _reset_y_limits(self, *args): if self.y_att is None: return self.y_lim_helper.percentile = 100 self.y_lim_helper.update_values(force=True) def reset_limits(self): self._reset_x_limits() self._reset_y_limits() def flip_x(self): """ Flip the x_min/x_max limits. """ self.x_lim_helper.flip_limits() def flip_y(self): """ Flip the y_min/y_max limits. """ self.y_lim_helper.flip_limits() @property def x_categories(self): return self._categories(self.x_att) @property def y_categories(self): return self._categories(self.y_att) def _categories(self, cid): categories = [] for layer_state in self.layers: if isinstance(layer_state.layer, BaseData): layer = layer_state.layer else: layer = layer_state.layer.data try: if layer.data.get_kind(cid) == 'categorical': categories.append(layer.data.get_data(cid).categories) except IncompatibleAttribute: pass if len(categories) == 0: return None else: return np.unique(np.hstack(categories)) @property def x_kinds(self): return self._component_kinds(self.x_att) @property def y_kinds(self): return self._component_kinds(self.y_att) def _component_kinds(self, cid): # Construct list of component kinds over all layers kinds = set() for layer_state in self.layers: if isinstance(layer_state.layer, BaseData): layer = layer_state.layer else: layer = layer_state.layer.data try: kinds.add(layer.data.get_kind(cid)) except IncompatibleAttribute: pass return kinds def _layers_changed(self, *args): layers_data = self.layers_data layers_data_cache = getattr(self, '_layers_data_cache', []) if layers_data == layers_data_cache: return self.x_att_helper.set_multiple_data(self.layers_data) self.y_att_helper.set_multiple_data(self.layers_data) self._layers_data_cache = layers_data
class ImageViewerState(MatplotlibDataViewerState): """ A state class that includes all the attributes for an image viewer. """ x_att = DDCProperty(docstring='The component ID giving the pixel component ' 'shown on the x axis') y_att = DDCProperty(docstring='The component ID giving the pixel component ' 'shown on the y axis') x_att_world = DDSCProperty(docstring='The component ID giving the world component ' 'shown on the x axis', default_index=-1) y_att_world = DDSCProperty(docstring='The component ID giving the world component ' 'shown on the y axis', default_index=-2) aspect = DDCProperty('equal', docstring='Whether to enforce square pixels (``equal``) ' 'or fill the axes (``auto``)') reference_data = DDSCProperty(docstring='The dataset that is used to define the ' 'available pixel/world components, and ' 'which defines the coordinate frame in ' 'which the images are shown') slices = DDCProperty(docstring='The current slice along all dimensions') color_mode = DDCProperty('Colormaps', docstring='Whether each layer can have ' 'its own colormap (``Colormaps``) or ' 'whether each layer is assigned ' 'a single color (``One color per layer``)') dpi = DDCProperty(72, docstring='The resolution (in dots per inch) of density maps, if present') def __init__(self, **kwargs): super(ImageViewerState, self).__init__() self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper(self, attribute='x_att', lower='x_min', upper='x_max', limits_cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper(self, attribute='y_att', lower='y_min', upper='y_max', limits_cache=self.limits_cache) self.ref_data_helper = ManualDataComboHelper(self, 'reference_data') self.xw_att_helper = ComponentIDComboHelper(self, 'x_att_world', numeric=False, categorical=False, world_coord=True) self.yw_att_helper = ComponentIDComboHelper(self, 'y_att_world', numeric=False, categorical=False, world_coord=True) self.add_callback('reference_data', self._reference_data_changed, priority=1000) self.add_callback('layers', self._layers_changed, priority=1000) self.add_callback('x_att', self._on_xatt_change, priority=500) self.add_callback('y_att', self._on_yatt_change, priority=500) self.add_callback('x_att_world', self._update_att, priority=500) self.add_callback('y_att_world', self._update_att, priority=500) self.add_callback('x_att_world', self._on_xatt_world_change, priority=1000) self.add_callback('y_att_world', self._on_yatt_world_change, priority=1000) self.update_from_dict(kwargs) def reset_limits(self): if self.reference_data is None or self.x_att is None or self.y_att is None: return nx = self.reference_data.shape[self.x_att.axis] ny = self.reference_data.shape[self.y_att.axis] with delay_callback(self, 'x_min', 'x_max', 'y_min', 'y_max'): self.x_min = -0.5 self.x_max = nx - 0.5 self.y_min = -0.5 self.y_max = ny - 0.5 def _reference_data_changed(self, *args): with delay_callback(self, 'x_att_world', 'y_att_world', 'slices'): self._update_combo_att() self._set_default_slices() def _layers_changed(self, *args): # The layers callback gets executed if anything in the layers changes, # but we only care about whether the actual set of 'layer' attributes # for all layers change. layers_data = self.layers_data layers_data_cache = getattr(self, '_layers_data_cache', []) if layers_data == layers_data_cache: return self._update_combo_ref_data() self._set_reference_data() self._update_syncing() self._layers_data_cache = layers_data def _update_syncing(self): # If there are multiple layers for a given dataset, we disable the # syncing by default. layer_state_by_data = defaultdict(list) for layer_state in self.layers: if isinstance(layer_state.layer, Data): layer_state_by_data[layer_state.layer].append(layer_state) for data, layer_states in layer_state_by_data.items(): if len(layer_states) > 1: for layer_state in layer_states: # Scatter layers don't have global_sync so we need to be # careful here and make sure we return a default value if getattr(layer_state, 'global_sync', False): layer_state.global_sync = False def _update_combo_ref_data(self): self.ref_data_helper.set_multiple_data(self.layers_data) def _update_combo_att(self): with delay_callback(self, 'x_att_world', 'y_att_world'): if self.reference_data is None: self.xw_att_helper.set_multiple_data([]) self.yw_att_helper.set_multiple_data([]) else: self.xw_att_helper.set_multiple_data([self.reference_data]) self.yw_att_helper.set_multiple_data([self.reference_data]) def _update_priority(self, name): if name == 'layers': return 3 elif name == 'reference_data': return 2 elif name.endswith(('_min', '_max')): return 0 else: return 1 @defer_draw def _update_att(self, *args): # Need to delay the callbacks here to make sure that we get a chance to # update both x_att and y_att otherwise could end up triggering image # slicing with two pixel components that are the same. with delay_callback(self, 'x_att', 'y_att'): if self.x_att_world is not None: index = self.reference_data.world_component_ids.index(self.x_att_world) self.x_att = self.reference_data.pixel_component_ids[index] if self.y_att_world is not None: index = self.reference_data.world_component_ids.index(self.y_att_world) self.y_att = self.reference_data.pixel_component_ids[index] @defer_draw def _on_xatt_change(self, *args): if self.x_att is not None: self.x_att_world = self.reference_data.world_component_ids[self.x_att.axis] @defer_draw def _on_yatt_change(self, *args): if self.y_att is not None: self.y_att_world = self.reference_data.world_component_ids[self.y_att.axis] @defer_draw def _on_xatt_world_change(self, *args): if self.x_att_world is not None and self.x_att_world == self.y_att_world: world_ids = self.reference_data.world_component_ids if self.x_att_world == world_ids[-1]: self.y_att_world = world_ids[-2] else: self.y_att_world = world_ids[-1] @defer_draw def _on_yatt_world_change(self, *args): if self.y_att_world is not None and self.y_att_world == self.x_att_world: world_ids = self.reference_data.world_component_ids if self.y_att_world == world_ids[-1]: self.x_att_world = world_ids[-2] else: self.x_att_world = world_ids[-1] def _set_reference_data(self): if self.reference_data is None: for layer in self.layers: if isinstance(layer.layer, Data): self.reference_data = layer.layer return def _set_default_slices(self): # Need to make sure this gets called immediately when reference_data is changed if self.reference_data is None: self.slices = () else: self.slices = (0,) * self.reference_data.ndim @property def numpy_slice_aggregation_transpose(self): """ Returns slicing information usable by Numpy. This returns two objects: the first is an object that can be used to slice Numpy arrays and return a 2D array, and the second object is a boolean indicating whether to transpose the result. """ if self.reference_data is None: return None slices = [] agg_func = [] for i in range(self.reference_data.ndim): if i == self.x_att.axis or i == self.y_att.axis: slices.append(slice(None)) agg_func.append(None) else: if isinstance(self.slices[i], AggregateSlice): slices.append(self.slices[i].slice) agg_func.append(self.slices[i].function) else: slices.append(self.slices[i]) transpose = self.y_att.axis > self.x_att.axis return slices, agg_func, transpose @property def wcsaxes_slice(self): """ Returns slicing information usable by WCSAxes. This returns an iterable of slices, and including ``'x'`` and ``'y'`` for the dimensions along which we are not slicing. """ if self.reference_data is None: return None slices = [] for i in range(self.reference_data.ndim): if i == self.x_att.axis: slices.append('x') elif i == self.y_att.axis: slices.append('y') else: if isinstance(self.slices[i], AggregateSlice): slices.append(self.slices[i].center) else: slices.append(self.slices[i]) return slices[::-1] def flip_x(self): """ Flip the x_min/x_max limits. """ self.x_lim_helper.flip_limits() def flip_y(self): """ Flip the y_min/y_max limits. """ self.y_lim_helper.flip_limits()
class WWTTableLayerState(LayerState): """ A state object for WWT layers """ layer = CallbackProperty() color = CallbackProperty() size = CallbackProperty() alpha = CallbackProperty() size_mode = SelectionCallbackProperty(default_index=0) size = CallbackProperty() size_att = SelectionCallbackProperty() size_vmin = CallbackProperty() size_vmax = CallbackProperty() size_scaling = CallbackProperty(1) color_mode = SelectionCallbackProperty(default_index=0) cmap_att = SelectionCallbackProperty() cmap_vmin = CallbackProperty() cmap_vmax = CallbackProperty() cmap = CallbackProperty() cmap_mode = color_mode size_limits_cache = CallbackProperty({}) cmap_limits_cache = CallbackProperty({}) img_data_att = SelectionCallbackProperty(default_index=0) def __init__(self, layer=None, **kwargs): self._sync_markersize = None super(WWTTableLayerState, 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') self.color = self.layer.style.color self.size = self.layer.style.markersize self.alpha = self.layer.style.alpha self.size_att_helper = ComponentIDComboHelper(self, 'size_att', numeric=True, categorical=False) self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_att', numeric=True, categorical=False) self.img_data_att_helper = ComponentIDComboHelper(self, 'img_data_att', numeric=True, categorical=False) 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] # Color and size encoding depending on attributes is only available # in PyWWT 0.6 or later. if PYWWT_LT_06: modes = ['Fixed'] else: modes = ['Fixed', 'Linear'] WWTTableLayerState.color_mode.set_choices(self, modes) WWTTableLayerState.size_mode.set_choices(self, modes) 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([]) self.img_data_att_helper.set_multiple_data([]) else: self.cmap_att_helper.set_multiple_data([self.layer]) self.size_att_helper.set_multiple_data([self.layer]) self.img_data_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(WWTTableLayerState, 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()
class ScatterLayerState(MatplotlibLayerState): """ A state class that includes all the attributes for layers in a scatter plot. """ # General properties style = DDSCProperty(docstring="The layer style") size = DDCProperty(docstring="The size of the markers") # Scatter layer cmap_mode = DDSCProperty(docstring="Whether to use color to encode an attribute") cmap_att = DDSCProperty(docstring="The attribute to use for the color") cmap_vmin = DDCProperty(docstring="The lower level for the colormap") cmap_vmax = DDCProperty(docstring="The upper level for the colormap") cmap = DDCProperty(docstring="The colormap to use (when in colormap mode)") size_mode = DDSCProperty(docstring="Whether to use size to encode an attribute") size_att = DDSCProperty(docstring="The attribute to use for the size") size_vmin = DDCProperty(docstring="The lower level for the size mapping") size_vmax = DDCProperty(docstring="The upper level for the size mapping") size_scaling = DDCProperty(1, docstring="Relative scaling of the size") xerr_visible = DDCProperty(False, docstring="Whether to show x error bars") yerr_visible = DDCProperty(False, docstring="Whether to show y error bars") xerr_att = DDSCProperty(docstring="The attribute to use for the x error bars") yerr_att = DDSCProperty(docstring="The attribute to use for the y error bars") # Line plot layer linewidth = DDCProperty(1, docstring="The line width") linestyle = DDSCProperty(docstring="The line style") def __init__(self, viewer_state=None, layer=None, **kwargs): super(ScatterLayerState, self).__init__(viewer_state=viewer_state, layer=layer) self.limits_cache = {} self.cmap_lim_helper = StateAttributeLimitsHelper(self, attribute='cmap_att', lower='cmap_vmin', upper='cmap_vmax', limits_cache=self.limits_cache) self.size_lim_helper = StateAttributeLimitsHelper(self, attribute='size_att', lower='size_vmin', upper='size_vmax', limits_cache=self.limits_cache) self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_att', numeric=True, categorical=False) self.size_att_helper = ComponentIDComboHelper(self, 'size_att', numeric=True, categorical=False) self.xerr_att_helper = ComponentIDComboHelper(self, 'xerr_att', numeric=True, categorical=False) self.yerr_att_helper = ComponentIDComboHelper(self, 'yerr_att', numeric=True, categorical=False) ScatterLayerState.style.set_choices(self, ['Scatter', 'Line']) ScatterLayerState.cmap_mode.set_choices(self, ['Fixed', 'Linear']) ScatterLayerState.size_mode.set_choices(self, ['Fixed', 'Linear']) linestyle_display = {'solid': '–––––––', 'dashed': '– – – – –', 'dotted': '· · · · · · · ·', 'dashdot': '– · – · – ·'} ScatterLayerState.linestyle.set_choices(self, ['solid', 'dashed', 'dotted', 'dashdot']) ScatterLayerState.linestyle.set_display_func(self, linestyle_display.get) self.add_callback('layer', self._on_layer_change) if layer is not None: self._on_layer_change() self.cmap = colormaps.members[0][1] self.size = self.layer.style.markersize self._sync_size = keep_in_sync(self, 'size', self.layer.style, 'markersize') 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]) if self.layer is None: self.xerr_att_helper.set_multiple_data([]) self.yerr_att_helper.set_multiple_data([]) else: self.xerr_att_helper.set_multiple_data([self.layer]) self.yerr_att_helper.set_multiple_data([self.layer]) def flip_cmap(self): """ Flip the cmap_vmin/cmap_vmax limits. """ self.cmap_lim_helper.flip_limits() def flip_size(self): """ Flip the size_vmin/size_vmax limits. """ self.size_lim_helper.flip_limits()
class Vispy3DViewerState(ViewerState): """ A common state object for all vispy 3D viewers """ x_att = SelectionCallbackProperty() x_min = CallbackProperty(0) x_max = CallbackProperty(1) x_stretch = CallbackProperty(1.) y_att = SelectionCallbackProperty(default_index=1) y_min = CallbackProperty(0) y_max = CallbackProperty(1) y_stretch = CallbackProperty(1.) z_att = SelectionCallbackProperty(default_index=2) z_min = CallbackProperty(0) z_max = CallbackProperty(1) z_stretch = CallbackProperty(1.) visible_axes = CallbackProperty(True) perspective_view = CallbackProperty(False) clip_data = CallbackProperty(True) native_aspect = CallbackProperty(False) line_width = CallbackProperty(1.) layers = ListCallbackProperty() limits_cache = CallbackProperty() def _update_priority(self, name): if name == 'layers': return 2 elif name.endswith(('_min', '_max')): return 0 else: return 1 def __init__(self, **kwargs): super(Vispy3DViewerState, self).__init__(**kwargs) if self.limits_cache is None: self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper(self, attribute='x_att', lower='x_min', upper='x_max', cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper(self, attribute='y_att', lower='y_min', upper='y_max', cache=self.limits_cache) self.z_lim_helper = StateAttributeLimitsHelper(self, attribute='z_att', lower='z_min', upper='z_max', cache=self.limits_cache) # TODO: if limits_cache is re-assigned to a different object, we need to # update the attribute helpers. However if in future we make limits_cache # into a smart dictionary that can call callbacks when elements are # changed then we shouldn't always call this. It'd also be nice to # avoid this altogether and make it more clean. self.add_callback('limits_cache', self._update_limits_cache) def reset_limits(self): self.x_lim_helper.log = False self.x_lim_helper.percentile = 100. self.x_lim_helper.update_values(force=True) self.y_lim_helper.log = False self.y_lim_helper.percentile = 100. self.y_lim_helper.update_values(force=True) self.z_lim_helper.log = False self.z_lim_helper.percentile = 100. self.z_lim_helper.update_values(force=True) def _update_limits_cache(self, *args): self.x_lim_helper._cache = self.limits_cache self.x_lim_helper._update_attribute() self.y_lim_helper._cache = self.limits_cache self.y_lim_helper._update_attribute() self.z_lim_helper._cache = self.limits_cache self.z_lim_helper._update_attribute() @property def aspect(self): # TODO: this could be cached based on the limits, but is not urgent aspect = np.array([1, 1, 1], dtype=float) if self.native_aspect: aspect[0] = 1. aspect[1] = (self.y_max - self.y_min) / (self.x_max - self.x_min) aspect[2] = (self.z_max - self.z_min) / (self.x_max - self.x_min) aspect /= aspect.max() return aspect def reset(self): pass def flip_x(self): self.x_lim_helper.flip_limits() def flip_y(self): self.y_lim_helper.flip_limits() def flip_z(self): self.z_lim_helper.flip_limits() @property def clip_limits(self): return (self.x_min, self.x_max, self.y_min, self.y_max, self.z_min, self.z_max) def set_limits(self, x_min, x_max, y_min, y_max, z_min, z_max): with delay_callback(self, 'x_min', 'x_max', 'y_min', 'y_max', 'z_min', 'z_max'): self.x_min = x_min self.x_max = x_max self.y_min = y_min self.y_max = y_max self.z_min = z_min self.z_max = z_max
class ImageLayerState(BaseImageLayerState): """ A state class that includes all the attributes for data layers in an image plot. """ attribute = DDSCProperty(docstring='The attribute shown in the layer') v_min = DDCProperty(docstring='The lower level shown') v_max = DDCProperty(docstring='The upper leven shown') percentile = DDSCProperty(docstring='The percentile value used to ' 'automatically calculate levels') contrast = DDCProperty(1, docstring='The contrast of the layer') bias = DDCProperty(0.5, docstring='A constant value that is added to the ' 'layer before rendering') cmap = DDCProperty(docstring='The colormap used to render the layer') stretch = DDSCProperty(docstring='The stretch used to render the layer, ' 'which should be one of ``linear``, ' '``sqrt``, ``log``, or ``arcsinh``') global_sync = DDCProperty(True, docstring='Whether the color and transparency ' 'should be synced with the global ' 'color and transparency for the data') def __init__(self, layer=None, viewer_state=None, **kwargs): super(ImageLayerState, self).__init__(layer=layer, viewer_state=viewer_state) self.attribute_lim_helper = StateAttributeLimitsHelper(self, attribute='attribute', percentile='percentile', lower='v_min', upper='v_max') self.attribute_att_helper = ComponentIDComboHelper(self, 'attribute', numeric=True, categorical=False) percentile_display = {100: 'Min/Max', 99.5: '99.5%', 99: '99%', 95: '95%', 90: '90%', 'Custom': 'Custom'} ImageLayerState.percentile.set_choices(self, [100, 99.5, 99, 95, 90, 'Custom']) ImageLayerState.percentile.set_display_func(self, percentile_display.get) stretch_display = {'linear': 'Linear', 'sqrt': 'Square Root', 'arcsinh': 'Arcsinh', 'log': 'Logarithmic'} ImageLayerState.stretch.set_choices(self, ['linear', 'sqrt', 'arcsinh', 'log']) ImageLayerState.stretch.set_display_func(self, stretch_display.get) self.add_callback('global_sync', self._update_syncing) self.add_callback('layer', self._update_attribute) self._update_syncing() if layer is not None: self._update_attribute() self.update_from_dict(kwargs) if self.cmap is None: self.cmap = colormaps.members[0][1] def _update_attribute(self, *args): if self.layer is not None: self.attribute_att_helper.set_multiple_data([self.layer]) self.attribute = self.layer.visible_components[0] def _update_priority(self, name): if name == 'layer': return 3 elif name == 'attribute': return 2 elif name == 'global_sync': return 1.5 elif name.endswith(('_min', '_max')): return 0 else: return 1 def _update_syncing(self, *args): if self.global_sync: self._sync_color.enable_syncing() self._sync_alpha.enable_syncing() else: self._sync_color.disable_syncing() self._sync_alpha.disable_syncing() def _get_image(self, view=None): return self.layer[self.attribute, view] def flip_limits(self): """ Flip the image levels. """ self.attribute_lim_helper.flip_limits() def reset_contrast_bias(self): with delay_callback(self, 'contrast', 'bias'): self.contrast = 1 self.bias = 0.5
class ScatterLayerState(MatplotlibLayerState): """ A state class that includes all the attributes for layers in a scatter plot. """ # Color cmap_mode = DDSCProperty( docstring="Whether to use color to encode an attribute") cmap_att = DDSCProperty(docstring="The attribute to use for the color") cmap_vmin = DDCProperty(docstring="The lower level for the colormap") cmap_vmax = DDCProperty(docstring="The upper level for the colormap") cmap = DDCProperty(docstring="The colormap to use (when in colormap mode)") # Points points_mode = DDSCProperty( docstring='Whether to use markers or a density map') # Markers markers_visible = DDCProperty(True, docstring="Whether to show markers") size = DDCProperty(docstring="The size of the markers") size_mode = DDSCProperty( docstring="Whether to use size to encode an attribute") size_att = DDSCProperty(docstring="The attribute to use for the size") size_vmin = DDCProperty(docstring="The lower level for the size mapping") size_vmax = DDCProperty(docstring="The upper level for the size mapping") size_scaling = DDCProperty(1, docstring="Relative scaling of the size") fill = DDCProperty(True, docstring="Whether to fill the markers") # Density map density_map = DDCProperty( False, docstring="Whether to show the points as a density map") stretch = DDSCProperty(default='log', docstring='The stretch used to render the layer, ' 'which should be one of ``linear``, ' '``sqrt``, ``log``, or ``arcsinh``') density_contrast = DDCProperty( 1, docstring="The dynamic range of the density map") # Note that we keep the dpi in the viewer state since we want it to always # be in sync between layers. # Line line_visible = DDCProperty( False, docstring="Whether to show a line connecting all positions") linewidth = DDCProperty(1, docstring="The line width") linestyle = DDSCProperty(docstring="The line style") # Errorbars xerr_visible = DDCProperty(False, docstring="Whether to show x error bars") yerr_visible = DDCProperty(False, docstring="Whether to show y error bars") xerr_att = DDSCProperty( docstring="The attribute to use for the x error bars") yerr_att = DDSCProperty( docstring="The attribute to use for the y error bars") # Vectors vector_visible = DDCProperty(False, docstring="Whether to show vector plot") vx_att = DDSCProperty( docstring="The attribute to use for the x vector arrow") vy_att = DDSCProperty( docstring="The attribute to use for the y vector arrow") vector_arrowhead = DDCProperty(False, docstring="Whether to show vector arrow") vector_mode = DDSCProperty( default_index=0, docstring="Whether to plot the vectors in cartesian or polar mode") vector_origin = DDSCProperty( default_index=1, docstring= "Whether to place the vector so that the origin is at the tail, middle, or tip" ) vector_scaling = DDCProperty( 1, docstring="The relative scaling of the arrow length") def __init__(self, viewer_state=None, layer=None, **kwargs): super(ScatterLayerState, self).__init__(viewer_state=viewer_state, layer=layer) self.limits_cache = {} self.cmap_lim_helper = StateAttributeLimitsHelper( self, attribute='cmap_att', lower='cmap_vmin', upper='cmap_vmax', limits_cache=self.limits_cache) self.size_lim_helper = StateAttributeLimitsHelper( self, attribute='size_att', lower='size_vmin', upper='size_vmax', limits_cache=self.limits_cache) self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_att', numeric=True, categorical=False) self.size_att_helper = ComponentIDComboHelper(self, 'size_att', numeric=True, categorical=False) self.xerr_att_helper = ComponentIDComboHelper(self, 'xerr_att', numeric=True, categorical=False) self.yerr_att_helper = ComponentIDComboHelper(self, 'yerr_att', numeric=True, categorical=False) self.vx_att_helper = ComponentIDComboHelper(self, 'vx_att', numeric=True, categorical=False) self.vy_att_helper = ComponentIDComboHelper(self, 'vy_att', numeric=True, categorical=False) points_mode_display = { 'auto': 'Density map or markers (auto)', 'markers': 'Markers', 'density': 'Density map' } ScatterLayerState.points_mode.set_choices( self, ['auto', 'markers', 'density']) ScatterLayerState.points_mode.set_display_func(self, points_mode_display.get) self.add_callback('points_mode', self._update_density_map_mode) ScatterLayerState.cmap_mode.set_choices(self, ['Fixed', 'Linear']) ScatterLayerState.size_mode.set_choices(self, ['Fixed', 'Linear']) linestyle_display = { 'solid': '–––––––', 'dashed': '– – – – –', 'dotted': '· · · · · · · ·', 'dashdot': '– · – · – ·' } ScatterLayerState.linestyle.set_choices( self, ['solid', 'dashed', 'dotted', 'dashdot']) ScatterLayerState.linestyle.set_display_func(self, linestyle_display.get) ScatterLayerState.vector_mode.set_choices(self, ['Cartesian', 'Polar']) vector_origin_display = { 'tail': 'Tail of vector', 'middle': 'Middle of vector', 'tip': 'Tip of vector' } ScatterLayerState.vector_origin.set_choices(self, ['tail', 'middle', 'tip']) ScatterLayerState.vector_origin.set_display_func( self, vector_origin_display.get) stretch_display = { 'linear': 'Linear', 'sqrt': 'Square Root', 'arcsinh': 'Arcsinh', 'log': 'Logarithmic' } ScatterLayerState.stretch.set_choices( self, ['linear', 'sqrt', 'arcsinh', 'log']) ScatterLayerState.stretch.set_display_func(self, stretch_display.get) self.add_callback('layer', self._on_layer_change) if layer is not None: self._on_layer_change() self.cmap = colormaps.members[0][1] self.size = self.layer.style.markersize self._sync_size = keep_in_sync(self, 'size', self.layer.style, 'markersize') self.update_from_dict(kwargs) def _on_layer_change(self, layer=None): with delay_callback(self, 'cmap_vmin', 'cmap_vmax', 'size_vmin', 'size_vmax', 'density_map'): self._update_density_map_mode() 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]) if self.layer is None: self.xerr_att_helper.set_multiple_data([]) self.yerr_att_helper.set_multiple_data([]) else: self.xerr_att_helper.set_multiple_data([self.layer]) self.yerr_att_helper.set_multiple_data([self.layer]) if self.layer is None: self.vx_att_helper.set_multiple_data([]) self.vy_att_helper.set_multiple_data([]) else: self.vx_att_helper.set_multiple_data([self.layer]) self.vy_att_helper.set_multiple_data([self.layer]) def _update_density_map_mode(self, *args): if self.points_mode == 'auto': if self.layer.size > 100000: self.density_map = True else: self.density_map = False elif self.points_mode == 'density': self.density_map = True else: self.density_map = False def flip_cmap(self): """ Flip the cmap_vmin/cmap_vmax limits. """ self.cmap_lim_helper.flip_limits() def flip_size(self): """ Flip the size_vmin/size_vmax limits. """ self.size_lim_helper.flip_limits() @property def cmap_name(self): return colormaps.name_from_cmap(self.cmap) @classmethod def __setgluestate__(cls, rec, context): # Patch for glue files produced with glue v0.11 if 'style' in rec['values']: style = context.object(rec['values'].pop('style')) if style == 'Scatter': rec['values']['markers_visible'] = True rec['values']['line_visible'] = False elif style == 'Line': rec['values']['markers_visible'] = False rec['values']['line_visible'] = True return super(ScatterLayerState, cls).__setgluestate__(rec, context)
class ScatterViewerState(MatplotlibDataViewerState): """ A state class that includes all the attributes for a scatter viewer. """ x_att = DDSCProperty(docstring='The attribute to show on the x-axis', default_index=0) y_att = DDSCProperty(docstring='The attribute to show on the y-axis', default_index=1) def __init__(self, **kwargs): super(ScatterViewerState, self).__init__() self.limits_cache = {} self.x_lim_helper = StateAttributeLimitsHelper(self, attribute='x_att', lower='x_min', upper='x_max', log='x_log', limits_cache=self.limits_cache) self.y_lim_helper = StateAttributeLimitsHelper(self, attribute='y_att', lower='y_min', upper='y_max', log='y_log', limits_cache=self.limits_cache) self.add_callback('layers', self._layers_changed) self.x_att_helper = ComponentIDComboHelper(self, 'x_att') self.y_att_helper = ComponentIDComboHelper(self, 'y_att') self.update_from_dict(kwargs) def _update_priority(self, name): if name == 'layers': return 2 elif name.endswith('_log'): return 0.5 elif name.endswith(('_min', '_max')): return 0 else: return 1 def flip_x(self): """ Flip the x_min/x_max limits. """ self.x_lim_helper.flip_limits() def flip_y(self): """ Flip the y_min/y_max limits. """ self.y_lim_helper.flip_limits() def _get_x_components(self): return self._get_components(self.x_att) def _get_y_components(self): return self._get_components(self.y_att) def _get_components(self, cid): # Construct list of components over all layers components = [] for layer_state in self.layers: if isinstance(layer_state.layer, Data): layer = layer_state.layer else: layer = layer_state.layer.data try: components.append(layer.data.get_component(cid)) except IncompatibleAttribute: pass return components def _layers_changed(self, *args): layers_data = self.layers_data layers_data_cache = getattr(self, '_layers_data_cache', []) if layers_data == layers_data_cache: return self.x_att_helper.set_multiple_data(self.layers_data) self.y_att_helper.set_multiple_data(self.layers_data) self._layers_data_cache = layers_data
def __init__(self, viewer_state=None, layer=None, **kwargs): super(ScatterLayerState, self).__init__(viewer_state=viewer_state, layer=layer) self.limits_cache = {} self.cmap_lim_helper = StateAttributeLimitsHelper( self, attribute='cmap_att', lower='cmap_vmin', upper='cmap_vmax', limits_cache=self.limits_cache) self.size_lim_helper = StateAttributeLimitsHelper( self, attribute='size_att', lower='size_vmin', upper='size_vmax', limits_cache=self.limits_cache) self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_att', numeric=True, categorical=False) self.size_att_helper = ComponentIDComboHelper(self, 'size_att', numeric=True, categorical=False) self.xerr_att_helper = ComponentIDComboHelper(self, 'xerr_att', numeric=True, categorical=False) self.yerr_att_helper = ComponentIDComboHelper(self, 'yerr_att', numeric=True, categorical=False) self.vx_att_helper = ComponentIDComboHelper(self, 'vx_att', numeric=True, categorical=False) self.vy_att_helper = ComponentIDComboHelper(self, 'vy_att', numeric=True, categorical=False) points_mode_display = { 'auto': 'Density map or markers (auto)', 'markers': 'Markers', 'density': 'Density map' } ScatterLayerState.points_mode.set_choices( self, ['auto', 'markers', 'density']) ScatterLayerState.points_mode.set_display_func(self, points_mode_display.get) self.add_callback('points_mode', self._update_density_map_mode) ScatterLayerState.cmap_mode.set_choices(self, ['Fixed', 'Linear']) ScatterLayerState.size_mode.set_choices(self, ['Fixed', 'Linear']) linestyle_display = { 'solid': '–––––––', 'dashed': '– – – – –', 'dotted': '· · · · · · · ·', 'dashdot': '– · – · – ·' } ScatterLayerState.linestyle.set_choices( self, ['solid', 'dashed', 'dotted', 'dashdot']) ScatterLayerState.linestyle.set_display_func(self, linestyle_display.get) ScatterLayerState.vector_mode.set_choices(self, ['Cartesian', 'Polar']) vector_origin_display = { 'tail': 'Tail of vector', 'middle': 'Middle of vector', 'tip': 'Tip of vector' } ScatterLayerState.vector_origin.set_choices(self, ['tail', 'middle', 'tip']) ScatterLayerState.vector_origin.set_display_func( self, vector_origin_display.get) stretch_display = { 'linear': 'Linear', 'sqrt': 'Square Root', 'arcsinh': 'Arcsinh', 'log': 'Logarithmic' } ScatterLayerState.stretch.set_choices( self, ['linear', 'sqrt', 'arcsinh', 'log']) ScatterLayerState.stretch.set_display_func(self, stretch_display.get) self.add_callback('layer', self._on_layer_change) if layer is not None: self._on_layer_change() self.cmap = colormaps.members[0][1] self.size = self.layer.style.markersize self._sync_size = keep_in_sync(self, 'size', self.layer.style, 'markersize') self.update_from_dict(kwargs)
class ScatterLayerState(MatplotlibLayerState): """ A state class that includes all the attributes for layers in a scatter plot. """ # Color cmap_mode = DDSCProperty(docstring="Whether to use color to encode an attribute") cmap_att = DDSCProperty(docstring="The attribute to use for the color") cmap_vmin = DDCProperty(docstring="The lower level for the colormap") cmap_vmax = DDCProperty(docstring="The upper level for the colormap") cmap = DDCProperty(docstring="The colormap to use (when in colormap mode)") # Points points_mode = DDSCProperty(docstring='Whether to use markers or a density map') # Markers markers_visible = DDCProperty(True, docstring="Whether to show markers") size = DDCProperty(docstring="The size of the markers") size_mode = DDSCProperty(docstring="Whether to use size to encode an attribute") size_att = DDSCProperty(docstring="The attribute to use for the size") size_vmin = DDCProperty(docstring="The lower level for the size mapping") size_vmax = DDCProperty(docstring="The upper level for the size mapping") size_scaling = DDCProperty(1, docstring="Relative scaling of the size") fill = DDCProperty(True, docstring="Whether to fill the markers") # Density map density_map = DDCProperty(False, docstring="Whether to show the points as a density map") stretch = DDSCProperty(default='log', docstring='The stretch used to render the layer, ' 'which should be one of ``linear``, ' '``sqrt``, ``log``, or ``arcsinh``') density_contrast = DDCProperty(1, docstring="The dynamic range of the density map") # Note that we keep the dpi in the viewer state since we want it to always # be in sync between layers. # Line line_visible = DDCProperty(False, docstring="Whether to show a line connecting all positions") linewidth = DDCProperty(1, docstring="The line width") linestyle = DDSCProperty(docstring="The line style") # Errorbars xerr_visible = DDCProperty(False, docstring="Whether to show x error bars") yerr_visible = DDCProperty(False, docstring="Whether to show y error bars") xerr_att = DDSCProperty(docstring="The attribute to use for the x error bars") yerr_att = DDSCProperty(docstring="The attribute to use for the y error bars") # Vectors vector_visible = DDCProperty(False, docstring="Whether to show vector plot") vx_att = DDSCProperty(docstring="The attribute to use for the x vector arrow") vy_att = DDSCProperty(docstring="The attribute to use for the y vector arrow") vector_arrowhead = DDCProperty(False, docstring="Whether to show vector arrow") vector_mode = DDSCProperty(default_index=0, docstring="Whether to plot the vectors in cartesian or polar mode") vector_origin = DDSCProperty(default_index=1, docstring="Whether to place the vector so that the origin is at the tail, middle, or tip") vector_scaling = DDCProperty(1, docstring="The relative scaling of the arrow length") def __init__(self, viewer_state=None, layer=None, **kwargs): super(ScatterLayerState, self).__init__(viewer_state=viewer_state, layer=layer) self.limits_cache = {} self.cmap_lim_helper = StateAttributeLimitsHelper(self, attribute='cmap_att', lower='cmap_vmin', upper='cmap_vmax', limits_cache=self.limits_cache) self.size_lim_helper = StateAttributeLimitsHelper(self, attribute='size_att', lower='size_vmin', upper='size_vmax', limits_cache=self.limits_cache) self.cmap_att_helper = ComponentIDComboHelper(self, 'cmap_att', numeric=True, categorical=False) self.size_att_helper = ComponentIDComboHelper(self, 'size_att', numeric=True, categorical=False) self.xerr_att_helper = ComponentIDComboHelper(self, 'xerr_att', numeric=True, categorical=False) self.yerr_att_helper = ComponentIDComboHelper(self, 'yerr_att', numeric=True, categorical=False) self.vx_att_helper = ComponentIDComboHelper(self, 'vx_att', numeric=True, categorical=False) self.vy_att_helper = ComponentIDComboHelper(self, 'vy_att', numeric=True, categorical=False) points_mode_display = {'auto': 'Density map or markers (auto)', 'markers': 'Markers', 'density': 'Density map'} ScatterLayerState.points_mode.set_choices(self, ['auto', 'markers', 'density']) ScatterLayerState.points_mode.set_display_func(self, points_mode_display.get) self.add_callback('points_mode', self._update_density_map_mode) ScatterLayerState.cmap_mode.set_choices(self, ['Fixed', 'Linear']) ScatterLayerState.size_mode.set_choices(self, ['Fixed', 'Linear']) linestyle_display = {'solid': '–––––––', 'dashed': '– – – – –', 'dotted': '· · · · · · · ·', 'dashdot': '– · – · – ·'} ScatterLayerState.linestyle.set_choices(self, ['solid', 'dashed', 'dotted', 'dashdot']) ScatterLayerState.linestyle.set_display_func(self, linestyle_display.get) ScatterLayerState.vector_mode.set_choices(self, ['Cartesian', 'Polar']) vector_origin_display = {'tail': 'Tail of vector', 'middle': 'Middle of vector', 'tip': 'Tip of vector'} ScatterLayerState.vector_origin.set_choices(self, ['tail', 'middle', 'tip']) ScatterLayerState.vector_origin.set_display_func(self, vector_origin_display.get) stretch_display = {'linear': 'Linear', 'sqrt': 'Square Root', 'arcsinh': 'Arcsinh', 'log': 'Logarithmic'} ScatterLayerState.stretch.set_choices(self, ['linear', 'sqrt', 'arcsinh', 'log']) ScatterLayerState.stretch.set_display_func(self, stretch_display.get) self.add_callback('layer', self._on_layer_change) if layer is not None: self._on_layer_change() self.cmap = colormaps.members[0][1] self.size = self.layer.style.markersize self._sync_size = keep_in_sync(self, 'size', self.layer.style, 'markersize') self.update_from_dict(kwargs) def _on_layer_change(self, layer=None): with delay_callback(self, 'cmap_vmin', 'cmap_vmax', 'size_vmin', 'size_vmax', 'density_map'): self._update_density_map_mode() 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]) if self.layer is None: self.xerr_att_helper.set_multiple_data([]) self.yerr_att_helper.set_multiple_data([]) else: self.xerr_att_helper.set_multiple_data([self.layer]) self.yerr_att_helper.set_multiple_data([self.layer]) if self.layer is None: self.vx_att_helper.set_multiple_data([]) self.vy_att_helper.set_multiple_data([]) else: self.vx_att_helper.set_multiple_data([self.layer]) self.vy_att_helper.set_multiple_data([self.layer]) def _update_density_map_mode(self, *args): if self.points_mode == 'auto': if self.layer.size > 100000: self.density_map = True else: self.density_map = False elif self.points_mode == 'density': self.density_map = True else: self.density_map = False def flip_cmap(self): """ Flip the cmap_vmin/cmap_vmax limits. """ self.cmap_lim_helper.flip_limits() def flip_size(self): """ Flip the size_vmin/size_vmax limits. """ self.size_lim_helper.flip_limits() @property def cmap_name(self): return colormaps.name_from_cmap(self.cmap) @classmethod def __setgluestate__(cls, rec, context): # Patch for glue files produced with glue v0.11 if 'style' in rec['values']: style = context.object(rec['values'].pop('style')) if style == 'Scatter': rec['values']['markers_visible'] = True rec['values']['line_visible'] = False elif style == 'Line': rec['values']['markers_visible'] = False rec['values']['line_visible'] = True return super(ScatterLayerState, cls).__setgluestate__(rec, context)