def set_backend(self, backend): """ Set the backend to the new value (implies setting a new layer). """ if self.backend != backend: Signals.disconnect_list(self.backend_signals) self.backend = backend if self.backend is not None: # If no active layer is set, even though there are layers, # then we should set the first layer as being active. if self.backend.layer is None and len(self.backend.plot.layers) > 0: self.backend.layer = self.backend.plot.layers[0] self.layer = self.backend.layer # make sure we keep track of changes to the active layer self.backend_signals.append( Signals.connect(backend, "notify::layer", (lambda sender, layer: self.set_layer(layer))) ) else: self.layer = None # propagate the new backend to all tools self.dock.foreach((lambda tool: tool.set_backend(self.backend))) # Adjust the active index of the combobox so that the new # backend is displayed. if self.backend is None: index = -1 else: model = self.combobox.get_model() index = self.project.backends.index(backend) self.combobox.set_active(index)
def __init__(self, project=None): " 'project' may be a Project object or a filename. " self.eConfig = config.read_configfile(self, const.CONFIG_FILE) Signals.connect(self, "write-config", (lambda sender: self.write_recentfiles())) self.plugins = dict() self.recent_files = list() self.read_recentfiles() # init() is a good place for initialization of derived class self.init() # Set up the Project... self._project = None if isinstance(project, basestring): try: self.load_project(project) except IOError: logger.error("Failed to load project '%s'\nSetting up an empty project instead." % project) self.set_project(Project()) else: self.set_project(project) self.init_plugins()
def new_dataset(self, key='dataset', undolist=None): """ Add a new Dataset object to the Project. The `data` field contains a nearly empty numarray (1 row, 2 columns, all zero). If no key is given, then one is created. If the key already exists, then the method assures that it is unique within the Project. Returns newly created Dataset. """ if undolist is None: undolist = self.journal key = pdict.unique_key(self.datasets, key) ds = Dataset() pdict.setitem(self.datasets, key, ds) ds.data = Table(nrows=1,ncols=2) ds.data.column(0).designation = 'X' ds.data.column(1).designation = 'Y' Signals.emit(self, "notify::datasets") ui = UndoInfo(self.remove_objects, [ds], False) ui.describe("Create new Dataset '%s'" % key) undolist.append(ui) return ds
def cb_interpolate(self, action): plugin = self.app.get_plugin('pygsl') pygsl = plugin.pygsl table = self.dataset.get_data() x, y = table[0], table[1] steps = table.nrows * 3 start, end = x[0], x[-1] stepwidth = (end - start) / steps new_x = Numeric.arange(start=start, stop=end+stepwidth, step=stepwidth) new_table = Table(nrows=steps, ncols=2, typecodes=[table.get_typecode(0), table.get_typecode(1)]) sp = pygsl.spline.cspline(table.nrows) sp.init(x, y) iter = new_table.row(0) for xi in new_x: iter.set( (xi, sp.eval(xi)) ) try: iter = iter.next() except StopIteration: print "Iteration stopped" # set new Dataset self.project.datasets.append( Dataset(key="Niklas", data=new_table) ) Signals.emit(self.project.datasets, "changed")
def set(container, *args, **kwargs): undolist = kwargs.pop('undolist', UndoList()) olditems = dict() changeset = [] arglist = list(args) while len(arglist) > 1: key = arglist.pop(0) value = arglist.pop(0) olditems[key] = container.get_value(key, None) setattr(container, key, value) changeset.append(key) for (key, value) in kwargs.iteritems(): olditems[key] = container.get_value(key, None) setattr(container, key, value) changeset.append(key) undolist.append( UndoInfo(set, container, **olditems) ) if len(changeset) > 0: Signals.emit(container, "notify", changeset) # TODO: remove, it's deprecated Signals.emit(container, "prop-changed", changeset)
def smart_set(container, *args, **kwargs): """ Like 'set', but only add undo information, if the values have actually changed. """ undolist = kwargs.pop('undolist', UndoList()) olditems = dict() changed_props = [] def do_set(key, value): old_value = container.get_value(key, None) setattr(container, key, value) if old_value != container.get_value(key, None): olditems[key] = old_value changed_props.append(key) print "Prop '%s' has changed from '%s' to '%s'." % (key, container.get_value(key, None), old_value) arglist = list(args) while len(arglist) > 1: do_set(arglist.pop(0), arglist.pop(0)) for (key, value) in kwargs.iteritems(): do_set(key, value) if len(changed_props) > 0: undolist.append( UndoInfo(smart_set, container, **olditems) ) Signals.emit(container, "prop-changed", changed_props) else: undolist.append( NullUndo() )
def _construct_toolwindow(self): window = tools.ToolWindow(self.app, None) window.set_transient_for(self) window.set_destroy_with_parent(True) window.hide() def cb_toggle_window(action, window): if action.get_active() is True: window.show() else: window.hide() t = gtk.ToggleAction('ToggleToolWindow', 'Show tools window', None, None) t.connect("toggled", cb_toggle_window, window) uihelper.get_action_group(self.uimanager, 'Application').add_action(t) def cb_window_hideshow(window): action = self.uimanager.get_action('/MainMenu/ViewMenu/ToggleToolWindow') action.set_active(window.get_property('visible')) window.connect('hide', cb_window_hideshow) window.connect('show', cb_window_hideshow) def on_notify_project(sender, project, toolwin): print "==> project = ", project print "==> toolwin = ", toolwin toolwin.set_project(project) Signals.connect(self.app, 'notify::project', on_notify_project, window) return window
def set_dataset(self, dataset): if dataset is None: self.set_title("(no dataset)") else: self.set_title("DS: %s" % dataset.key) # FIXME # this is inconsistent: we expect 'table' to be fixed, # even though we argued before that the dataset.data field # is not necessarily fixed, only the Dataset. table = dataset.get_data() if not isinstance(table, Table): raise TypeError("TableWindow can only use Datasets with a Table as data.") self.tableview.set_table(table) for signal in self._signals: Signals.disconnect(signal) self._signals += [ Signals.connect(table, 'update-columns', (lambda sender: self.tableview.setup_columns())), Signals.connect(dataset,'notify', (lambda sender: self.tableview.queue_draw())) ] # TODO: set metadata widget self._dataset = dataset
def set_plot(self, plot): Signals.disconnect_list(self._signals) self.backend is not None and self.backend.disconnect() if plot is None: return self.plot = plot self.set_title( "Plot: %s" % plot.key ) self.backend = project.new_backend('gnuplot/x11', plot=plot) # connect signals for treeview # these are disconnect by the backend if it closes Signals.connect(self.backend, 'gnuplot-send-cmd', self.on_send_cmd) Signals.connect(self.backend, 'gnuplot-finish-cmd', self.on_finish_cmd) Signals.connect(self.backend, 'gnuplot-start-plotting', self.on_start_plotting) # connect signal for plot # these should be disconnected before the plot needs to do it. self._signals += [ Signals.connect(plot, "plot-changed", (lambda sender: self.backend.draw())), Signals.connect(plot, "closed", (lambda sender: self.destroy())) ] self.backend.draw()
def __call__(self, cmd): """Send string to gnuplot""" encoded_cmd = cmd.encode( self.encoding ) #encoded_cmd = cmd self.gpout.flush() Signals.emit(self, 'gnuplot-send-cmd', cmd=cmd) self.gpwrite.write(encoded_cmd + "\n") self.gpwrite.write("print '<--END-->'\n") self.gpwrite.flush() result = [] while result[-1:] != ["<--END-->\n"]: if self.process.poll() is not None: break result.append( self.gpout.readline() ) if len(result) == 0: result = None elif result[-1:] == ["<--END-->\n"]: result = result[:-1] self.history.append( (encoded_cmd, result) ) Signals.emit(self, 'gnuplot-finish-cmd', cmd=cmd, result=result) return result
def mouse_move(self, event): if not event.inaxes: return ax = event.inaxes minx, maxx = ax.get_xlim() miny, maxy = ax.get_ylim() x, y = event.xdata, event.ydata Signals.emit(self, "move", x, y)
def request_backend(self, key, plot=None): matches = self.find_backends(key=key, plot=plot) if len(matches) > 0: return matches[0] else: backend = BackendRegistry[key](project=self, plot=plot) self.backends.append(backend) Signals.emit(self, "notify::backends") return backend
def _cb_select_line(self, action): def finish_select_line(sender): print "FINISHED SELECT LINE", sender.line s = mpl_selector.SelectLine(self.backend.figure,mode=mpl_selector.SELECTLINE_VERTICAL) Signals.connect(s, "finished", finish_select_line) self.select(s)
def add_plotwidget(self, widget): n = self.plotbook.append_page(widget) self.plotbook.set_tab_label_text(widget, "Plot") # TODO: this signal should be a gobject signal Signals.connect(widget, "closed", self.detach_plotwidget) for ag in widget.get_actiongroups(): self.uimanager.insert_action_group(ag, 0) self.add_accel_group(self.uimanager.get_accel_group()) self.uimanager.add_ui_from_string(widget.get_uistring())
def load_project(self, filename): # load new project and if it is sucessfully loaded, # detach the old project new_project = load_project(filename) if new_project: self.set_project(new_project) self.recent_files.insert(0, os.path.abspath(filename)) if len(self.recent_files) > 10: self.recent_files.pop(-1) Signals.emit(self, "update-recent-files")
def __init__(self, app, project, plot): gtk.Window.__init__(self) self.set_size_request(width=360,height=400) self.app = app self.project = project self.plot = None # will be set after everything else is set up self.backend = None self._signals = list() # some icons are not right at all.... groups = { 'Common': [('Replot', gtk.STOCK_REFRESH, 'Replot', '<control>R', 'Replot everything', '_cb_replot'), ('Edit', gtk.STOCK_PROPERTIES, 'Edit Plot', None, 'Edit Plot', '_cb_edit_plot'), ('ZoomSelection', gtk.STOCK_ZOOM_FIT, 'use current range', None, 'Use Current Range', '_cb_zoom_selection'), ('ZoomAutoscale', gtk.STOCK_ZOOM_100, 'do not limit range', None, 'Do not limit Range', '_cb_zoom_autoscale'), ('ExportPostscript', gtk.STOCK_SAVE, 'export as postscript', None, 'Export as Postscript file', '_cb_export_postscript') ] } ui = \ """ <ui> <toolbar name='Toolbar'> <toolitem action='Replot'/> <separator/> <toolitem action='Edit'/> <toolitem action='ZoomSelection'/> <toolitem action='ZoomAutoscale'/> <separator/> <toolitem action='ExportPostscript'/> </toolbar> </ui> """ self.uimanager = self._construct_uimanager(groups,ui) self.toolbar = self._construct_toolbar() # vbox self.vbox = gtk.VBox(False) self.vbox.pack_start(self.toolbar, expand=False, fill=True) self.vbox.pack_start(self._construct_history(), expand=True, fill=True) self.vbox.show() self.add(self.vbox) self.connect("destroy", (lambda sender: self.destroy())) Signals.connect(self.project, "close", (lambda sender: self.destroy())) self.set_plot(plot)
def set_layer(self, layer): if layer == self.layer: return Signals.disconnect_list(self.layer_signals) self.layer = layer if layer is not None: # maybe connect to layer properties: is it visible, position, ... pass self.update_layer()
def set_current_layer(self, layer): """ Set the current layer. The layer must be either None or a Layer instance that is contained in self.layers. """ if layer is None or layer in self.layers: self._current_layer = layer Signals.emit(self, "notify::current_layer", layer) else: raise ValueError("Layer %s can't be set as current, because it is not part of the Plot!" % layer)
def set_backend(self, backend): if backend == self.backend: return Signals.disconnect_list(self.backend_signals) self.backend = backend self.update_backend() if backend is not None: self.set_layer(backend.layer) else: self.set_layer(None)
def _cb_zoom_axes(self, action): def finish_moving(sender): ul = UndoList().describe("Zoom") layer = self.backend.axes_to_layer[sender.axes] self.zoom_to_region(layer, sender.region, undolist=ul) self.project.journal.add_undo(ul) s = mpl_selector.ZoomAxes(self.backend.figure) Signals.connect(s, "finished", finish_moving) self.select(s)
def on_action_SelectLine(self, action): def finish_select_line(sender): print "FINISHED SELECT LINE", sender.line layer = self.backend.layer axes = self.backend.layer_to_axes[layer] s = mpl_selector.SelectLine(self.backend.figure, axes, mode=mpl_selector.SELECTLINE_VERTICAL) Signals.connect(s, "finished", finish_select_line) self.select(s)
def set_layer(self, layer): if layer == self.layer: return Signals.disconnect_list(self.layer_signals) self.layer = layer if layer is not None: self.layer_signals.append( Signals.connect(self.layer, "notify::labels", self.on_notify_labels) ) self.update_layer()
def mouse_move(self, event): if not event.inaxes: return ax = event.inaxes minx, maxx = ax.get_xlim() miny, maxy = ax.get_ylim() x, y = event.xdata, event.ydata Signals.emit("newcoords", x, y) # return value self.point = (x, y)
def button_press(self, event): ax = event.inaxes if event.button == 3: Signals.emit(self, "picked-axes", ax) elif event.button == 1: if ax is not None: obj = ax.pick(event.x, event.y) else: obj = None print "RMB, you picked", obj
def update_cols(self): """ Call this whenever you add/remove a column or when you change the type of a column. """ self._colcount = len(self._columns) self._typecodes = map(lambda x: x.typecode(), self._columns) type_map = {'d': float, 'f': float, 'O': str} self._converters = map(lambda tc: type_map[tc], self._typecodes) Signals.emit(self, 'update-columns') # FIXME
def update_cols(self): """ Call this whenever you add/remove a column or when you change the type of a column. """ self._ncols = len(self._columns) self._typecodes = map(lambda x: x.typecode(), self._columns) # TODO: move to types.h type_map = {'d': float, 'f': float, 'O': str, 'l': long, 'i': int} self._converters = map(lambda tc: type_map[tc], self._typecodes) Signals.emit(self, 'update-columns') # FIXME
def update_cols(self): """ Call this whenever you add/remove a column or when you change the type of a column. """ self._ncols = len(self._columns) self._typecodes = map(lambda x: x.typecode(), self._columns) # TODO: move to types.h type_map = {"d": float, "f": float, "O": str, "l": long} self._converters = map(lambda tc: type_map[tc], self._typecodes) Signals.emit(self, "update-columns") # FIXME
def new_plot(self, undolist=None): " Returns a new Plot. " if undolist is None: undolist = self.journal new_plot = new_lineplot2d() new_plot.key = pdict.unique_key(self.plots, "new lineplot2d") self.add_plot(new_plot) ui = UndoInfo(self.remove_plot, new_plot).describe("New Plot") undolist.append(ui) Signals.emit(self, "notify::plots") return new_plot
def set_new_index(self, index): " Sets the new index (but keeps the line). " if index >= self.bounds[0] and index <= self.bounds[1]: self.index = index xdata = self.line.get_xdata()[index] ydata = self.line.get_ydata()[index] self.point = (xdata, ydata) self.coords = self.axes.transData.xy_tup((xdata, ydata)) Signals.emit(self, "update-position", self.line, self.index, self.point) self.draw()
def on_action_MoveAxes(self, action): def finish_moving(sender): ul = UndoList().describe("Move Graph") layer = self.backend.axes_to_layer[sender.axes] self.zoom_to_region(layer, sender.region, undolist=ul) self.project.journal.add_undo(ul) layer = self.backend.layer axes = self.backend.layer_to_axes[layer] s = mpl_selector.MoveAxes(self.backend.figure, axes) Signals.connect(s, "finished", finish_moving) self.select(s)