class ReflexInteractiveWxApp(wx.App): def __init__(self, interactive_app, dataPlotManager): self.inter_app = interactive_app self.dataPlotManager = dataPlotManager # Initialize wx GUI application wx.App.__init__(self, 0) def OnInit(self): 'Create the main window and insert the custom frame' if hasattr(self.dataPlotManager, 'xrc_file') and \ self.dataPlotManager.xrc_file != None: respath = self.dataPlotManager.xrc_file else: respath = os.path.join(os.path.dirname(__file__), 'reflex_interactive_gui.xrc') self.res = xrc.XmlResource(respath) self.frame = self.res.LoadFrame(None, 'ReflexInteractiveWxApp') self.setXrcObjects() self.bindXrcObjects() self.setFitsFiles() self.setWindowTitle() self.setDatasetInfoText() self.setupParameters() self.createPlotsArea() self.connectPlottingWidgets() self.frame.Show(True) return True def setXrcObjects(self): self.plotPanel = xrc.XRCCTRL(self.frame, 'plotPanel') self.statusBar = xrc.XRCCTRL(self.frame, 'statusBar') self.parameterNotebook = xrc.XRCCTRL(self.frame, 'parameterNotebook') self.datasetInfoText = xrc.XRCCTRL(self.frame, 'datasetInfoText') self.setDisableCheck = xrc.XRCCTRL(self.frame, 'setDisableCheck') self.setInitSopCheck = xrc.XRCCTRL(self.frame, 'setInitSopCheck') if (not self.inter_app.is_init_sop_enable()): self.setInitSopCheck.Hide() def bindXrcObjects(self): self.Bind(wx.EVT_BUTTON, self.onCont, id=xrc.XRCID('contBtn')) self.Bind(wx.EVT_BUTTON, self.onRepeat, id=xrc.XRCID('repeatBtn')) self.Bind(wx.EVT_BUTTON, self.onHelp, id=xrc.XRCID('helpBtn')) self.Bind(wx.EVT_CHECKBOX, self.onSetDisable, self.setDisableCheck) if (self.inter_app.is_init_sop_enable()): self.Bind(wx.EVT_CHECKBOX, self.onSetInitSop, self.setInitSopCheck) def setWindowTitle(self): if not self.frame: raise Exception("Frame not found") if hasattr(self.dataPlotManager, 'setWindowTitle'): self.frame.SetTitle(self.dataPlotManager.setWindowTitle()) def setupParameters(self): # Get the list of recipe parameter groups self.requestedParamList = self.dataPlotManager.setInteractiveParameters( ) parameterGroups = list() for param in self.requestedParamList: if parameterGroups.count(param.group) == 0: parameterGroups.append(param.group) self.parameterGrid = {} self.parameterTabs = {} for paramGroup in parameterGroups: self.parameterGrid[paramGroup] = wx.FlexGridSizer(cols=2, vgap=4, hgap=4) self.parameterGrid[paramGroup].AddGrowableCol(1) self.parameterTabs[paramGroup] = wx.Panel(self.parameterNotebook) self.parameterTabs[paramGroup].SetSizer( self.parameterGrid[paramGroup], 1) self.parameterNotebook.AddPage(self.parameterTabs[paramGroup], paramGroup) # The widgets for the parameters self.shownParam = list() self.shownParamWidgets = list() for param in self.requestedParamList: for param_in_sop in self.inter_app.inputs.in_sop: if param_in_sop.recipe == param.recipe and \ param_in_sop.displayName == param.displayName: param.value = param_in_sop.value param.name = param_in_sop.name self.shownParam.append(param) paramWidget = ParamWidget(self.parameterTabs[param.group], param) self.shownParamWidgets.append((param.group, paramWidget)) # Pack parameter widgets for (paramGroup, paramWidget) in self.shownParamWidgets: self.parameterGrid[paramGroup].Add(paramWidget.paramLabel, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=5) self.parameterGrid[paramGroup].Add(paramWidget.paramEditText, flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5) def createPlotsArea(self): # Read the pipeline data self.dataPlotManager.readFitsData(self.all_fitsFiles) # The matplotlib figure self.figure = Figure() self.figureCanvas = FigureCanvasWxAgg(self.plotPanel, wx.ID_ANY, self.figure) # self.canvas.SetToolTip(wx.ToolTip(tip = '')) # Setup toolbar self.toolbar = reflex_navigation_toolbar.ReflexNavigationToolbar( self.figureCanvas) self.frame.SetToolBar(self.toolbar) # Bind actions for status bar and tooltips self.figureCanvas.mpl_connect('motion_notify_event', self.onMotion) self.figureCanvas.mpl_connect('axes_enter_event', self.onEnterAxes) self.figureCanvas.mpl_connect('axes_leave_event', self.onLeaveAxes) # Bind actions for proper size self.plotPanel.Bind(wx.EVT_SIZE, self.onResize) self.plotPanel.Bind(wx.EVT_IDLE, self.onIdle) self.needs_resize = False self.dataPlotManager.addSubplots(self.figure) self.dataPlotManager.plotProductsGraphics() self.figure.subplots_adjust(wspace=0.40, hspace=0.40, top=0.93, bottom=0.07, left=0.1, right=0.95) def setFitsFiles(self): try: self.in_sof_fitsFiles = self.inter_app.inputs.in_sof.files self.dataset = self.inter_app.inputs.in_sof.datasetName self.in_sof_rec_orig_fitsFiles = self.inter_app.inputs.in_sof_rec_orig.files self.all_fitsFiles = self.in_sof_fitsFiles + \ self.in_sof_rec_orig_fitsFiles if len(self.in_sof_rec_orig_fitsFiles) == 0: self.purposes = 'INVALID' else: self.purposes = self.in_sof_rec_orig_fitsFiles[0].purposes except ValueError: print "Error parsing input sof." print "Syntax should be LOSO_NAME|file1;CATEGORY;PURPOSE,file2;..." sys.exit() def setDatasetInfoText(self): # The general info status bar datasetInfoAreaText = ''' This data belongs to dataset: ''' + self.dataset self.datasetInfoText.SetLabel(datasetInfoAreaText) def connectPlottingWidgets(self): if hasattr(self.dataPlotManager, 'plotWidgets'): self.widgets = self.dataPlotManager.plotWidgets() for widget in self.widgets: widget.setPostCallback(self.onPlotWidgetEvent) def onPlotWidgetEvent(self, new_params=None): self.figureCanvas.draw() if new_params is not None: for new_param in new_params: for widget in self.shownParamWidgets: if new_param.displayName == widget[ 1].parameter.displayName: widget[1].paramEditText.SetValue(new_param.value) def onCont(self, event): self.inter_app.set_continue_mode() self.frame.Close(True) def onRepeat(self, event): # This will update the output parameters based on the entry boxes. # It also contains all the parameters that are not shown in the window user_edited_param = list() for param_in_sop in self.inter_app.inputs.in_sop: newParam = param_in_sop for (paramGroup, paramWidget) in self.shownParamWidgets: if param_in_sop.displayName == paramWidget.parameter.displayName and \ param_in_sop.recipe == paramWidget.parameter.recipe: paramWidget.setValue(event=None) newParam = paramWidget.parameter user_edited_param.append(newParam) self.inter_app.set_repeat_mode(user_edited_param) self.frame.Close(True) def onHelp(self, event): window_help_msg = self.dataPlotManager.setWindowHelp() general_help_msg = """ The window has several parts:\n 1. Plot area. This area shows how good the reduction was performed 2. Parameter area. This area shows the parameters used for the execution of the recipe. The parameters can be changed if the recipe has to be re-run with new parameters 3. Button area. These buttons control the interactivity of the window\n a) Continue wkf. This button sends the current results to the next recipe in the workflow.\n b) Re-run recipe. This button will execute the predict recipe again with the new parameters\n d) Help. This button shows this help 4. Top toolbar area. These buttons allow certain interactivity with the plots (zoom, shift, layout) as well as exporting to png """ dlg = wx.MessageDialog(self.frame, window_help_msg + general_help_msg, self.dataPlotManager.setWindowTitle() + " Help", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onSetDisable(self, event): if self.setDisableCheck.GetValue(): self.inter_app.set_disable_next_iteration() def onSetInitSop(self, event): if self.setInitSopCheck.GetValue(): self.inter_app.set_next_init_sop() def onMotion(self, event): if event.inaxes: self.statusBar.SetStatusText( event.inaxes.format_coord(event.xdata, event.ydata)) else: self.statusBar.SetStatusText((''), 0) def onEnterAxes(self, event): if hasattr(event.inaxes, 'tooltip'): tip = self.figureCanvas.GetToolTip() if not tip: tip = wx.ToolTip(tip=event.inaxes.tooltip) self.figureCanvas.SetToolTip(tip) else: tip.SetTip(event.inaxes.tooltip) tip.Enable(True) def onLeaveAxes(self, event): try: self.figureCanvas.GetToolTip().Enable(False) except: pass def onResize(self, event): self.needs_resize = True def onIdle(self, event): if self.needs_resize: self.figureCanvas.SetSize(self.plotPanel.GetSize()) self.needs_resize = False wx.WakeUpIdle()
class PanelGraph(wx.Panel): def __init__(self, panel, notify, settings, status, remoteControl): self.panel = panel self.notify = notify self.plot = None self.settings = settings self.status = status self.remoteControl = remoteControl self.spectrum = None self.isLimited = None self.limit = None self.extent = None self.annotate = None self.isDrawing = False self.toolTip = wx.ToolTip('') self.mouseSelect = None self.mouseZoom = None self.measureTable = None self.background = None self.selectStart = None self.selectEnd = None self.menuClearSelect = [] self.measure = None self.show = None self.doDraw = False wx.Panel.__init__(self, panel) self.figure = matplotlib.figure.Figure(facecolor='white') self.figure.set_size_inches(0, 0) self.canvas = FigureCanvas(self, -1, self.figure) self.canvas.SetToolTip(self.toolTip) self.measureTable = PanelMeasure(self, settings) self.toolbar = NavigationToolbar(self.canvas, self, settings, self.__hide_overlay) self.toolbar.Realize() vbox = wx.BoxSizer(wx.VERTICAL) vbox.Add(self.canvas, 1, wx.EXPAND) vbox.Add(self.measureTable, 0, wx.EXPAND) vbox.Add(self.toolbar, 0, wx.EXPAND) self.SetSizer(vbox) vbox.Fit(self) self.create_plot() self.canvas.mpl_connect('button_press_event', self.__on_press) self.canvas.mpl_connect('figure_enter_event', self.__on_enter) self.canvas.mpl_connect('axes_leave_event', self.__on_leave) self.canvas.mpl_connect('motion_notify_event', self.__on_motion) self.canvas.mpl_connect('draw_event', self.__on_draw) self.canvas.mpl_connect('idle_event', self.__on_idle) self.Bind(wx.EVT_SIZE, self.__on_size) self.timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.__on_timer, self.timer) def __set_fonts(self): axes = self.plot.get_axes() if axes is not None: axes.xaxis.label.set_size('small') axes.yaxis.label.set_size('small') if self.settings.display == Display.SURFACE: axes.zaxis.label.set_size('small') axes.tick_params(axis='both', which='major', labelsize='small') axes = self.plot.get_axes_bar() if axes is not None: axes.tick_params(axis='both', which='major', labelsize='small') def __enable_menu(self, state): for menu in self.menuClearSelect: menu.Enable(state) def __on_press(self, event): if self.settings.clickTune and matplotlib.__version__ >= '1.2' and event.dblclick: frequency = int(event.xdata * 1e6) self.remoteControl.tune(frequency) elif isinstance(self.plot, PlotterPreview): self.plot.to_front() def __on_enter(self, _event): self.toolTip.Enable(False) def __on_leave(self, _event): self.toolTip.Enable(True) self.status.set_info('', level=None) def __on_motion(self, event): axes = self.plot.get_axes() axesBar = self.plot.get_axes_bar() xpos = event.xdata ypos = event.ydata text = "" if (xpos is None or ypos is None or self.spectrum is None or event.inaxes is None): spectrum = None elif event.inaxes == axesBar: spectrum = None level = self.plot.get_bar().norm.inverse(ypos) text = "{}".format(format_precision(self.settings, level=level)) elif self.settings.display == Display.PLOT: timeStamp = max(self.spectrum) spectrum = self.spectrum[timeStamp] elif self.settings.display == Display.SPECT: timeStamp = num2epoch(ypos) if timeStamp in self.spectrum: spectrum = self.spectrum[timeStamp] else: nearest = min(self.spectrum.keys(), key=lambda k: abs(k - timeStamp)) spectrum = self.spectrum[nearest] elif self.settings.display == Display.SURFACE: spectrum = None coords = axes.format_coord(event.xdata, event.ydata) match = re.match('x=([-|0-9|\.]+).*y=([0-9|\:]+).*z=([-|0-9|\.]+)', coords) if match is not None and match.lastindex == 3: freq = float(match.group(1)) level = float(match.group(3)) text = "{}, {}".format( *format_precision(self.settings, freq, level)) else: spectrum = None if spectrum is not None and len(spectrum) > 0: x = min(spectrum.keys(), key=lambda freq: abs(freq - xpos)) if min(spectrum.keys(), key=float) <= xpos <= max(spectrum.keys(), key=float): y = spectrum[x] text = "{}, {}".format(*format_precision(self.settings, x, y)) else: text = format_precision(self.settings, xpos) markers = find_artists(self.figure, 'peak') markers.extend(find_artists(self.figure, 'peakThres')) hit = False for marker in markers: if isinstance(marker, Line2D): location = marker.get_path().vertices[0] markX, markY = axes.transData.transform(location) dist = abs(math.hypot(event.x - markX, event.y - markY)) if dist <= 5: if self.settings.display == Display.PLOT: tip = "{}, {}".format(*format_precision( self.settings, location[0], location[1])) else: tip = "{}".format( format_precision(self.settings, location[0])) self.toolTip.SetTip(tip) hit = True break self.toolTip.Enable(hit) self.status.set_info(text, level=None) def __on_size(self, event): ppi = wx.ScreenDC().GetPPI() size = [float(v) for v in self.canvas.GetSize()] width = size[0] / ppi[0] height = size[1] / ppi[1] self.figure.set_figwidth(width) self.figure.set_figheight(height) self.figure.set_dpi(ppi[0]) event.Skip() def __on_draw(self, _event): axes = self.plot.get_axes() if axes is not None: self.background = self.canvas.copy_from_bbox(axes.bbox) self.__draw_overlay() def __on_idle(self, _event): if self.doDraw and self.plot.get_plot_thread() is None: self.__hide_overlay() self.doDraw = False if os.name == 'nt': threading.Thread(target=self.__draw_canvas, name='Draw').start() else: self.__draw_canvas() def __on_timer(self, _event): self.timer.Stop() self.set_plot(None, None, None, None, self.annotate) def __draw_canvas(self): try: self.isDrawing = True self.canvas.draw() except wx.PyDeadObjectError: pass self.isDrawing = False wx.CallAfter(self.status.set_busy, False) def __draw_overlay(self): if self.background is not None: self.canvas.restore_region(self.background) self.__draw_select() self.draw_measure() axes = self.plot.get_axes() if axes is not None: self.canvas.blit(axes.bbox) def __draw_select(self): if self.selectStart is not None and self.selectEnd is not None: self.mouseSelect.draw(self.selectStart, self.selectEnd) def __hide_overlay(self): if self.plot is not None: self.plot.hide_measure() self.__hide_select() def __hide_select(self): if self.mouseSelect is not None: self.mouseSelect.hide() def create_plot(self): if self.plot is not None: self.plot.close() self.toolbar.set_auto(True) if self.settings.display == Display.PLOT: self.plot = Plotter(self.notify, self.figure, self.settings) elif self.settings.display == Display.SPECT: self.plot = Spectrogram(self.notify, self.figure, self.settings) elif self.settings.display == Display.SURFACE: self.plot = Plotter3d(self.notify, self.figure, self.settings) elif self.settings.display == Display.STATUS: self.plot = PlotterStatus(self.notify, self.figure, self.settings) elif self.settings.display == Display.TIMELINE: self.plot = PlotterTime(self.notify, self.figure, self.settings) elif self.settings.display == Display.PREVIEW: self.plot = PlotterPreview(self.notify, self.figure, self.settings) self.plot.set_window(self) self.__set_fonts() self.toolbar.set_plot(self.plot) self.toolbar.set_type(self.settings.display) self.measureTable.set_type(self.settings.display) self.set_plot_title() self.figure.subplots_adjust(top=0.85) self.redraw_plot() self.plot.scale_plot(True) self.mouseZoom = MouseZoom(self.toolbar, plot=self.plot, callbackHide=self.__hide_overlay) self.mouseSelect = MouseSelect(self.plot, self.on_select, self.on_selected) self.measureTable.show(self.settings.showMeasure) self.panel.SetFocus() def on_select(self): self.hide_measure() def on_selected(self, start, end): self.__enable_menu(True) self.selectStart = start self.selectEnd = end self.measureTable.set_selected(self.spectrum, start, end) def add_menu_clear_select(self, menu): self.menuClearSelect.append(menu) menu.Enable(False) def draw(self): self.doDraw = True def show_measure_table(self, show): self.measureTable.show(show) self.Layout() def set_plot(self, spectrum, isLimited, limit, extent, annotate=False): if spectrum is not None and extent is not None: if isLimited is not None and limit is not None: self.spectrum = copy.copy(spectrum) self.extent = extent self.annotate = annotate self.isLimited = isLimited self.limit = limit if self.plot.get_plot_thread() is None and not self.isDrawing: self.timer.Stop() self.measureTable.set_selected(self.spectrum, self.selectStart, self.selectEnd) if isLimited: self.spectrum = reduce_points(spectrum, limit) self.status.set_busy(True) self.plot.set_plot(self.spectrum, self.extent, annotate) if self.settings.display == Display.PREVIEW: self.status.set_busy(False) else: self.timer.Start(200, oneShot=True) def set_plot_title(self): if len(self.settings.devicesRtl) > 0: gain = self.settings.devicesRtl[self.settings.indexRtl].gain else: gain = 0 self.plot.set_title("Frequency Spectrogram\n{} - {} MHz," " gain = {}dB".format(self.settings.start, self.settings.stop, gain)) def redraw_plot(self): if self.spectrum is not None: self.set_plot(self.spectrum, self.settings.pointsLimit, self.settings.pointsMax, self.extent, self.settings.annotate) def set_grid(self, on): self.plot.set_grid(on) def set_selected(self, start, end): self.selectStart = start self.selectEnd = end self.__draw_select() def hide_toolbar(self, hide): self.toolbar.Show(not hide) def hide_measure(self): if self.plot is not None: self.plot.hide_measure() def draw_measure(self): if self.measure is not None and self.measure.is_valid(): self.plot.draw_measure(self.measure, self.show) def update_measure(self, measure=None, show=None): if not measure and not show: self.measureTable.update_measure() else: self.measure = measure self.show = show self.__draw_overlay() def get_figure(self): return self.figure def get_axes(self): return self.plot.get_axes() def get_canvas(self): return self.canvas def get_toolbar(self): return self.toolbar def get_mouse_select(self): return self.mouseSelect def scale_plot(self, force=False): self.plot.scale_plot(force) def clear_plots(self): self.plot.clear_plots() self.spectrum = None self.doDraw = True def clear_selection(self): self.measure = None self.measureTable.clear_measurement() self.selectStart = None self.selectEnd = None self.mouseSelect.clear() self.__enable_menu(False) def close(self): self.plot.close() close_modeless()
class plotTimeSeries(wx.Panel): def __init__(self, parent, id, pos, size, style, name): self._init_ctrls(parent) def _init_coll_boxSizer1_Items(self, parent): # generated method, don't edit parent.AddWindow(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) parent.AddWindow(self.toolbar, 0, wx.EXPAND) def _init_ctrls(self, parent): wx.Panel.__init__(self, parent, -1) self.parent = parent #init Plot # matplotlib.figure.Figure self.figure = plt.figure() # matplotlib.axes.AxesSubplot self.timeSeries = host_subplot(111, axes_class=AA.Axes) self.setTimeSeriesTitle("No Data to Plot") # matplotlib.backends.backend_wxagg.FigureCanvasWxAgg self.canvas = FigCanvas(self, -1, self.figure) self.canvas.SetFont( wx.Font(20, wx.SWISS, wx.NORMAL, wx.NORMAL, False, u'Tahoma')) self.isShowLegendEnabled = False self.canvas.mpl_connect('figure_leave_event', self._onFigureLeave) Publisher.subscribe(self.updateCursor, "updateCursor") # Create the navigation toolbar, tied to the canvas self.toolbar = NavigationToolbar(self.canvas, allowselect=True) self.toolbar.Realize() self.seriesPlotInfo = None #set properties self.fontP = FontProperties() self.fontP.set_size('x-small') self.format = '-o' self.alpha = 1 self._setColor("WHITE") left = 0.125 # the left side of the subplots of the figure #right = 0.9 # the right side of the subplots of the figure #bottom = 0.51 # the bottom of the subplots of the figure #top = 1.2 # the top of the subplots of the figure #wspace = .8 # the amount of width reserved for blank space between subplots #hspace = .8 # the amount of height reserved for white space between subplots plt.subplots_adjust( left= left #, bottom=bottom, right=right, top=top, wspace=wspace, hspace=hspace ) plt.tight_layout() #init hover tooltip # create a long tooltip with newline to get around wx bug (in v2.6.3.3) # where newlines aren't recognized on subsequent self.tooltip.SetTip() calls self.tooltip = wx.ToolTip( tip='tip with a long %s line and a newline\n') self.canvas.SetToolTip(self.tooltip) self.tooltip.Enable(False) self.tooltip.SetDelay(0) #init lists #self.lines = {} self.lines = [] self.axislist = {} self.curveindex = -1 self.editseriesID = -1 self.editCurve = None self.editPoint = None self.hoverAction = None self.selplot = None self.cursors = [] self.canvas.draw() self._init_sizers() def _init_sizers(self): # generated method, don't edit self.boxSizer1 = wx.BoxSizer(orient=wx.VERTICAL) self._init_coll_boxSizer1_Items(self.boxSizer1) self.SetSizer(self.boxSizer1) ''' def changePlotSelection(self, datetime_list=[]): cc= ColorConverter() # k black, # r red # needs to have graph first selected = cc.to_rgba('r', 1) unselected = cc.to_rgba('k', 0.1) allunselected = cc.to_rgba('k', 1) if self.editPoint: colorlist=[allunselected] *len(self.editCurve.dataTable) if len(datetime_list)>0: for i in xrange(len(self.editCurve.dataTable)): if self.editCurve.dataTable[i][1] in datetime_list: colorlist[i]=selected else: colorlist[i]=unselected self.editPoint.set_color(colorlist) #self.editPoint.set_color(['k' if x == 0 else 'r' for x in tflist]) self.canvas.draw() ''' ## TODO 10/15/2014 Change function so that it will accept a list of datavalues. This will remove the need to loop through the values currently plotted and we would instead plot the list of datetimes and datavalues together. def changePlotSelection(self, filtered_datetime): """ Selected points have a scatter plot drawn over them to indicated the point being selected """ if self.selplot: self.selplot.remove() del self.selplot self.selplot = None result = None if isinstance(filtered_datetime, pd.DataFrame): result = filtered_datetime.sort_index() if isinstance(filtered_datetime, list): df = self.editCurve.dataTable result = df[df['LocalDateTime'].isin(filtered_datetime)].astype( datetime.datetime) if isinstance(result, pd.DataFrame): if result.empty: self.canvas.draw() return else: if not result: self.canvas.draw() return values = result['DataValue'].values.tolist() dates = result.index.astype(datetime.datetime) self.selplot = self.axislist[self.editSeries.axisTitle].scatter( dates, values, s=35, c='red', edgecolors='none', zorder=12, marker='s', alpha=1) self.canvas.draw() def lassoChangeSelection(self, filtered_datetime): self.parent.record_service.select_points(dataframe=filtered_datetime) def onShowLegend(self, isVisible): if isVisible: self.isShowLegendEnabled = True plt.subplots_adjust(bottom=.1 + .1) leg = self.timeSeries.legend(loc='upper right', ncol=2, fancybox=True, prop=self.fontP) leg.get_frame().set_alpha(.5) leg.draggable(state=True) else: self.isShowLegendEnabled = False plt.subplots_adjust(bottom=.1) self.timeSeries.legend_ = None plt.gcf().autofmt_xdate() self.canvas.draw() def onPlotType(self, ptype): # self.timeSeries.clear() if ptype == "line": ls = '-' m = 'None' elif ptype == "point": ls = 'None' m = 'o' else: ls = '-' m = 'o' self.format = ls + m for k, v in self.axislist.iteritems(): lines = v.get_lines() for line in lines: plt.setp(line, linestyle=ls, marker=m) if self.isShowLegendEnabled: self.onShowLegend(self.isShowLegendEnabled) plt.gcf().autofmt_xdate() self.canvas.draw() def stopEdit(self): self.clear() self.selectedlist = None self.selplot = None self.lman = None #self.canvas.mpl_disconnect(self.hoverAction) try: self.canvas.mpl_disconnect(self.pointPick) self.pointPick = None except AttributeError as e: logger.error(e) self.hoverAction = None self.xys = None self.alpha = 1 self.curveindex = -1 self.editCurve = None # self.RefreshPlot() if self.seriesPlotInfo and self.seriesPlotInfo.isPlotted( self.editseriesID): self.updatePlot() self.toolbar.stopEdit() self.editseriesID = -1 def updateValues(self): # self.addEdit(self.editCursor, self.editSeries, self.editDataFilter) #clear current edit points and curve if self.editCurve: curraxis = self.axislist[self.editCurve.axisTitle] for l in curraxis.lines: if l.get_label() == self.editCurve.plotTitle: curraxis.lines.remove(l) #redraw editpoints and curve self.seriesPlotInfo.updateEditSeries() self.editCurve = self.seriesPlotInfo.getEditSeriesInfo() self.drawEditPlot(self.editCurve) self.canvas.draw() Publisher.sendMessage("refreshTable", e=self.editCurve.dataTable) # self.parent.parent.dataTable.Refresh() plt.gcf().autofmt_xdate() self.canvas.draw() def drawEditPlot(self, oneSeries): self.axislist[oneSeries.axisTitle].set_zorder(10) self.lines[self.curveindex] = self.axislist[oneSeries.axisTitle] data = oneSeries.dataTable dates = data.index.astype(datetime.datetime) curraxis = self.axislist[oneSeries.axisTitle] curraxis.plot_date(dates, data['DataValue'], "-s", color=oneSeries.color, xdate=True, label=oneSeries.plotTitle, zorder=10, alpha=1, picker=5.0, pickradius=5.0, markersize=4.5) curraxis.set_xlabel('Date') convertedDates = matplotlib.dates.date2num(dates) self.xys = zip(convertedDates, oneSeries.dataTable['DataValue']) self.toolbar.editSeries(self.xys, self.editCurve) self.pointPick = self.canvas.mpl_connect('pick_event', self._onPick) self.editSeries = oneSeries def _setColor(self, color): """Set figure and canvas colours to be the same. :rtype : object """ plt.gcf().set_facecolor(color) plt.gcf().set_edgecolor(color) self.canvas.SetBackgroundColour(color) def close(self): #plt.clf() #plt.close() pass def Plot(self, seriesPlotInfo): self.seriesPlotInfo = seriesPlotInfo self.updatePlot() # resets the home view - will remove any previous zooming self.toolbar.update() self.toolbar.push_current() #self._views.home() #self._positions.home() #self.set_history_buttons() #clear plot def clear(self): """ :return: """ lines = [] for key, ax in self.axislist.items(): ax.clear() self.axislist = {} #self.canvas.draw() # self.stopEdit() #print "TimeSeries: ", dir(self.timeSeries), type(self.timeSeries) #plt.cla() #plt.clf() #self.timeSeries.plot([], [], picker=5) def setUpYAxis(self): """ Setting up multiple axes :return: """ self.axislist = {} left = 0 right = 0 adj = .05 editaxis = None ## Identify Axes and save them to axislist #loop through the list of curves and add an axis for each for oneSeries in self.seriesPlotInfo.getAllSeries(): #test to see if the axis already exists if oneSeries.edit: editaxis = oneSeries.axisTitle if not oneSeries.axisTitle in self.axislist: self.axislist[oneSeries.axisTitle] = None keys = self.axislist.keys() ## Put editing axis at the beginning of the list if editaxis: for i in range(len(keys)): if keys[i] == editaxis: keys.pop(i) break keys.insert(0, editaxis) leftadjust = -30 for i, axis in zip(range(len(self.axislist)), keys): if i % 2 == 0: left = left + 1 #add to the left(yaxis) if i == 0: #if first plot use the orig axis newAxis = self.timeSeries else: newAxis = self.timeSeries.twinx() ''' Spines idea #newAxis.spines["left"].set_position(("axes", leftadjust * left)) newAxis.spines["left"].set_position(("axes", -.1)) newAxis.spines["left"].set_visible(True) newAxis.yaxis.set_label_position("left") newAxis.yaxis.set_ticks_position("left") ''' new_fixed_axis = newAxis.get_grid_helper().new_fixed_axis newAxis.axis['left'] = new_fixed_axis(loc='left', axes=newAxis, offset=(leftadjust * left, 0)) newAxis.axis["left"].toggle(all=True) newAxis.axis["right"].toggle(all=False) leftadjust -= 15 else: right = right + 1 #add to the right(y2axis) newAxis = self.timeSeries.twinx() ''' Spines idea #newAxis.spines["right"].set_position(("axes", -1*60*(right - 1))) newAxis.spines["right"].set_position(("axes", 1.0)) newAxis.spines["right"].set_visible(True) newAxis.yaxis.set_label_position("right") newAxis.yaxis.set_ticks_position("right") ''' new_fixed_axis = newAxis.get_grid_helper().new_fixed_axis newAxis.axis['right'] = new_fixed_axis(loc='right', axes=newAxis, offset=(60 * (right - 1), 0)) newAxis.axis['right'].toggle(all=True) a = newAxis.set_ylabel(axis, picker=True) a.set_picker(True) #logger.debug("axis label: %s" % (axis)) self.axislist[axis] = newAxis plt.tight_layout() self.canvas.draw() def updatePlot(self): self.clear() count = self.seriesPlotInfo.count() self.setUpYAxis() self.lines = [] ## Spine initialization ## for oneSeries in self.seriesPlotInfo.getAllSeries(): if oneSeries.seriesID == self.seriesPlotInfo.getEditSeriesID(): """ Edited Series """ self.curveindex = len(self.lines) self.lines.append("") self.editCurve = oneSeries self.drawEditPlot(oneSeries) else: """ Plotted Series """ curraxis = self.axislist[oneSeries.axisTitle] curraxis.set_zorder(1) data = oneSeries.dataTable dates = data.index.astype(datetime.datetime) #data.plot(ax=curraxis) curraxis.plot_date(dates, data['DataValue'], color=oneSeries.color, fmt=self.format, xdate=True, tz=None, antialiased=True, label=oneSeries.plotTitle, alpha=self.alpha, picker=5.0, pickradius=5.0, markersize=4) curraxis.set_xlabel('Date') ''' data = oneSeries.dataTable #dates = data['LocalDateTime'].astype(datetime.datetime) data['LocalDateTime'] = pd.to_datetime(data['LocalDateTime']) data['LocalDateTime'].astype(datetime.datetime) data.plot(ax=curraxis) oneSeries.dataTable.plot(ax=curraxis) curraxis.set_xlabel('Date') ''' if count > 1: self.setTimeSeriesTitle("") plt.subplots_adjust(bottom=.1 + .1) # self.timeSeries.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05), # ncol=2, prop = self.fontP) self.timeSeries.legend(loc='upper center', bbox_to_anchor=(0.5, -1.75), ncol=2, prop=self.fontP) elif count == 0: self.setTimeSeriesTitle("") self.timeSeries.legend_ = None else: self.setTimeSeriesTitle(oneSeries.siteName) plt.subplots_adjust(bottom=.1) self.timeSeries.legend_ = None self.timeSeries.set_xlabel("Date", picker=True) #self.timeSeries.set_xlim(matplotlib.dates.date2num([self.seriesPlotInfo.currentStart, self.seriesPlotInfo.currentEnd])) #self.timeSeries.axis[:].set_major_formatter(FormatStrFormatter('%.2f')) self.timeSeries.axis[:].major_ticks.set_tick_out(True) self.timeSeries.axis["bottom"].label.set_pad(20) self.timeSeries.axis["bottom"].major_ticklabels.set_pad(15) self.timeSeries.axis["bottom"].major_ticklabels.set_rotation(15) self.timeSeries.axis[:].major_ticklabels.set_picker(True) plt.gcf().autofmt_xdate() #self.figure.tight_layout() if not self.toolbar._views.empty(): for v in self.toolbar._views: del (v) self.toolbar.push_current() self.canvas.draw() def updateCursor(self, selectedObject=None, deselectedObject=None): """ :param selectedObject: """ try: if selectedObject: """ Activate Cursor. Happens when a plot is selected """ if self.seriesPlotInfo: seriesInfo = self.seriesPlotInfo.getSeries( selectedObject.id) if seriesInfo: currentAxis = None # If there a key with the axisTitle we are interested in, set currentaxis to that. if seriesInfo.axisTitle in self.axislist.keys(): currentAxis = self.axislist[seriesInfo.axisTitle] # If nothing is in the axislist, we don't care about it elif len(self.axislist) < 1: currentAxis = None self.configureCursor(currentAxis=currentAxis) elif deselectedObject: """ Deactivate Cursor. This happens when the plot is deselected """ self.deactivateCursor(deselectedObject) except AttributeError as e: print "Ignoring Attribute Error", e def deactivateCursor(self, deselectedObject=None): # Remove an object if supplied if deselectedObject: for i in self.cursors: if i.selected == deselectedObject: i.disable() break # Disable existing Cursors elif self.cursors: for i in self.cursors: i.disable() def configureCursor(self, currentAxis=None): """Creates the cursors for each axes in order to provide data hovering""" self.deactivateCursor() self.cursors = [] # initialize cursors for axes from currently selected axes for k, v in self.axislist.iteritems(): i = Cursor(self.canvas, self.toolbar, v, k) ## If I have selected an axis that is in the axislist if v == currentAxis: i.enable() i.setSelected(currentAxis) # If there is only one axis in the axislist, default to the first axis elif len(self.axislist) == 1: i.enable() i.setSelected(self.axislist.values()[0]) # Else I disable the other axes that I don't care about else: i.setSelected(None) i.disable() self.cursors.append(i) def setTimeSeriesTitle(self, title=""): """Set the title of the TimeSeries plot""" self.timeSeries.set_title(title, picker=True) def setEdit(self, id): self.editseriesID = id self.alpha = .5 if self.seriesPlotInfo and self.seriesPlotInfo.isPlotted( self.editseriesID): self.editCurve = self.seriesPlotInfo.getSeries(self.editseriesID) ## TODO Duplicate UpdatePlot? logger.debug("Called duplicate updateplot") self.updatePlot() def make_patch_spines_invisible(self, ax): ax.set_frame_on(True) ax.patch.set_visible(False) for sp in ax.spines.itervalues(): sp.set_visible(False) def _onMotion(self, event): """ :type event: matplotlib.backend_bases.MouseEvent :return: """ try: if event.xdata and event.ydata: xValue = matplotlib.dates.num2date( event.xdata).replace(tzinfo=None) #self.toolbar.msg.SetLabelText("X= %s, Y= %.2f" % (xValue.strftime("%Y-%m-%d %H:%M:%S"), event.ydata)) #self.toolbar.msg.SetLabelText("X= %s, Y= %.2f" % (xValue.strftime("%b %d, %Y %H:%M:%S"), event.ydata)) self.toolbar.msg.SetLabelText( "X= %s, Y= %.2f" % (xValue.strftime("%b %d, %Y %H:%M"), event.ydata)) self.toolbar.msg.SetForegroundColour((66, 66, 66)) else: self.toolbar.msg.SetLabelText("") except ValueError: pass def _onPick(self, event): """ :param event: :return: """ if isinstance(event.artist, Line2D): thisline = event.artist xdata = thisline.get_xdata() ydata = thisline.get_ydata() ind = event.ind xValue = xdata[ind][0] yValue = ydata[ind][0] #tip = '(%s, %s)' % (xValue.strftime("%Y-%m-%d %H:%M:%S"), yValue) #tip = '(%s, %s)' % (xValue.strftime("%b %d, %Y %H:%M:%S"), yValue) tip = '(%s, %s)' % (xValue.strftime("%b %d, %Y %H:%M"), yValue) self.tooltip.SetTip(tip) self.tooltip.Enable(True) self.tooltip.SetAutoPop(10000) elif isinstance(event.artist, Text): text = event.artist #print "Picking Label: ", text.get_text() def _onFigureLeave(self, event): """Catches mouse leaving the figure :param event: :return: """ if self.tooltip.Window.Enabled: self.tooltip.SetTip("")