source: sasview/src/sas/qtgui/Plotting/Plotter.py @ 3c4f02e

ESS_GUIESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 3c4f02e was d0952de, checked in by wojciech, 6 years ago

Enabled linear scale for Dmax plots

  • Property mode set to 100644
File size: 25.9 KB
Line 
1from PyQt5 import QtCore
2from PyQt5 import QtGui
3from PyQt5 import QtWidgets
4
5import functools
6import copy
7import matplotlib as mpl
8import numpy as np
9from matplotlib.font_manager import FontProperties
10from sas.qtgui.Plotting.PlotterData import Data1D
11from sas.qtgui.Plotting.PlotterBase import PlotterBase
12from sas.qtgui.Plotting.AddText import AddText
13from sas.qtgui.Plotting.SetGraphRange import SetGraphRange
14from sas.qtgui.Plotting.LinearFit import LinearFit
15from sas.qtgui.Plotting.PlotProperties import PlotProperties
16from sas.qtgui.Plotting.ScaleProperties import ScaleProperties
17
18import sas.qtgui.Utilities.GuiUtils as GuiUtils
19import sas.qtgui.Plotting.PlotUtilities as PlotUtilities
20
21class PlotterWidget(PlotterBase):
22    """
23    1D Plot widget for use with a QDialog
24    """
25    def __init__(self, parent=None, manager=None, quickplot=False):
26        super(PlotterWidget, self).__init__(parent, manager=manager, quickplot=quickplot)
27
28        self.parent = parent
29
30        # Dictionary of {plot_id:Data1d}
31        self.plot_dict = {}
32        # Dictionaty of {plot_id:line}
33
34        self.plot_lines = {}
35        # Window for text add
36        self.addText = AddText(self)
37
38        # Log-ness of the axes
39        self.xLogLabel = "log10(x)"
40        self.yLogLabel = "log10(y)"
41
42        # Data container for the linear fit
43        self.fit_result = Data1D(x=[], y=[], dy=None)
44        self.fit_result.symbol = 13
45        self.fit_result.name = "Fit"
46
47    @property
48    def data(self):
49        return self._data
50
51    @data.setter
52    def data(self, value):
53        """ data setter """
54        self._data = value
55        if value._xunit:
56            self.xLabel = "%s(%s)"%(value._xaxis, value._xunit)
57        else:
58            self.xLabel = "%s"%(value._xaxis)
59        if value._yunit:
60            self.yLabel = "%s(%s)"%(value._yaxis, value._yunit)
61        else:
62            self.yLabel = "%s"%(value._yaxis)
63
64        if value.scale == 'linear' or value.isSesans:
65            self.xscale = 'linear'
66            self.yscale = 'linear'
67        self.title(title=value.name)
68
69    def plot(self, data=None, color=None, marker=None, hide_error=False, transform=True):
70        """
71        Add a new plot of self._data to the chart.
72        """
73        # Data1D
74        if isinstance(data, Data1D):
75            self.data = data
76        assert(self._data)
77
78        is_fit = (self.data.id=="fit")
79
80        if not is_fit:
81            # make sure we have some function to operate on
82            if self.data.xtransform is None:
83                self.data.xtransform = 'log10(x)'
84            if self.data.ytransform is None:
85                self.data.ytransform = 'log10(y)'
86            #Added condition to Dmax explorer from P(r) perspective
87            if self.data._xaxis == 'D_{max}':
88                self.xscale = 'linear'
89            # Transform data if required.
90            if transform and (self.data.xtransform is not None or self.data.ytransform is not None):
91                _, _, xscale, yscale = GuiUtils.xyTransform(self.data, self.data.xtransform, self.data.ytransform)
92                if xscale != 'log':
93                    self.xscale = xscale
94                if yscale != 'log':
95                    self.yscale = yscale
96
97                # Redefine the Scale properties dialog
98                self.properties = ScaleProperties(self,
99                                        init_scale_x=self.data.xtransform,
100                                        init_scale_y=self.data.ytransform)
101
102        # Shortcuts
103        ax = self.ax
104        x = self._data.view.x
105        y = self._data.view.y
106
107        # Marker symbol. Passed marker is one of matplotlib.markers characters
108        # Alternatively, picked up from Data1D as an int index of PlotUtilities.SHAPES dict
109        if marker is None:
110            marker = self.data.symbol
111            # Try name first
112            try:
113                marker = dict(PlotUtilities.SHAPES)[marker]
114            except KeyError:
115                marker = list(PlotUtilities.SHAPES.values())[marker]
116
117        assert marker is not None
118        # Plot name
119        if self.data.title:
120            self.title(title=self.data.title)
121        else:
122            self.title(title=self.data.name)
123
124        # Error marker toggle
125        if hide_error is None:
126            hide_error = self.data.hide_error
127
128        # Plot color
129        if color is None:
130            color = self.data.custom_color
131
132        color = PlotUtilities.getValidColor(color)
133        self.data.custom_color = color
134
135        markersize = self._data.markersize
136
137        # Include scaling (log vs. linear)
138        ax.set_xscale(self.xscale, nonposx='clip')
139        ax.set_yscale(self.yscale, nonposy='clip')
140
141        # define the ranges
142        self.setRange = SetGraphRange(parent=self,
143            x_range=self.ax.get_xlim(), y_range=self.ax.get_ylim())
144
145        # Draw non-standard markers
146        l_width = markersize * 0.4
147        if marker == '-' or marker == '--':
148            line = self.ax.plot(x, y, color=color, lw=l_width, marker='',
149                             linestyle=marker, label=self._title, zorder=10)[0]
150
151        elif marker == 'vline':
152            y_min = min(y)*9.0/10.0 if min(y) < 0 else 0.0
153            line = self.ax.vlines(x=x, ymin=y_min, ymax=y, color=color,
154                            linestyle='-', label=self._title, lw=l_width, zorder=1)
155
156        elif marker == 'step':
157            line = self.ax.step(x, y, color=color, marker='', linestyle='-',
158                                label=self._title, lw=l_width, zorder=1)[0]
159
160        else:
161            # plot data with/without errorbars
162            if hide_error:
163                line = ax.plot(x, y, marker=marker, color=color, markersize=markersize,
164                        linestyle='', label=self._title, picker=True)
165            else:
166                dy = self._data.view.dy
167                # Convert tuple (lo,hi) to array [(x-lo),(hi-x)]
168                if dy is not None and type(dy) == type(()):
169                    dy = np.vstack((y - dy[0], dy[1] - y)).transpose()
170
171                line = ax.errorbar(x, y,
172                            yerr=dy,
173                            xerr=None,
174                            capsize=2, linestyle='',
175                            barsabove=False,
176                            color=color,
177                            marker=marker,
178                            markersize=markersize,
179                            lolims=False, uplims=False,
180                            xlolims=False, xuplims=False,
181                            label=self._title,
182                            zorder=1,
183                            picker=True)
184
185        # Update the list of data sets (plots) in chart
186        self.plot_dict[self._data.name] = self.data
187
188        self.plot_lines[self._data.name] = line
189
190        # Now add the legend with some customizations.
191
192        if self.showLegend:
193            self.legend = ax.legend(loc='upper right', shadow=True)
194            if self.legend:
195                self.legend.set_picker(True)
196
197        # Current labels for axes
198        if self.y_label and not is_fit:
199            ax.set_ylabel(self.y_label)
200        if self.x_label and not is_fit:
201            ax.set_xlabel(self.x_label)
202
203        # refresh canvas
204        self.canvas.draw()
205
206    def createContextMenu(self):
207        """
208        Define common context menu and associated actions for the MPL widget
209        """
210        self.defaultContextMenu()
211
212        # Separate plots
213        self.addPlotsToContextMenu()
214
215        # Additional menu items
216        self.contextMenu.addSeparator()
217        self.actionAddText = self.contextMenu.addAction("Add Text")
218        self.actionRemoveText = self.contextMenu.addAction("Remove Text")
219        self.contextMenu.addSeparator()
220        self.actionChangeScale = self.contextMenu.addAction("Change Scale")
221        self.contextMenu.addSeparator()
222        self.actionSetGraphRange = self.contextMenu.addAction("Set Graph Range")
223        self.actionResetGraphRange =\
224            self.contextMenu.addAction("Reset Graph Range")
225        # Add the title change for dialogs
226        #if self.parent:
227        self.contextMenu.addSeparator()
228        self.actionWindowTitle = self.contextMenu.addAction("Window Title")
229
230        # Define the callbacks
231        self.actionAddText.triggered.connect(self.onAddText)
232        self.actionRemoveText.triggered.connect(self.onRemoveText)
233        self.actionChangeScale.triggered.connect(self.onScaleChange)
234        self.actionSetGraphRange.triggered.connect(self.onSetGraphRange)
235        self.actionResetGraphRange.triggered.connect(self.onResetGraphRange)
236        self.actionWindowTitle.triggered.connect(self.onWindowsTitle)
237
238    def addPlotsToContextMenu(self):
239        """
240        Adds operations on all plotted sets of data to the context menu
241        """
242        for id in list(self.plot_dict.keys()):
243            plot = self.plot_dict[id]
244
245            name = plot.name if plot.name else plot.title
246            plot_menu = self.contextMenu.addMenu('&%s' % name)
247
248            self.actionDataInfo = plot_menu.addAction("&DataInfo")
249            self.actionDataInfo.triggered.connect(
250                                functools.partial(self.onDataInfo, plot))
251
252            self.actionSavePointsAsFile = plot_menu.addAction("&Save Points as a File")
253            self.actionSavePointsAsFile.triggered.connect(
254                                functools.partial(self.onSavePoints, plot))
255            plot_menu.addSeparator()
256
257            if plot.id != 'fit':
258                self.actionLinearFit = plot_menu.addAction('&Linear Fit')
259                self.actionLinearFit.triggered.connect(
260                                functools.partial(self.onLinearFit, id))
261                plot_menu.addSeparator()
262
263            self.actionRemovePlot = plot_menu.addAction("Remove")
264            self.actionRemovePlot.triggered.connect(
265                                functools.partial(self.onRemovePlot, id))
266
267            if not plot.is_data:
268                self.actionFreeze = plot_menu.addAction('&Freeze')
269                self.actionFreeze.triggered.connect(
270                                functools.partial(self.onFreeze, id))
271            plot_menu.addSeparator()
272
273            if plot.is_data:
274                self.actionHideError = plot_menu.addAction("Hide Error Bar")
275                if plot.dy is not None and plot.dy != []:
276                    if plot.hide_error:
277                        self.actionHideError.setText('Show Error Bar')
278                else:
279                    self.actionHideError.setEnabled(False)
280                self.actionHideError.triggered.connect(
281                                functools.partial(self.onToggleHideError, id))
282                plot_menu.addSeparator()
283
284            self.actionModifyPlot = plot_menu.addAction('&Modify Plot Property')
285            self.actionModifyPlot.triggered.connect(
286                                functools.partial(self.onModifyPlot, id))
287
288    def createContextMenuQuick(self):
289        """
290        Define context menu and associated actions for the quickplot MPL widget
291        """
292        # Default actions
293        self.defaultContextMenu()
294
295        # Additional actions
296        self.actionToggleGrid = self.contextMenu.addAction("Toggle Grid On/Off")
297        self.contextMenu.addSeparator()
298        self.actionChangeScale = self.contextMenu.addAction("Change Scale")
299
300        # Define the callbacks
301        self.actionToggleGrid.triggered.connect(self.onGridToggle)
302        self.actionChangeScale.triggered.connect(self.onScaleChange)
303
304    def onScaleChange(self):
305        """
306        Show a dialog allowing axes rescaling
307        """
308        if self.properties.exec_() == QtWidgets.QDialog.Accepted:
309            self.xLogLabel, self.yLogLabel = self.properties.getValues()
310            self.data.xtransform = self.xLogLabel
311            self.data.ytransform = self.yLogLabel
312            self.xyTransform(self.xLogLabel, self.yLogLabel)
313
314    def onAddText(self):
315        """
316        Show a dialog allowing adding custom text to the chart
317        """
318        if self.addText.exec_() != QtWidgets.QDialog.Accepted:
319            return
320
321        # Retrieve the new text, its font and color
322        extra_text = self.addText.text()
323        extra_font = self.addText.font()
324        extra_color = self.addText.color()
325
326        # Place the text on the screen at the click location
327        pos_x = self.x_click
328        pos_y = self.y_click
329
330        # Map QFont onto MPL font
331        mpl_font = FontProperties()
332        mpl_font.set_size(int(extra_font.pointSize()))
333        mpl_font.set_family(str(extra_font.family()))
334        mpl_font.set_weight(int(extra_font.weight()))
335        # MPL style names
336        styles = ['normal', 'italic', 'oblique']
337        # QFont::Style maps directly onto the above
338        try:
339            mpl_font.set_style(styles[extra_font.style()])
340        except:
341            pass
342
343        if len(extra_text) > 0:
344            new_text = self.ax.text(pos_x,
345                                    pos_y,
346                                    extra_text,
347                                    color=extra_color,
348                                    fontproperties=mpl_font)
349
350            # Update the list of annotations
351            self.textList.append(new_text)
352            self.canvas.draw()
353
354    def onRemoveText(self):
355        """
356        Remove the most recently added text
357        """
358        num_text = len(self.textList)
359        if num_text < 1:
360            return
361        txt = self.textList[num_text - 1]
362        text_remove = txt.get_text()
363        try:
364            txt.remove()
365        except ValueError:
366            # Text got already deleted somehow
367            pass
368        self.textList.remove(txt)
369
370        self.canvas.draw_idle()
371
372    def onSetGraphRange(self):
373        """
374        Show a dialog allowing setting the chart ranges
375        """
376        # min and max of data
377        if self.setRange.exec_() == QtWidgets.QDialog.Accepted:
378            x_range = self.setRange.xrange()
379            y_range = self.setRange.yrange()
380            if x_range is not None and y_range is not None:
381                self.ax.set_xlim(x_range)
382                self.ax.set_ylim(y_range)
383                self.canvas.draw_idle()
384
385    def onResetGraphRange(self):
386        """
387        Resets the chart X and Y ranges to their original values
388        """
389        x_range = (self.data.x.min(), self.data.x.max())
390        y_range = (self.data.y.min(), self.data.y.max())
391        if x_range is not None and y_range is not None:
392            self.ax.set_xlim(x_range)
393            self.ax.set_ylim(y_range)
394            self.canvas.draw_idle()
395
396    def onLinearFit(self, id):
397        """
398        Creates and displays a simple linear fit for the selected plot
399        """
400        selected_plot = self.plot_dict[id]
401
402        maxrange = (min(selected_plot.x), max(selected_plot.x))
403        fitrange = self.ax.get_xlim()
404
405        fit_dialog = LinearFit(parent=self,
406                    data=selected_plot,
407                    max_range=maxrange,
408                    fit_range=fitrange,
409                    xlabel=self.xLogLabel,
410                    ylabel=self.yLogLabel)
411        fit_dialog.updatePlot.connect(self.onFitDisplay)
412        if fit_dialog.exec_() == QtWidgets.QDialog.Accepted:
413            return
414
415    def replacePlot(self, id, new_plot):
416        """
417        Remove plot 'id' and add 'new_plot' to the chart.
418        This effectlvely refreshes the chart with changes to one of its plots
419        """
420        self.removePlot(id)
421        self.plot(data=new_plot)
422
423    def onRemovePlot(self, id):
424        """
425        Responds to the plot delete action
426        """
427        self.removePlot(id)
428
429        if len(self.plot_dict) == 0:
430            # last plot: graph is empty must be the panel must be destroyed
431                self.parent.close()
432
433    def removePlot(self, id):
434        """
435        Deletes the selected plot from the chart
436        """
437        if id not in list(self.plot_dict.keys()):
438            return
439
440        selected_plot = self.plot_dict[id]
441
442        plot_dict = copy.deepcopy(self.plot_dict)
443
444        # Labels might have been changed
445        xl = self.ax.xaxis.label.get_text()
446        yl = self.ax.yaxis.label.get_text()
447
448        self.plot_dict = {}
449
450        mpl.pyplot.cla()
451        self.ax.cla()
452
453        for ids in plot_dict:
454            if ids != id:
455                self.plot(data=plot_dict[ids], hide_error=plot_dict[ids].hide_error)
456
457        # Reset the labels
458        self.ax.set_xlabel(xl)
459        self.ax.set_ylabel(yl)
460        self.canvas.draw()
461
462    def onFreeze(self, id):
463        """
464        Freezes the selected plot to a separate chart
465        """
466        plot = self.plot_dict[id]
467        self.manager.add_data(data_list=[plot])
468
469    def onModifyPlot(self, id):
470        """
471        Allows for MPL modifications to the selected plot
472        """
473        selected_plot = self.plot_dict[id]
474        selected_line = self.plot_lines[id]
475        # Old style color - single integer for enum color
476        # New style color - #hhhhhh
477        color = selected_plot.custom_color
478        # marker symbol and size
479        marker = selected_plot.symbol
480        marker_size = selected_plot.markersize
481        # plot name
482        legend = selected_plot.title
483
484        plotPropertiesWidget = PlotProperties(self,
485                                color=color,
486                                marker=marker,
487                                marker_size=marker_size,
488                                legend=legend)
489        if plotPropertiesWidget.exec_() == QtWidgets.QDialog.Accepted:
490            # Update Data1d
491            selected_plot.markersize = plotPropertiesWidget.markersize()
492            selected_plot.custom_color = plotPropertiesWidget.color()
493            selected_plot.symbol = plotPropertiesWidget.marker()
494            selected_plot.title = plotPropertiesWidget.legend()
495
496            # Redraw the plot
497            self.replacePlot(id, selected_plot)
498
499    def onToggleHideError(self, id):
500        """
501        Toggles hide error/show error menu item
502        """
503        selected_plot = self.plot_dict[id]
504        current = selected_plot.hide_error
505
506        # Flip the flag
507        selected_plot.hide_error = not current
508
509        plot_dict = copy.deepcopy(self.plot_dict)
510        self.plot_dict = {}
511
512        # Clean the canvas
513        mpl.pyplot.cla()
514        self.ax.cla()
515
516        # Recreate the plots but reverse the error flag for the current
517        for ids in plot_dict:
518            if ids == id:
519                self.plot(data=plot_dict[ids], hide_error=(not current))
520            else:
521                self.plot(data=plot_dict[ids], hide_error=plot_dict[ids].hide_error)               
522
523    def xyTransform(self, xLabel="", yLabel=""):
524        """
525        Transforms x and y in View and set the scale
526        """
527        # Transform all the plots on the chart
528        for id in list(self.plot_dict.keys()):
529            current_plot = self.plot_dict[id]
530            if current_plot.id == "fit":
531                self.removePlot(id)
532                continue
533
534            new_xlabel, new_ylabel, xscale, yscale =\
535                GuiUtils.xyTransform(current_plot, xLabel, yLabel)
536            self.xscale = xscale
537            self.yscale = yscale
538
539            # Plot the updated chart
540            self.removePlot(id)
541
542            # This assignment will wrap the label in Latex "$"
543            self.xLabel = new_xlabel
544            self.yLabel = new_ylabel
545
546            self.plot(data=current_plot, transform=False)
547
548        pass # debug hook
549
550    def onFitDisplay(self, fit_data):
551        """
552        Add a linear fitting line to the chart
553        """
554        # Create new data structure with fitting result
555        tempx = fit_data[0]
556        tempy = fit_data[1]
557        self.fit_result.x = []
558        self.fit_result.y = []
559        self.fit_result.x = tempx
560        self.fit_result.y = tempy
561        self.fit_result.dx = None
562        self.fit_result.dy = None
563
564        #Remove another Fit, if exists
565        self.removePlot("Fit")
566
567        self.fit_result.reset_view()
568        #self.offset_graph()
569
570        # Set plot properties
571        self.fit_result.id = 'fit'
572        self.fit_result.title = 'Fit'
573        self.fit_result.name = 'Fit'
574
575        # Plot the line
576        self.plot(data=self.fit_result, marker='-', hide_error=True)
577
578    def onMplMouseDown(self, event):
579        """
580        Left button down and ready to drag
581        """
582        # Check that the LEFT button was pressed
583        if event.button != 1:
584            return
585
586        self.leftdown = True
587        for text in self.textList:
588            if text.contains(event)[0]: # If user has clicked on text
589                self.selectedText = text
590                return
591        if event.inaxes is None:
592            return
593        try:
594            self.x_click = float(event.xdata)  # / size_x
595            self.y_click = float(event.ydata)  # / size_y
596        except:
597            self.position = None
598
599    def onMplMouseUp(self, event):
600        """
601        Set the data coordinates of the click
602        """
603        self.x_click = event.xdata
604        self.y_click = event.ydata
605
606        # Check that the LEFT button was released
607        if event.button == 1:
608            self.leftdown = False
609            self.selectedText = None
610
611        #release the legend
612        if self.gotLegend == 1:
613            self.gotLegend = 0
614
615    def onMplMouseMotion(self, event):
616        """
617        Check if the left button is press and the mouse in moving.
618        Compute delta for x and y coordinates and then perform the drag
619        """
620        if self.gotLegend == 1 and self.leftdown:
621            self.onLegendMotion(event)
622            return
623
624        #if self.leftdown and self.selectedText is not None:
625        if not self.leftdown or self.selectedText is None:
626            return
627        # User has clicked on text and is dragging
628        if event.inaxes is None:
629            # User has dragged outside of axes
630            self.selectedText = None
631        else:
632            # Only move text if mouse is within axes
633            self.selectedText.set_position((event.xdata, event.ydata))
634            self.canvas.draw_idle()
635        return
636
637    def onMplPick(self, event):
638        """
639        On pick legend
640        """
641        legend = self.legend
642        if event.artist != legend:
643            return
644        # Get the box of the legend.
645        bbox = self.legend.get_window_extent()
646        # Get mouse coordinates at time of pick.
647        self.mouse_x = event.mouseevent.x
648        self.mouse_y = event.mouseevent.y
649        # Get legend coordinates at time of pick.
650        self.legend_x = bbox.xmin
651        self.legend_y = bbox.ymin
652        # Indicate we picked up the legend.
653        self.gotLegend = 1
654
655        #self.legend.legendPatch.set_alpha(0.5)
656
657    def onLegendMotion(self, event):
658        """
659        On legend in motion
660        """
661        ax = event.inaxes
662        if ax is None:
663            return
664        # Event occurred inside a plotting area
665        lo_x, hi_x = ax.get_xlim()
666        lo_y, hi_y = ax.get_ylim()
667        # How much the mouse moved.
668        x = mouse_diff_x = self.mouse_x - event.x
669        y = mouse_diff_y = self.mouse_y - event.y
670        # Put back inside
671        if x < lo_x:
672            x = lo_x
673        if x > hi_x:
674            x = hi_x
675        if y < lo_y:
676            y = lo_y
677        if y > hi_y:
678            y = hi_y
679        # Move the legend from its previous location by that same amount
680        loc_in_canvas = self.legend_x - mouse_diff_x, \
681                        self.legend_y - mouse_diff_y
682        # Transform into legend coordinate system
683        trans_axes = self.legend.parent.transAxes.inverted()
684        loc_in_norm_axes = trans_axes.transform_point(loc_in_canvas)
685        self.legend_pos_loc = tuple(loc_in_norm_axes)
686        self.legend._loc = self.legend_pos_loc
687        # self.canvas.draw()
688        self.canvas.draw_idle()
689
690    def onMplWheel(self, event):
691        """
692        Process mouse wheel as zoom events
693        """
694        ax = event.inaxes
695        step = event.step
696
697        if ax is not None:
698            # Event occurred inside a plotting area
699            lo, hi = ax.get_xlim()
700            lo, hi = PlotUtilities.rescale(lo, hi, step,
701                              pt=event.xdata, scale=ax.get_xscale())
702            if not self.xscale == 'log' or lo > 0:
703                self._scale_xlo = lo
704                self._scale_xhi = hi
705                ax.set_xlim((lo, hi))
706
707            lo, hi = ax.get_ylim()
708            lo, hi = PlotUtilities.rescale(lo, hi, step, pt=event.ydata,
709                              scale=ax.get_yscale())
710            if not self.yscale == 'log' or lo > 0:
711                self._scale_ylo = lo
712                self._scale_yhi = hi
713                ax.set_ylim((lo, hi))
714        else:
715            # Check if zoom happens in the axes
716            xdata, ydata = None, None
717            x, y = event.x, event.y
718
719            for ax in self.axes:
720                insidex, _ = ax.xaxis.contains(event)
721                if insidex:
722                    xdata, _ = ax.transAxes.inverted().transform_point((x, y))
723                insidey, _ = ax.yaxis.contains(event)
724                if insidey:
725                    _, ydata = ax.transAxes.inverted().transform_point((x, y))
726            if xdata is not None:
727                lo, hi = ax.get_xlim()
728                lo, hi = PlotUtilities.rescale(lo, hi, step,
729                                  bal=xdata, scale=ax.get_xscale())
730                if not self.xscale == 'log' or lo > 0:
731                    self._scale_xlo = lo
732                    self._scale_xhi = hi
733                    ax.set_xlim((lo, hi))
734            if ydata is not None:
735                lo, hi = ax.get_ylim()
736                lo, hi = PlotUtilities.rescale(lo, hi, step, bal=ydata,
737                                  scale=ax.get_yscale())
738                if not self.yscale == 'log' or lo > 0:
739                    self._scale_ylo = lo
740                    self._scale_yhi = hi
741                    ax.set_ylim((lo, hi))
742        self.canvas.draw_idle()
743
744
745class Plotter(QtWidgets.QDialog, PlotterWidget):
746    def __init__(self, parent=None, quickplot=False):
747
748        QtWidgets.QDialog.__init__(self)
749        PlotterWidget.__init__(self, parent=self, manager=parent, quickplot=quickplot)
750        icon = QtGui.QIcon()
751        icon.addPixmap(QtGui.QPixmap(":/res/ball.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
752        self.setWindowIcon(icon)
753
754
Note: See TracBrowser for help on using the repository browser.