def connect_float_edit(client, prop, widget): """ Connect widget.setText and client.prop Also pretty-print the number client.prop should be a callback property """ v = QtGui.QDoubleValidator(None) v.setDecimals(4) widget.setValidator(v) def update_prop(): val = widget.text() try: setattr(client, prop, float(val)) except ValueError: setattr(client, prop, 0) def update_widget(val): if val is None: val = 0. widget.setText(pretty_number(val)) add_callback(client, prop, update_widget) widget.editingFinished.connect(update_prop) update_widget(getattr(client, prop))
def __init__(self, layer, axes, viewer_state): # Keep a reference to the layer (data or subset) and axes self.layer = layer self.axes = axes self.viewer_state = viewer_state # Watch for changes in the viewer state which would require the # layers to be redrawn # TODO: don't connect to ALL signals here self.viewer_state.connect_all(nonpartial(self.update)) # Set up a state object for the layer artists self.layer_state = ScatterLayerState() self.layer_state.layer = layer self.layer_state.connect_all(self.update) # TODO: need to connect to visual properties of layer in one go add_callback(self.layer.style, 'color', nonpartial(self.update)) add_callback(self.layer.style, 'markersize', nonpartial(self.update)) # Set up the layer style editor self.style_editor = ScatterLayerStyleEditor(self.layer_state) # Set up an initially empty artist self.artist1 = self.axes.plot([], [], 'o')[0] self.artist2 = self.axes.plot([], [], '-')[0] self.zorder = 0 self.update()
def connect_bool_button(client, prop, widget): """ Connect widget.setChecked and client.prop client.prop should be a callback property """ add_callback(client, prop, widget.setChecked) widget.toggled.connect(partial(setattr, client, prop))
def connect_current_combo(client, prop, widget): """ Connect widget.currentIndexChanged and client.prop client.prop should be a callback property """ def _push_combo(value): # NOTE: we can't use findData here because if the data is not a # string, PySide will crash try: idx = _find_combo_data(widget, value) except ValueError: if value is None: idx = -1 else: raise widget.setCurrentIndex(idx) def _pull_combo(idx): if idx == -1: setattr(client, prop, None) else: setattr(client, prop, widget.itemData(idx)) add_callback(client, prop, _push_combo) widget.currentIndexChanged.connect(_pull_combo)
def connect_current_combo(client, prop, widget): """ Connect widget.currentIndexChanged and client.prop client.prop should be a callback property """ def update_widget(value): try: idx = _find_combo_data(widget, value) except ValueError: if value is None: idx = -1 else: raise widget.setCurrentIndex(idx) def update_prop(idx): if idx == -1: setattr(client, prop, None) else: setattr(client, prop, widget.itemData(idx)) add_callback(client, prop, update_widget) widget.currentIndexChanged.connect(update_prop) update_widget(getattr(client, prop))
def __init__(self, viewer, **kwargs): super(GingaPVSlicerMode, self).__init__(viewer, **kwargs) self._path_obj = None self._shape = 'freepath' add_callback(viewer.client, 'display_data', self._display_data_hook) self._slice_widget = None
def connect_int_spin(client, prop, widget): """ Connect client.prop to widget.valueChanged client.prop should be a callback property """ add_callback(client, prop, widget.setValue) widget.valueChanged.connect(partial(setattr, client, prop))
def connect_color(client, prop, widget): def update_widget(text): widget.setColor(text) def update_prop(): setattr(client, prop, widget.color()) add_callback(client, prop, update_widget) widget.colorChanged.connect(nonpartial(update_prop))
def __init__(self, parent=None): super(VispyWidget, self).__init__(parent=parent) # Prepare Vispy canvas. We set the depth_size to 24 to avoid issues # with isosurfaces on MacOS X self.canvas = scene.SceneCanvas(keys='interactive', show=False, config={'depth_size': 24}) # Set up a viewbox self.view = self.canvas.central_widget.add_view() self.view.parent = self.canvas.scene # Set whether we are emulating a 3D texture. This needs to be enabled # as a workaround on Windows otherwise VisPy crashes. self.emulate_texture = (sys.platform == 'win32' and sys.version_info[0] < 3) self.scene_transform = scene.STTransform() self.limit_transforms = {} # Add a 3D cube to show us the unit cube. The 1.001 factor is to make # sure that the grid lines are not 'hidden' by volume renderings on the # front side due to numerical precision. vertices, filled_indices, outline_indices = create_cube() self.axis = scene.visuals.Mesh(vertices['position'], outline_indices, color=(1, 1, 1), mode='lines') self.axis.transform = self.scene_transform self.view.add(self.axis) # Create a turntable camera. For now, this is the only camerate type # we support, but if we support more in future, we should implement # that here # Remove the fov=60 here to solve the mismatch of selection problem # self.view.camera = scene.cameras.TurntableCamera(parent=self.view.scene, distance=2) self.view.camera = scene.cameras.TurntableCamera( parent=self.view.scene, distance=2.0) # Add the native canvas widget to this widget layout = QtGui.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.canvas.native) self.setLayout(layout) # We need to call render here otherwise we'll later encounter an OpenGL # program validation error. self.canvas.render() # Set up callbacks add_callback(self, 'visible_axes', nonpartial(self._toggle_axes))
def connect_text(client, prop, widget): def update_prop(): val = widget.text() setattr(client, prop, val) def update_widget(val): widget.setText(val) add_callback(client, prop, update_widget) try: widget.editingFinished.connect(update_prop) except AttributeError: pass
def __init__(self, parent=None): super(VispyWidget, self).__init__(parent=parent) # Prepare Vispy canvas. We set the depth_size to 24 to avoid issues # with isosurfaces on MacOS X self.canvas = scene.SceneCanvas(keys='interactive', show=False, config={'depth_size': 24}) # Set up a viewbox self.view = self.canvas.central_widget.add_view() self.view.parent = self.canvas.scene # Set whether we are emulating a 3D texture. This needs to be enabled # as a workaround on Windows otherwise VisPy crashes. self.emulate_texture = (sys.platform == 'win32' and sys.version_info[0] < 3) self.scene_transform = scene.STTransform() self.limit_transforms = {} # Add a 3D cube to show us the unit cube. The 1.001 factor is to make # sure that the grid lines are not 'hidden' by volume renderings on the # front side due to numerical precision. vertices, filled_indices, outline_indices = create_cube() self.axis = scene.visuals.Mesh(vertices['position'], outline_indices, color=(1,1,1), mode='lines') self.axis.transform = self.scene_transform self.view.add(self.axis) # Create a turntable camera. For now, this is the only camerate type # we support, but if we support more in future, we should implement # that here # Remove the fov=60 here to solve the mismatch of selection problem # self.view.camera = scene.cameras.TurntableCamera(parent=self.view.scene, distance=2) self.view.camera = scene.cameras.TurntableCamera(parent=self.view.scene, distance=2.0) # Add the native canvas widget to this widget layout = QtGui.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.canvas.native) self.setLayout(layout) # We need to call render here otherwise we'll later encounter an OpenGL # program validation error. self.canvas.render() # Set up callbacks add_callback(self, 'visible_axes', nonpartial(self._toggle_axes))
def __init__(self, parent=None): # Prepare Vispy canvas. We set the depth_size to 24 to avoid issues # with isosurfaces on MacOS X self.canvas = scene.SceneCanvas(keys=None, show=False, config={'depth_size': 24}, bgcolor=rgb(settings.BACKGROUND_COLOR)) # Set up a viewbox self.view = self.canvas.central_widget.add_view() self.view.parent = self.canvas.scene # Set whether we are emulating a 3D texture. This needs to be enabled # as a workaround on Windows otherwise VisPy crashes. self.emulate_texture = (sys.platform == 'win32' and sys.version_info[0] < 3) self.scene_transform = scene.STTransform() self.limit_transforms = {} fc = rgb(settings.FOREGROUND_COLOR) self.axis = AxesVisual3D(axis_color=fc, tick_color=fc, text_color=fc, tick_width=1, minor_tick_length=2, major_tick_length=4, axis_width=0, tick_label_margin=10, axis_label_margin=25, tick_font_size=6, axis_font_size=8, view=self.view, transform=self.scene_transform) # Create a turntable camera. For now, this is the only camerate type # we support, but if we support more in future, we should implement # that here # Orthographic perspective view as default self.view.camera = scene.cameras.TurntableCamera(parent=self.view.scene, fov=0., distance=4.0) # We need to call render here otherwise we'll later encounter an OpenGL # program validation error. # self.canvas.render() # Set up callbacks add_callback(self, 'visible_axes', nonpartial(self._toggle_axes)) add_callback(self, 'perspective_view', nonpartial(self._toggle_perspective))
def __init__(self, x, y, dy, models=None): self.x = x self.y = y self.dy = dy if models is None: models = [models.Const1D(0.3)] self.models = models self.ui = ModelBrowserUI() self.plot, self.resid = _build_axes(self.ui.canvas.fig) self._draw(preserve_limits=False) self.mouse_handler = ModelEventHandler(self.plot, self.active_model) add_callback(self.mouse_handler, 'model', self.set_model) self._connect() self._sync_model_list()
def connect_value(client, prop, widget, value_range=None, log=False): """ Connect client.prop to widget.valueChanged client.prop should be a callback property If ``value_range`` is set, the slider values are mapped to that range. If ``log`` is set, the mapping is assumed to be logarithmic instead of linear. """ if log: if value_range is None: raise ValueError( "log option can only be set if value_range is given") else: value_range = math.log10(value_range[0]), math.log10( value_range[1]) def update_prop(): val = widget.value() if value_range is not None: imin, imax = widget.minimum(), widget.maximum() val = (val - imin) / (imax - imin) * ( value_range[1] - value_range[0]) + value_range[0] if log: val = 10**val setattr(client, prop, val) def update_widget(val): if val is None: widget.setValue(0) return if log: val = math.log10(val) if value_range is not None: imin, imax = widget.minimum(), widget.maximum() val = (val - value_range[0]) / ( value_range[1] - value_range[0]) * (imax - imin) + imin widget.setValue(val) add_callback(client, prop, update_widget) widget.valueChanged.connect(update_prop) update_widget(getattr(client, prop))
def __init__(self, session, parent=None): super(MatplotlibDataViewer, self).__init__(session, parent) # Use MplWidget to set up a Matplotlib canvas inside the Qt window self.mpl_widget = MplWidget() self.setCentralWidget(self.mpl_widget) # TODO: shouldn't have to do this self.central_widget = self.mpl_widget self.figure, self._axes = init_mpl(self.mpl_widget.canvas.fig) # Set up the state which will contain everything needed to represent # the current state of the viewer self.state = self._state_cls() self.state.data_collection = session.data_collection # Set up the options widget, which will include options that control the # viewer state self.options = self._options_cls(viewer_state=self.state, session=session) add_callback(self.state, 'x_min', nonpartial(self.limits_to_mpl)) add_callback(self.state, 'x_max', nonpartial(self.limits_to_mpl)) add_callback(self.state, 'y_min', nonpartial(self.limits_to_mpl)) add_callback(self.state, 'y_max', nonpartial(self.limits_to_mpl)) self.axes.callbacks.connect('xlim_changed', nonpartial(self.limits_from_mpl)) self.axes.callbacks.connect('ylim_changed', nonpartial(self.limits_from_mpl)) self.state.add_callback('x_log', nonpartial(self.update_x_log)) self.state.add_callback('y_log', nonpartial(self.update_y_log)) self.axes.set_autoscale_on(False) # TODO: in future could move the following to a more basic data viewer class # When layer artists are removed from the layer artist container, we need # to make sure we remove matching layer states in the viewer state # layers attribute. self._layer_artist_container.on_changed( nonpartial(self._sync_state_layers)) # And vice-versa when layer states are removed from the viewer state, we # need to keep the layer_artist_container in sync self.state.add_callback('layers', nonpartial(self._sync_layer_artist_container))
def __init__(self, x, y, dy, initial_models=None): QObject.__init__(self) self.x = x self.y = y self.dy = dy if initial_models is None: initial_models = [models.Const1D(0.0)] self.models = initial_models self.ui = ModelBrowserUI(self, self.models, self.x, self.y) self.plot, self.resid = _build_axes(self.ui.canvas.fig) self._draw(preserve_limits=False) self.mouse_handler = ModelEventHandler(self.plot, self.active_model) add_callback(self.mouse_handler, 'model', self.set_model) self.ui.fit.pressed.connect(nonpartial(self.fit)) self._sync_model_list()
def __init__(self, session, parent=None): super(BaseVispyViewer, self).__init__(session, parent=parent) self._vispy_widget = VispyWidgetHelper() self.setCentralWidget(self._vispy_widget.canvas.native) self._options_widget = VispyOptionsWidget(vispy_widget=self._vispy_widget, data_viewer=self) add_callback(self._vispy_widget, 'clip_data', nonpartial(self._toggle_clip)) add_callback(self._vispy_widget, 'clip_limits', nonpartial(self._toggle_clip)) self.status_label = None self.client = None # If imageio is available, we can add the record icon try: import imageio # noqa except ImportError: pass else: self.tools.insert(1, 'vispy:record')
def connect_value(client, prop, widget, value_range=None, log=False): """ Connect client.prop to widget.valueChanged client.prop should be a callback property If ``value_range`` is set, the slider values are mapped to that range. If ``log`` is set, the mapping is assumed to be logarithmic instead of linear. """ if log: if value_range is None: raise ValueError("log option can only be set if value_range is given") else: value_range = math.log10(value_range[0]), math.log10(value_range[1]) def update_prop(): val = widget.value() if value_range is not None: imin, imax = widget.minimum(), widget.maximum() val = (val - imin) / (imax - imin) * (value_range[1] - value_range[0]) + value_range[0] if log: val = 10 ** val setattr(client, prop, val) def update_widget(val): if val is None: widget.setValue(0) return if log: val = math.log10(val) if value_range is not None: imin, imax = widget.minimum(), widget.maximum() val = (val - value_range[0]) / (value_range[1] - value_range[0]) * (imax - imin) + imin widget.setValue(val) add_callback(client, prop, update_widget) widget.valueChanged.connect(update_prop) update_widget(getattr(client, prop))
def __init__(self, layer, vispy_viewer): super(IsosurfaceLayerArtist, self).__init__(layer) self.layer = layer self.vispy_viewer = vispy_viewer self._iso_visual = scene.Isosurface(np.ones((3, 3, 3)), level=0.5, shading='smooth') self.vispy_viewer.add_data_visual(self._iso_visual) # Set up connections so that when any of the properties are # modified, we update the appropriate part of the visualization add_callback(self, 'attribute', nonpartial(self._update_data)) add_callback(self, 'level', nonpartial(self._update_level)) add_callback(self, 'color', nonpartial(self._update_color)) add_callback(self, 'alpha', nonpartial(self._update_color))
def __init__(self, layer, vispy_viewer): super(IsosurfaceLayerArtist, self).__init__(layer) self.layer = layer self.vispy_viewer = vispy_viewer self._iso_visual = Isosurface(np.ones((3, 3, 3)), level=0.5, shading='smooth') self.vispy_viewer.add_data_visual(self._iso_visual) # Set up connections so that when any of the properties are # modified, we update the appropriate part of the visualization add_callback(self, 'attribute', nonpartial(self._update_data)) add_callback(self, 'level', nonpartial(self._update_level)) add_callback(self, 'color', nonpartial(self._update_color)) add_callback(self, 'alpha', nonpartial(self._update_color))
def connect(self, name, callback): add_callback(self, name, callback)
def __init__(self, viewer, **kwargs): super(PVSlicerMode, self).__init__(viewer, **kwargs) add_callback(viewer.client, 'display_data', self._display_data_hook) self._roi_callback = self._extract_callback self._slice_widget = None
def __init__(self, layer, vispy_viewer): super(VolumeLayerArtist, self).__init__(layer) self.layer = layer self.vispy_viewer = vispy_viewer # We create a unique ID for this layer artist, that will be used to # refer to the layer artist in the MultiVolume. We have to do this # rather than use self.id because we can't guarantee the latter is # unique. self.id = str(uuid.uuid4()) # We need to use MultiVolume instance to store volumes, but we should # only have one per canvas. Therefore, we store the MultiVolume # instance in the vispy viewer instance. if not hasattr(vispy_viewer, '_multivol'): # Set whether we are emulating a 3D texture. This needs to be # enabled as a workaround on Windows otherwise VisPy crashes. emulate_texture = (sys.platform == 'win32' and sys.version_info[0] < 3) try: multivol = MultiVolume(threshold=0.1, emulate_texture=emulate_texture) except: multivol = MultiVolumeLegacy(threshold=0.1, emulate_texture=emulate_texture) self.vispy_viewer.add_data_visual(multivol) vispy_viewer._multivol = multivol self._multivol = vispy_viewer._multivol self._multivol.allocate(self.id) # Set up connections so that when any of the properties are # modified, we update the appropriate part of the visualization add_callback(self, 'attribute', nonpartial(self._update_data)) add_callback(self, 'vmin', nonpartial(self._update_limits)) add_callback(self, 'vmax', nonpartial(self._update_limits)) add_callback(self, 'color', nonpartial(self._update_cmap_from_color)) add_callback(self, 'cmap', nonpartial(self._update_cmap)) add_callback(self, 'alpha', nonpartial(self._update_alpha)) if isinstance(self.layer, Subset): add_callback(self, 'subset_mode', nonpartial(self._update_data))
def __init__(self, layer, vispy_viewer): super(ScatterLayerArtist, self).__init__(layer) self.layer = layer self.vispy_viewer = vispy_viewer # We create a unique ID for this layer artist, that will be used to # refer to the layer artist in the MultiColorScatter. We have to do this # rather than use self.id because we can't guarantee the latter is # unique. self.id = str(uuid.uuid4()) # We need to use MultiColorScatter instance to store scatter plots, but # we should only have one per canvas. Therefore, we store the # MultiColorScatter instance in the vispy viewer instance. if not hasattr(vispy_viewer, '_multiscat'): multiscat = MultiColorScatter() self.vispy_viewer.add_data_visual(multiscat) vispy_viewer._multiscat = multiscat self._multiscat = vispy_viewer._multiscat self._multiscat.allocate(self.id) self._multiscat.set_zorder(self.id, self.get_zorder) # Set up connections so that when any of the size properties are # modified, we update the marker sizes add_callback(self, 'size_mode', nonpartial(self._update_sizes)) add_callback(self, 'size', nonpartial(self._update_sizes)) add_callback(self, 'size_attribute', nonpartial(self._update_sizes)) add_callback(self, 'size_vmin', nonpartial(self._update_sizes)) add_callback(self, 'size_vmax', nonpartial(self._update_sizes)) add_callback(self, 'size_scaling', nonpartial(self._update_sizes)) # Set up connections so that when any of the color properties are # modified, we update the marker colors add_callback(self, 'color_mode', nonpartial(self._update_colors)) add_callback(self, 'color', nonpartial(self._update_colors)) add_callback(self, 'cmap_attribute', nonpartial(self._update_colors)) add_callback(self, 'cmap_vmin', nonpartial(self._update_colors)) add_callback(self, 'cmap_vmax', nonpartial(self._update_colors)) add_callback(self, 'cmap', nonpartial(self._update_colors)) add_callback(self, 'alpha', nonpartial(self._update_alpha)) # Set data caches self._marker_data = None self._color_data = None self._size_data = None
def __init__(self, layer, vispy_viewer=None): super(VolumeLayerArtist, self).__init__(layer) self.layer = layer self.vispy_viewer = vispy_viewer self.vispy_widget = vispy_viewer._vispy_widget # We create a unique ID for this layer artist, that will be used to # refer to the layer artist in the MultiVolume. We have to do this # rather than use self.id because we can't guarantee the latter is # unique. self.id = str(uuid.uuid4()) # We need to use MultiVolume instance to store volumes, but we should # only have one per canvas. Therefore, we store the MultiVolume # instance in the vispy viewer instance. if not hasattr(self.vispy_widget, '_multivol'): # Set whether we are emulating a 3D texture. This needs to be # enabled as a workaround on Windows otherwise VisPy crashes. emulate_texture = (sys.platform == 'win32' and sys.version_info[0] < 3) multivol = MultiVolume(threshold=0.1, emulate_texture=emulate_texture) self.vispy_widget.add_data_visual(multivol) self.vispy_widget._multivol = multivol self._multivol = self.vispy_widget._multivol self._multivol.allocate(self.id) # Set up connections so that when any of the properties are # modified, we update the appropriate part of the visualization add_callback(self, 'attribute', nonpartial(self._update_data)) add_callback(self, 'vmin', nonpartial(self._update_limits)) add_callback(self, 'vmax', nonpartial(self._update_limits)) add_callback(self, 'color', nonpartial(self._update_cmap_from_color)) add_callback(self, 'cmap', nonpartial(self._update_cmap)) add_callback(self, 'alpha', nonpartial(self._update_alpha)) if isinstance(self.layer, Subset): add_callback(self, 'subset_mode', nonpartial(self._update_data))