def __init__(self, wintitle="plotpy plot", icon="plotpy.svg", toolbar=False, options=None, panels=None): PlotManager.__init__(self, main=self) self.plot_layout = QGridLayout() if options is None: options = {} self.plot_widget = None self.create_plot(options) if panels is not None: for panel in panels: self.add_panel(panel) self.toolbar = QToolBar(_("Tools")) if not toolbar: self.toolbar.hide() # Configuring widget layout self.setup_widget_properties(wintitle=wintitle, icon=icon) self.setup_widget_layout() # Configuring plot manager self.add_toolbar(self.toolbar, "default") self.register_tools()
def __init__(self, item, parent_layout): super(FloatArrayWidget, self).__init__(item, parent_layout) _label = item.get_prop_value("display", "label") self.groupbox = self.group = QGroupBox(_label) self.layout = QGridLayout() self.layout.setAlignment(Qt.AlignLeft) self.groupbox.setLayout(self.layout) self.first_line, self.dim_label = get_image_layout( "shape.png", _("Number of rows x Number of columns")) edit_button = QPushButton(get_icon("arredit.png"), "") edit_button.setToolTip(_("Edit array contents")) edit_button.setMaximumWidth(32) self.first_line.addWidget(edit_button) self.layout.addLayout(self.first_line, 0, 0) self.min_line, self.min_label = get_image_layout( "min.png", _("Smallest element in array")) self.layout.addLayout(self.min_line, 1, 0) self.max_line, self.max_label = get_image_layout( "max.png", _("Largest element in array")) self.layout.addLayout(self.max_line, 2, 0) edit_button.clicked.connect(self.edit_array) self.arr = None # le tableau si il a été modifié self.instance = None
class SubplotWidget(QSplitter): """Construct a Widget that helps managing several plots together handled by the same manager Since the plots must be added to the manager before the panels the add_itemlist method can be called after having declared all the subplots """ def __init__(self, manager, parent=None, **kwargs): super(SubplotWidget, self).__init__(parent, **kwargs) self.setOrientation(Qt.Horizontal) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.manager = manager self.plots = [] self.itemlist = None main = QWidget() self.plotlayout = QGridLayout() main.setLayout(self.plotlayout) self.addWidget(main) def add_itemlist(self, show_itemlist=False): self.itemlist = PlotItemList(self) self.itemlist.setVisible(show_itemlist) self.addWidget(self.itemlist) configure_plot_splitter(self) self.manager.add_panel(self.itemlist) def add_subplot(self, plot, i=0, j=0, plot_id=None): """Add a plot to the grid of plots""" self.plotlayout.addWidget(plot, i, j) self.plots.append(plot) if plot_id is None: plot_id = id(plot) self.manager.add_plot(plot, plot_id)
def __init__(self, wintitle): super(Window, self).__init__() self.default_tool = None self.plots = [] self.itemlist = PlotItemList(None) self.contrast = ContrastAdjustment(None) self.xcsw = XCrossSection(None) self.ycsw = YCrossSection(None) self.manager = PlotManager(self) self.toolbar = QToolBar(_("Tools"), self) self.manager.add_toolbar(self.toolbar, "default") self.toolbar.setMovable(True) self.toolbar.setFloatable(True) self.addToolBar(Qt.TopToolBarArea, self.toolbar) frame = QFrame(self) self.setCentralWidget(frame) self.layout = QGridLayout() layout = QVBoxLayout(frame) frame.setLayout(layout) layout.addLayout(self.layout) self.frame = frame self.setWindowTitle(wintitle) self.setWindowIcon(get_icon('plotpy.svg'))
def __init__(self, item, parent_layout): super(TabGroupWidget, self).__init__(item, parent_layout) self.tabs = QTabWidget() items = item.item.group self.widgets = [] for item in items: if item.get_prop_value("display", parent_layout.instance, "hide", False): continue item.set_prop("display", embedded=True) widget = parent_layout.build_widget(item) frame = QFrame() label = widget.item.get_prop_value("display", "label") icon = widget.item.get_prop_value("display", "icon", None) if icon is not None: self.tabs.addTab(frame, get_icon(icon), label) else: self.tabs.addTab(frame, label) layout = QGridLayout() layout.setAlignment(Qt.AlignTop) frame.setLayout(layout) widget.place_on_grid(layout, 0, 0, 1) try: widget.get() except Exception: print("Error building item :", item.item._name) raise self.widgets.append(widget)
def __init__(self, manager, parent=None, **kwargs): super(SubplotWidget, self).__init__(parent, **kwargs) self.setOrientation(Qt.Horizontal) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.manager = manager self.plots = [] self.itemlist = None main = QWidget() self.plotlayout = QGridLayout() main.setLayout(self.plotlayout) self.addWidget(main)
def __init__(self, item, parent_layout): super(FloatArrayWidget, self).__init__(item, parent_layout) _label = item.get_prop_value("display", "label") self.groupbox = self.group = QGroupBox(_label) self.layout = QGridLayout() self.layout.setAlignment(Qt.AlignLeft) self.groupbox.setLayout(self.layout) self.first_line, self.dim_label = get_image_layout("shape.png", _("Number of rows x Number of columns")) edit_button = QPushButton(get_icon("arredit.png"), "") edit_button.setToolTip(_("Edit array contents")) edit_button.setMaximumWidth(32) self.first_line.addWidget(edit_button) self.layout.addLayout(self.first_line, 0, 0) self.min_line, self.min_label = get_image_layout("min.png", _("Smallest element in array")) self.layout.addLayout(self.min_line, 1, 0) self.max_line, self.max_label = get_image_layout("max.png", _("Largest element in array")) self.layout.addLayout(self.max_line, 2, 0) edit_button.clicked.connect(self.edit_array) self.arr = None # le tableau si il a été modifié self.instance = None
def setup_widget_layout(self): self.fit_layout = QHBoxLayout() self.params_layout = QGridLayout() params_group = create_groupbox(self, _("Fit parameters"), layout=self.params_layout) if self.auto_fit_enabled: auto_group = self.create_autofit_group() self.fit_layout.addWidget(auto_group) self.fit_layout.addWidget(params_group) self.plot_layout.addLayout(self.fit_layout, 1, 0) vlayout = QVBoxLayout(self) vlayout.addWidget(self.toolbar) vlayout.addLayout(self.plot_layout) self.setLayout(vlayout)
def __init__(self, parent): QWidget.__init__(self, parent) layout = QGridLayout() self.setLayout(layout) self.plot1 = ImagePlot(self) layout.addWidget(self.plot1, 0, 0, 1, 1) self.plot2 = ImagePlot(self) layout.addWidget(self.plot2, 1, 0, 1, 1) self.contrast = ContrastAdjustment(self) layout.addWidget(self.contrast, 2, 0, 1, 2) self.itemlist = PlotItemList(self) layout.addWidget(self.itemlist, 0, 1, 2, 1) self.manager = PlotManager(self) for plot in (self.plot1, self.plot2): self.manager.add_plot(plot) for panel in (self.itemlist, self.contrast): self.manager.add_panel(panel)
def __init__(self, item, parent_layout): super(GroupWidget, self).__init__(item, parent_layout) embedded = item.get_prop_value("display", "embedded", False) if not embedded: self.group = QGroupBox(item.get_prop_value("display", "label")) else: self.group = QFrame() self.layout = QGridLayout() EditLayoutClass = parent_layout.__class__ self.edit = EditLayoutClass(self.group, item.instance, self.layout, item.item.group) self.group.setLayout(self.layout)
def __init__(self, label, klass, wordwrap=False, **kwargs): QGroupBox.__init__(self, label) self.klass = klass self.dataset = klass(**kwargs) self.layout = QVBoxLayout() if self.dataset.get_comment(): label = QLabel(self.dataset.get_comment()) label.setWordWrap(wordwrap) self.layout.addWidget(label) self.grid_layout = QGridLayout() self.layout.addLayout(self.grid_layout) self.setLayout(self.layout) self.edit = self.get_edit_layout()
def __init__(self, item, parent_layout): super(DataSetWidget, self).__init__(item, parent_layout) self.dataset = self.klass() # Création du layout contenant les champs d'édition du signal embedded = item.get_prop_value("display", "embedded", False) if not embedded: self.group = QGroupBox(item.get_prop_value("display", "label")) else: self.group = QFrame() self.layout = QGridLayout() self.group.setLayout(self.layout) EditLayoutClass = parent_layout.__class__ self.edit = EditLayoutClass(self.parent_layout.parent, self.dataset, self.layout)
def __init__(self, item, parent_layout): super(MultipleChoiceWidget, self).__init__(item, parent_layout) self.groupbox = self.group = QGroupBox(item.get_prop_value("display", "label")) layout = QGridLayout() self.boxes = [] nx, ny = item.get_prop_value("display", "shape") cx, cy = 0, 0 _choices = item.get_prop_value("data", "choices") for _, choice, _img in _choices: checkbox = QCheckBox(choice) layout.addWidget(checkbox, cx, cy) if nx < 0: cy += 1 if cy >= ny: cy = 0 cx += 1 else: cx += 1 if cx >= nx: cx = 0 cy += 1 self.boxes.append(checkbox) self.groupbox.setLayout(layout)
def __init__(self, item, parent_layout): super(MultipleChoiceWidget, self).__init__(item, parent_layout) self.groupbox = self.group = QGroupBox( item.get_prop_value("display", "label")) layout = QGridLayout() self.boxes = [] nx, ny = item.get_prop_value("display", "shape") cx, cy = 0, 0 _choices = item.get_prop_value("data", "choices") for _, choice, _img in _choices: checkbox = QCheckBox(choice) layout.addWidget(checkbox, cx, cy) if nx < 0: cy += 1 if cy >= ny: cy = 0 cx += 1 else: cx += 1 if cx >= nx: cx = 0 cy += 1 self.boxes.append(checkbox) self.groupbox.setLayout(layout)
def setup_instance(self, instance): """Override DataSetEditDialog method""" from plotpy.dataset.datatypes import DataSetGroup assert isinstance(instance, DataSetGroup) tabs = QTabWidget() # tabs.setUsesScrollButtons(False) self.layout.addWidget(tabs) for dataset in instance.datasets: layout = QVBoxLayout() layout.setAlignment(Qt.AlignTop) if dataset.get_comment(): label = QLabel(dataset.get_comment()) label.setWordWrap(self.wordwrap) layout.addWidget(label) grid = QGridLayout() self.edit_layout.append(self.layout_factory(dataset, grid)) layout.addLayout(grid) page = QWidget() page.setLayout(layout) if dataset.get_icon(): tabs.addTab(page, get_icon(dataset.get_icon()), dataset.get_title()) else: tabs.addTab(page, dataset.get_title())
def setup_instance(self, instance): """Construct main layout""" grid = QGridLayout() grid.setAlignment(Qt.AlignTop) self.layout.addLayout(grid) self.edit_layout.append( self.layout_factory( instance, grid) )
def setup_instance(self, instance): """Construct main layout""" grid = QGridLayout() grid.setAlignment(Qt.AlignTop) self.layout.addLayout(grid) self.edit_layout.append(self.layout_factory(instance, grid))
class Window(QMainWindow): def __init__(self, wintitle): super(Window, self).__init__() self.default_tool = None self.plots = [] self.itemlist = PlotItemList(None) self.contrast = ContrastAdjustment(None) self.xcsw = XCrossSection(None) self.ycsw = YCrossSection(None) self.manager = PlotManager(self) self.toolbar = QToolBar(_("Tools"), self) self.manager.add_toolbar(self.toolbar, "default") self.toolbar.setMovable(True) self.toolbar.setFloatable(True) self.addToolBar(Qt.TopToolBarArea, self.toolbar) frame = QFrame(self) self.setCentralWidget(frame) self.layout = QGridLayout() layout = QVBoxLayout(frame) frame.setLayout(layout) layout.addLayout(self.layout) self.frame = frame self.setWindowTitle(wintitle) self.setWindowIcon(get_icon('plotpy.svg')) def closeEvent(self, event): global _figures, _current_fig, _current_axes figure_title = to_text_string(self.windowTitle()) if _figures.pop(figure_title) == _current_fig: _current_fig = None _current_axes = None self.itemlist.close() self.contrast.close() self.xcsw.close() self.ycsw.close() event.accept() def add_plot(self, i, j, plot): self.layout.addWidget(plot, i, j) self.manager.add_plot(plot) self.plots.append(plot) def replot(self): for plot in self.plots: plot.replot() item = plot.get_default_item() if item is not None: plot.set_active_item(item) item.unselect() def add_panels(self, images=False): self.manager.add_panel(self.itemlist) if images: for panel in (self.ycsw, self.xcsw, self.contrast): panel.hide() self.manager.add_panel(panel) def register_tools(self, images=False): if images: self.manager.register_all_image_tools() else: self.manager.register_all_curve_tools() def display(self): self.show() self.replot() self.manager.get_default_tool().activate() self.manager.update_tools_status()
class FloatArrayWidget(AbstractDataSetWidget): """ FloatArrayItem widget """ def __init__(self, item, parent_layout): super(FloatArrayWidget, self).__init__(item, parent_layout) _label = item.get_prop_value("display", "label") self.groupbox = self.group = QGroupBox(_label) self.layout = QGridLayout() self.layout.setAlignment(Qt.AlignLeft) self.groupbox.setLayout(self.layout) self.first_line, self.dim_label = get_image_layout("shape.png", _("Number of rows x Number of columns")) edit_button = QPushButton(get_icon("arredit.png"), "") edit_button.setToolTip(_("Edit array contents")) edit_button.setMaximumWidth(32) self.first_line.addWidget(edit_button) self.layout.addLayout(self.first_line, 0, 0) self.min_line, self.min_label = get_image_layout("min.png", _("Smallest element in array")) self.layout.addLayout(self.min_line, 1, 0) self.max_line, self.max_label = get_image_layout("max.png", _("Largest element in array")) self.layout.addLayout(self.max_line, 2, 0) edit_button.clicked.connect(self.edit_array) self.arr = None # le tableau si il a été modifié self.instance = None def edit_array(self): """Open an array editor dialog""" parent = self.parent_layout.parent label = self.item.get_prop_value("display", "label") try: # Spyder 3.0 from spyder.widgets.variableexplorer import arrayeditor except ImportError: # Spyder 3.0- try: from spyderlib.widgets.variableexplorer import arrayeditor except ImportError: # Spyder 2 from spyderlib.widgets import arrayeditor editor = arrayeditor.ArrayEditor(parent) if editor.setup_and_check(self.arr, title=label): if editor.exec_(): self.update(self.arr) def get(self): """Override AbstractDataSetWidget method""" self.arr = numpy.array(self.item.get(), copy=False) if self.item.get_prop_value("display", "transpose"): self.arr = self.arr.T self.update(self.arr) def update(self, arr): """Override AbstractDataSetWidget method""" shape = arr.shape if len(shape) == 1: shape = (1,) + shape dim = " x ".join( [ str(d) for d in shape ]) self.dim_label.setText(dim) format = self.item.get_prop_value("display", "format") minmax = self.item.get_prop_value("display", "minmax") try: if minmax == "all": mint = format % arr.min() maxt = format % arr.max() elif minmax == "columns": mint = ", ".join([format % arr[r,:].min() for r in range(arr.shape[0])]) maxt = ", ".join([format % arr[r,:].max() for r in range(arr.shape[0])]) else: mint = ", ".join([format % arr[:, r].min() for r in range(arr.shape[1])]) maxt = ", ".join([format % arr[:, r].max() for r in range(arr.shape[1])]) except (TypeError, IndexError): mint, maxt = "-", "-" self.min_label.setText(mint) self.max_label.setText(maxt) def set(self): """Override AbstractDataSetWidget method""" if self.item.get_prop_value("display", "transpose"): value = self.value().T else: value = self.value() self.item.set(value) def value(self): return self.arr def place_on_grid(self, layout, row, label_column, widget_column, row_span=1, column_span=1): """Override AbstractDataSetWidget method""" layout.addWidget(self.group, row, label_column, row_span, column_span+1)
class FitWidgetMixin(CurveWidgetMixin): def __init__(self, wintitle="plotpy plot", icon="plotpy.svg", toolbar=False, options=None, panels=None, param_cols=1, legend_anchor='TR', auto_fit=True): if wintitle is None: wintitle = _('Curve fitting') self.x = None self.y = None self.fitfunc = None self.fitargs = None self.fitkwargs = None self.fitparams = None self.autofit_prm = None self.data_curve = None self.fit_curve = None self.legend = None self.legend_anchor = legend_anchor self.xrange = None self.show_xrange = False self.param_cols = param_cols self.auto_fit_enabled = auto_fit self.button_list = [] # list of buttons to be disabled at startup self.fit_layout = None self.params_layout = None CurveWidgetMixin.__init__(self, wintitle=wintitle, icon=icon, toolbar=toolbar, options=options, panels=panels) self.refresh() # QWidget API -------------------------------------------------------------- def resizeEvent(self, event): QWidget.resizeEvent(self, event) self.get_plot().replot() # CurveWidgetMixin API ----------------------------------------------------- def setup_widget_layout(self): self.fit_layout = QHBoxLayout() self.params_layout = QGridLayout() params_group = create_groupbox(self, _("Fit parameters"), layout=self.params_layout) if self.auto_fit_enabled: auto_group = self.create_autofit_group() self.fit_layout.addWidget(auto_group) self.fit_layout.addWidget(params_group) self.plot_layout.addLayout(self.fit_layout, 1, 0) vlayout = QVBoxLayout(self) vlayout.addWidget(self.toolbar) vlayout.addLayout(self.plot_layout) self.setLayout(vlayout) def create_plot(self, options): CurveWidgetMixin.create_plot(self, options) for plot in self.get_plots(): plot.SIG_RANGE_CHANGED.connect(self.range_changed) # Public API --------------------------------------------------------------- def set_data(self, x, y, fitfunc=None, fitparams=None, fitargs=None, fitkwargs=None): if self.fitparams is not None and fitparams is not None: self.clear_params_layout() self.x = x self.y = y if fitfunc is not None: self.fitfunc = fitfunc if fitparams is not None: self.fitparams = fitparams if fitargs is not None: self.fitargs = fitargs if fitkwargs is not None: self.fitkwargs = fitkwargs self.autofit_prm = AutoFitParam(title=_("Automatic fitting options")) self.autofit_prm.xmin = x.min() self.autofit_prm.xmax = x.max() self.compute_imin_imax() if self.fitparams is not None and fitparams is not None: self.populate_params_layout() self.refresh() def set_fit_data(self, fitfunc, fitparams, fitargs=None, fitkwargs=None): if self.fitparams is not None: self.clear_params_layout() self.fitfunc = fitfunc self.fitparams = fitparams self.fitargs = fitargs self.fitkwargs = fitkwargs self.populate_params_layout() self.refresh() def clear_params_layout(self): for i, param in enumerate(self.fitparams): for widget in param.get_widgets(): if widget is not None: self.params_layout.removeWidget(widget) widget.hide() def populate_params_layout(self): add_fitparam_widgets_to(self.params_layout, self.fitparams, self.refresh, param_cols=self.param_cols) def create_autofit_group(self): auto_button = QPushButton(get_icon('apply.png'), _("Run"), self) auto_button.clicked.connect(self.autofit) autoprm_button = QPushButton(get_icon('settings.png'), _("Settings"), self) autoprm_button.clicked.connect(self.edit_parameters) xrange_button = QPushButton(get_icon('xrange.png'), _("Bounds"), self) xrange_button.setCheckable(True) xrange_button.toggled.connect(self.toggle_xrange) auto_layout = QVBoxLayout() auto_layout.addWidget(auto_button) auto_layout.addWidget(autoprm_button) auto_layout.addWidget(xrange_button) self.button_list += [auto_button, autoprm_button, xrange_button] return create_groupbox(self, _("Automatic fit"), layout=auto_layout) def get_fitfunc_arguments(self): """Return fitargs and fitkwargs""" fitargs = self.fitargs if self.fitargs is None: fitargs = [] fitkwargs = self.fitkwargs if self.fitkwargs is None: fitkwargs = {} return fitargs, fitkwargs def refresh(self, slider_value=None): """Refresh Fit Tool dialog box""" # Update button states enable = self.x is not None and self.y is not None \ and self.x.size > 0 and self.y.size > 0 \ and self.fitfunc is not None and self.fitparams is not None \ and len(self.fitparams) > 0 for btn in self.button_list: btn.setEnabled(enable) if not enable: # Fit widget is not yet configured return fitargs, fitkwargs = self.get_fitfunc_arguments() yfit = self.fitfunc(self.x, [p.value for p in self.fitparams], *fitargs, **fitkwargs) plot = self.get_plot() if self.legend is None: self.legend = make.legend(anchor=self.legend_anchor) plot.add_item(self.legend) if self.xrange is None: self.xrange = make.range(0., 1.) plot.add_item(self.xrange) self.xrange.set_range(self.autofit_prm.xmin, self.autofit_prm.xmax) self.xrange.setVisible(self.show_xrange) if self.data_curve is None: self.data_curve = make.curve([], [], _("Data"), color="b", linewidth=2) plot.add_item(self.data_curve) self.data_curve.set_data(self.x, self.y) if self.fit_curve is None: self.fit_curve = make.curve([], [], _("Fit"), color="r", linewidth=2) plot.add_item(self.fit_curve) self.fit_curve.set_data(self.x, yfit) plot.replot() plot.disable_autoscale() def range_changed(self, xrange_obj, xmin, xmax): self.autofit_prm.xmin, self.autofit_prm.xmax = xmin, xmax self.compute_imin_imax() def toggle_xrange(self, state): self.xrange.setVisible(state) plot = self.get_plot() plot.replot() if state: plot.set_active_item(self.xrange) self.show_xrange = state def edit_parameters(self): if self.autofit_prm.edit(parent=self): self.xrange.set_range(self.autofit_prm.xmin, self.autofit_prm.xmax) plot = self.get_plot() plot.replot() self.compute_imin_imax() def compute_imin_imax(self): self.i_min = self.x.searchsorted(self.autofit_prm.xmin) self.i_max = self.x.searchsorted(self.autofit_prm.xmax, side='right') def errorfunc(self, params): x = self.x[self.i_min:self.i_max] y = self.y[self.i_min:self.i_max] fitargs, fitkwargs = self.get_fitfunc_arguments() return y - self.fitfunc(x, params, *fitargs, **fitkwargs) def autofit(self): meth = self.autofit_prm.method x0 = np.array([p.value for p in self.fitparams]) if meth == "lq": x = self.autofit_lq(x0) elif meth == "simplex": x = self.autofit_simplex(x0) elif meth == "powel": x = self.autofit_powel(x0) elif meth == "bfgs": x = self.autofit_bfgs(x0) elif meth == "l_bfgs_b": x = self.autofit_l_bfgs(x0) elif meth == "cg": x = self.autofit_cg(x0) else: return for v, p in zip(x, self.fitparams): p.value = v self.refresh() for prm in self.fitparams: prm.update() def get_norm_func(self): prm = self.autofit_prm err_norm = eval(prm.err_norm) def func(params): err = np.linalg.norm(self.errorfunc(params), err_norm) return err return func def autofit_simplex(self, x0): prm = self.autofit_prm from scipy.optimize import fmin x = fmin(self.get_norm_func(), x0, xtol=prm.xtol, ftol=prm.ftol) return x def autofit_powel(self, x0): prm = self.autofit_prm from scipy.optimize import fmin_powell x = fmin_powell(self.get_norm_func(), x0, xtol=prm.xtol, ftol=prm.ftol) return x def autofit_bfgs(self, x0): prm = self.autofit_prm from scipy.optimize import fmin_bfgs x = fmin_bfgs(self.get_norm_func(), x0, gtol=prm.gtol, norm=eval(prm.norm)) return x def autofit_l_bfgs(self, x0): prm = self.autofit_prm bounds = [(p.min, p.max) for p in self.fitparams] from scipy.optimize import fmin_l_bfgs_b x, _f, _d = fmin_l_bfgs_b(self.get_norm_func(), x0, pgtol=prm.gtol, approx_grad=1, bounds=bounds) return x def autofit_cg(self, x0): prm = self.autofit_prm from scipy.optimize import fmin_cg x = fmin_cg(self.get_norm_func(), x0, gtol=prm.gtol, norm=eval(prm.norm)) return x def autofit_lq(self, x0): prm = self.autofit_prm def func(params): err = self.errorfunc(params) return err from scipy.optimize import leastsq x, _ier = leastsq(func, x0, xtol=prm.xtol, ftol=prm.ftol) return x def get_values(self): """Convenience method to get fit parameter values""" return [param.value for param in self.fitparams]
class CurveWidgetMixin(PlotManager): def __init__(self, wintitle="plotpy plot", icon="plotpy.svg", toolbar=False, options=None, panels=None): PlotManager.__init__(self, main=self) self.plot_layout = QGridLayout() if options is None: options = {} self.plot_widget = None self.create_plot(options) if panels is not None: for panel in panels: self.add_panel(panel) self.toolbar = QToolBar(_("Tools")) if not toolbar: self.toolbar.hide() # Configuring widget layout self.setup_widget_properties(wintitle=wintitle, icon=icon) self.setup_widget_layout() # Configuring plot manager self.add_toolbar(self.toolbar, "default") self.register_tools() def setup_widget_layout(self): raise NotImplementedError def setup_widget_properties(self, wintitle, icon): self.setWindowTitle(wintitle) if is_text_string(icon): icon = get_icon(icon) if icon is not None: self.setWindowIcon(icon) self.setMinimumSize(320, 240) self.resize(640, 480) def register_tools(self): """ Register the plotting dialog box tools: the base implementation provides standard, curve-related and other tools - i.e. calling this method is exactly the same as calling :py:meth:`plotpy.plot.CurveDialog.register_all_curve_tools` This method may be overriden to provide a fully customized set of tools """ self.register_all_curve_tools() def create_plot(self, options, row=0, column=0, rowspan=1, columnspan=1): """ Create the plotting widget (which is an instance of class :py:class:`plotpy.plot.BaseCurveWidget`), add it to the dialog box main layout (:py:attr:`plotpy.plot.CurveDialog.plot_layout`) and then add the `item list` panel May be overriden to customize the plot layout (:py:attr:`plotpy.plot.CurveDialog.plot_layout`) """ self.plot_widget = BaseCurveWidget(self, **options) self.plot_layout.addWidget(self.plot_widget, row, column, rowspan, columnspan) # Configuring plot manager self.add_plot(self.plot_widget.plot) self.add_panel(self.plot_widget.itemlist)
class FloatArrayWidget(AbstractDataSetWidget): """ FloatArrayItem widget """ def __init__(self, item, parent_layout): super(FloatArrayWidget, self).__init__(item, parent_layout) _label = item.get_prop_value("display", "label") self.groupbox = self.group = QGroupBox(_label) self.layout = QGridLayout() self.layout.setAlignment(Qt.AlignLeft) self.groupbox.setLayout(self.layout) self.first_line, self.dim_label = get_image_layout( "shape.png", _("Number of rows x Number of columns")) edit_button = QPushButton(get_icon("arredit.png"), "") edit_button.setToolTip(_("Edit array contents")) edit_button.setMaximumWidth(32) self.first_line.addWidget(edit_button) self.layout.addLayout(self.first_line, 0, 0) self.min_line, self.min_label = get_image_layout( "min.png", _("Smallest element in array")) self.layout.addLayout(self.min_line, 1, 0) self.max_line, self.max_label = get_image_layout( "max.png", _("Largest element in array")) self.layout.addLayout(self.max_line, 2, 0) edit_button.clicked.connect(self.edit_array) self.arr = None # le tableau si il a été modifié self.instance = None def edit_array(self): """Open an array editor dialog""" parent = self.parent_layout.parent label = self.item.get_prop_value("display", "label") try: # Spyder 3.0 from spyder.widgets.variableexplorer import arrayeditor except ImportError: # Spyder 3.0- try: from spyderlib.widgets.variableexplorer import arrayeditor except ImportError: # Spyder 2 from spyderlib.widgets import arrayeditor editor = arrayeditor.ArrayEditor(parent) if editor.setup_and_check(self.arr, title=label): if editor.exec_(): self.update(self.arr) def get(self): """Override AbstractDataSetWidget method""" self.arr = numpy.array(self.item.get(), copy=False) if self.item.get_prop_value("display", "transpose"): self.arr = self.arr.T self.update(self.arr) def update(self, arr): """Override AbstractDataSetWidget method""" shape = arr.shape if len(shape) == 1: shape = (1, ) + shape dim = " x ".join([str(d) for d in shape]) self.dim_label.setText(dim) format = self.item.get_prop_value("display", "format") minmax = self.item.get_prop_value("display", "minmax") try: if minmax == "all": mint = format % arr.min() maxt = format % arr.max() elif minmax == "columns": mint = ", ".join( [format % arr[r, :].min() for r in range(arr.shape[0])]) maxt = ", ".join( [format % arr[r, :].max() for r in range(arr.shape[0])]) else: mint = ", ".join( [format % arr[:, r].min() for r in range(arr.shape[1])]) maxt = ", ".join( [format % arr[:, r].max() for r in range(arr.shape[1])]) except (TypeError, IndexError): mint, maxt = "-", "-" self.min_label.setText(mint) self.max_label.setText(maxt) def set(self): """Override AbstractDataSetWidget method""" if self.item.get_prop_value("display", "transpose"): value = self.value().T else: value = self.value() self.item.set(value) def value(self): return self.arr def place_on_grid(self, layout, row, label_column, widget_column, row_span=1, column_span=1): """Override AbstractDataSetWidget method""" layout.addWidget(self.group, row, label_column, row_span, column_span + 1)
class FitWidgetMixin(CurveWidgetMixin): def __init__(self, wintitle="plotpy plot", icon="plotpy.svg", toolbar=False, options=None, panels=None, param_cols=1, legend_anchor='TR', auto_fit=True): if wintitle is None: wintitle = _('Curve fitting') self.x = None self.y = None self.fitfunc = None self.fitargs = None self.fitkwargs = None self.fitparams = None self.autofit_prm = None self.data_curve = None self.fit_curve = None self.legend = None self.legend_anchor = legend_anchor self.xrange = None self.show_xrange = False self.param_cols = param_cols self.auto_fit_enabled = auto_fit self.button_list = [] # list of buttons to be disabled at startup self.fit_layout = None self.params_layout = None CurveWidgetMixin.__init__(self, wintitle=wintitle, icon=icon, toolbar=toolbar, options=options, panels=panels) self.refresh() # QWidget API -------------------------------------------------------------- def resizeEvent(self, event): QWidget.resizeEvent(self, event) self.get_plot().replot() # CurveWidgetMixin API ----------------------------------------------------- def setup_widget_layout(self): self.fit_layout = QHBoxLayout() self.params_layout = QGridLayout() params_group = create_groupbox(self, _("Fit parameters"), layout=self.params_layout) if self.auto_fit_enabled: auto_group = self.create_autofit_group() self.fit_layout.addWidget(auto_group) self.fit_layout.addWidget(params_group) self.plot_layout.addLayout(self.fit_layout, 1, 0) vlayout = QVBoxLayout(self) vlayout.addWidget(self.toolbar) vlayout.addLayout(self.plot_layout) self.setLayout(vlayout) def create_plot(self, options): CurveWidgetMixin.create_plot(self, options) for plot in self.get_plots(): plot.SIG_RANGE_CHANGED.connect(self.range_changed) # Public API --------------------------------------------------------------- def set_data(self, x, y, fitfunc=None, fitparams=None, fitargs=None, fitkwargs=None): if self.fitparams is not None and fitparams is not None: self.clear_params_layout() self.x = x self.y = y if fitfunc is not None: self.fitfunc = fitfunc if fitparams is not None: self.fitparams = fitparams if fitargs is not None: self.fitargs = fitargs if fitkwargs is not None: self.fitkwargs = fitkwargs self.autofit_prm = AutoFitParam(title=_("Automatic fitting options")) self.autofit_prm.xmin = x.min() self.autofit_prm.xmax = x.max() self.compute_imin_imax() if self.fitparams is not None and fitparams is not None: self.populate_params_layout() self.refresh() def set_fit_data(self, fitfunc, fitparams, fitargs=None, fitkwargs=None): if self.fitparams is not None: self.clear_params_layout() self.fitfunc = fitfunc self.fitparams = fitparams self.fitargs = fitargs self.fitkwargs = fitkwargs self.populate_params_layout() self.refresh() def clear_params_layout(self): for i, param in enumerate(self.fitparams): for widget in param.get_widgets(): if widget is not None: self.params_layout.removeWidget(widget) widget.hide() def populate_params_layout(self): add_fitparam_widgets_to(self.params_layout, self.fitparams, self.refresh, param_cols=self.param_cols) def create_autofit_group(self): auto_button = QPushButton(get_icon('apply.png'), _("Run"), self) auto_button.clicked.connect(self.autofit) autoprm_button = QPushButton(get_icon('settings.png'), _("Settings"), self) autoprm_button.clicked.connect(self.edit_parameters) xrange_button = QPushButton(get_icon('xrange.png'), _("Bounds"), self) xrange_button.setCheckable(True) xrange_button.toggled.connect(self.toggle_xrange) auto_layout = QVBoxLayout() auto_layout.addWidget(auto_button) auto_layout.addWidget(autoprm_button) auto_layout.addWidget(xrange_button) self.button_list += [auto_button, autoprm_button, xrange_button] return create_groupbox(self, _("Automatic fit"), layout=auto_layout) def get_fitfunc_arguments(self): """Return fitargs and fitkwargs""" fitargs = self.fitargs if self.fitargs is None: fitargs = [] fitkwargs = self.fitkwargs if self.fitkwargs is None: fitkwargs = {} return fitargs, fitkwargs def refresh(self, slider_value=None): """Refresh Fit Tool dialog box""" # Update button states enable = self.x is not None and self.y is not None \ and self.x.size > 0 and self.y.size > 0 \ and self.fitfunc is not None and self.fitparams is not None \ and len(self.fitparams) > 0 for btn in self.button_list: btn.setEnabled(enable) if not enable: # Fit widget is not yet configured return fitargs, fitkwargs = self.get_fitfunc_arguments() yfit = self.fitfunc(self.x, [p.value for p in self.fitparams], *fitargs, **fitkwargs) plot = self.get_plot() if self.legend is None: self.legend = make.legend(anchor=self.legend_anchor) plot.add_item(self.legend) if self.xrange is None: self.xrange = make.range(0., 1.) plot.add_item(self.xrange) self.xrange.set_range(self.autofit_prm.xmin, self.autofit_prm.xmax) self.xrange.setVisible(self.show_xrange) if self.data_curve is None: self.data_curve = make.curve([], [], _("Data"), color="b", linewidth=2) plot.add_item(self.data_curve) self.data_curve.set_data(self.x, self.y) if self.fit_curve is None: self.fit_curve = make.curve([], [], _("Fit"), color="r", linewidth=2) plot.add_item(self.fit_curve) self.fit_curve.set_data(self.x, yfit) plot.replot() plot.disable_autoscale() def range_changed(self, xrange_obj, xmin, xmax): self.autofit_prm.xmin, self.autofit_prm.xmax = xmin, xmax self.compute_imin_imax() def toggle_xrange(self, state): self.xrange.setVisible(state) plot = self.get_plot() plot.replot() if state: plot.set_active_item(self.xrange) self.show_xrange = state def edit_parameters(self): if self.autofit_prm.edit(parent=self): self.xrange.set_range(self.autofit_prm.xmin, self.autofit_prm.xmax) plot = self.get_plot() plot.replot() self.compute_imin_imax() def compute_imin_imax(self): self.i_min = self.x.searchsorted(self.autofit_prm.xmin) self.i_max = self.x.searchsorted(self.autofit_prm.xmax, side='right') def errorfunc(self, params): x = self.x[self.i_min:self.i_max] y = self.y[self.i_min:self.i_max] fitargs, fitkwargs = self.get_fitfunc_arguments() return y - self.fitfunc(x, params, *fitargs, **fitkwargs) def autofit(self): meth = self.autofit_prm.method x0 = np.array([p.value for p in self.fitparams]) if meth == "lq": x = self.autofit_lq(x0) elif meth=="simplex": x = self.autofit_simplex(x0) elif meth=="powel": x = self.autofit_powel(x0) elif meth=="bfgs": x = self.autofit_bfgs(x0) elif meth=="l_bfgs_b": x = self.autofit_l_bfgs(x0) elif meth=="cg": x = self.autofit_cg(x0) else: return for v, p in zip(x, self.fitparams): p.value = v self.refresh() for prm in self.fitparams: prm.update() def get_norm_func(self): prm = self.autofit_prm err_norm = eval(prm.err_norm) def func(params): err = np.linalg.norm(self.errorfunc(params), err_norm) return err return func def autofit_simplex(self, x0): prm = self.autofit_prm from scipy.optimize import fmin x = fmin(self.get_norm_func(), x0, xtol=prm.xtol, ftol=prm.ftol) return x def autofit_powel(self, x0): prm = self.autofit_prm from scipy.optimize import fmin_powell x = fmin_powell(self.get_norm_func(), x0, xtol=prm.xtol, ftol=prm.ftol) return x def autofit_bfgs(self, x0): prm = self.autofit_prm from scipy.optimize import fmin_bfgs x = fmin_bfgs(self.get_norm_func(), x0, gtol=prm.gtol, norm=eval(prm.norm)) return x def autofit_l_bfgs(self, x0): prm = self.autofit_prm bounds = [(p.min, p.max) for p in self.fitparams] from scipy.optimize import fmin_l_bfgs_b x, _f, _d = fmin_l_bfgs_b(self.get_norm_func(), x0, pgtol=prm.gtol, approx_grad=1, bounds=bounds) return x def autofit_cg(self, x0): prm = self.autofit_prm from scipy.optimize import fmin_cg x = fmin_cg(self.get_norm_func(), x0, gtol=prm.gtol, norm=eval(prm.norm)) return x def autofit_lq(self, x0): prm = self.autofit_prm def func(params): err = self.errorfunc(params) return err from scipy.optimize import leastsq x, _ier = leastsq(func, x0, xtol=prm.xtol, ftol=prm.ftol) return x def get_values(self): """Convenience method to get fit parameter values""" return [param.value for param in self.fitparams]