def _refresh_mpl_widget(self): """ Create the mpl widget and update the underlying control. """ # Delete the old widgets in the layout, it's just shenanigans # to try to reuse the old widgets when the figure changes. widget = self.widget layout = widget.layout() while layout.count(): layout_item = layout.takeAt(0) layout_item.widget().deleteLater() # Create the new figure and toolbar widgets. It seems that key # events will not be processed without an mpl figure manager. # However, a figure manager will create a new toplevel window, # which is certainly not desired in this case. This appears to # be a limitation of matplotlib. The canvas is manually set to # visible, or QVBoxLayout will ignore it for size hinting. figure = self.declaration.figure if figure: canvas = FigureCanvasQTAgg(figure) canvas.setParent(widget) canvas.setFocusPolicy(Qt.ClickFocus) canvas.setVisible(True) toolbar = NavigationToolbar2QTAgg(canvas, widget) toolbar.setVisible(self.declaration.toolbar_visible) layout.addWidget(toolbar) layout.addWidget(canvas)
def _refresh_mpl_widget(self): """ Create the mpl widget and update the underlying control. """ # Delete the old widgets in the layout, it's just shenanigans # to try to reuse the old widgets when the figure changes. widget = self.widget layout = widget.layout() while layout.count(): layout_item = layout.takeAt(0) layout_item.widget().deleteLater() # Create the new figure and toolbar widgets. It seems that key # events will not be processed without an mpl figure manager. # However, a figure manager will create a new toplevel window, # which is certainly not desired in this case. This appears to # be a limitation of matplotlib. The canvas is manually set to # visible, or QVBoxLayout will ignore it for size hinting. figure = self.declaration.figure if figure: canvas = FigureCanvasQTAgg(figure) canvas.setParent(widget) canvas.setFocusPolicy(Qt.ClickFocus) canvas.setVisible(True) toolbar = NavigationToolbar2QT(canvas, widget) toolbar.setVisible(self.declaration.toolbar_visible) layout.addWidget(toolbar) layout.addWidget(canvas)
class GraphViewer(Graphics): signalShowTitle = QtCore.pyqtSignal(str) signalGraphUpdate = pyqtSignal() waitEvent = threading.Event() signalPrint = pyqtSignal() signalPrintEnd = threading.Event() def __init__(self, parent = None): Graphics.__init__(self,parent) self.parent = parent self.create_main_frame() def create_main_frame(self): self.canvas = FigureCanvas(self.fig) self.canvas2 = FigureCanvas(self.fig2) self.canvas.setParent(self.parent.ui.frame) self.canvas.setFocusPolicy(Qt.StrongFocus) self.canvas.setFocus() # self.mpl_toolbar = CustomToolbar(self.canvas, self.parent.ui.mpl,self) self.canvas.mpl_connect('pick_event',self.onPick) self.canvas.mpl_connect('key_press_event', self.on_key_press) # self.vbox = QVBoxLayout() self.vbox.addWidget(self.canvas) # the matplotlib canvas self.vbox.addWidget(self.canvas2) # the matplotlib canvas self.vbox.addWidget(self.mpl_toolbar) self.parent.ui.frame.setLayout(self.vbox) # # # self.fig.clear() # self.genPlotPage() self.genTextPage() self.canvas.setVisible(True) self.canvas2.setVisible(False) self.canvas.setFocusPolicy(Qt.StrongFocus) self.canvas.setFocus() self.page = 1 self.signalGraphUpdate.emit() def genImage(self): self.fig.savefig('../WorkingDir/Page1.png', format='png')
class ThumbnailPlotter(QWidget): def __init__(self, title="Time domain preview"): QWidget.__init__(self) plt.close() plt.clf() self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.figure.patch.set_facecolor('none') self.ax = self.figure.add_subplot(111) self.figure.subplots_adjust(left=0, right=0.99, top=0.99, bottom=0.01) self.main_vbox = QVBoxLayout() self.main_vbox.addWidget(QLabel("<h3>" + title + "</h3>")) self.main_vbox.addWidget(self.canvas) self.canvas.setVisible(False) self.setLayout(self.main_vbox) self.movie = QMovie("ajax-loader.gif") self.process_label = QLabel() self.process_label.setMovie(self.movie) self.movie.start() self.main_hbox = QHBoxLayout() self.main_vbox.addLayout(self.main_hbox) self.main_hbox.addStretch() self.main_hbox.addWidget(self.process_label) self.main_hbox.addStretch() self.process_label.setVisible(False) self.sizepolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) self.setSizePolicy(self.sizepolicy) self.main_vbox.setContentsMargins(0, 0, 0, 0) self.main_vbox.setAlignment(Qt.AlignTop) self.setLoading() def setLoading(self): self.canvas.setVisible(False) self.process_label.setVisible(True) def draw(self, y): self.canvas.setVisible(True) self.process_label.setVisible(False) self.ax.clear() self.ax.plot(y) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.canvas.draw() def sizeHint(self, *args, **kwargs): return QSize(100, 150)
class ThumbnailPlotter(QWidget): def __init__(self, title="Time domain preview"): QWidget.__init__(self) plt.close() plt.clf() self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.figure.patch.set_facecolor('none') self.ax = self.figure.add_subplot(111) self.figure.subplots_adjust(left=0, right=0.99, top=0.99, bottom=0.01) self.main_vbox = QVBoxLayout() self.main_vbox.addWidget(QLabel("<h3>"+title+"</h3>")) self.main_vbox.addWidget(self.canvas) self.canvas.setVisible(False) self.setLayout(self.main_vbox) self.movie = QMovie("ajax-loader.gif") self.process_label = QLabel() self.process_label.setMovie(self.movie) self.movie.start() self.main_hbox = QHBoxLayout() self.main_vbox.addLayout(self.main_hbox) self.main_hbox.addStretch() self.main_hbox.addWidget(self.process_label) self.main_hbox.addStretch() self.process_label.setVisible(False) self.sizepolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) self.setSizePolicy(self.sizepolicy) self.main_vbox.setContentsMargins(0, 0, 0, 0) self.main_vbox.setAlignment(Qt.AlignTop) self.setLoading() def setLoading(self): self.canvas.setVisible(False) self.process_label.setVisible(True) def draw(self, y): self.canvas.setVisible(True) self.process_label.setVisible(False) self.ax.clear() self.ax.plot(y) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.canvas.draw() def sizeHint(self, *args, **kwargs): return QSize(100, 150)
class MiniMap(QtGui.QWidget): """Shows the entire signal and allows the user to navigate through it. Provides an scrollable selector over the entire signal. Attributes: xmin: Selector lower limit (measured in h-axis units). xmax: Selector upper limit (measured in h-axis units). step: Selector length (measured in h-axis units). """ def __init__(self, parent, ax, record=None): super(MiniMap, self).__init__(parent) self.ax = ax self.xmin = 0.0 self.xmax = 0.0 self.step = 10.0 self.xrange = np.array([]) self.minimapFig = plt.figure() self.minimapFig.set_figheight(0.75) self.minimapFig.add_axes((0, 0, 1, 1)) self.minimapCanvas = FigureCanvas(self.minimapFig) self.minimapCanvas.setFixedHeight(64) self.minimapSelector = self.minimapFig.axes[0].axvspan(0, self.step, color='gray', alpha=0.5, animated=True) self.minimapSelection = self.minimapFig.axes[0].axvspan( 0, self.step, color='LightCoral', alpha=0.5, animated=True) self.minimapSelection.set_visible(False) self.minimapBackground = [] self.minimapSize = (self.minimapFig.bbox.width, self.minimapFig.bbox.height) self.press_selector = None self.playback_marker = None self.minimapCanvas.mpl_connect('button_press_event', self.onpress) self.minimapCanvas.mpl_connect('button_release_event', self.onrelease) self.minimapCanvas.mpl_connect('motion_notify_event', self.onmove) # Animation related attrs. self.background = None self.animated = False # Set the layout self.layout = QtGui.QVBoxLayout(self) self.layout.addWidget(self.minimapCanvas) # Animation related attributes self.parentViewer = parent # Set Markers dict self.markers = {} self.record = None if record is not None: self.set_record(record) def set_record(self, record, step): self.record = record self.step = step self.xrange = np.linspace(0, len(self.record.signal) / self.record.fs, num=len(self.record.signal), endpoint=False) self.xmin = self.xrange[0] self.xmax = self.xrange[-1] self.markers = {} ax = self.minimapFig.axes[0] ax.lines = [] formatter = FuncFormatter( lambda x, pos: str(datetime.timedelta(seconds=x))) ax.xaxis.set_major_formatter(formatter) ax.grid(True, which='both') # Set dataseries to plot xmin = self.xmin * self.record.fs xmax = self.xmax * self.record.fs pixel_width = np.ceil(self.minimapFig.get_figwidth() * self.minimapFig.get_dpi()) x_data, y_data = plotting.reduce_data(self.xrange, self.record.signal, pixel_width, xmin, xmax) # self._plot_data.set_xdata(x_data) # self._plot_data.set_ydata(y_data) ax.plot(x_data, y_data, color='black', rasterized=True) ax.set_xlim(self.xmin, self.xmax) plotting.adjust_axes_height(ax) # Set the playback marker self.playback_marker = PlayBackMarker(self.minimapFig, self) self.playback_marker.markers[0].set_animated(True) # Draw canvas self.minimapCanvas.draw() self.minimapBackground = self.minimapCanvas.copy_from_bbox( self.minimapFig.bbox) self.draw_animate() def onpress(self, event): self.press_selector = event xdata = round(self.get_xdata(event), 2) xmin = round(xdata - (self.step / 2.0), 2) xmax = round(xdata + (self.step / 2.0), 2) self.parentViewer._set_animated(True) self.set_selector_limits(xmin, xmax) def onrelease(self, event): self.press_selector = None # Finish parent animation self.parentViewer._set_animated(False) def onmove(self, event): if self.press_selector is not None: xdata = round(self.get_xdata(event), 2) xmin = round(xdata - (self.step / 2.0), 2) xmax = round(xdata + (self.step / 2.0), 2) self.set_selector_limits(xmin, xmax) def get_xdata(self, event): inv = self.minimapFig.axes[0].transData.inverted() xdata, _ = inv.transform((event.x, event.y)) return xdata def set_selector_limits(self, xmin, xmax): step = xmax - xmin if step >= self.xmax - self.xmin: xleft = self.xmin xright = self.xmax if xmin < self.xmin: xleft = self.xmin xright = self.step elif xmax > self.xmax: xleft = self.xmax - step xright = self.xmax else: xleft = xmin xright = xmax if (xleft, xright) != (self.minimapSelector.xy[1, 0], self.minimapSelector.xy[2, 0]): self.step = step self.minimapSelector.xy[:2, 0] = xleft self.minimapSelector.xy[2:4, 0] = xright self.ax.set_xlim(xleft, xright) self.draw_animate() else: self.parentViewer.draw() def get_selector_limits(self): return self.minimapSelector.xy[0, 0], self.minimapSelector.xy[2, 0] def draw(self): self.draw_animate() def draw_animate(self): size = self.minimapFig.bbox.width, self.minimapFig.bbox.height if size != self.minimapSize: self.minimapSize = size self.minimapCanvas.draw() self.minimapBackground = self.minimapCanvas.copy_from_bbox( self.minimapFig.bbox) self.minimapCanvas.restore_region(self.minimapBackground) self.minimapFig.draw_artist(self.minimapSelection) self.minimapFig.draw_artist(self.minimapSelector) self.minimapFig.draw_artist(self.playback_marker.markers[0]) for marker in self.markers.values(): self.minimapFig.draw_artist(marker) self.minimapCanvas.blit(self.minimapFig.bbox) def set_visible(self, value): self.minimapCanvas.setVisible(value) def get_visible(self): return self.minimapCanvas.isVisible() def set_selection_limits(self, xleft, xright): self.minimapSelection.xy[:2, 0] = xleft self.minimapSelection.xy[2:4, 0] = xright self.draw_animate() def set_selection_visible(self, value): self.minimapSelection.set_visible(value) self.draw_animate() def create_marker(self, key, position, **kwargs): if self.xmin <= position <= self.xmax: marker = self.minimapFig.axes[0].axvline(position, animated=True) self.markers[key] = marker self.markers[key].set(**kwargs) def set_marker_position(self, key, value): marker = self.markers.get(key) if marker is not None: if self.xmin <= value <= self.xmax: marker.set_xdata(value) def set_marker(self, key, **kwargs): marker = self.markers.get(key) if marker is not None: kwargs.pop( "animated", None ) # marker's animated property must be always true to be drawn properly marker.set(**kwargs) def delete_marker(self, key): marker = self.markers.get(key) if marker is not None: self.minimapFig.axes[0].lines.remove(marker) self.markers.pop(key)
class PluginDialog(QDialog): def __init__(self, iface, parent=None, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) uic.loadUi(UI_PATH, self) self.iface = iface self.input_layer = None self.raster_layer = None self.roughness_layer = None #add channel info self.channel_info = None # self.name_box.setExpression('') # self.station_box.setExpression('') self.delta_box.setExpression('0.1') self.connection_box.setExpression("'standard'") self.type_box.setExpression("'river'") self.initial_box.setExpression('0.5') self.point_bc_enabled_box.setExpression('False') self.point_bc_stationary_box.setExpression('True') self.point_bc_value_box.setExpression('0') self.lateral_bc_enabled_box.setExpression('False') self.lateral_bc_stationary_box.setExpression('True') self.lateral_bc_value_box.setExpression('0') self.overflow_left_enabled_box.setExpression('True') self.overflow_left_poleni_box.setExpression('0.577') self.overflow_right_enabled_box.setExpression('True') self.overflow_right_poleni_box.setExpression('0.577') self.localbridgeheight_box.setExpression('1.5') self.bridgebodyheight_box.setExpression('4.0') self.groupBox_bridge.setCollapsed(True) self.mGroupBox_6.setCollapsed(True) self.mGroupBox.setCollapsed(True) self.mGroupBox_4.setCollapsed(True) self.mGroupBox_3.setCollapsed(True) self.mGroupBox_2.setCollapsed(True) self.groupBox_main.setCollapsed(True) self.mGroupBox_4.setCollapsed(False) #set DGM layer self.raster_layer_box.setFilters(QgsMapLayerProxyModel.RasterLayer) self.raster_layer_box.layerChanged.connect(self.setRasterLayer) self.raster_band_box.setEnabled(False) self.method_box.addItem('nearest neighbor (downscaling/upscaling)') self.method_box.addItem('bi-linear (downscaling)') self.method_box.addItem('bi-cubic (downscaling)') #set roughness layer self.roughness_layer_box.setFilters(QgsMapLayerProxyModel.RasterLayer) self.roughness_layer_box.layerChanged.connect(self.setRoughnessLayer) self.roughness_layer_box.setLayer(None) #set channel layer self.comboBox_main.setFilters(QgsMapLayerProxyModel.PolygonLayer) self.comboBox_main.layerChanged.connect(self.setChannelLayer) self.comboBox_main.setLayer(None) self.browse_button.clicked.connect(self.onBrowseButtonClicked) self.HelpButton.clicked.connect(self.Help) self.iface.currentLayerChanged.connect(self.setInputLayer) ############################################# #autostationing button function def autoclicked(state): if state > 0: self.profileid_box.setEnabled(True) self.station_box.setEnabled(False) self.preview_button.setDisabled(True) else: self.profileid_box.setEnabled(False) self.station_box.setEnabled(True) self.preview_button.setDisabled(False) self.profileid_box.setEnabled(False) self.autostation_box.stateChanged.connect(autoclicked) ############################################# if PREVIEW_ENABLED: self.figure = Figure(figsize=(10, 4), dpi=100) self.axes = self.figure.add_subplot(111) self.axes.set_xlabel('Stationing') self.axes.set_ylabel('Elevation [m+NHN]') self.figure.tight_layout() self.canvas = Canvas(self.figure) self.canvas.setParent(self) self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.layout().addWidget(self.canvas) self.canvas.setVisible(False) self.cursor = None self.preview_button.toggled.connect(self.canvas.setVisible) self.preview_button.toggled.connect(self.update_button.setEnabled) self.update_button.clicked.connect(self.updateLongitudinalPreview) else: self.preview_button.setDisabled(True) self.figure = None self.axes = None self.canvas = None self.cursor = None self.setInputLayer(self.iface.activeLayer()) self.setRasterLayer(self.raster_layer_box.currentLayer()) def __del__(self): #self.iface.currentLayerChanged.disconnect(self.setInputLayer) print('Done') def Help(self): webbrowser.open("https://promaides.myjetbrains.com/youtrack/articles/PMDP-A-45/1D-River-Profile-Export") def onBrowseButtonClicked(self): current_filename = self.filename_edit.text() new_filename, __ = QFileDialog.getSaveFileName(self.iface.mainWindow(), '1D-River Profile Export', current_filename) if new_filename != '': self.filename_edit.setText(new_filename) self.filename_edit.editingFinished.emit() def setInputLayer(self, layer): """ """ if not layer: self.input_layer = None self.input_label.setText(u'<i>No layer selected.<br>' u'Please select a polyline layer.</i>') else: layer_name = layer.name() if layer.type() == QgsMapLayer.VectorLayer: if layer.geometryType() == QgsWkbTypes.LineGeometry: self.input_layer = layer if layer.selectedFeatureCount(): self.input_label.setText(u'<i>Input layer is "{}" with {} selected feature(s).</i>' .format(layer_name, layer.selectedFeatureCount())) else: self.input_label.setText(u'<i>Input layer is "{}" with {} feature(s).</i>' .format(layer_name, layer.featureCount())) else: self.input_layer = None self.input_label.setText(u'<i>Selected layer "{}" is not a polyline layer.<br>' u'Please select a polyline layer.</i>' .format(layer_name)) else: self.input_layer = None self.input_label.setText(u'<i>Selected layer "{}" is not a vector layer.<br>' u'Please select a polyline layer.</i>' .format(layer_name)) self.name_box.setLayer(self.input_layer) self.station_box.setLayer(self.input_layer) self.delta_box.setLayer(self.input_layer) self.connection_box.setLayer(self.input_layer) self.type_box.setLayer(self.input_layer) self.initial_box.setLayer(self.input_layer) self.profileid_box.setLayer(self.input_layer) self.point_bc_enabled_box.setLayer(self.input_layer) self.point_bc_stationary_box.setLayer(self.input_layer) self.point_bc_value_box.setLayer(self.input_layer) self.lateral_bc_enabled_box.setLayer(self.input_layer) self.lateral_bc_stationary_box.setLayer(self.input_layer) self.lateral_bc_value_box.setLayer(self.input_layer) self.overflow_left_enabled_box.setLayer(self.input_layer) self.overflow_left_poleni_box.setLayer(self.input_layer) self.overflow_right_enabled_box.setLayer(self.input_layer) self.overflow_right_poleni_box.setLayer(self.input_layer) self.localbridgeheight_box.setLayer(self.input_layer) self.bridgebodyheight_box.setLayer(self.input_layer) self.updateButtonBox() def setRasterLayer(self, layer): self.raster_layer = layer if layer: self.raster_band_box.setEnabled(True) self.raster_band_box.setRange(1, layer.bandCount()) else: self.raster_band_box.setEnabled(False) self.updateButtonBox() def setRoughnessLayer(self, layer): self.roughness_layer = layer if layer: self.roughness_band_box.setEnabled(True) self.roughness_band_box.setRange(1, layer.bandCount()) else: self.roughness_band_box.setEnabled(False) def setChannelLayer(self, layer): self.channel_info = layer def updateButtonBox(self): if self.input_layer and self.raster_layer: self.button_box.button(QDialogButtonBox.Ok).setEnabled(True) else: self.button_box.button(QDialogButtonBox.Ok).setEnabled(False) def updateLongitudinalPreview(self): if not PREVIEW_ENABLED: self.iface.messageBar().pushCritical( 'River Profile Export', 'Preview is disabled since Python module "matplotlib" is not installed!' ) return flip_directions = self.flip_directions_box.isChecked() addfullriver = self.fullriver_box.isChecked() autostation = self.autostation_box.isChecked() abs_init = self.abs_init_box.isChecked() adjust_elevation = self.adjust_elevation_box.isChecked() input_layer = self.input_layer if not input_layer: return if input_layer.selectedFeatureCount(): selected = True features = input_layer.selectedFeatures() else: selected = False features = input_layer.getFeatures() stations, ok = QgsVectorLayerUtils.getValues(input_layer, self.station_box.expression(), selected) if not autostation: if not ok: self.iface.messageBar().pushCritical( 'River Profile Export', 'Invalid expression for stations!' ) return init_values, ok = QgsVectorLayerUtils.getValues(input_layer, self.initial_box.expression(), selected) if not ok: self.iface.messageBar().pushCritical( 'River Profile Export', 'Invalid expression for initial condition!' ) return dem_layer = self.raster_layer dem_band = self.raster_band_box.value() dem_method = self.method_box.currentText() dem_nan = self.nan_box.value() dem_interpol = RasterInterpolator(dem_layer, dem_band, 10, 10, dem_method, dem_nan) base, left, right, h = [], [], [], [] # iterate over profiles and extract base elevation, # left and right bank elevation, and init value for i, f in enumerate(features): # line = f.geometry().asPolyline() line = [] buff = f.geometry() for p in buff.vertices(): line.append(p) if flip_directions: line = list(reversed(line)) z = [dem_interpol(QgsPointXY(p)) for p in line] if adjust_elevation: if z[0] <= z[1]: z[0] = z[1] + 0.01 if z[-1] <= z[-2]: z[-1] = z[-2] + 0.01 i_min = np.argmin(z) # minimum profile elevation z_min = z[int(i_min)] base.append(z_min) left.append(z[0]) right.append(z[-1]) init_value = float(init_values[i]) # init values are absolute values if not abs_init: init_value += z_min h.append(init_value) s, base, left, right, h = list(zip(*sorted(zip(stations, base, left, right, h)))) self.axes.cla() self.axes.plot(s, base, 'k', lw=1.5, label='base') self.axes.plot(s, left, 'r', lw=1.0, label='left bank') self.axes.plot(s, right, 'g', lw=1.0, label='right bank') self.axes.plot(s, h, 'b--', lw=0.5, label='init. h') self.axes.legend() self.axes.set_xticks(s) self.axes.set_xticklabels(list(map(str, s)), rotation=90, fontdict=dict(fontsize=9)) self.axes.set_xlabel('Stationing') self.axes.set_ylabel('Elevation [m+NHN]') self.figure.tight_layout() self.cursor = Cursor(self.axes, useblit=True, color='0.5', linewidth=0.5) self.canvas.draw()
class StreamViewerWidget(QtGui.QWidget): """Shows the entire signal and allows the user to navigate through it. Provides an scrollable selector over the entire signal. Attributes: xmin: Selector lower limit (measured in h-axis units). xmax: Selector upper limit (measured in h-axis units). step: Selector length (measured in h-axis units). """ trace_selected = QtCore.Signal(int) selection_made = QtCore.Signal(bool) def __init__(self, parent, stream=None): super(StreamViewerWidget, self).__init__(parent) self.fig = plt.figure() self.canvas = FigureCanvas(self.fig) self.canvas.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Expanding, QtGui.QSizePolicy.Policy.Expanding)) self.canvas.setMinimumHeight(320) self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus) self.canvas.setFocus() self.graphArea = QtGui.QScrollArea(self) self.graphArea.setWidget(self.canvas) self.graphArea.setWidgetResizable(True) self.graphArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) # Set the layout self.layout = QtGui.QVBoxLayout(self) self.layout.addWidget(self.graphArea) # Animation related attrs. self.background = [] self.animated = False self.size = (self.fig.bbox.width, self.fig.bbox.height) # Set TracePlot list self.trace_plots = [] self.stream = None if stream is not None: self.set_stream(stream) # Event handling self.visible_axes = [] self._selected_traces = set() self.shift_pressed = False self.press_selector = None self.fig.canvas.mpl_connect('motion_notify_event', self.on_move) self.fig.canvas.mpl_connect('button_press_event', self.on_press) self.fig.canvas.mpl_connect('key_press_event', self.on_key_press) self.fig.canvas.mpl_connect('key_release_event', self.on_key_release) @property def selected_traces(self): if self.stream is not None: return [self.stream.traces[i] for i in self._selected_traces] return [] def on_move(self, event): axes_selected = False for i, axes in enumerate(self.fig.axes): if axes.get_visible(): ymin, ymax = axes.get_position().ymin, axes.get_position().ymax xmin, xmax = axes.get_position().xmin, axes.get_position().xmax xfig, yfig = self._event_to_fig_coords(event) if ymin <= yfig <= ymax and xmin <= xfig <= xmax: self.canvas.setToolTip(self.stream.traces[i].name) axes_selected = True break if not axes_selected: self.canvas.setToolTip("") def on_key_press(self, event): if event.key == 'control': self.shift_pressed = True def on_key_release(self, event): self.shift_pressed = False def on_press(self, event): trace_selected = False if event.button == 1:# and event.dblclick: for i, ax in enumerate(self.fig.axes): if ax.get_visible(): ymin, ymax = ax.get_position().ymin, ax.get_position().ymax xmin, xmax = ax.get_position().xmin, ax.get_position().xmax xfig, yfig = self._event_to_fig_coords(event) if ymin <= yfig <= ymax and xmin <= xfig <= xmax: trace_selected = True if self.shift_pressed: if self._selected_traces: self.trace_selected.emit(i) self.selection_made.emit(True) self._selected_traces.add(i) else: self.trace_selected.emit(i) self.selection_made.emit(True) self._selected_traces = {i} break # if the user clicked out of any trace (and he's not using shift), then deselect all if not trace_selected and not self.shift_pressed: self._selected_traces = set() self.selection_made.emit(False) # Now update selection status on plots for i, plot in enumerate(self.trace_plots): plot.set_selected(i in self._selected_traces) self.draw() def _event_to_fig_coords(self, event): inv = self.fig.transFigure.inverted() return inv.transform((event.x, event.y)) def set_stream(self, stream): self.stream = stream self._selected_traces = set() # Clear canvas for plot in self.trace_plots: plot.remove() self.trace_plots = [] # Plot stream traces for i, trace in enumerate(self.stream.traces): self.trace_plots.append(TracePlot(self, trace, fig_nrows=len(stream), ax_pos=i + 1)) # Draw canvas self.subplots_adjust() self.canvas.draw() self.background = self.canvas.copy_from_bbox(self.fig.bbox) self.draw() def refresh_stream_data(self): for plot in self.trace_plots: plot.update_data() def draw(self): self.canvas.draw() #self.draw_animate() def draw_animate(self): size = self.fig.bbox.width, self.fig.bbox.height if size != self.size: self.size = size self.canvas.draw() self.background = self.canvas.copy_from_bbox(self.fig.bbox) self.canvas.restore_region(self.background) for artist in self._get_animated_artists(): if artist.get_visible(): ax = artist.get_axes() if ax is not None: if artist.get_axes().get_visible(): self.fig.draw_artist(artist) else: self.fig.draw_artist(artist) self.canvas.blit(self.fig.bbox) def _get_animated_artists(self): artists = [] for ax in self.fig.axes: artists.extend(ax.images) artists.extend(ax.lines) artists.append(ax.xaxis) artists.append(ax.yaxis) artists.extend(ax.patches) artists.extend(ax.spines.values()) for artist in artists: if artist.get_animated(): yield artist def set_visible(self, value): self.canvas.setVisible(value) def get_visible(self): return self.canvas.isVisible() def remove_trace(self, idx): self.trace_plots.pop(idx).remove() def subplots_adjust(self): visible_subplots = [ax for ax in self.fig.get_axes() if ax.get_visible()] for i, ax in enumerate(visible_subplots): correct_geometry = (len(visible_subplots), 1, i + 1) if correct_geometry != ax.get_geometry(): ax.change_geometry(len(visible_subplots), 1, i + 1) # Adjust space between subplots self.fig.subplots_adjust(left=0.02, right=0.98, bottom=0.02, top=0.98, hspace=0.05) def showEvent(self, event): self.draw() def resizeEvent(self, event): self.draw() def update_markers(self): for plot in self.trace_plots: plot.update_markers() self.draw() def visualize_stream_range(self, start_trace=None, end_trace=None): for i, ax in enumerate(self.fig.axes): ax.set_visible(start_trace <= i < end_trace) self.subplots_adjust() self.canvas.draw()
class AppForm(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setWindowTitle('Web Log Analysis') self.create_menu() self.create_main_frame() self.create_status_bar() #self.on_draw() def save_plot(self): file_choices = "PNG (*.png)|*.png" path = unicode(QFileDialog.getSaveFileName(self, 'Save file', '', file_choices)) if path: self.canvas.print_figure(path, dpi=self.dpi) self.statusBar().showMessage('Saved to %s' % path, 2000) def on_about(self): msg = """ * All the fields of packets are displayed in table * These packets can be filtered out Filtering is done on the basis of IP and request method. syntax is: IP==82.28.27.27 METHOD==GET or METHOD==POST * Colour coding scheme is used for displaying packets For ex: RED :- Status code is 4xx or 5xx * After clicking on each packet, All the information about packet is displayed * There is toolbar and Menubar. Various options are present there. * After pressing graph menu, graph is displayed. Graph is plotted Number of bytes in MB/Number of days in may """ QMessageBox.about(self, "About the demo", msg.strip()) def on_pick(self, event): # The event received here is of the type # matplotlib.backend_bases.PickEvent # # It carries lots of information, of which we're using # only a small amount here. # box_points = event.artist.get_bbox().get_points() msg = "You've clicked on a bar with coords:\n %s" % box_points QMessageBox.information(self, "Click!", msg) def on_draw(self): if(len(self.data)!=0): print self.data[0][3] print self.data[0][9] d = {} print len(self.data) i = 0 for a in self.data: st = a[3] got_date = st[:2] if str(a[9]) == '-': print "Do nothing" else: got_date = int(got_date) s = d.keys() if got_date in s: print got_date," : ",d[got_date] d[got_date] = int(d[got_date]) + int(a[9]) else: d[got_date] = int(a[9]) print d[got_date] print d x = d.keys() y = d.values() for i in range(0,len(y)): y[i] = float(y[i])/ 1000000.0 print x print y # clear the axes and redraw the plot anew # self.axes.clear() self.axes.grid(True) self.axes.set_xlabel('Date of month') self.axes.set_ylabel('Size of data sent in MB') self.axes.bar( left=x, height=y, width=20.00 / 100.0, align='center', alpha=0.44, picker=10) self.canvas.draw() def myapply(self): expression = self.textbox.displayText() print "Expression in filter is "+expression if expression == "": tablemodel = MyTableModel(self, self.tabledata, self.header) self.tableview.setModel(tablemodel) self.tableview.resizeColumnsToContents() hh = self.tableview.horizontalHeader() hh.setStretchLastSection(True) elif expression[:4] == "IP==": IP_addr = expression[4:] temp = [] for a in self.tabledata: if a[0] == IP_addr: temp.append(a) if len(temp) == 0: QMessageBox.about(self, "Ooopps", "IP enterred is either wrong or there isn't entry for this IP.") else: tablemodel = MyTableModel(self, temp, self.header) self.tableview.setModel(tablemodel) self.tableview.resizeColumnsToContents() hh = self.tableview.horizontalHeader() hh.setStretchLastSection(True) elif expression[:8] == "METHOD==": method = expression[8:] temp = [] for a in self.tabledata: if a[2] == method: temp.append(a) if len(temp) == 0: QMessageBox.about(self, "Ooopps", "METHOD enterred is either wrong or there isn't entry for this.") else: tablemodel = MyTableModel(self, temp, self.header) self.tableview.setModel(tablemodel) self.tableview.resizeColumnsToContents() hh = self.tableview.horizontalHeader() hh.setStretchLastSection(True) else: if len(self.tabledata) == 0: QMessageBox.about(self, "Ooopps", "Table is empty") else: QMessageBox.about(self, "Ooopps", "Check your enterred expression!!") def up(self): print "Up" def myrefresh(self): print "refresh" def down(self): print "down" def show_graph(self): self.tableview.setVisible(False) self.list.setVisible(False) print "graph" self.canvas.setVisible(True) self.mpl_toolbar.setVisible(True) self.on_draw() def show_table(self): self.canvas.setVisible(False) self.mpl_toolbar.setVisible(False) print "show_table" self.tableview.setVisible(True) self.list.setVisible(True) def myopen(self): print "open" self.tabledata = [] self.data = [] filename = QFileDialog.getOpenFileName(self, 'Open File', '/') print filename f = open(filename,'r+') for line in f: matchObj = re.match( r'(.*?) (.*?) (.*?) \[(.*?) (.*?)\] "(.*?) (.*?) (.*?)" (.*?) (.*?) "(.*?)" "(.*)"', line, re.M|re.I) if matchObj: a = (matchObj.group(1),matchObj.group(4),matchObj.group(6),matchObj.group(9),matchObj.group(10),matchObj.group(7)) self.tabledata.append(a) b = (matchObj.group(1),matchObj.group(2),matchObj.group(3),matchObj.group(4),matchObj.group(5),matchObj.group(6),matchObj.group(7),matchObj.group(8),matchObj.group(9),matchObj.group(10),matchObj.group(11),matchObj.group(12)) self.data.append(b) tablemodel = MyTableModel(self, self.tabledata, self.header) self.tableview.setModel(tablemodel) self.tableview.resizeColumnsToContents() hh = self.tableview.horizontalHeader() hh.setStretchLastSection(True) self.btn.setEnabled(True) def myclose(self): print "close" self.close() def viewclicked(self,index): row = index.row() self.list.clear() self.list.addItem(QListWidgetItem("Ip address "+self.data[row][0])) self.list.addItem(QListWidgetItem("User-identifier "+self.data[row][1])) self.list.addItem(QListWidgetItem("Frank "+self.data[row][2])) self.list.addItem(QListWidgetItem("Date and Time "+self.data[row][3])) self.list.addItem(QListWidgetItem("Request Method "+self.data[row][5])) self.list.addItem(QListWidgetItem("URL "+self.data[row][6])) self.list.addItem(QListWidgetItem("Http version "+self.data[row][7])) self.list.addItem(QListWidgetItem("Status "+self.data[row][8])) self.list.addItem(QListWidgetItem("Bytes sent "+self.data[row][9])) self.list.addItem(QListWidgetItem("Web page referred "+self.data[row][10])) self.list.addItem(QListWidgetItem("Browser information"+self.data[row][11])) def create_main_frame(self): self.main_frame = QWidget() self.data = [] exitAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'Exit', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(self.myclose) openAction = QtGui.QAction(QtGui.QIcon('open24.jpeg'), 'Open', self) openAction.setShortcut('Ctrl+O') openAction.setStatusTip('Open File') openAction.triggered.connect(self.myopen) tableAction = QtGui.QAction(QtGui.QIcon('table24.png'), 'Table', self) tableAction.setShortcut('Ctrl+T') tableAction.setStatusTip('Table View') tableAction.triggered.connect(self.show_table) graphAction = QtGui.QAction(QtGui.QIcon('graph24.png'), 'Graph', self) graphAction.setShortcut('Ctrl+G') graphAction.setStatusTip('Graphical View') graphAction.triggered.connect(self.show_graph) refreshAction = QtGui.QAction(QtGui.QIcon('refresh24.gif'), 'Refresh', self) refreshAction.setStatusTip('Refresh') refreshAction.triggered.connect(self.myrefresh) upAction = QtGui.QAction(QtGui.QIcon('up24.gif'), 'Up', self) upAction.setStatusTip('Up') upAction.triggered.connect(self.up) downAction = QtGui.QAction(QtGui.QIcon('down24.gif'), 'Down', self) downAction.setStatusTip('Down') downAction.triggered.connect(self.down) self.dpi = 150 self.fig = Figure((5.0, 4.0), dpi=self.dpi) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.main_frame) self.axes = self.fig.add_subplot(111) self.canvas.mpl_connect('pick_event', self.on_pick) self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame) self.canvas.move(280,80) self.mpl_toolbar.move(280,80) self.canvas.setVisible(False) self.mpl_toolbar.setVisible(False) toolbar = self.addToolBar('Exit') toolbar.setStyleSheet('QToolBar{spacing:10px;}') toolbar.addAction(openAction) toolbar.addSeparator() toolbar.addAction(tableAction) toolbar.addAction(graphAction) toolbar.addSeparator() toolbar.addAction(refreshAction) toolbar.addAction(upAction) toolbar.addAction(downAction) toolbar.addSeparator() toolbar.addAction(exitAction) self.textbox = QtGui.QLineEdit(self) self.textbox.resize(280,35) self.textbox.move(10, 70) self.btn = QPushButton('Apply', self) self.btn.setToolTip('Click to apply expression') self.btn.resize(self.btn.sizeHint()) self.btn.move(300, 73) self.btn.clicked.connect(self.myapply) self.btn.setEnabled(False) self.tabledata = [()] self.header = [" IP address "," Date and time "," Request Method "," Status code "," Number of bytes "," URL "] tablemodel = MyTableModel(self, self.tabledata, self.header) self.tableview = QTableView(self) self.tableview.setModel(tablemodel) self.tableview.move(10, 130) screen = QtGui.QDesktopWidget().screenGeometry() self.tableview.resize((screen.width())-100, ((screen.height())/7)*3) # set font font = QFont("Arial Black", 10) self.tableview.setFont(font) # set column width to fit contents (set font first!) #self.tableview.resizeColumnsToContents() self.tableview.setShowGrid(False) self.tableview.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.tableview.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self.tableview.setStyleSheet('background-color:rgb(180, 250, 140);') self.tableview.clicked.connect(self.viewclicked) #hh = self.tableview.horizontalHeader() #hh.setStretchLastSection(True) # set row height nrows = len(self.tabledata) for row in xrange(nrows): self.tableview.setRowHeight(row, 24) vh = self.tableview.verticalHeader() vh.setVisible(False) screen = QtGui.QDesktopWidget().screenGeometry() self.list = QListWidget(self) self.list.move(10 , 150 + ((screen.height())/7)*3) self.list.resize((screen.width())-100, ((screen.height())/4)) self.showMaximized() self.setCentralWidget(self.canvas) def create_status_bar(self): self.status_text = QLabel("Ready") self.statusBar().addWidget(self.status_text, 1) def create_menu(self): self.file_menu = self.menuBar().addMenu("&File") load_file_action = self.create_action("&Save plot", shortcut="Ctrl+S", slot=self.save_plot, tip="Save the plot") quit_action = self.create_action("&Quit", slot=self.close, shortcut="Ctrl+Q", tip="Close the application") self.add_actions(self.file_menu, (load_file_action, None, quit_action)) self.help_menu = self.menuBar().addMenu("&Help") about_action = self.create_action("&About", shortcut='F1', slot=self.on_about, tip='About the demo') self.add_actions(self.help_menu, (about_action,)) def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def create_action( self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action
class StreamViewerWidget(QtGui.QWidget): """Shows the entire signal and allows the user to navigate through it. Provides an scrollable selector over the entire signal. Attributes: xmin: Selector lower limit (measured in h-axis units). xmax: Selector upper limit (measured in h-axis units). step: Selector length (measured in h-axis units). """ trace_selected = QtCore.Signal(int) selection_made = QtCore.Signal(bool) def __init__(self, parent, stream=None): super(StreamViewerWidget, self).__init__(parent) self.fig = plt.figure() self.canvas = FigureCanvas(self.fig) self.canvas.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Expanding, QtGui.QSizePolicy.Policy.Expanding)) self.canvas.setMinimumHeight(320) self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus) self.canvas.setFocus() self.graphArea = QtGui.QScrollArea(self) self.graphArea.setWidget(self.canvas) self.graphArea.setWidgetResizable(True) self.graphArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) # Set the layout self.layout = QtGui.QVBoxLayout(self) self.layout.addWidget(self.graphArea) # Animation related attrs. self.background = [] self.animated = False self.size = (self.fig.bbox.width, self.fig.bbox.height) # Set TracePlot list self.trace_plots = [] self.stream = None if stream is not None: self.set_stream(stream) # Event handling self.visible_axes = [] self._selected_traces = set() self.shift_pressed = False self.press_selector = None self.fig.canvas.mpl_connect('motion_notify_event', self.on_move) self.fig.canvas.mpl_connect('button_press_event', self.on_press) self.fig.canvas.mpl_connect('key_press_event', self.on_key_press) self.fig.canvas.mpl_connect('key_release_event', self.on_key_release) @property def selected_traces(self): if self.stream is not None: return [self.stream.traces[i] for i in self._selected_traces] return [] def on_move(self, event): axes_selected = False for i, axes in enumerate(self.fig.axes): if axes.get_visible(): ymin, ymax = axes.get_position().ymin, axes.get_position().ymax xmin, xmax = axes.get_position().xmin, axes.get_position().xmax xfig, yfig = self._event_to_fig_coords(event) if ymin <= yfig <= ymax and xmin <= xfig <= xmax: self.canvas.setToolTip(self.stream.traces[i].name) axes_selected = True break if not axes_selected: self.canvas.setToolTip("") def on_key_press(self, event): if event.key == 'control': self.shift_pressed = True def on_key_release(self, event): self.shift_pressed = False def on_press(self, event): trace_selected = False if event.button == 1: # and event.dblclick: for i, ax in enumerate(self.fig.axes): if ax.get_visible(): ymin, ymax = ax.get_position().ymin, ax.get_position().ymax xmin, xmax = ax.get_position().xmin, ax.get_position().xmax xfig, yfig = self._event_to_fig_coords(event) if ymin <= yfig <= ymax and xmin <= xfig <= xmax: trace_selected = True if self.shift_pressed: if self._selected_traces: self.trace_selected.emit(i) self.selection_made.emit(True) self._selected_traces.add(i) else: self.trace_selected.emit(i) self.selection_made.emit(True) self._selected_traces = {i} break # if the user clicked out of any trace (and he's not using shift), then deselect all if not trace_selected and not self.shift_pressed: self._selected_traces = set() self.selection_made.emit(False) # Now update selection status on plots for i, plot in enumerate(self.trace_plots): plot.set_selected(i in self._selected_traces) self.draw() def _event_to_fig_coords(self, event): inv = self.fig.transFigure.inverted() return inv.transform((event.x, event.y)) def set_stream(self, stream): self.stream = stream self._selected_traces = set() # Clear canvas for plot in self.trace_plots: plot.remove() self.trace_plots = [] # Plot stream traces for i, trace in enumerate(self.stream.traces): self.trace_plots.append( TracePlot(self, trace, fig_nrows=len(stream), ax_pos=i + 1)) # Draw canvas self.subplots_adjust() self.canvas.draw() self.background = self.canvas.copy_from_bbox(self.fig.bbox) self.draw() def refresh_stream_data(self): for plot in self.trace_plots: plot.update_data() def draw(self): self.canvas.draw() #self.draw_animate() def draw_animate(self): size = self.fig.bbox.width, self.fig.bbox.height if size != self.size: self.size = size self.canvas.draw() self.background = self.canvas.copy_from_bbox(self.fig.bbox) self.canvas.restore_region(self.background) for artist in self._get_animated_artists(): if artist.get_visible(): ax = artist.get_axes() if ax is not None: if artist.get_axes().get_visible(): self.fig.draw_artist(artist) else: self.fig.draw_artist(artist) self.canvas.blit(self.fig.bbox) def _get_animated_artists(self): artists = [] for ax in self.fig.axes: artists.extend(ax.images) artists.extend(ax.lines) artists.append(ax.xaxis) artists.append(ax.yaxis) artists.extend(ax.patches) artists.extend(ax.spines.values()) for artist in artists: if artist.get_animated(): yield artist def set_visible(self, value): self.canvas.setVisible(value) def get_visible(self): return self.canvas.isVisible() def remove_trace(self, idx): self.trace_plots.pop(idx).remove() def subplots_adjust(self): visible_subplots = [ ax for ax in self.fig.get_axes() if ax.get_visible() ] for i, ax in enumerate(visible_subplots): correct_geometry = (len(visible_subplots), 1, i + 1) if correct_geometry != ax.get_geometry(): ax.change_geometry(len(visible_subplots), 1, i + 1) # Adjust space between subplots self.fig.subplots_adjust(left=0.02, right=0.98, bottom=0.02, top=0.98, hspace=0.05) def showEvent(self, event): self.draw() def resizeEvent(self, event): self.draw() def update_markers(self): for plot in self.trace_plots: plot.update_markers() self.draw() def visualize_stream_range(self, start_trace=None, end_trace=None): for i, ax in enumerate(self.fig.axes): ax.set_visible(start_trace <= i < end_trace) self.subplots_adjust() self.canvas.draw()
class MiniMap(QtGui.QWidget): """Shows the entire signal and allows the user to navigate through it. Provides an scrollable selector over the entire signal. Attributes: xmin: Selector lower limit (measured in h-axis units). xmax: Selector upper limit (measured in h-axis units). step: Selector length (measured in h-axis units). """ def __init__(self, parent, ax, record=None): super(MiniMap, self).__init__(parent) self.ax = ax self.xmin = 0.0 self.xmax = 0.0 self.step = 10.0 self.xrange = np.array([]) self.minimapFig = plt.figure() self.minimapFig.set_figheight(0.75) self.minimapFig.add_axes((0, 0, 1, 1)) self.minimapCanvas = FigureCanvas(self.minimapFig) self.minimapCanvas.setFixedHeight(64) self.minimapSelector = self.minimapFig.axes[0].axvspan(0, self.step, color='gray', alpha=0.5, animated=True) self.minimapSelection = self.minimapFig.axes[0].axvspan(0, self.step, color='LightCoral', alpha = 0.5, animated=True) self.minimapSelection.set_visible(False) self.minimapBackground = [] self.minimapSize = (self.minimapFig.bbox.width, self.minimapFig.bbox.height) self.press_selector = None self.playback_marker = None self.minimapCanvas.mpl_connect('button_press_event', self.onpress) self.minimapCanvas.mpl_connect('button_release_event', self.onrelease) self.minimapCanvas.mpl_connect('motion_notify_event', self.onmove) # Animation related attrs. self.background = None self.animated = False # Set the layout self.layout = QtGui.QVBoxLayout(self) self.layout.addWidget(self.minimapCanvas) # Animation related attributes self.parentViewer = parent # Set Markers dict self.markers = {} self.record = None if record is not None: self.set_record(record) def set_record(self, record, step): self.record = record self.step = step self.xrange = np.linspace(0, len(self.record.signal) / self.record.fs, num=len(self.record.signal), endpoint=False) self.xmin = self.xrange[0] self.xmax = self.xrange[-1] self.markers = {} ax = self.minimapFig.axes[0] ax.lines = [] formatter = FuncFormatter(lambda x, pos: str(datetime.timedelta(seconds=x))) ax.xaxis.set_major_formatter(formatter) ax.grid(True, which='both') # Set dataseries to plot xmin = self.xmin * self.record.fs xmax = self.xmax * self.record.fs pixel_width = np.ceil(self.minimapFig.get_figwidth() * self.minimapFig.get_dpi()) x_data, y_data = plotting.reduce_data(self.xrange, self.record.signal, pixel_width, xmin, xmax) # self._plot_data.set_xdata(x_data) # self._plot_data.set_ydata(y_data) ax.plot(x_data, y_data, color='black', rasterized=True) ax.set_xlim(self.xmin, self.xmax) plotting.adjust_axes_height(ax) # Set the playback marker self.playback_marker = PlayBackMarker(self.minimapFig, self) self.playback_marker.markers[0].set_animated(True) # Draw canvas self.minimapCanvas.draw() self.minimapBackground = self.minimapCanvas.copy_from_bbox(self.minimapFig.bbox) self.draw_animate() def onpress(self, event): self.press_selector = event xdata = round(self.get_xdata(event), 2) xmin = round(xdata - (self.step / 2.0), 2) xmax = round(xdata + (self.step / 2.0), 2) self.parentViewer._set_animated(True) self.set_selector_limits(xmin, xmax) def onrelease(self, event): self.press_selector = None # Finish parent animation self.parentViewer._set_animated(False) def onmove(self, event): if self.press_selector is not None: xdata = round(self.get_xdata(event), 2) xmin = round(xdata - (self.step / 2.0), 2) xmax = round(xdata + (self.step / 2.0), 2) self.set_selector_limits(xmin, xmax) def get_xdata(self, event): inv = self.minimapFig.axes[0].transData.inverted() xdata, _ = inv.transform((event.x, event.y)) return xdata def set_selector_limits(self, xmin, xmax): step = xmax - xmin if step >= self.xmax - self.xmin: xleft = self.xmin xright = self.xmax if xmin < self.xmin: xleft = self.xmin xright = self.step elif xmax > self.xmax: xleft = self.xmax - step xright = self.xmax else: xleft = xmin xright = xmax if (xleft, xright) != (self.minimapSelector.xy[1, 0], self.minimapSelector.xy[2, 0]): self.step = step self.minimapSelector.xy[:2, 0] = xleft self.minimapSelector.xy[2:4, 0] = xright self.ax.set_xlim(xleft, xright) self.draw_animate() else: self.parentViewer.draw() def get_selector_limits(self): return self.minimapSelector.xy[0, 0], self.minimapSelector.xy[2, 0] def draw(self): self.draw_animate() def draw_animate(self): size = self.minimapFig.bbox.width, self.minimapFig.bbox.height if size != self.minimapSize: self.minimapSize = size self.minimapCanvas.draw() self.minimapBackground = self.minimapCanvas.copy_from_bbox(self.minimapFig.bbox) self.minimapCanvas.restore_region(self.minimapBackground) self.minimapFig.draw_artist(self.minimapSelection) self.minimapFig.draw_artist(self.minimapSelector) self.minimapFig.draw_artist(self.playback_marker.markers[0]) for marker in self.markers.values(): self.minimapFig.draw_artist(marker) self.minimapCanvas.blit(self.minimapFig.bbox) def set_visible(self, value): self.minimapCanvas.setVisible(value) def get_visible(self): return self.minimapCanvas.isVisible() def set_selection_limits(self, xleft, xright): self.minimapSelection.xy[:2, 0] = xleft self.minimapSelection.xy[2:4, 0] = xright self.draw_animate() def set_selection_visible(self, value): self.minimapSelection.set_visible(value) self.draw_animate() def create_marker(self, key, position, **kwargs): if self.xmin <= position <= self.xmax: marker = self.minimapFig.axes[0].axvline(position, animated=True) self.markers[key] = marker self.markers[key].set(**kwargs) def set_marker_position(self, key, value): marker = self.markers.get(key) if marker is not None: if self.xmin <= value <= self.xmax: marker.set_xdata(value) def set_marker(self, key, **kwargs): marker = self.markers.get(key) if marker is not None: kwargs.pop("animated", None) # marker's animated property must be always true to be drawn properly marker.set(**kwargs) def delete_marker(self, key): marker = self.markers.get(key) if marker is not None: self.minimapFig.axes[0].lines.remove(marker) self.markers.pop(key)