class MatplotlibPlot: """ Class encapsulating a matplotlib plot""" def __init__(self, parent = None, dpi = 100, size = (5,5)): """ Class initialiser """ self.dpi = dpi self.figure = Figure(size, dpi = self.dpi) self.canvas = FigureCanvas(self.figure) self.canvas.setParent(parent) # Create the navigation toolbar, tied to the canvas self.toolbar = NavigationToolbar(self.canvas, parent) self.canvas.show() self.toolbar.show() # Reset the plot landscape self.figure.clear() def plotMultiPixel(self, info, data): """ Generate multi-pixel plot """ # Tabula Rasa self.figure.clear() rows = math.ceil(math.sqrt(info['nbeams'])) # Display a subplot per beam (randomly for now) for i in range(info['nbeams']): ax = self.figure.add_subplot(rows, rows, i) ax.plot(data[:,512,i]) def updatePlot(self): self.canvas.draw()
class MatplotlibPlot: """ Class encapsulating an matplotlib plot""" def __init__(self, parent=None, dpi=100, size=(5, 4)): """ Class initialiser """ self.dpi = dpi self.figure = Figure(size, dpi=self.dpi) self.canvas = FigureCanvas(self.figure) self.canvas.setParent(parent) # Create the navigation toolbar, tied to the canvas self.toolbar = NavigationToolbar(self.canvas, parent) self.canvas.show() self.toolbar.show() def plotCurve(self, data, xAxisRange=None, yAxisRange=None, xLabel="", yLabel=""): """ Plot the data as a curve""" # clear the axes and redraw the plot anew self.figure.clear() self.axes = self.figure.add_subplot(111) self.axes.grid(True) self.axes.plot(range(np.size(data)), data) if xAxisRange is not None: self.xAxisRange = xAxisRange self.axes.xaxis.set_major_formatter( ticker.FuncFormatter( lambda x, pos=None: '%.2f' % self.xAxisRange[x] if 0 <= x < len(xAxisRange) else '')) for tick in self.axes.xaxis.get_ticklabels(): tick.set_rotation(15) if yAxisRange is not None: self.yAxisRange = yAxisRange self.axes.xaxis.set_major_formatter( ticker.FuncFormatter( lambda x, pos=None: '%.1f' % self.yAxisRange[y] if 0 <= y < len(yAxisRange) else '')) for tick in self.axes.yaxis.get_ticklabels(): tick.set_rotation(15) self.axes.xaxis.set_label_text(xLabel) self.axes.yaxis.set_label_text(yLabel) self.canvas.draw()
class MatplotlibPlot: """ Class encapsulating an matplotlib plot""" def __init__(self, parent = None, dpi = 100, size = (5,4)): """ Class initialiser """ self.dpi = dpi self.figure = Figure(size, dpi = self.dpi) self.canvas = FigureCanvas(self.figure) self.canvas.setParent(parent) # Create the navigation toolbar, tied to the canvas self.toolbar = NavigationToolbar(self.canvas, parent) self.canvas.show() self.toolbar.show() def plotCurve(self, data, xAxisRange = None, yAxisRange = None, xLabel = "", yLabel = ""): """ Plot the data as a curve""" # clear the axes and redraw the plot anew self.figure.clear() self.axes = self.figure.add_subplot(111) self.axes.grid(True) self.axes.plot(range(np.size(data)), data) if xAxisRange is not None: self.xAxisRange = xAxisRange self.axes.xaxis.set_major_formatter(ticker.FuncFormatter( lambda x, pos=None: '%.2f' % self.xAxisRange[x] if 0 <= x < len(xAxisRange) else '')) for tick in self.axes.xaxis.get_ticklabels(): tick.set_rotation(15) if yAxisRange is not None: self.yAxisRange = yAxisRange self.axes.xaxis.set_major_formatter(ticker.FuncFormatter( lambda x, pos=None: '%.1f' % self.yAxisRange[y] if 0 <= y < len(yAxisRange) else '')) for tick in self.axes.yaxis.get_ticklabels(): tick.set_rotation(15) self.axes.xaxis.set_label_text(xLabel) self.axes.yaxis.set_label_text(yLabel) self.canvas.draw()
class MatplotlibPlot: """ Class encapsulating an matplotlib plot """ def __init__(self, parent=None, dpi=100, size=(5, 4)): """ Class initialiser """ self.dpi = dpi self.figure = Figure(dpi=self.dpi) self.canvas = FigureCanvas(self.figure) self.canvas.setParent(parent) # Create the navigation toolbar, tied to the canvas self.toolbar = NavigationToolbar(self.canvas, parent) self.canvas.show() self.toolbar.show() def plotCurve(self, data, numCurves=1, labels=None, xAxisRange=None, yAxisRange=None, xLabel="", yLabel=""): """ Normal plots """ self.figure.clear() self.axes = self.figure.add_subplot(111) self.axes.grid(True) # Set empty labels if non defined if labels is None: labels = ['' for i in range(numImages)] # Place all plots in axes for i in range(numCurves): self.axes.plot(data[:, i], label=labels[i]) self.axes.set_xlim((0, len(data[:, i]))) # Final touches self.axes.xaxis.set_label_text(xLabel) self.axes.yaxis.set_label_text(yLabel) self.canvas.draw() def subplotCurve(self, data, numPlots=1, labels=None, xAxisRange=None, yAxisRange=None, xLabel="", yLabel=""): """ Subplot mode """ self.figure.clear() # Set empty labels if non defined if labels is None: labels = ['' for i in range(numImages)] if numPlots == 1: ax = self.figure.add_subplot(111) ax.plot(data[:]) ax.set_xlabel(xLabel) ax.set_ylabel(yLabel) ax.set_title(labels[0]) ax.grid(True) else: # Plot each image num_rows = ceil(sqrt(numPlots)) for i in range(numPlots): ax = self.figure.add_subplot(num_rows, num_rows, i + 1) ax.plot(data[:, i]) ax.set_xlim((0, len(data[:, i]))) ax.set_xlabel(xLabel) ax.set_ylabel(yLabel) ax.set_title(labels[i]) ax.grid(True) # Final touches self.figure.tight_layout() self.canvas.draw() def plotImage(self, data, numImages=1, labels=None, xAxisRange=None, yAxisRange=None, xLabel="", yLabel=""): """ Image plot """ self.figure.clear() self.axes = self.figure.add_subplot(111) # Show image im = self.axes.imshow(data, origin='lower', aspect='auto') # Final touches self.axes.xaxis.set_label_text(xLabel) self.axes.yaxis.set_label_text(yLabel) self.figure.colorbar(im) self.canvas.draw() def subplotImage(self, data, numImages=1, labels=None, xAxisRange=None, yAxisRange=None, xLabel="", yLabel=""): """ Image subplot """ # Clear figure self.figure.clear() # Set empty labels if non defined if labels is None: labels = ['' for i in range(numImages)] # Plot each image num_rows = ceil(sqrt(numImages)) for i in range(numImages): ax = self.figure.add_subplot(num_rows, num_rows, i + 1) im = ax.imshow(data[:, :, i], origin='lower', aspect='auto') ax.set_xlabel(xLabel) ax.set_ylabel(yLabel) ax.set_title(labels[i]) # Final touches self.figure.tight_layout() self.canvas.draw()
class plothistogram(QFrame): def __init__(self, parent): print "__init__()" # DEBUG QFrame.__init__(self) self.parent=parent #self.setModal(False) self.data1=self.parent.y1 # get plotted y values from solutions plot self.data2=self.parent.y2 # get plotted y values from parameter plot self.nbins=50 # default=50 bins self.parameter=self.parent.parent.parametersComboBox.currentText() self.data=self.parent.y2 # set histogram to solver parameter data #print "self.data = ", self.data # DEBUG # Create canvas for plotting self.rim=0.1 self.fig = Figure((5, 4), dpi=100) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self) self.fig.subplots_adjust(left=self.rim, right=1.0-self.rim, top=1.0-self.rim, bottom=self.rim) # set a small rim self.mpl_toolbar = NavigationToolbar(self.canvas, self) self.mpl_toolbar.show() # first hide the toolbar self.ax=self.fig.add_subplot(111) self.createWidgets() self.createLayout() self.connectSignals() self.setLabels() self.plot() def createWidgets(self): #print "createWidgets()" # DEBUG self.closeButton=QPushButton("Close") self.closeButton.setToolTip("close this plotwindow") self.closeButton.show() self.histogramBinSpin=QSpinBox() # spinbox for histogram binsize self.histogramBinSpin.setToolTip("Number of bins to histogram into") self.histogramBinSpin.setMinimum(5) #self.histogramBinSpin.setMaximum(150) # set a maximum of 150 (reasonable?) self.histogramBinSpin.setSingleStep(10) # allow only stepping by 10 self.histogramBinSpin.setMaximumWidth(120) self.histogramBinSpin.setMinimumHeight(25) self.histogramBinSpin.setValue(self.nbins) self.histogramBinSpin.show() self.histogramBinLabel=QLabel("Bins") self.normedCheckBox=QCheckBox() self.normedCheckLabel=QLabel("Normalize") self.normedCheckBox.setToolTip("Normalize histogram") self.normedCheckBox.show() #self.dpi = 100 self.dataComboBox=QComboBox() self.dataComboBox.addItem(self.parent.parent.parmValueComboBox.currentText()) self.dataComboBox.addItem(self.parent.parent.parametersComboBox.currentText()) self.dataComboBox.setMaximumWidth(120) self.dataComboBox.setMinimumHeight(25) self.dataComboBox.setCurrentIndex(1) def createLayout(self): #print "createLayout()" # DEBUG self.normedLayout=QHBoxLayout() self.normedLayout.addWidget(self.normedCheckBox) self.normedLayout.addWidget(self.normedCheckLabel) self.buttonLayout=QVBoxLayout() self.plotLayout=QVBoxLayout() self.mainLayout=QHBoxLayout() self.buttonLayout.addLayout(self.normedLayout) #self.buttonLayout.addWidget(self.normedCheckBox) #self.buttonLayout.addWidget(self.normedCheckLabel) self.buttonLayout.addWidget(self.histogramBinSpin) self.buttonLayout.addWidget(self.dataComboBox) self.buttonLayout.insertStretch(-1) self.buttonLayout.addWidget(self.closeButton) self.plotLayout.addWidget(self.canvas) self.plotLayout.addWidget(self.mpl_toolbar) self.mainLayout.addLayout(self.buttonLayout) self.mainLayout.addLayout(self.plotLayout) self.setLayout(self.mainLayout) def setLabels(self): self.ax.xlabel="Bin" self.ax.ylabel="N" def setTitle(self): #=self.parent.parametersComboBox.currentText() #self.ax.xlabel=self.parmValueComboBox.currentText() #self.ax.xlabel="Bin No." #self.ax.ylabel="n" self.ax.title=self.parent.parent.parametersComboBox.currentText() def connectSignals(self): self.connect(self.closeButton, SIGNAL('clicked()'), SLOT('close()')) self.connect(self.histogramBinSpin, SIGNAL('valueChanged(int)'), self.on_changeBinSpin) self.connect(self.normedCheckBox, SIGNAL('stateChanged(int)'), self.on_normedCheckBox) self.connect(self.dataComboBox, SIGNAL('currentIndexChanged(int)'), self.on_data) def on_changeBinSpin(self): self.nbins=self.histogramBinSpin.value() # create histogram #n, bins = np.histogram(self.data, self.histogramBinSpin.value(), normed=self.normedCheckBox.isChecked()) #hist, bins=np.histogram(self.data, self.nbins, normed=self.normedCheckBox.isChecked()) #print "len(bins) = ", len(bins), " len(n) = ", len(n) #self.ax.plot(bins[1:], n, color='red') #self.canvas.draw() #self.ax.legend() #self.fig.draw_idle() # redraw (preferably when idle) self.plot() def on_normedCheckBox(self): self.plot() def on_data(self): print "on_data()" # DEBUG if self.dataComboBox.currentText()==self.parent.parent.parametersComboBox.currentText(): self.data=self.data2 else: self.data=self.data1 self.plot() def plot(self): self.fig.delaxes(self.ax) # delete all axes first self.ax=self.fig.add_subplot(111) n, bins = np.histogram(self.data, self.histogramBinSpin.value(), normed=self.normedCheckBox.isChecked()) self.xmin=bins[1] self.xmax=bins[len(bins)-1] self.ax.bar(bins[1:], n, color='blue', width=(self.xmax-self.xmin)/len(bins)) self.canvas.draw()
class MatplotlibPlot: """ Class encapsulating a matplotlib plot""" def __init__(self, parent = None, dpi = 100, size = (5,5)): """ Class initialiser """ self.dpi = dpi self.figure = Figure(size, dpi = self.dpi) self.canvas = FigureCanvas(self.figure) self.canvas.setParent(parent) # Create the navigation toolbar, tied to the canvas self.toolbar = NavigationToolbar(self.canvas, parent) self.canvas.show() self.toolbar.show() # Reset the plot landscape self.figure.clear() self.nSubplot=0 def resetSubplots(self): self.nSubplot=0 def plotCurve(self, data, xAxisRange = None, yAxisRange = None, xLabel = "", yLabel = "", title="", label="", plotLog=False, nSubplots=1, hold=False): """ Plot the data as a curve""" if len(data) != 0: # Plan what dimensions the grid will have if there are to be subplots # Attempt to be roughly square but give preference to vertical stacking nSubplots_v = np.ceil(np.sqrt(nSubplots)) nSubplots_h = np.ceil(float(nSubplots)/nSubplots_v) yAxisRange=np.array(yAxisRange) if yAxisRange is not None: auto_scale_y = False if plotLog: data[data==0] = 1 yAxisRange[yAxisRange==0] = 1 data= 10*np.log(data) yAxisRange = 10*np.log(yAxisRange) else: auto_scale_y = True # draw the new plot if self.nSubplot < nSubplots: self.axes = self.figure.add_subplot(nSubplots_v, nSubplots_h, self.nSubplot+1, label=label, title=title, ylim=yAxisRange) #subplots start from 1 self.axes.grid(True) #if plotLog: # self.axes.semilogy(range(np.size(data)), data, scaley=auto_scale_y) #else: # self.axes.plot(range(np.size(data)), data, scaley=auto_scale_y) self.axes.plot(range(np.size(data)), data, scaley=auto_scale_y) #if xAxisRange is not None: # self.xAxisRange = xAxisRange # self.axes.xaxis.set_major_formatter(ticker.FuncFormatter( # lambda x, pos=None: '%.2f' % self.xAxisRange[x] if 0 <= x < len(xAxisRange) else '')) # for tick in self.axes.xaxis.get_ticklabels(): # tick.set_rotation(15) #if yAxisRange is not None: # self.yAxisRange = yAxisRange # self.axes.xaxis.set_major_formatter(ticker.FuncFormatter( # lambda x, pos=None: '%.1f' % self.yAxisRange[y] if 0 <= y < len(yAxisRange) else '')) # for tick in self.axes.yaxis.get_ticklabels(): # tick.set_rotation(15) self.axes.xaxis.set_label_text(xLabel) self.axes.yaxis.set_label_text(yLabel) # Increment the subplot number ready for the plot method to be called again. # Count modulo number of subplots so that nSubplots=1 is the same as having a # single shared axis. # Skip this step if hold is set, in which case the next plot will be overlaid with the current one if not hold: self.nSubplot = (self.nSubplot + 1) def plotNewCurve(self, data, xAxisRange=None, yAxisRange=None, xLabel="", yLabel="", plotLog=False): # Clear the plot self.figure.clear() # Start from a new set of subplots self.nSubplot = 0 self.plotCurve(self, data, xAxisRange=xAxisRange, yAxisRange=yAxisRange, xLabel=xLabel, yLabel=yLabel, plotLog=plotLog) def updatePlot(self): self.canvas.draw()
class MatplotlibPlot: """ Class encapsulating an matplotlib plot """ def __init__(self, parent = None, dpi = 100, size = (5,4)): """ Class initialiser """ self.dpi = dpi self.figure = Figure(dpi = self.dpi) self.canvas = FigureCanvas(self.figure) self.canvas.setParent(parent) # Create the navigation toolbar, tied to the canvas self.toolbar = NavigationToolbar(self.canvas, parent) self.canvas.show() self.toolbar.show() def plotCurve(self, data, numCurves = 1, labels = None, xAxisRange = None, yAxisRange = None, xLabel = "", yLabel = ""): """ Normal plots """ self.figure.clear() self.axes = self.figure.add_subplot(111) self.axes.grid(True) # Set empty labels if non defined if labels is None: labels = ['' for i in range(numImages)] # Place all plots in axes for i in range(numCurves): self.axes.plot(data[:,i], label=labels[i]) self.axes.set_xlim((0, len(data[:,i]))) # Final touches self.axes.xaxis.set_label_text(xLabel) self.axes.yaxis.set_label_text(yLabel) self.canvas.draw() def subplotCurve(self, data, numPlots = 1, labels = None, xAxisRange = None, yAxisRange = None, xLabel = "", yLabel = ""): """ Subplot mode """ self.figure.clear() # Set empty labels if non defined if labels is None: labels = ['' for i in range(numImages)] if numPlots == 1: ax = self.figure.add_subplot(111) ax.plot(data[:]) ax.set_xlabel(xLabel) ax.set_ylabel(yLabel) ax.set_title(labels[0]) ax.grid(True) else: # Plot each image num_rows = ceil(sqrt(numPlots)) for i in range(numPlots): ax = self.figure.add_subplot(num_rows, num_rows, i + 1) ax.plot(data[:,i]) ax.set_xlim((0, len(data[:,i]))) ax.set_xlabel(xLabel) ax.set_ylabel(yLabel) ax.set_title(labels[i]) ax.grid(True) # Final touches self.figure.tight_layout() self.canvas.draw() def plotImage(self, data, numImages = 1, labels = None, xAxisRange = None, yAxisRange = None, xLabel = "", yLabel = ""): """ Image plot """ self.figure.clear() self.axes = self.figure.add_subplot(111) # Show image im = self.axes.imshow(data, origin='lower', aspect='auto') # Final touches self.axes.xaxis.set_label_text(xLabel) self.axes.yaxis.set_label_text(yLabel) self.figure.colorbar(im) self.canvas.draw() def subplotImage(self, data, numImages = 1, labels = None, xAxisRange = None, yAxisRange = None, xLabel = "", yLabel = ""): """ Image subplot """ # Clear figure self.figure.clear() # Set empty labels if non defined if labels is None: labels = ['' for i in range(numImages)] # Plot each image num_rows = ceil(sqrt(numImages)) for i in range(numImages): ax = self.figure.add_subplot(num_rows, num_rows, i + 1) im = ax.imshow(data[:,:,i], origin='lower', aspect='auto') ax.set_xlabel(xLabel) ax.set_ylabel(yLabel) ax.set_title(labels[i]) # Final touches self.figure.tight_layout() self.canvas.draw()
class MatplotlibWidget(QtGui.QWidget): """ This subclass of QtWidget will manage the widget drawing; name matches the class in the *_ui.py file""" # Global colors dictionary colors_dict = { "Discharge": "b", "Subsurface Flow": "g", "Impervious Flow": "SteelBlue", "Infiltration Excess": "SeaGreen", "Initial Abstracted Flow": "MediumBlue", "Overland Flow": "RoyalBlue", "PET": "orange", "AET": "DarkOrange", "Average Soil Root zone": "Gray", "Average Soil Unsaturated Zone": "DarkGray", "Snow Pack": "PowderBlue", "Precipitation": "SkyBlue", "Storage Deficit": "Brown", "Return Flow": "Aqua", "Water Use": "DarkCyan", "Discharge + Water Use": "DarkBlue" } def __init__(self, parent=None): super(MatplotlibWidget, self).__init__(parent) # create object scope variables for watertxt data plot; used by radio buttons and span selector self.watertxt_data = None self.parameter = None self.color_str = None self.axes_text = None self.axes_radio = None self.parent = parent # create figure self.figure = Figure() # create canvas and set some of its properties self.canvas = FigureCanvas(self.figure) self.canvas.setParent(parent) self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.canvas.updateGeometry() self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus) self.canvas.setFocus() # set up axes and its properties self.ax = self.figure.add_subplot(111) self.ax.grid(True) # create toolbar self.matplotlib_toolbar = NavigationToolbar( self.canvas, parent) # the matplotlib toolbar object # create the layout self.layout = QtGui.QVBoxLayout() # add the widgets to the layout self.layout.addWidget(self.matplotlib_toolbar) self.layout.addWidget(self.canvas) # set the layout self.setLayout(self.layout) #-------------------------------- WATER.txt Parameter Plot ------------------------------------ def setup_watertxt_plot(self): """ Setup the watertxt plot """ self.clear_watertxt_plot() # set up axes and its properties self.axes = self.figure.add_subplot(111) self.axes.grid(True) # create radio buttons self.axes_radio = self.figure.add_axes( [0.01, 0.02, 0.10, 0.15] ) # [left, bottom, width, height] = fractions of figure width and height self.figure.subplots_adjust(bottom=0.2) self.radio_buttons = RadioButtons(ax=self.axes_radio, labels=("Span On", "Span Off"), active=1, activecolor="r") self.radio_buttons.on_clicked(self.toggle_selector) # create SpanSelector; invisble at first unless activated with toggle selector self.span_selector = SpanSelector(self.axes, self.on_select_axes, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red')) self.span_selector.visible = False def plot_watertxt_parameter(self, watertxt_data, name): """ Plot a parameter from a WATER.txt file """ self.reset_watertxt_plot() self.dates = watertxt_data["dates"] self.watertxt_data = watertxt_data self.parameter = watertxt.get_parameter(watertxt_data, name=name) assert self.parameter is not None, "Parameter name {} is not in watertxt_data".format( name) self.axes.set_title("Parameter: {}".format(self.parameter["name"])) self.axes.set_xlabel("Date") ylabel = "\n".join(wrap(self.parameter["name"], 60)) self.axes.set_ylabel(ylabel) # get proper color that corresponds to parameter name self.color_str = self.colors_dict[name.split('(')[0].strip()] # plot parameter self.axes.plot(self.dates, self.parameter["data"], color=self.color_str, label=self.parameter["name"], linewidth=2) # legend; make it transparent handles, labels = self.axes.get_legend_handles_labels() legend = self.axes.legend(handles, labels, fancybox=True) legend.get_frame().set_alpha(0.5) legend.draggable(state=True) # show text of mean, max, min values on graph; use matplotlib.patch.Patch properies and bbox text = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format( self.parameter["mean"], self.parameter["max"], self.parameter["min"]) patch_properties = { "boxstyle": "round", "facecolor": "wheat", "alpha": 0.5 } self.axes_text = self.axes.text(0.05, 0.95, text, transform=self.axes.transAxes, fontsize=14, verticalalignment="top", horizontalalignment="left", bbox=patch_properties) # use a more precise date string for the x axis locations in the toolbar and rotate labels self.axes.fmt_xdata = mdates.DateFormatter("%Y-%m-%d") # rotate and align the tick labels so they look better; note that self.figure.autofmt_xdate() does not work because of the radio button axes for label in self.axes.get_xticklabels(): label.set_ha("right") label.set_rotation(30) # draw the plot self.canvas.draw() def on_select_helper(self, xmin, xmax): """ Helper for on_select methods """ # convert matplotlib float dates to a datetime format date_min = mdates.num2date(xmin) date_max = mdates.num2date(xmax) # put the xmin and xmax in datetime format to compare date_min = datetime.datetime(date_min.year, date_min.month, date_min.day, date_min.hour, date_min.minute) date_max = datetime.datetime(date_max.year, date_max.month, date_max.day, date_max.hour, date_max.minute) # find the indices that were selected indices = np.where((self.dates >= date_min) & (self.dates <= date_max)) indices = indices[0] # get the selected dates and values selected_dates = self.dates[indices] selected_values = self.parameter["data"][indices] # compute simple stats on selected values selected_values_mean = nanmean(selected_values) selected_value_max = np.nanmax(selected_values) selected_value_min = np.nanmin(selected_values) return selected_dates, selected_values, selected_values_mean, selected_value_max, selected_value_min def on_select_axes(self, xmin, xmax): """ A select handler for SpanSelector that updates axes with the new x and y limits selected by user """ selected_dates, selected_values, selected_values_mean, selected_value_max, selected_value_min = self.on_select_helper( xmin, xmax) # plot the selected values and update plots limits and text self.axes.plot(selected_dates, selected_values, self.color_str) self.axes.set_xlim(selected_dates[0], selected_dates[-1]) self.axes.set_ylim(selected_values.min(), selected_values.max()) text = 'mean = %.2f\nmax = %.2f\nmin = %.2f' % ( selected_values_mean, selected_value_max, selected_value_min) self.axes_text.set_text(text) # draw the updated plot self.canvas.draw() def toggle_selector(self, radio_button_label): """ A toggle radio buttons for the matplotlib SpanSelector widget. """ if radio_button_label == "Span On": self.span_selector.visible = True self.matplotlib_toolbar.hide() elif radio_button_label == "Span Off": self.span_selector.visible = False self.matplotlib_toolbar.show() self.plot_watertxt_parameter(watertxt_data=self.watertxt_data, name=self.parameter["name"]) def clear_watertxt_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_watertxt_plot(self): """ Clear the plot axes """ self.axes.clear() self.canvas.draw() self.axes.grid(True) #-------------------------------- WATER.txt Parameter Comparison Plot ------------------------------------ def setup_watertxtcmp_plot(self): """ Setup the watertxt plot """ self.clear_watertxtcmp_plot() # set up axes and its properties self.axes1 = self.figure.add_subplot(211) self.axes2 = self.figure.add_subplot(212, sharex=self.axes1) self.axes1.grid(True) self.axes2.grid(True) def plot_watertxtcmp_parameter(self, watertxt_data1, watertxt_data2, filename1, filename2, name): """ Plot a parameter from a WATER.txt file """ self.reset_watertxtcmp_plot() dates = watertxt_data1["dates"] parameter1 = watertxt.get_parameter(watertxt_data=watertxt_data1, name=name) parameter2 = watertxt.get_parameter(watertxt_data=watertxt_data2, name=name) assert parameter1 is not None, "Parameter name {} is not in watertxt_data".format( name) assert parameter2 is not None, "Parameter name {} is not in watertxt_data".format( name) # calculate the difference diff = parameter2["data"] - parameter1["data"] # plot parameters on axes1 self.axes1.plot(dates, parameter1["data"], color="b", label=filename1 + ": " + parameter1["name"], linewidth=2) self.axes1.hold(True) self.axes1.plot(dates, parameter2["data"], color="r", label=filename2 + ": " + parameter2["name"], linewidth=2) # plot the difference on axes2 self.axes2.plot(dates, diff, color="k", linewidth=2) # add title, labels, legend self.axes1.set_title(parameter1["name"]) self.axes2.set_xlabel("Date") self.axes2.set_ylabel("Difference") handles1, labels1 = self.axes1.get_legend_handles_labels() legend1 = self.axes1.legend(handles1, labels1, fancybox=True) legend1.get_frame().set_alpha(0.5) legend1.draggable(state=True) # show text of mean, max, min values on graph; use matplotlib.patch.Patch properies and bbox text1 = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format( parameter1["mean"], parameter1["max"], parameter1["min"]) text2 = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format( parameter2["mean"], parameter2["max"], parameter2["min"]) text_diff = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format( nanmean(diff), np.max(diff), np.min(diff)) patch_properties1 = { "boxstyle": "round", "facecolor": "b", "alpha": 0.5 } patch_properties2 = { "boxstyle": "round", "facecolor": "r", "alpha": 0.5 } patch_properties_diff = { "boxstyle": "round", "facecolor": "wheat", "alpha": 0.5 } self.axes1.text(0.02, 0.95, text1, transform=self.axes1.transAxes, fontsize=12, verticalalignment="top", horizontalalignment="left", bbox=patch_properties1) self.axes1.text(0.02, 0.45, text2, transform=self.axes1.transAxes, fontsize=12, verticalalignment="top", horizontalalignment="left", bbox=patch_properties2) self.axes2.text(0.02, 0.95, text_diff, transform=self.axes2.transAxes, fontsize=12, verticalalignment="top", horizontalalignment="left", bbox=patch_properties_diff) # use a more precise date string for the x axis locations in the toolbar and rotate labels self.axes2.fmt_xdata = mdates.DateFormatter("%Y-%m-%d") # rotate and align the tick labels so they look better self.figure.autofmt_xdate() # draw the plot self.canvas.draw() def clear_watertxtcmp_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_watertxtcmp_plot(self): """ Clear the plot axes """ self.axes1.clear() self.axes2.clear() self.canvas.draw() self.axes1.grid(True) self.axes2.grid(True) #-------------------------------- Basemap Plot ------------------------------------ def setup_basemap_plot(self): """ Setup the watertxt plot """ self.clear_basemap_plot() # set up axes and its properties self.basemap_axes = self.figure.add_subplot(111) self.basemap_axes.grid(True) def get_map_extents(self, shapefiles, shp_name=None): """ Get max and min extent coordinates from a list of shapefiles to use as the extents on the map. Use the map extents to calculate the map center and the standard parallels. Parameters ---------- shapefiles : list List of shapefile_data dictionaries shp_name : string String name of shapefile to use for getting map extents Returns ------- extent_coords : dictionary Dictionary containing "lon_min", "lon_max", "lat_max", "lat_min" keys with respective calculated values center_coords : dictionary Dictionary containing "lon", "lat" keys with respective calculated values standard_parallels : dictionary Dictionary containing "first", "second" keys with respective calculated values (first = min(lat), second = max(lat)) """ extent_coords = {} center_coords = {} standard_parallels = {} lons = [] lats = [] if shp_name: for shapefile_data in shapefiles: if shp_name in shapefile_data["name"].split("_")[0]: lons.append(shapefile_data["extents"][0:2]) lats.append(shapefile_data["extents"][2:]) else: for shapefile_data in shapefiles: lons.append(shapefile_data["extents"][0:2]) lats.append(shapefile_data["extents"][2:]) extent_coords["lon_min"] = np.min(lons) extent_coords["lon_max"] = np.max(lons) extent_coords["lat_min"] = np.min(lats) extent_coords["lat_max"] = np.max(lats) center_coords["lon"] = np.mean( [extent_coords["lon_min"], extent_coords["lon_max"]]) center_coords["lat"] = np.mean( [extent_coords["lat_min"], extent_coords["lat_max"]]) standard_parallels["first"] = extent_coords["lat_min"] standard_parallels["second"] = extent_coords["lat_max"] return extent_coords, center_coords, standard_parallels def plot_shapefiles_map(self, shapefiles, display_fields=[], colors=[], title=None, shp_name=None, buff=1.0): """ Generate a map showing all the shapefiles in the shapefile_list. Shapefiles should be in a Geographic Coordinate System (longitude and latitude coordinates) such as World WGS84; Matplotlib"s basemap library does the proper transformation to a projected coordinate system. The projected coordinate system used is Albers Equal Area. Parameters ---------- shapefiles : list List of dictionaries containing shapefile information title : string String title for plot display_fields : list List of strings that correspond to a shapefile field where the corresponding value(s) will be displayed. colors : list List of strings that correspond to colors to be displayed shp_name : string String name of shapefile to use for getting map extents buff : float Float value in coordinate degrees to buffer the map with """ self.setup_basemap_plot() extent_coords, center_coords, standard_parallels = self.get_map_extents( shapefiles, shp_name=shp_name) # create the basemap object with Albers Equal Area Conic Projection bmap = Basemap(projection="aea", llcrnrlon=extent_coords["lon_min"] - buff, llcrnrlat=extent_coords["lat_min"] - buff, urcrnrlon=extent_coords["lon_max"] + buff, urcrnrlat=extent_coords["lat_max"] + buff, lat_1=standard_parallels["first"], lat_2=standard_parallels["second"], lon_0=center_coords["lon"], lat_0=center_coords["lat"], resolution="h", area_thresh=10000, ax=self.basemap_axes) # have basemap object plot background stuff bmap.drawcoastlines() bmap.drawcountries() bmap.drawrivers(linewidth=1, color="blue") bmap.drawstates() bmap.drawmapboundary(fill_color="aqua") bmap.fillcontinents(color="coral", lake_color="aqua") bmap.drawparallels(np.arange(-80., 81., 1.), labels=[1, 0, 0, 0], linewidth=0.5) bmap.drawmeridians(np.arange(-180., 181., 1.), labels=[0, 0, 0, 1], linewidth=0.5) # plot each shapefile on the basemap legend_handles = [] legend_labels = [] colors_index = 0 colors_list = [ "b", "g", "y", "r", "c", "y", "m", "orange", "aqua", "darksalmon", "gold", "k" ] for shapefile_data in shapefiles: # set up colors to use if colors: color = colors[colors_index] elif colors_index > len(colors_list) - 1: color = np.random.rand(3, ) else: color = colors_list[colors_index] full_path = os.path.join(shapefile_data["path"], shapefile_data["name"].split(".")[0]) shp_tuple = bmap.readshapefile( full_path, "shp", drawbounds=False ) # use basemap shapefile reader for ease of plotting for shape_dict, shape in zip( bmap.shp_info, bmap.shp ): # zip the shapefile information and its shape as defined by basemap if shapefile_data["type"] == "POLYGON": p1 = Polygon(shape, facecolor=color, edgecolor="k", linewidth=1, alpha=0.7, label=shapefile_data["name"]) self.basemap_axes.add_patch(p1) xx, yy = zip(*shape) txt_x = str(np.mean(xx)) txt_y = str(np.mean(yy)) elif shapefile_data["type"] == "POINT": x, y = shape if "usgsgages" in shapefile_data["name"].split("_")[0]: p1 = bmap.plot(x, y, color=color, marker="^", markersize=10, label=shapefile_data["name"]) elif "wateruse" in shapefile_data["name"].split("_")[0]: p1 = bmap.plot(x, y, color=color, marker="o", markersize=5, label=shapefile_data["name"]) else: print("what!!") p1 = bmap.plot(x, y, color=color, marker="o", markersize=10, label=shapefile_data["name"]) txt_x = str(x) txt_y = str(y) else: xx, yy = zip(*shape) p1 = bmap.plot(xx, yy, linewidth=1, color=color, label=shapefile_data["name"]) txt_x = str(np.mean(xx)) txt_y = str(np.mean(yy)) if isinstance(p1, list): p1 = p1[0] # control text display of shapefile fields for display_field in display_fields: if display_field in shape_dict.keys(): self.basemap_axes.text(txt_x, txt_y, shape_dict[display_field], color="k", fontsize=12, fontweight="bold") colors_index += 1 legend_handles.append(p1) legend_labels.append(shapefile_data["name"].split("_")[0]) handles, labels = self.basemap_axes.get_legend_handles_labels() # edit the contents of handles and labels to only show 1 legend per shape handles = legend_handles labels = legend_labels legend = self.basemap_axes.legend(handles, labels, fancybox=True, numpoints=1) legend.get_frame().set_alpha(0.5) legend.draggable(state=True) # draw the plot self.canvas.draw() def clear_basemap_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_basemap_plot(self): """ Clear the plot axes """ self.basemap_axes.clear() self.canvas.draw()
class PlotWindow(QFrame): # Init the class: create plot window and canvas layout (and corresponding buttons) # def __init__(self, parent): QDialog.__init__(self) self.rim=0.05 # rim around plot # The plot class holds its data now, so that it can be exported after a different # PlotWindow has been created self.parent=parent # parent object/class self.fig=None self.showCursor=False self.cursorId=None self.markerId=None self.marker1=None # position marker in the plot self.marker2=None self.x = parent.x # plotted x axis data self.x0 = self.parent.solverQuery.getTimeSlots()[0]['STARTTIME'] self.y1 = parent.y1 # plotted y axis data self.y2 = parent.y2 # plotted y2 axis data self.xdata = None # cursor click x coordinate in data value self.ydata = None # cursor click y coordinate in data value self.messages = parent.messages # solver messages # Create canvas for plotting self.fig = Figure((5, 4), dpi=100) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self) self.fig.subplots_adjust(left=self.rim+0.05, right=1.0-self.rim, top=1.0-self.rim, bottom=self.rim) # set a small rim self.mpl_toolbar = NavigationToolbar(self.canvas, self) self.mpl_toolbar.show() # first hide the toolbar self.setMinimumWidth(900) self.setMinimumHeight(600) self.setWindowTitle = self.parent.tableName + ": " + str(self.parent.solverQuery.getRank()) + " Parameters" self.createWidgets() self.createConnections() self.createLayouts() def createWidgets(self): # Create Buttons for data export # self.exportButton=QPushButton("&Export Data") self.exportButton.setToolTip("Export the currently plotted data") self.exportButton.setMaximumWidth(100) self.exportComboBox=QComboBox() self.exportComboBox.addItem("ASCII") # export in Matlab format is only possible if scipy.io module has been imported if self.parent.haveModule('scipy') == True or self.parent.haveModule('scipy.io') == True: self.exportComboBox.addItem("Matlab") self.exportComboBox.setToolTip('File format for exporting data') self.exportComboBox.setMaximumWidth(100) self.exportComboBox.setMinimumHeight(25) self.showCursorCheckBox=QCheckBox("Show cursor") self.showCursorCheckBox.setToolTip("Show a marker line in plot") self.showCursorCheckBox.setCheckState(Qt.Unchecked) # default off self.histogramButton=QPushButton("&Histogram") # button to create a histogram self.histogramButton.setToolTip("Create a histogram of the current parameter") self.histogramButton.setMaximumWidth(150) self.histogramButton.setToolTip('Create a histogram of current data') self.onClickLabel=QLabel("On click display:") self.onClickComboBox=QComboBox() self.onClickComboBox.setMaximumWidth(150) self.onClickComboBox.setToolTip('What to display when data point in graph is clicked') self.onClickComboBox.addItem("CorrMatrix") # first, default = correlation matrix self.onClickComboBox.addItem("Zoom") #self.onClickComboBox.addItem("Per iteration") #self.onClickComboBox.addItem("CorrMatrix and Iterations") self.solverMessageLabel=QLabel("Solver Message:") self.solverMessageText=QLineEdit() self.solverMessageText.setText('Undefined') self.solverMessageText.setToolTip('Message returned by LSQFit after iteration') self.solverMessageText.setReadOnly(True) self.solverMessageText.setMaximumWidth(125) self.closeButton=QPushButton() self.closeButton.setText('Close') self.closeButton.setToolTip('close this plot window') self.closeButton.setMaximumWidth(120) def createConnections(self): # Set connections self.connect(self.exportButton, SIGNAL('clicked()'), self.on_export) self.connect(self.histogramButton, SIGNAL('clicked()'), self.on_histogram) self.connect(self.closeButton, SIGNAL('clicked()'), SLOT('close()')) self.connect(self.showCursorCheckBox, SIGNAL('stateChanged(int)'), self.on_cursor) self.connect(self.onClickComboBox, SIGNAL('valueChanged(int)'), self.on_onClickComboBox) # Layouts for canvas and buttons # def createLayouts(self): buttonLayout = QVBoxLayout() buttonLayout.addWidget(self.exportButton) buttonLayout.addWidget(self.exportComboBox) buttonLayout.addWidget(self.showCursorCheckBox) buttonLayout.addWidget(self.histogramButton) buttonLayout.addWidget(self.onClickComboBox) buttonLayout.addWidget(self.solverMessageLabel) buttonLayout.addWidget(self.solverMessageText) buttonLayout.insertStretch(-1) buttonLayout.addWidget(self.closeButton) #buttonLayout.insertStretch(-1) #buttonLayout.setMaximumWidth(160) # Canvas layout canvasLayout = QVBoxLayout() canvasLayout.addWidget(self.canvas, 1) canvasLayout.addWidget(self.mpl_toolbar) mainLayout = QHBoxLayout() mainLayout.addLayout(buttonLayout) mainLayout.addLayout(canvasLayout) self.setLayout(mainLayout) self.show() # show the plotWindow widget self.parent.setXLabel() self.parent.setYLabel() # Matplotlib event connections #if self.showMarker==True: # cid = self.fig.canvas.mpl_connect('motion_notify_event', self.update_marker) # cid = self.fig.canvas.mpl_connect('button_press_event', onclick) cid = self.fig.canvas.mpl_connect('motion_notify_event', self.on_solverMessage) # TODO: this doesn work self.cursorId = self.fig.canvas.mpl_connect('button_press_event', self.on_click) self.plot() # React on showMarkerCheckBox signal # """ def on_marker(self): #print "on_marker checkState = ", self.showMarkerCheckBox.checkState() # DEBUG if self.showMarkerCheckBox.isChecked()==True: self.showMarker=True self.markerId = self.fig.canvas.mpl_connect('motion_notify_event', self.update_marker) else: print "on_marker() disconnecting marker event" self.showMarker=False self.fig.canvas.mpl_disconnect(self.markerId) # Plot a vertical line marker on the solutions plot showing the solution # of the currently plotted solver parameters # TODO: EXPERIMENTAL # def update_marker(self, event): #print "plotMarker() pos = ", event.xdata # DEBUG #print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%( # event.button, event.x, event.y, event.xdata, event.ydata) # DEBUG # Create markers (vertical lines) in both plots self.marker1=self.ax1.axvline(x=event.xdata, linewidth=1.5, color='r') self.marker2=self.ax2.axvline(x=event.xdata, linewidth=1.5, color='r') # We need to remove all unnecessary marker in plot 1 and plot 2 # TODO: find better method, keeps double marker sometimes while len(self.ax1.lines)-1 > 1: self.ax1.lines[len(self.ax1.lines)-1].remove() while len(self.ax2.lines)-1 > 1: self.ax2.lines[len(self.ax1.lines)-1].remove() self.marker1=self.ax1.axvline(x=event.xdata, linewidth=1.5, color='r') self.marker2=self.ax1.axvline(x=event.xdata, linewidth=1.5, color='r') # self.canvas.draw_idle() self.canvas.draw() """ def plotcorrmatrix(self): print "plotcorrmatrix()" # DEBUG #print "self.parent.xAxisType = ", self.parent.xAxisType # DEBUG indx = np.searchsorted(self.x, [self.xdata])[0] if self.parent.xAxisType=="Time": start_time=self.parent.solverQuery.timeSlots[indx]['STARTTIME'] end_time=self.parent.solverQuery.timeSlots[indx]['ENDTIME'] start_freq=self.parent.solverQuery.frequencies[self.parent.frequencyStartSlider.value()]['STARTFREQ'] end_freq=self.parent.solverQuery.frequencies[self.parent.frequencyEndSlider.value()]['ENDFREQ'] elif self.parent.xAxisType=="Freq": start_freq=self.parent.solverQuery.frequencySlots[indx]['STARTFREQ'] end_freq=self.parent.solverQuery.frequencylots[indx]['ENDFREQ'] start_time=self.parent.solverQuery.frequencies[self.parent.timeStartSlider.value()]['STARTTIME'] end_time=self.parent.solverQuery.frequencies[self.parent.timeEndSlider.value()]['ENDTIME'] else: # Iteration start_time=self.parent.solverQuery.timeSlots[self.parent.timeStartSlider.value()]['STARTTIME'] end_time=self.parent.solverQuery.timeSlots[self.parent.timeEndSlider.value()]['ENDTIME'] start_freq=self.parent.solverQuery.frequencies[self.parent.frequencyStartSlider.value()]['STARTFREQ'] end_freq=self.parent.solverQuery.frequencies[self.parent.frequencyEndSlider.value()]['ENDFREQ'] #print "plotwindow::plotcorrmatri() start_time = ", start_time # DEBUG #print "plotwindow::plotcorrmatri() end_time = ", end_time # DEBUG #print "plotwindow::plotcorrmatri() start_freq = ", start_freq # DEBUG #print "plotwindow::plotcorrmatri() end_freq = ", end_freq # DEBUG corrMatrix=self.parent.solverQuery.getCorrMatrix(start_time, end_time, start_freq, end_freq) self.corrmatrixDialog=pc.plotCorrmatrix(self, corrMatrix) self.corrmatrixDialog.show() # Activate / Deactivate Matplotlib demo cursor # def on_cursor(self): print "on_cursor()" # DEBUG self.showCursor=self.showCursorCheckBox.isChecked() print "on_cursor() self.showCursor = ", self.showCursor if self.showCursor==True: self.cursor = Cursor(self.ax1, self) #self.cursor = SnaptoCursor(self.ax1, self.x, self.y1, self) self.fig.canvas.mpl_connect('motion_notify_event', self.cursor.mouse_move) else: self.cursor.lx.remove() self.cursor.ly.remove() self.fig.canvas.mpl_disconnect(self.cursorId) # Handle export button clicked() # def on_export(self): fileformat=self.exportComboBox.currentText() self.parent.on_export(fileformat) # TODO! def on_logarithmic(self): self.yscale('log') # Functio to execute on a click event (experimental) # def on_click(self, event): print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%( event.button, event.x, event.y, event.xdata, event.ydata) # DEBUG print "event.key = ", event.key # DEBUG self.xdata=event.xdata self.ydata=event.ydata # Depending on the setting in the onClickComboBox launch appropriate dialog # if self.onClickComboBox.currentText()=="CorrMatrix": # if CorrMatrix should be displayed # Pick per iteration details if possible if self.parent.tableType == "PERSOLUTION_CORRMATRIX" or self.parent.tableType == "PERITERATION_CORRMATRIX": self.plotcorrmatrix() else: print "on_clickMarker() table is not of correct type" elif self.onClickComboBox.currentText()=="Per iteration": print "plotwindow::on_click() trying to launch per iteration plotwindow" # Display a histogram of the converged solutions (i.e. LASTITER=TRUE) # for the currently selected parameter # def on_histogram(self): self.histoDialog=ph.plothistogram(self) self.histoDialog.show() def on_onClickComboBox(self): print "on_onClickComboBox()" # DEBUG if self.onClickComboBox.currentText()=="Zoom": self.fig.canvas.mpl_disconnect(self.cursorId) elif self.onClickComboBox.currentText()=="CorrMatrix": self.cursorId = self.fig.canvas.mpl_connect('button_press_event', self.on_click) elif self.onClickComboBox.currentText()=="Per iteration": self.cursorId = self.fig.canvas.mpl_connect('button_press_event', self.on_click) def on_solverMessage(self, event): if self.messages!=None: # only if we indeed inherited messages from parent self.xdata = event.xdata self.ydata = event.ydata # get cursor position from figure index = np.searchsorted(self.x, [self.xdata])[0] # get Message for the index of cursor position resultType=self.messages['result'] #print "resultType = ", resultType #print "len(self.messages) = ", len(self.messages['last']) #print "self.xdata = ", self.xdata #print "on_solverMessage() index = ", index #print "self.messages[index] = ", self.messages[resultType][index] #print "self.parent.messages = ", self.parent.messages #self.solverMessageText.setText(self.messages[resultType][index]) self.solverMessageText.setReadOnly(False) # make it writable #print "resultType =", resultType # DEBUG if resultType=="last": #self.solverMessageText.setText(self.messages[resultType][index]) self.solverMessageText.setText(self.messages[index]) elif resultType=="all": #self.solverMessageText.setText(self.messages[resultType][index]) self.solverMessageText.setText(self.messages[index]) elif resultType==None: print "on_solverMessage() None messages" return self.solverMessageText.setReadOnly(True) # make it readonly again that user can't mess with it # Plot data that has been read # def plot(self): print "PlotWindow::plot()" # DEBUG parm=self.parent.parmsComboBox.currentText() # Solution parameter, e.g. Gain:1:1:LBA001 parameter=str(self.parent.parametersComboBox.currentText()) # Get solver parameter from drop down # Give for Time axis only time relative to start time # TODO this does not work if self.parent.xAxisType=="Time": self.x=self.parent.computeRelativeX() self.ax1=self.fig.add_subplot(211) # create solutions subplot # Set title and labels self.ax1.set_xlabel(self.parent.xLabel) self.ax1.set_ylabel(parm + ":" + self.parent.parmValueComboBox.currentText()) np.set_printoptions(precision=1) # self.ax1.get_xaxis().set_visible(False) # TODO: How to get correct x-axis ticks? np.set_printoptions(precision=2) # does this work? if self.parent.perIteration==True: x=range(1, len(self.y1)+1) # we want the first iteration to be called "1" if self.parent.scatterCheckBox.isChecked()==True: self.ax1.scatter(x, self.y1) else: self.ax1.plot(x, self.y1) else: if self.parent.scatterCheckBox.isChecked()==True: self.ax1.scatter(self.x, self.y1) else: if len(self.y1)==1 or isinstance(self.y1, float): self.ax1.scatter(self.x, self.y1) else: self.ax1.plot(self.x, self.y1) # Solver log plot self.ax2=self.fig.add_subplot(212, sharex=self.ax1) # sharex for common zoom # Set labels #self.ax2.set_xticklabels(self.ax1.get_xticklabels(), visible=True) self.ax2.set_ylabel(self.parent.parametersComboBox.currentText()) if self.parent.perIteration==True: x=range(1, len(self.y2)+1) if self.parent.scatterCheckBox.isChecked()==True: self.ax2.scatter(x, self.y2) else: self.ax2.plot(x, self.y2) # have to increase lower y limit (for unknown reason) else: if self.parent.scatterCheckBox.isChecked()==True: self.ax2.scatter(self.x, self.y2) else: if len(self.y1)==1 or isinstance(self.y2, float): self.ax2.scatter(self.x, self.y2) else: self.ax2.plot(self.x, self.y2) self.fig.canvas.draw()
class plotCorrmatrix(QDialog): def __init__(self, parent, corrmatrix): QFrame.__init__(self) self.setWindowTitle("Correlation Matrix") self.corrmatrix = [[]] self.rank = None self.rim = 0.05 self.parent = parent # parent object/class self.fig = None # Create canvas for plotting self.fig = Figure((7, 7), dpi=100) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self) self.fig.subplots_adjust(left=self.rim, right=1.0 - self.rim, top=1.0 - self.rim, bottom=self.rim) # set a small rim self.ax = self.fig.add_subplot(111) self.mpl_toolbar = NavigationToolbar(self.canvas, self) self.mpl_toolbar.show() self.setMinimumWidth(700) self.setMinimumHeight(700) self.corrmatrix = corrmatrix self.xLabel = "Parameter index" self.yLabel = "Parameter index" self.createWidgets() self.createLayouts() self.connectSignals() self.plot(self.corrmatrix) def createWidgets(self): # Get time indices (and frequency range) from solverdialog class according to plotwindow index self.index = np.searchsorted(self.parent.x, [self.parent.xdata])[0] print("self.index = ", self.index) # DEBUG self.start_time = self.parent.parent.solverQuery.timeSlots[ self.index]['STARTTIME'] self.end_time = self.parent.parent.solverQuery.timeSlots[ self.index]['ENDTIME'] self.start_freq = self.parent.parent.solverQuery.frequencies[ self.parent.parent.frequencyStartSlider.value()]['STARTFREQ'] self.end_freq = self.parent.parent.solverQuery.frequencies[ self.parent.parent.frequencyEndSlider.value()]['ENDFREQ'] self.timeLabel = QLabel("Time cell") self.startTimeLabel = QLabel( "S: " + str(self.parent.parent.convertDate(self.start_time))) self.endTimeLabel = QLabel( "E: " + str(self.parent.parent.convertDate(self.end_time))) self.startTimeLabel.show() self.endTimeLabel.show() self.freqLabel = QLabel("Freq cell") self.startFreqLabel = QLabel("S: " + str(self.start_freq) + " Hz") self.endFreqLabel = QLabel("E: " + str(self.end_freq) + " Hz") self.startFreqLabel.show() self.endFreqLabel.show() self.closeButton = QPushButton() self.closeButton = QPushButton() self.closeButton.setText('Close') self.closeButton.setToolTip('close this plotcorrmatrix window') self.closeButton.setMaximumWidth(120) self.closeButton.show() self.prevButton = QPushButton("Prev") self.nextButton = QPushButton("Next") def createLayouts(self): self.buttonLayout = QVBoxLayout() # layout containing widgets self.matrixLayout = QVBoxLayout( ) # layout containing canvas and toolbar self.mainLayout = QHBoxLayout() self.buttonLayout.addWidget(self.timeLabel) self.buttonLayout.addWidget(self.startTimeLabel) self.buttonLayout.addWidget(self.endTimeLabel) self.buttonLayout.addWidget(self.freqLabel) self.buttonLayout.addWidget(self.startFreqLabel) self.buttonLayout.addWidget(self.endFreqLabel) self.prevNextLayout = QHBoxLayout() if self.parent.parent.xAxisType != "Iteration": # we don't support previous and next in iteration mode self.prevNextLayout.addWidget(self.prevButton) self.prevNextLayout.addWidget(self.nextButton) self.buttonLayout.addLayout(self.prevNextLayout) self.buttonLayout.insertStretch(-1) self.buttonLayout.addWidget(self.closeButton) self.matrixLayout.addWidget(self.canvas) self.matrixLayout.addWidget(self.mpl_toolbar) self.mainLayout.addLayout(self.buttonLayout) self.mainLayout.addLayout(self.matrixLayout) self.setLayout(self.mainLayout) def connectSignals(self): self.connect(self.closeButton, SIGNAL('clicked()'), SLOT('close()')) self.connect(self.prevButton, SIGNAL('clicked()'), self.on_prevButton) self.connect(self.nextButton, SIGNAL('clicked()'), self.on_nextButton) self.connect(self.prevButton, SIGNAL('clicked()'), self.retrieveCorrMatrix) self.connect(self.nextButton, SIGNAL('clicked()'), self.retrieveCorrMatrix) #********************************************* # # Handler functions for events # #********************************************* def on_prevButton(self): self.index = self.index - 1 if self.index == 0: self.prevButton.setDisabled(True) def on_nextButton(self): self.index = self.index + 1 if self.index > 0 and self.index < len(self.parent.x) - 1: self.prevButton.setEnabled(True) if self.index == len(self.parent.x) - 1: self.nextButton.setDisabled(True) def retrieveCorrMatrix(self): if self.parent.parent.xAxisType == "Time": self.start_time = self.parent.parent.solverQuery.timeSlots[ self.index]['STARTTIME'] self.end_time = self.parent.parent.solverQuery.timeSlots[ self.index]['ENDTIME'] self.start_freq = self.parent.parent.solverQuery.frequencies[ self.parent.parent.frequencyStartSlider.value()]['STARTFREQ'] self.end_freq = self.parent.parent.solverQuery.frequencies[ self.parent.parent.frequencyEndSlider.value()]['ENDFREQ'] elif self.parent.parent.xAxisType == "Freq": self.start_freq = self.parent.parent.solverQuery.frequencySlots[ self.index]['STARTFREQ'] self.end_freq = self.parent.parent.solverQuery.frequencylots[ self.index]['ENDFREQ'] self.start_time = self.parent.parent.solverQuery.frequencies[ self.parent.parent.timeStartSlider.value()]['STARTTIME'] self.end_time = self.parent.solverQuery.frequencies[ self.parent.parent.timeEndSlider.value()]['ENDTIME'] else: # Iteration # Do nothing? Because there is only one Corrmatrix per solution but not per iteration!? print( "plotcorrmatrix::retrieveCorrMatrix() can't step forward or backward in per iteration mode" ) return self.start_time = self.parent.parent.solverQuery.timeSlots[ self.parent.parent.timeStartSlider.value()]['STARTTIME'] self.end_time = self.parent.parent.solverQuery.timeSlots[ self.parent.parent.timeEndSlider.value()]['ENDTIME'] self.start_freq = self.parent.parent.solverQuery.frequencies[ self.parent.parent.frequencyStartSlider.value()]['STARTFREQ'] self.end_freq = self.parent.parent.solverQuery.frequencies[ self.parent.parent.frequencyEndSlider.value()]['ENDFREQ'] print("plotcorrmatrix::retrieveCorrMatrix()") # DEBUG print("plotwindow::plotcorrmatri() start_time = ", self.start_time) # DEBUG print("plotwindow::plotcorrmatri() end_time = ", self.end_time) # DEBUG print("plotwindow::plotcorrmatri() start_freq = ", self.start_freq) # DEBUG print("plotwindow::plotcorrmatri() end_freq = ", self.end_freq) # DEBUG self.corrmatrix = self.parent.parent.solverQuery.getCorrMatrix( self.start_time, self.end_time, self.start_freq, self.end_freq) self.updateLabels() self.plot(self.corrmatrix) def updateLabels(self): self.startTimeLabel.setText( "S: " + str(self.parent.parent.convertDate(self.start_time))) self.endTimeLabel.setText( "E: " + str(self.parent.parent.convertDate(self.end_time))) self.startFreqLabel.setText("S: " + str(self.start_freq) + " Hz") self.endFreqLabel.setText("E: " + str(self.end_freq) + " Hz") #********************************************* # # Plot a correlation matrix in a plotWindow # #********************************************* # # corrmatrix - numpy.ndarray holding (linearized) correlation Matrix # def plot(self, corrmatrix): print("plotCorrmatrix::plotCorrMatrix()") # DEBUG # We plot into the existing canvas object of the PlotWindow class rank = self.parent.parent.solverQuery.getRank() if rank != math.sqrt(len(corrmatrix)): raise ValueError shape = corrmatrix.shape # get shape of array (might be 1-D) corrmatrix = np.reshape(corrmatrix, (rank, rank)) if len(shape) == 1: # if we got only one dimension... if shape[0] != rank * rank: # if the length of the array is not rank^2 raise ValueError else: corrmatrix = np.reshape(corrmatrix, (rank, rank)) elif len(shape) == 2: # we already have a two-dimensional array print("shape[0] = ", shape[0], " shape[1] = ", shape[1]) # DEBUG if shape[0] != rank or shape[1] != rank: raise ValueError # Clear all axes, and clear figure (needed to remove colorbar) self.ax.cla() self.fig.clf() self.ax = self.fig.add_subplot(111) # create axes again in figure # plot CorrMatrix as a figure image self.img = self.ax.imshow(corrmatrix, cmap=cm.jet, aspect='equal', interpolation=None) self.colorbar = self.fig.colorbar(self.img) self.canvas.draw()
def rebuild_widget(self, number_of_plots, plot_stretching): self.__number_of_plots = number_of_plots self.__plot_stretching = plot_stretching ids = [] if self.__top_vbox.count() < self.__number_of_plots: ids = range(self.__top_vbox.count(), self.__number_of_plots) for i in ids: label = QLabel() label.setFont(self.__font) label.setAlignment(Qt.AlignCenter) # Create the mpl Figure and FigCanvas objects. # 5x4 inches, 100 dots-per-inch # #dpi = 100 #self.fig = Figure((5.0, 4.0), dpi=self.dpi) fig = pyplot.figure() canvas = FigureCanvas(fig) canvas.setParent(self) # Since we have only one plot, we can use add_axes # instead of add_subplot, but then the subplot # configuration tool in the navigation toolbar wouldn't # work. # axes = fig.add_subplot(111) # Create the navigation toolbar, tied to the canvas # mpl_toolbar = NavigationToolbar(canvas, self, False) if self.__show_toolbar: mpl_toolbar.show() else: mpl_toolbar.hide() # Other GUI controls # tmp_vbox = QVBoxLayout() tmp_vbox.addWidget(label) tmp_vbox.addWidget(canvas, 1) tmp_vbox.addWidget(mpl_toolbar) widget = QWidget() widget.setLayout(tmp_vbox) self.__plots.append((label, canvas, fig, axes, mpl_toolbar, widget)) self.__plot_infos.append((self.PLOT_TYPE_NONE, '', None, {})) self.__top_vbox.addWidget(widget) for i in xrange(self.__number_of_plots): stretch = 0 if plot_stretching != None: stretch = plot_stretching[i] self.__top_vbox.setStretch(i, stretch) else: self.__top_vbox.setStretch(i, 1) plot = self.__plots[i] label, canvas, fig, axes, mpl_toolbar, widget = plot widget.show() for i in xrange(self.__number_of_plots, self.__top_vbox.count()): plot = self.__plots[i] label, canvas, fig, axes, mpl_toolbar, widget = plot widget.hide() if self.__show_menu: menubar = QMenuBar() save_menu = menubar.addMenu("&Save") menu_items = [] for i,plot_info in enumerate(self.__plot_infos): plot_caption = plot_info[1] menu_name = "Save &plot '%s' [%d]" % (plot_caption, i+1) if len(plot_caption) == 0: menu_name = "Save &plot #%d" % (i+1) save_plot_action = self.__make_action(menu_name, shortcut="Ctrl+P", slot=functools.partial(self.on_save_plot, i)) menu_items.append(save_plot_action) menu_items.append(None) save_all_action = self.__make_action("Save &all plots", shortcut="Ctrl+A", slot=self.on_save_all_plots) menu_items.append(save_all_action) self.__add_actions(save_menu, menu_items) self.layout().setMenuBar(menubar)
class PlotWindow(QFrame): # Init the class: create plot window and canvas layout (and corresponding buttons) # def __init__(self, parent): QDialog.__init__(self) self.rim = 0.05 # rim around plot # The plot class holds its data now, so that it can be exported after a different # PlotWindow has been created self.parent = parent # parent object/class self.fig = None self.showCursor = False self.cursorId = None self.markerId = None self.marker1 = None # position marker in the plot self.marker2 = None self.x = parent.x # plotted x axis data self.x0 = self.parent.solverQuery.getTimeSlots()[0]['STARTTIME'] self.y1 = parent.y1 # plotted y axis data self.y2 = parent.y2 # plotted y2 axis data self.xdata = None # cursor click x coordinate in data value self.ydata = None # cursor click y coordinate in data value self.messages = parent.messages # solver messages # Create canvas for plotting self.fig = Figure((5, 4), dpi=100) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self) self.fig.subplots_adjust(left=self.rim + 0.05, right=1.0 - self.rim, top=1.0 - self.rim, bottom=self.rim) # set a small rim self.mpl_toolbar = NavigationToolbar(self.canvas, self) self.mpl_toolbar.show() # first hide the toolbar self.setMinimumWidth(900) self.setMinimumHeight(600) self.setWindowTitle = self.parent.tableName + ": " + str( self.parent.solverQuery.getRank()) + " Parameters" self.createWidgets() self.createConnections() self.createLayouts() def createWidgets(self): # Create Buttons for data export # self.exportButton = QPushButton("&Export Data") self.exportButton.setToolTip("Export the currently plotted data") self.exportButton.setMaximumWidth(100) self.exportComboBox = QComboBox() self.exportComboBox.addItem("ASCII") # export in Matlab format is only possible if scipy.io module has been imported if self.parent.haveModule('scipy') == True or self.parent.haveModule( 'scipy.io') == True: self.exportComboBox.addItem("Matlab") self.exportComboBox.setToolTip('File format for exporting data') self.exportComboBox.setMaximumWidth(100) self.exportComboBox.setMinimumHeight(25) self.showCursorCheckBox = QCheckBox("Show cursor") self.showCursorCheckBox.setToolTip("Show a marker line in plot") self.showCursorCheckBox.setCheckState(Qt.Unchecked) # default off self.histogramButton = QPushButton( "&Histogram") # button to create a histogram self.histogramButton.setToolTip( "Create a histogram of the current parameter") self.histogramButton.setMaximumWidth(150) self.histogramButton.setToolTip('Create a histogram of current data') self.onClickLabel = QLabel("On click display:") self.onClickComboBox = QComboBox() self.onClickComboBox.setMaximumWidth(150) self.onClickComboBox.setToolTip( 'What to display when data point in graph is clicked') self.onClickComboBox.addItem( "CorrMatrix") # first, default = correlation matrix self.onClickComboBox.addItem("Zoom") #self.onClickComboBox.addItem("Per iteration") #self.onClickComboBox.addItem("CorrMatrix and Iterations") self.solverMessageLabel = QLabel("Solver Message:") self.solverMessageText = QLineEdit() self.solverMessageText.setText('Undefined') self.solverMessageText.setToolTip( 'Message returned by LSQFit after iteration') self.solverMessageText.setReadOnly(True) self.solverMessageText.setMaximumWidth(125) self.closeButton = QPushButton() self.closeButton.setText('Close') self.closeButton.setToolTip('close this plot window') self.closeButton.setMaximumWidth(120) def createConnections(self): # Set connections self.connect(self.exportButton, SIGNAL('clicked()'), self.on_export) self.connect(self.histogramButton, SIGNAL('clicked()'), self.on_histogram) self.connect(self.closeButton, SIGNAL('clicked()'), SLOT('close()')) self.connect(self.showCursorCheckBox, SIGNAL('stateChanged(int)'), self.on_cursor) self.connect(self.onClickComboBox, SIGNAL('valueChanged(int)'), self.on_onClickComboBox) # Layouts for canvas and buttons # def createLayouts(self): buttonLayout = QVBoxLayout() buttonLayout.addWidget(self.exportButton) buttonLayout.addWidget(self.exportComboBox) buttonLayout.addWidget(self.showCursorCheckBox) buttonLayout.addWidget(self.histogramButton) buttonLayout.addWidget(self.onClickComboBox) buttonLayout.addWidget(self.solverMessageLabel) buttonLayout.addWidget(self.solverMessageText) buttonLayout.insertStretch(-1) buttonLayout.addWidget(self.closeButton) #buttonLayout.insertStretch(-1) #buttonLayout.setMaximumWidth(160) # Canvas layout canvasLayout = QVBoxLayout() canvasLayout.addWidget(self.canvas, 1) canvasLayout.addWidget(self.mpl_toolbar) mainLayout = QHBoxLayout() mainLayout.addLayout(buttonLayout) mainLayout.addLayout(canvasLayout) self.setLayout(mainLayout) self.show() # show the plotWindow widget self.parent.setXLabel() self.parent.setYLabel() # Matplotlib event connections #if self.showMarker==True: # cid = self.fig.canvas.mpl_connect('motion_notify_event', self.update_marker) # cid = self.fig.canvas.mpl_connect('button_press_event', onclick) cid = self.fig.canvas.mpl_connect( 'motion_notify_event', self.on_solverMessage) # TODO: this doesn work self.cursorId = self.fig.canvas.mpl_connect('button_press_event', self.on_click) self.plot() # React on showMarkerCheckBox signal # """ def on_marker(self): #print "on_marker checkState = ", self.showMarkerCheckBox.checkState() # DEBUG if self.showMarkerCheckBox.isChecked()==True: self.showMarker=True self.markerId = self.fig.canvas.mpl_connect('motion_notify_event', self.update_marker) else: print "on_marker() disconnecting marker event" self.showMarker=False self.fig.canvas.mpl_disconnect(self.markerId) # Plot a vertical line marker on the solutions plot showing the solution # of the currently plotted solver parameters # TODO: EXPERIMENTAL # def update_marker(self, event): #print "plotMarker() pos = ", event.xdata # DEBUG #print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%( # event.button, event.x, event.y, event.xdata, event.ydata) # DEBUG # Create markers (vertical lines) in both plots self.marker1=self.ax1.axvline(x=event.xdata, linewidth=1.5, color='r') self.marker2=self.ax2.axvline(x=event.xdata, linewidth=1.5, color='r') # We need to remove all unnecessary marker in plot 1 and plot 2 # TODO: find better method, keeps double marker sometimes while len(self.ax1.lines)-1 > 1: self.ax1.lines[len(self.ax1.lines)-1].remove() while len(self.ax2.lines)-1 > 1: self.ax2.lines[len(self.ax1.lines)-1].remove() self.marker1=self.ax1.axvline(x=event.xdata, linewidth=1.5, color='r') self.marker2=self.ax1.axvline(x=event.xdata, linewidth=1.5, color='r') # self.canvas.draw_idle() self.canvas.draw() """ def plotcorrmatrix(self): print("plotcorrmatrix()") # DEBUG #print "self.parent.xAxisType = ", self.parent.xAxisType # DEBUG indx = np.searchsorted(self.x, [self.xdata])[0] if self.parent.xAxisType == "Time": start_time = self.parent.solverQuery.timeSlots[indx]['STARTTIME'] end_time = self.parent.solverQuery.timeSlots[indx]['ENDTIME'] start_freq = self.parent.solverQuery.frequencies[ self.parent.frequencyStartSlider.value()]['STARTFREQ'] end_freq = self.parent.solverQuery.frequencies[ self.parent.frequencyEndSlider.value()]['ENDFREQ'] elif self.parent.xAxisType == "Freq": start_freq = self.parent.solverQuery.frequencySlots[indx][ 'STARTFREQ'] end_freq = self.parent.solverQuery.frequencylots[indx]['ENDFREQ'] start_time = self.parent.solverQuery.frequencies[ self.parent.timeStartSlider.value()]['STARTTIME'] end_time = self.parent.solverQuery.frequencies[ self.parent.timeEndSlider.value()]['ENDTIME'] else: # Iteration start_time = self.parent.solverQuery.timeSlots[ self.parent.timeStartSlider.value()]['STARTTIME'] end_time = self.parent.solverQuery.timeSlots[ self.parent.timeEndSlider.value()]['ENDTIME'] start_freq = self.parent.solverQuery.frequencies[ self.parent.frequencyStartSlider.value()]['STARTFREQ'] end_freq = self.parent.solverQuery.frequencies[ self.parent.frequencyEndSlider.value()]['ENDFREQ'] #print "plotwindow::plotcorrmatri() start_time = ", start_time # DEBUG #print "plotwindow::plotcorrmatri() end_time = ", end_time # DEBUG #print "plotwindow::plotcorrmatri() start_freq = ", start_freq # DEBUG #print "plotwindow::plotcorrmatri() end_freq = ", end_freq # DEBUG corrMatrix = self.parent.solverQuery.getCorrMatrix( start_time, end_time, start_freq, end_freq) self.corrmatrixDialog = pc.plotCorrmatrix(self, corrMatrix) self.corrmatrixDialog.show() # Activate / Deactivate Matplotlib demo cursor # def on_cursor(self): print("on_cursor()") # DEBUG self.showCursor = self.showCursorCheckBox.isChecked() print("on_cursor() self.showCursor = ", self.showCursor) if self.showCursor == True: self.cursor = Cursor(self.ax1, self) #self.cursor = SnaptoCursor(self.ax1, self.x, self.y1, self) self.fig.canvas.mpl_connect('motion_notify_event', self.cursor.mouse_move) else: self.cursor.lx.remove() self.cursor.ly.remove() self.fig.canvas.mpl_disconnect(self.cursorId) # Handle export button clicked() # def on_export(self): fileformat = self.exportComboBox.currentText() self.parent.on_export(fileformat) # TODO! def on_logarithmic(self): self.yscale('log') # Functio to execute on a click event (experimental) # def on_click(self, event): print('button=%d, x=%d, y=%d, xdata=%f, ydata=%f' % (event.button, event.x, event.y, event.xdata, event.ydata)) # DEBUG print("event.key = ", event.key) # DEBUG self.xdata = event.xdata self.ydata = event.ydata # Depending on the setting in the onClickComboBox launch appropriate dialog # if self.onClickComboBox.currentText( ) == "CorrMatrix": # if CorrMatrix should be displayed # Pick per iteration details if possible if self.parent.tableType == "PERSOLUTION_CORRMATRIX" or self.parent.tableType == "PERITERATION_CORRMATRIX": self.plotcorrmatrix() else: print("on_clickMarker() table is not of correct type") elif self.onClickComboBox.currentText() == "Per iteration": print( "plotwindow::on_click() trying to launch per iteration plotwindow" ) # Display a histogram of the converged solutions (i.e. LASTITER=TRUE) # for the currently selected parameter # def on_histogram(self): self.histoDialog = ph.plothistogram(self) self.histoDialog.show() def on_onClickComboBox(self): print("on_onClickComboBox()") # DEBUG if self.onClickComboBox.currentText() == "Zoom": self.fig.canvas.mpl_disconnect(self.cursorId) elif self.onClickComboBox.currentText() == "CorrMatrix": self.cursorId = self.fig.canvas.mpl_connect( 'button_press_event', self.on_click) elif self.onClickComboBox.currentText() == "Per iteration": self.cursorId = self.fig.canvas.mpl_connect( 'button_press_event', self.on_click) def on_solverMessage(self, event): if self.messages != None: # only if we indeed inherited messages from parent self.xdata = event.xdata self.ydata = event.ydata # get cursor position from figure index = np.searchsorted( self.x, [self.xdata ])[0] # get Message for the index of cursor position resultType = self.messages['result'] #print "resultType = ", resultType #print "len(self.messages) = ", len(self.messages['last']) #print "self.xdata = ", self.xdata #print "on_solverMessage() index = ", index #print "self.messages[index] = ", self.messages[resultType][index] #print "self.parent.messages = ", self.parent.messages #self.solverMessageText.setText(self.messages[resultType][index]) self.solverMessageText.setReadOnly(False) # make it writable #print "resultType =", resultType # DEBUG if resultType == "last": #self.solverMessageText.setText(self.messages[resultType][index]) self.solverMessageText.setText(self.messages[index]) elif resultType == "all": #self.solverMessageText.setText(self.messages[resultType][index]) self.solverMessageText.setText(self.messages[index]) elif resultType == None: print("on_solverMessage() None messages") return self.solverMessageText.setReadOnly( True) # make it readonly again that user can't mess with it # Plot data that has been read # def plot(self): print("PlotWindow::plot()") # DEBUG parm = self.parent.parmsComboBox.currentText( ) # Solution parameter, e.g. Gain:1:1:LBA001 parameter = str(self.parent.parametersComboBox.currentText() ) # Get solver parameter from drop down # Give for Time axis only time relative to start time # TODO this does not work if self.parent.xAxisType == "Time": self.x = self.parent.computeRelativeX() self.ax1 = self.fig.add_subplot(211) # create solutions subplot # Set title and labels self.ax1.set_xlabel(self.parent.xLabel) self.ax1.set_ylabel(parm + ":" + self.parent.parmValueComboBox.currentText()) np.set_printoptions(precision=1) # self.ax1.get_xaxis().set_visible(False) # TODO: How to get correct x-axis ticks? np.set_printoptions(precision=2) # does this work? if self.parent.perIteration == True: x = list(range(1, len(self.y1) + 1)) # we want the first iteration to be called "1" if self.parent.scatterCheckBox.isChecked() == True: self.ax1.scatter(x, self.y1) else: self.ax1.plot(x, self.y1) else: if self.parent.scatterCheckBox.isChecked() == True: self.ax1.scatter(self.x, self.y1) else: if len(self.y1) == 1 or isinstance(self.y1, float): self.ax1.scatter(self.x, self.y1) else: self.ax1.plot(self.x, self.y1) # Solver log plot self.ax2 = self.fig.add_subplot( 212, sharex=self.ax1) # sharex for common zoom # Set labels #self.ax2.set_xticklabels(self.ax1.get_xticklabels(), visible=True) self.ax2.set_ylabel(self.parent.parametersComboBox.currentText()) if self.parent.perIteration == True: x = list(range(1, len(self.y2) + 1)) if self.parent.scatterCheckBox.isChecked() == True: self.ax2.scatter(x, self.y2) else: self.ax2.plot( x, self.y2 ) # have to increase lower y limit (for unknown reason) else: if self.parent.scatterCheckBox.isChecked() == True: self.ax2.scatter(self.x, self.y2) else: if len(self.y1) == 1 or isinstance(self.y2, float): self.ax2.scatter(self.x, self.y2) else: self.ax2.plot(self.x, self.y2) self.fig.canvas.draw()
class plotCorrmatrix(QDialog): def __init__(self, parent, corrmatrix): QFrame.__init__(self) self.setWindowTitle("Correlation Matrix") self.corrmatrix=[[]] self.rank=None self.rim=0.05 self.parent=parent # parent object/class self.fig=None # Create canvas for plotting self.fig = Figure((7, 7), dpi=100) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self) self.fig.subplots_adjust(left=self.rim, right=1.0-self.rim, top=1.0-self.rim, bottom=self.rim) # set a small rim self.ax=self.fig.add_subplot(111) self.mpl_toolbar = NavigationToolbar(self.canvas, self) self.mpl_toolbar.show() self.setMinimumWidth(700) self.setMinimumHeight(700) self.corrmatrix=corrmatrix self.xLabel="Parameter index" self.yLabel="Parameter index" self.createWidgets() self.createLayouts() self.connectSignals() self.plot(self.corrmatrix) def createWidgets(self): # Get time indices (and frequency range) from solverdialog class according to plotwindow index self.index = np.searchsorted(self.parent.x, [self.parent.xdata])[0] print "self.index = ", self.index # DEBUG self.start_time=self.parent.parent.solverQuery.timeSlots[self.index]['STARTTIME'] self.end_time=self.parent.parent.solverQuery.timeSlots[self.index]['ENDTIME'] self.start_freq=self.parent.parent.solverQuery.frequencies[self.parent.parent.frequencyStartSlider.value()]['STARTFREQ'] self.end_freq=self.parent.parent.solverQuery.frequencies[self.parent.parent.frequencyEndSlider.value()]['ENDFREQ'] self.timeLabel=QLabel("Time cell") self.startTimeLabel=QLabel("S: " + str(self.parent.parent.convertDate(self.start_time))) self.endTimeLabel=QLabel("E: " + str(self.parent.parent.convertDate(self.end_time))) self.startTimeLabel.show() self.endTimeLabel.show() self.freqLabel=QLabel("Freq cell") self.startFreqLabel=QLabel("S: " + str(self.start_freq) + " Hz") self.endFreqLabel=QLabel("E: " + str(self.end_freq) + " Hz") self.startFreqLabel.show() self.endFreqLabel.show() self.closeButton=QPushButton() self.closeButton=QPushButton() self.closeButton.setText('Close') self.closeButton.setToolTip('close this plotcorrmatrix window') self.closeButton.setMaximumWidth(120) self.closeButton.show() self.prevButton=QPushButton("Prev") self.nextButton=QPushButton("Next") def createLayouts(self): self.buttonLayout=QVBoxLayout() # layout containing widgets self.matrixLayout=QVBoxLayout() # layout containing canvas and toolbar self.mainLayout=QHBoxLayout() self.buttonLayout.addWidget(self.timeLabel) self.buttonLayout.addWidget(self.startTimeLabel) self.buttonLayout.addWidget(self.endTimeLabel) self.buttonLayout.addWidget(self.freqLabel) self.buttonLayout.addWidget(self.startFreqLabel) self.buttonLayout.addWidget(self.endFreqLabel) self.prevNextLayout=QHBoxLayout() if self.parent.parent.xAxisType!="Iteration": # we don't support previous and next in iteration mode self.prevNextLayout.addWidget(self.prevButton) self.prevNextLayout.addWidget(self.nextButton) self.buttonLayout.addLayout(self.prevNextLayout) self.buttonLayout.insertStretch(-1) self.buttonLayout.addWidget(self.closeButton) self.matrixLayout.addWidget(self.canvas) self.matrixLayout.addWidget(self.mpl_toolbar) self.mainLayout.addLayout(self.buttonLayout) self.mainLayout.addLayout(self.matrixLayout) self.setLayout(self.mainLayout) def connectSignals(self): self.connect(self.closeButton, SIGNAL('clicked()'), SLOT('close()')) self.connect(self.prevButton, SIGNAL('clicked()'), self.on_prevButton) self.connect(self.nextButton, SIGNAL('clicked()'), self.on_nextButton) self.connect(self.prevButton, SIGNAL('clicked()'), self.retrieveCorrMatrix) self.connect(self.nextButton, SIGNAL('clicked()'), self.retrieveCorrMatrix) #********************************************* # # Handler functions for events # #********************************************* def on_prevButton(self): self.index = self.index - 1 if self.index == 0: self.prevButton.setDisabled(True) def on_nextButton(self): self.index = self.index + 1 if self.index > 0 and self.index < len(self.parent.x)-1: self.prevButton.setEnabled(True) if self.index == len(self.parent.x)-1: self.nextButton.setDisabled(True) def retrieveCorrMatrix(self): if self.parent.parent.xAxisType=="Time": self.start_time=self.parent.parent.solverQuery.timeSlots[self.index]['STARTTIME'] self.end_time=self.parent.parent.solverQuery.timeSlots[self.index]['ENDTIME'] self.start_freq=self.parent.parent.solverQuery.frequencies[self.parent.parent.frequencyStartSlider.value()]['STARTFREQ'] self.end_freq=self.parent.parent.solverQuery.frequencies[self.parent.parent.frequencyEndSlider.value()]['ENDFREQ'] elif self.parent.parent.xAxisType=="Freq": self.start_freq=self.parent.parent.solverQuery.frequencySlots[self.index]['STARTFREQ'] self.end_freq=self.parent.parent.solverQuery.frequencylots[self.index]['ENDFREQ'] self.start_time=self.parent.parent.solverQuery.frequencies[self.parent.parent.timeStartSlider.value()]['STARTTIME'] self.end_time=self.parent.solverQuery.frequencies[self.parent.parent.timeEndSlider.value()]['ENDTIME'] else: # Iteration # Do nothing? Because there is only one Corrmatrix per solution but not per iteration!? print "plotcorrmatrix::retrieveCorrMatrix() can't step forward or backward in per iteration mode" return self.start_time=self.parent.parent.solverQuery.timeSlots[self.parent.parent.timeStartSlider.value()]['STARTTIME'] self.end_time=self.parent.parent.solverQuery.timeSlots[self.parent.parent.timeEndSlider.value()]['ENDTIME'] self.start_freq=self.parent.parent.solverQuery.frequencies[self.parent.parent.frequencyStartSlider.value()]['STARTFREQ'] self.end_freq=self.parent.parent.solverQuery.frequencies[self.parent.parent.frequencyEndSlider.value()]['ENDFREQ'] print "plotcorrmatrix::retrieveCorrMatrix()" # DEBUG print "plotwindow::plotcorrmatri() start_time = ", self.start_time # DEBUG print "plotwindow::plotcorrmatri() end_time = ", self.end_time # DEBUG print "plotwindow::plotcorrmatri() start_freq = ", self.start_freq # DEBUG print "plotwindow::plotcorrmatri() end_freq = ", self.end_freq # DEBUG self.corrmatrix=self.parent.parent.solverQuery.getCorrMatrix(self.start_time, self.end_time, self.start_freq, self.end_freq) self.updateLabels() self.plot(self.corrmatrix) def updateLabels(self): self.startTimeLabel.setText("S: " + str(self.parent.parent.convertDate(self.start_time))) self.endTimeLabel.setText("E: " + str(self.parent.parent.convertDate(self.end_time))) self.startFreqLabel.setText("S: " + str(self.start_freq) + " Hz") self.endFreqLabel.setText("E: " + str(self.end_freq) + " Hz") #********************************************* # # Plot a correlation matrix in a plotWindow # #********************************************* # # corrmatrix - numpy.ndarray holding (linearized) correlation Matrix # def plot(self, corrmatrix): print "plotCorrmatrix::plotCorrMatrix()" # DEBUG # We plot into the existing canvas object of the PlotWindow class rank=self.parent.parent.solverQuery.getRank() if rank != math.sqrt(len(corrmatrix)): raise ValueError shape=corrmatrix.shape # get shape of array (might be 1-D) corrmatrix=np.reshape(corrmatrix, (rank, rank)) if len(shape)==1: # if we got only one dimension... if shape[0] != rank*rank: # if the length of the array is not rank^2 raise ValueError else: corrmatrix=np.reshape(corrmatrix, (rank, rank)) elif len(shape)==2: # we already have a two-dimensional array print "shape[0] = ", shape[0], " shape[1] = ", shape[1] # DEBUG if shape[0] != rank or shape[1] != rank: raise ValueError # Clear all axes, and clear figure (needed to remove colorbar) self.ax.cla() self.fig.clf() self.ax=self.fig.add_subplot(111) # create axes again in figure # plot CorrMatrix as a figure image self.img=self.ax.imshow(corrmatrix, cmap=cm.jet , aspect='equal', interpolation=None) self.colorbar = self.fig.colorbar(self.img) self.canvas.draw()
class MatplotlibWidget(QtGui.QWidget): """ This subclass of QtWidget will manage the widget drawing; name matches the class in the *_ui.py file""" # Global colors dictionary colors_dict = { "Discharge": "b", "Subsurface Flow": "g", "Impervious Flow": "SteelBlue", "Infiltration Excess": "SeaGreen", "Initial Abstracted Flow": "MediumBlue", "Overland Flow": "RoyalBlue", "PET": "orange", "AET": "DarkOrange", "Average Soil Root zone": "Gray", "Average Soil Unsaturated Zone": "DarkGray", "Snow Pack": "PowderBlue", "Precipitation": "SkyBlue", "Storage Deficit": "Brown", "Return Flow": "Aqua", "Water Use": "DarkCyan", "Discharge + Water Use": "DarkBlue" } def __init__(self, parent = None): super(MatplotlibWidget, self).__init__(parent) # create object scope variables for watertxt data plot; used by radio buttons and span selector self.watertxt_data = None self.parameter = None self.color_str = None self.axes_text = None self.axes_radio = None self.parent = parent # create figure self.figure = Figure() # create canvas and set some of its properties self.canvas = FigureCanvas(self.figure) self.canvas.setParent(parent) self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.canvas.updateGeometry() self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus) self.canvas.setFocus() # set up axes and its properties self.ax = self.figure.add_subplot(111) self.ax.grid(True) # create toolbar self.matplotlib_toolbar = NavigationToolbar(self.canvas, parent) # the matplotlib toolbar object # create the layout self.layout = QtGui.QVBoxLayout() # add the widgets to the layout self.layout.addWidget(self.matplotlib_toolbar) self.layout.addWidget(self.canvas) # set the layout self.setLayout(self.layout) #-------------------------------- WATER.txt Parameter Plot ------------------------------------ def setup_watertxt_plot(self): """ Setup the watertxt plot """ self.clear_watertxt_plot() # set up axes and its properties self.axes = self.figure.add_subplot(111) self.axes.grid(True) # create radio buttons self.axes_radio = self.figure.add_axes([0.01, 0.02, 0.10, 0.15]) # [left, bottom, width, height] = fractions of figure width and height self.figure.subplots_adjust(bottom=0.2) self.radio_buttons = RadioButtons(ax = self.axes_radio, labels = ("Span On", "Span Off"), active = 1, activecolor= "r") self.radio_buttons.on_clicked(self.toggle_selector) # create SpanSelector; invisble at first unless activated with toggle selector self.span_selector = SpanSelector(self.axes, self.on_select_axes, 'horizontal', useblit = True, rectprops = dict(alpha=0.5, facecolor='red')) self.span_selector.visible = False def plot_watertxt_parameter(self, watertxt_data, name): """ Plot a parameter from a WATER.txt file """ self.reset_watertxt_plot() self.dates = watertxt_data["dates"] self.watertxt_data = watertxt_data self.parameter = watertxt.get_parameter(watertxt_data, name = name) assert self.parameter is not None, "Parameter name {} is not in watertxt_data".format(name) self.axes.set_title("Parameter: {}".format(self.parameter["name"])) self.axes.set_xlabel("Date") ylabel = "\n".join(wrap(self.parameter["name"], 60)) self.axes.set_ylabel(ylabel) # get proper color that corresponds to parameter name self.color_str = self.colors_dict[name.split('(')[0].strip()] # plot parameter self.axes.plot(self.dates, self.parameter["data"], color = self.color_str, label = self.parameter["name"], linewidth = 2) # legend; make it transparent handles, labels = self.axes.get_legend_handles_labels() legend = self.axes.legend(handles, labels, fancybox = True) legend.get_frame().set_alpha(0.5) legend.draggable(state=True) # show text of mean, max, min values on graph; use matplotlib.patch.Patch properies and bbox text = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format(self.parameter["mean"], self.parameter["max"], self.parameter["min"]) patch_properties = {"boxstyle": "round", "facecolor": "wheat", "alpha": 0.5} self.axes_text = self.axes.text(0.05, 0.95, text, transform = self.axes.transAxes, fontsize = 14, verticalalignment = "top", horizontalalignment = "left", bbox = patch_properties) # use a more precise date string for the x axis locations in the toolbar and rotate labels self.axes.fmt_xdata = mdates.DateFormatter("%Y-%m-%d") # rotate and align the tick labels so they look better; note that self.figure.autofmt_xdate() does not work because of the radio button axes for label in self.axes.get_xticklabels(): label.set_ha("right") label.set_rotation(30) # draw the plot self.canvas.draw() def on_select_helper(self, xmin, xmax): """ Helper for on_select methods """ # convert matplotlib float dates to a datetime format date_min = mdates.num2date(xmin) date_max = mdates.num2date(xmax) # put the xmin and xmax in datetime format to compare date_min = datetime.datetime(date_min.year, date_min.month, date_min.day, date_min.hour, date_min.minute) date_max = datetime.datetime(date_max.year, date_max.month, date_max.day, date_max.hour, date_max.minute) # find the indices that were selected indices = np.where((self.dates >= date_min) & (self.dates <= date_max)) indices = indices[0] # get the selected dates and values selected_dates = self.dates[indices] selected_values = self.parameter["data"][indices] # compute simple stats on selected values selected_values_mean = nanmean(selected_values) selected_value_max = np.nanmax(selected_values) selected_value_min = np.nanmin(selected_values) return selected_dates, selected_values, selected_values_mean, selected_value_max, selected_value_min def on_select_axes(self, xmin, xmax): """ A select handler for SpanSelector that updates axes with the new x and y limits selected by user """ selected_dates, selected_values, selected_values_mean, selected_value_max, selected_value_min = self.on_select_helper(xmin, xmax) # plot the selected values and update plots limits and text self.axes.plot(selected_dates, selected_values, self.color_str) self.axes.set_xlim(selected_dates[0], selected_dates[-1]) self.axes.set_ylim(selected_values.min(), selected_values.max()) text = 'mean = %.2f\nmax = %.2f\nmin = %.2f' % (selected_values_mean, selected_value_max, selected_value_min) self.axes_text.set_text(text) # draw the updated plot self.canvas.draw() def toggle_selector(self, radio_button_label): """ A toggle radio buttons for the matplotlib SpanSelector widget. """ if radio_button_label == "Span On": self.span_selector.visible = True self.matplotlib_toolbar.hide() elif radio_button_label == "Span Off": self.span_selector.visible = False self.matplotlib_toolbar.show() self.plot_watertxt_parameter(watertxt_data = self.watertxt_data, name = self.parameter["name"]) def clear_watertxt_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_watertxt_plot(self): """ Clear the plot axes """ self.axes.clear() self.canvas.draw() self.axes.grid(True) #-------------------------------- WATER.txt Parameter Comparison Plot ------------------------------------ def setup_watertxtcmp_plot(self): """ Setup the watertxt plot """ self.clear_watertxtcmp_plot() # set up axes and its properties self.axes1 = self.figure.add_subplot(211) self.axes2 = self.figure.add_subplot(212, sharex = self.axes1) self.axes1.grid(True) self.axes2.grid(True) def plot_watertxtcmp_parameter(self, watertxt_data1, watertxt_data2, filename1, filename2, name): """ Plot a parameter from a WATER.txt file """ self.reset_watertxtcmp_plot() dates = watertxt_data1["dates"] parameter1 = watertxt.get_parameter(watertxt_data = watertxt_data1, name = name) parameter2 = watertxt.get_parameter(watertxt_data = watertxt_data2, name = name) assert parameter1 is not None, "Parameter name {} is not in watertxt_data".format(name) assert parameter2 is not None, "Parameter name {} is not in watertxt_data".format(name) # calculate the difference diff = parameter2["data"] - parameter1["data"] # plot parameters on axes1 self.axes1.plot(dates, parameter1["data"], color = "b", label = filename1 + ": " + parameter1["name"], linewidth = 2) self.axes1.hold(True) self.axes1.plot(dates, parameter2["data"], color = "r", label = filename2 + ": " + parameter2["name"], linewidth = 2) # plot the difference on axes2 self.axes2.plot(dates, diff, color = "k", linewidth = 2) # add title, labels, legend self.axes1.set_title(parameter1["name"]) self.axes2.set_xlabel("Date") self.axes2.set_ylabel("Difference") handles1, labels1 = self.axes1.get_legend_handles_labels() legend1 = self.axes1.legend(handles1, labels1, fancybox = True) legend1.get_frame().set_alpha(0.5) legend1.draggable(state=True) # show text of mean, max, min values on graph; use matplotlib.patch.Patch properies and bbox text1 = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format(parameter1["mean"], parameter1["max"], parameter1["min"]) text2 = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format(parameter2["mean"], parameter2["max"], parameter2["min"]) text_diff = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format(nanmean(diff), np.max(diff), np.min(diff)) patch_properties1 = {"boxstyle": "round", "facecolor": "b", "alpha": 0.5} patch_properties2 = {"boxstyle": "round", "facecolor": "r", "alpha": 0.5} patch_properties_diff = {"boxstyle": "round", "facecolor": "wheat", "alpha": 0.5} self.axes1.text(0.02, 0.95, text1, transform = self.axes1.transAxes, fontsize = 12, verticalalignment = "top", horizontalalignment = "left", bbox = patch_properties1) self.axes1.text(0.02, 0.45, text2, transform = self.axes1.transAxes, fontsize = 12, verticalalignment = "top", horizontalalignment = "left", bbox = patch_properties2) self.axes2.text(0.02, 0.95, text_diff, transform = self.axes2.transAxes, fontsize = 12, verticalalignment = "top", horizontalalignment = "left", bbox = patch_properties_diff) # use a more precise date string for the x axis locations in the toolbar and rotate labels self.axes2.fmt_xdata = mdates.DateFormatter("%Y-%m-%d") # rotate and align the tick labels so they look better self.figure.autofmt_xdate() # draw the plot self.canvas.draw() def clear_watertxtcmp_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_watertxtcmp_plot(self): """ Clear the plot axes """ self.axes1.clear() self.axes2.clear() self.canvas.draw() self.axes1.grid(True) self.axes2.grid(True) #-------------------------------- Basemap Plot ------------------------------------ def setup_basemap_plot(self): """ Setup the watertxt plot """ self.clear_basemap_plot() # set up axes and its properties self.basemap_axes = self.figure.add_subplot(111) self.basemap_axes.grid(True) def get_map_extents(self, shapefiles, shp_name = None): """ Get max and min extent coordinates from a list of shapefiles to use as the extents on the map. Use the map extents to calculate the map center and the standard parallels. Parameters ---------- shapefiles : list List of shapefile_data dictionaries shp_name : string String name of shapefile to use for getting map extents Returns ------- extent_coords : dictionary Dictionary containing "lon_min", "lon_max", "lat_max", "lat_min" keys with respective calculated values center_coords : dictionary Dictionary containing "lon", "lat" keys with respective calculated values standard_parallels : dictionary Dictionary containing "first", "second" keys with respective calculated values (first = min(lat), second = max(lat)) """ extent_coords = {} center_coords = {} standard_parallels = {} lons = [] lats = [] if shp_name: for shapefile_data in shapefiles: if shp_name in shapefile_data["name"].split("_")[0]: lons.append(shapefile_data["extents"][0:2]) lats.append(shapefile_data["extents"][2:]) else: for shapefile_data in shapefiles: lons.append(shapefile_data["extents"][0:2]) lats.append(shapefile_data["extents"][2:]) extent_coords["lon_min"] = np.min(lons) extent_coords["lon_max"] = np.max(lons) extent_coords["lat_min"] = np.min(lats) extent_coords["lat_max"] = np.max(lats) center_coords["lon"] = np.mean([extent_coords["lon_min"], extent_coords["lon_max"]]) center_coords["lat"] = np.mean([extent_coords["lat_min"], extent_coords["lat_max"]]) standard_parallels["first"] = extent_coords["lat_min"] standard_parallels["second"] = extent_coords["lat_max"] return extent_coords, center_coords, standard_parallels def plot_shapefiles_map(self, shapefiles, display_fields = [], colors = [], title = None, shp_name = None, buff = 1.0): """ Generate a map showing all the shapefiles in the shapefile_list. Shapefiles should be in a Geographic Coordinate System (longitude and latitude coordinates) such as World WGS84; Matplotlib"s basemap library does the proper transformation to a projected coordinate system. The projected coordinate system used is Albers Equal Area. Parameters ---------- shapefiles : list List of dictionaries containing shapefile information title : string String title for plot display_fields : list List of strings that correspond to a shapefile field where the corresponding value(s) will be displayed. colors : list List of strings that correspond to colors to be displayed shp_name : string String name of shapefile to use for getting map extents buff : float Float value in coordinate degrees to buffer the map with """ self.setup_basemap_plot() extent_coords, center_coords, standard_parallels = self.get_map_extents(shapefiles, shp_name = shp_name) # create the basemap object with Albers Equal Area Conic Projection bmap = Basemap(projection = "aea", llcrnrlon = extent_coords["lon_min"] - buff, llcrnrlat = extent_coords["lat_min"] - buff, urcrnrlon = extent_coords["lon_max"] + buff, urcrnrlat = extent_coords["lat_max"] + buff, lat_1 = standard_parallels["first"], lat_2 = standard_parallels["second"], lon_0 = center_coords["lon"], lat_0 = center_coords["lat"], resolution = "h", area_thresh = 10000, ax = self.basemap_axes) # have basemap object plot background stuff bmap.drawcoastlines() bmap.drawcountries() bmap.drawrivers(linewidth = 1, color = "blue") bmap.drawstates() bmap.drawmapboundary(fill_color = "aqua") bmap.fillcontinents(color = "coral", lake_color = "aqua") bmap.drawparallels(np.arange(-80., 81., 1.), labels = [1, 0, 0, 0], linewidth = 0.5) bmap.drawmeridians(np.arange(-180., 181., 1.), labels = [0, 0, 0, 1], linewidth = 0.5) # plot each shapefile on the basemap legend_handles = [] legend_labels = [] colors_index = 0 colors_list = ["b", "g", "y", "r", "c", "y", "m", "orange", "aqua", "darksalmon", "gold", "k"] for shapefile_data in shapefiles: # set up colors to use if colors: color = colors[colors_index] elif colors_index > len(colors_list) - 1: color = np.random.rand(3,) else: color = colors_list[colors_index] full_path = os.path.join(shapefile_data["path"], shapefile_data["name"].split(".")[0]) shp_tuple = bmap.readshapefile(full_path, "shp", drawbounds = False) # use basemap shapefile reader for ease of plotting for shape_dict, shape in zip(bmap.shp_info, bmap.shp): # zip the shapefile information and its shape as defined by basemap if shapefile_data["type"] == "POLYGON": p1 = Polygon(shape, facecolor = color, edgecolor = "k", linewidth = 1, alpha = 0.7, label = shapefile_data["name"]) self.basemap_axes.add_patch(p1) xx, yy = zip(*shape) txt_x = str(np.mean(xx)) txt_y = str(np.mean(yy)) elif shapefile_data["type"] == "POINT": x, y = shape if "usgsgages" in shapefile_data["name"].split("_")[0]: p1 = bmap.plot(x, y, color = color, marker = "^", markersize = 10, label = shapefile_data["name"]) elif "wateruse" in shapefile_data["name"].split("_")[0]: p1 = bmap.plot(x, y, color = color, marker = "o", markersize = 5, label = shapefile_data["name"]) else: print("what!!") p1 = bmap.plot(x, y, color = color, marker = "o", markersize = 10, label = shapefile_data["name"]) txt_x = str(x) txt_y = str(y) else: xx, yy = zip(*shape) p1 = bmap.plot(xx, yy, linewidth = 1, color = color, label = shapefile_data["name"]) txt_x = str(np.mean(xx)) txt_y = str(np.mean(yy)) if isinstance(p1, list): p1 = p1[0] # control text display of shapefile fields for display_field in display_fields: if display_field in shape_dict.keys(): self.basemap_axes.text(txt_x, txt_y, shape_dict[display_field], color = "k", fontsize = 12, fontweight = "bold") colors_index += 1 legend_handles.append(p1) legend_labels.append(shapefile_data["name"].split("_")[0]) handles, labels = self.basemap_axes.get_legend_handles_labels() # edit the contents of handles and labels to only show 1 legend per shape handles = legend_handles labels = legend_labels legend = self.basemap_axes.legend(handles, labels, fancybox = True, numpoints = 1) legend.get_frame().set_alpha(0.5) legend.draggable(state = True) # draw the plot self.canvas.draw() def clear_basemap_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_basemap_plot(self): """ Clear the plot axes """ self.basemap_axes.clear() self.canvas.draw()
class LMatplotlibWidget(LWidget): def __init__(self, parent=None): super(LMatplotlibWidget, self).__init__(parent) self.setName(WIDGET_NAME) self.buildUi() self.dataContainer = LMyDataContainer(self) self.actions = LMyActions(self.dataContainer,self) self.setDebugLevel(5) self.updateUi() @LInAndOut(DEBUG & WIDGETS) def buildUi(self): self.verticalLayout = QVBoxLayout(self) self.figure = Figure() self.canvas = Canvas(self.figure) # <-- figure required self.navigationToolbar = NavigationToolbar(self.canvas, self) self.verticalLayout.addWidget(self.canvas) self.verticalLayout.addWidget(self.navigationToolbar) #Canvas.setSizePolicy(self.canvas, QSizePolicy.Expanding, QSizePolicy.Expanding) #Canvas.updateGeometry(self.canvas) @LInAndOut(DEBUG & WIDGETS) def updateUi(self): left = self.dataContainer.leftMargin bottom = self.dataContainer.bottomMargin right = self.dataContainer.rightMargin top = self.dataContainer.topMargin wspace = self.dataContainer.verticalSeparation hspace = self.dataContainer.horizontalSeparation self.figure.subplots_adjust(left, bottom, right, top, wspace, hspace) if self.dataContainer.showNavigationToolbar: self.navigationToolbar.show() else: self.navigationToolbar.hide() #---------------------------------------------------------------------- # Interface (set) @LInAndOut(DEBUG & WIDGETS) def setOptions(self, options): super(LMatplotlibWidget, self).setOptions(options) if options.verboseLevel is not None: self.setVerboseLevel(options.verboseLevel) if options.navigationToolbar is not None: self.showNavigationToolbar(options.navigationToolbar) self.updateUi() @LInAndOut(DEBUG & WIDGETS) def setVerboseLevel(self, level): self.dataContainer.verboseLevel = level #---------------------------------------------------------------------- # Interface (get) def getFigure(self): return self.figure #---------------------------------------------------------------------- # Interface (misc) @LInAndOut(DEBUG & WIDGETS) def showNavigationToolbar(self, flag=True): self.dataContainer.showNavigationToolbar = flag self.updateUi() @LInAndOut(DEBUG & WIDGETS) def snapshot(self, fileName = None): if fileName is None: caption = "%s - Save File" % self.name filter = "PNG Image (*.png);;All files (*.*)" fileName = QFileDialog.getSaveFileName(self.parent(), caption=caption,filter=filter ) fileName = "%s" % fileName if len(fileName) > 0: self.figure.savefig(fileName, facecolor='w', edgecolor='w', orientation='portrait', papertype=None, format=None, transparent=False, bbox_inches=None, pad_inches=0.1) @LInAndOut(DEBUG & WIDGETS) def draw(self): self.canvas.draw()
class PlotWindow(QFrame): # Init the class: create plot window and canvas layout (and corresponding buttons) # Steps contains a dictionary of dictionaries with the identified steps # def __init__(self, parent): #QFrame.__init__(self) QMainWindow.__init__(self, None) self.setWindowTitle('BBS timing statistics') self.parent = parent # Parent: BBSTiming class self.currentPlotStyle = "bar" # current style of plot: bar, colorbar, lines self.plotStyles = ["bar", "colorbar", "line"] # supported plot styles # self.summation = False # show "individual" execution times or "summation" self.fig = None # figure self.axes = None # plot axes self.create_main_frame() self.createWidgets() self.createLayouts() self.createConnections() self.setMinimumWidth(700) self.setMinimumHeight(400) # Create a main frame # def create_main_frame(self): self.main_frame = QWidget() self.dpi = 75 self.setMinimumWidth(300) self.setMinimumHeight(300) # We want matplotlib export functionality, so include toolbar # MPL Canvas and Toolbar # Create canvas for plotting self.fig = Figure((5, 4), dpi=75) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self) self.fig.subplots_adjust(left=0.1, right=0.96, top=0.94, bottom=0.06) # set a small rim self.mpl_toolbar = NavigationToolbar(self.canvas, self) self.mpl_toolbar.show() # first hide the toolbar # Create the layouts for the widgets # def createLayouts(self): # Layouts self.buttonLayout = QVBoxLayout() self.canvasLayout = QVBoxLayout() self.mainLayout = QHBoxLayout() # Add Widgets to the layout self.buttonLayout.addWidget(self.loadButton) self.buttonLayout.addWidget(self.quitButton) self.buttonLayout.insertStretch(-1) self.subStepsLayout = QHBoxLayout() self.subStepsLayout.addWidget(self.showSubstepsCheckBox) self.subStepsLayout.addWidget(self.showSubstepsLabel) self.buttonLayout.addLayout(self.subStepsLayout) self.showIndividualStepsLayout = QHBoxLayout() self.showIndividualStepsLayout.addWidget(self.showIndividualCheckBox) self.showIndividualStepsLayout.addWidget(self.showIndividualLabel) self.buttonLayout.addLayout(self.showIndividualStepsLayout) self.buttonLayout.addWidget(self.stepComboBox) #self.buttonLayout.addWidget(self.stepListView) self.buttonLayout.addWidget(self.substepComboBox) self.buttonLayout.addWidget(self.keywordComboBox) self.buttonLayout.addWidget(self.plotStyleComboBox) self.buttonLayout.addWidget(self.stepComboBox) self.buttonLayout.addWidget(self.plotButton) self.buttonLayout.insertStretch(-1) self.canvasLayout.addWidget(self.canvas) self.canvasLayout.addWidget(self.mpl_toolbar) self.mainLayout.addLayout(self.buttonLayout) self.mainLayout.addLayout(self.canvasLayout) self.setLayout(self.mainLayout) # Create GUI widgets # def createWidgets(self): #print "createWidgets()" # DEBUG self.loadButton = QPushButton("Load logfile") self.loadButton.setToolTip('load a BBS kernellog file') self.loadButton.setMaximumWidth(200) self.quitButton = QPushButton("Quit") self.quitButton.setMaximumWidth(200) self.quitButton.setToolTip('Quit the application') self.quitButton.setMaximumWidth(200) self.plotButton = QPushButton("Plot") self.plotButton.setToolTip('force a replot') self.showSubstepsCheckBox = QCheckBox() self.showSubstepsLabel = QLabel("Show substeps") self.showSubstepsCheckBox.setToolTip("Show also substeps in timing") self.showSubstepsCheckBox.setCheckState(Qt.Unchecked) # Default: False self.showSubstepsCheckBox.show() self.showSubstepsLabel.show() self.showIndividualCheckBox = QCheckBox() self.showIndividualLabel = QLabel("Numbered steps") self.showIndividualCheckBox.setToolTip( "Show individually numbered steps") self.showIndividualCheckBox.setCheckState( Qt.Unchecked) # Default: False self.showIndividualCheckBox.show() self.showIndividualLabel.show() # GUI Widgets depending on log file self.createStepComboBox() # Selector for Step self.createKeywordComboBox() # Selector for: total, count, avg # Selector for plot type: bar, line, multibar self.createPlotstyleComboBox() self.createStepComboBox() #self.createStepListView() # This is now done in a function, too # self.substepComboBox=QComboBox() # we create this here once # self.substepComboBox.hide() # self.substepComboBox.setToolTip('Substeps of step') # self.substepComboBox.setMaximumWidth(200) self.createSubbandComboBox() # Create the step combobox containing the timed steps # This should be a multi-selection box to plot multiple # steps # def createStepComboBox(self): #print "createStepComboBox()" # DEBUG self.stepComboBox = QComboBox() for step in self.parent.timedSteps: self.stepComboBox.addItem(step) self.stepComboBox.addItem("all") self.stepComboBox.show() self.stepComboBox.setMaximumWidth(200) def createSubstepComboBox(self): print("createSubstepComboBox()") # DEBUG self.substepComboBox = QComboBox() # we create this here once self.substepComboBox.hide() self.substepComboBox.setToolTip('Substeps of step') self.substepComboBox.setMaximumWidth(200) # Fill step Checkbox with step names, either these are # grouped by their common name, or shown as individually # numbered steps # def fillSteps(self): print("fillSteps()") # DEBUG self.stepComboBox.clear() # Decide if we want the steps grouped or individually numbered if self.showIndividualCheckBox.isChecked() == True: steps = self.parent.timedStepsCount else: steps = self.parent.timedSteps #print "fillSteps() steps = ", steps for step in steps: # Check if that substep is already in there, avoid duplicates if self.stepComboBox.findData(step) == -1: self.stepComboBox.addItem(step) self.stepComboBox.addItem( "all") # we again have to add our "all" option # Get the corresponding substeps for a step # def fillSubsteps(self): print("fillSubsteps()") # DEBUG # Get substeps for currently selected step (or all if "all") step = str(self.stepComboBox.currentText()) self.substepComboBox.clear() # first clear substeps comboBox if step != "all" and step != "ALL": substeps = self.parent.getSubsteps(step) #print "fillSubsteps() substeps = ", substeps # DEBUG for substep in substeps: # Check if that substep is already in there, avoid duplicates if self.substepComboBox.findData(substep) == -1: self.substepComboBox.addItem(substep) else: self.substepComboBox.clear() # First remove existing substeps index = 0 while index < self.stepComboBox.count(): # loop over all steps # TODO: Might not be supported to show substeps for ALL steps... #substeps=str(self.stepComboBox.itemText(index)) #print "fillSubsteps() substeps = ", substeps #print "fillSubsteps() index = ", index, "maxCount = ", self.stepComboBox.count() step = str(self.stepComboBox.itemText(index)) print("fillSubsteps() step = ", step) if step != "all" and step != "ALL": substeps = self.parent.getSubsteps(step) keys = list(substeps.keys()) #print "keys = ", keys for j in range(len(substeps) - 1): #print "fillSubsteps() substeps = ", substeps substep = keys[j] if substep != "all" and substep != "ALL": self.substepComboBox.addItem(substep) j = j + 1 index = index + 1 self.substepComboBox.addItem("ALL") # we need to add an "ALL" """ # Alternative view, displaying all the steps # in a list view that then can be selected for # plotting # def createStepListView(self): print "createStepListBox()" # DEBUG self.stepListView=QListView() for step in self.parent.timedSteps: self.stepListView.insertStringList(step) self.stepListView.show() step.stepListView.setMaximumWidth(200) """ # On timing combobox event # def createKeywordComboBox(self): print("createTimingComboBox()") # DEBUG self.keywordComboBox = QComboBox() for key in self.parent.keywords: self.keywordComboBox.addItem(key) self.keywordComboBox.show() self.keywordComboBox.setMaximumWidth(200) # Create a comboBox offering different Matplotlib styles # def createPlotstyleComboBox(self): print("createPlotstyleComboBox()") # DEBUG self.plotStyleComboBox = QComboBox() for style in self.plotStyles: self.plotStyleComboBox.addItem(style) self.plotStyleComboBox.show() self.plotStyleComboBox.setMaximumWidth(200) # Create subbands comboBox which allows selection of an individual subband # from a pipeline.log def createSubbandComboBox(self): print("createSubbandComboBox()") # DEBUG self.subbandComboBox = QComboBox() for sub in self.parent.subbands: self.subbandComboBox.addItem(sub) self.subbandComboBox.show() self.subbandComboBox.setMaximumWidth(200) #************************************** # # Create connections # #************************************** def createConnections(self): print("createConnections()") # DEBUG self.connect(self.loadButton, SIGNAL('clicked()'), self.on_loadfile) self.connect(self.quitButton, SIGNAL('clicked()'), self, SLOT('close()')) self.connect(self.stepComboBox, SIGNAL('currentIndexChanged(int)'), self.on_step) self.connect(self.stepComboBox, SIGNAL('currentIndexChanged(int)'), self.on_showSubsteps) #self.connect(self.substepComboBox, SIGNAL('currentIndexChanged(int)'), self.on_step) self.connect(self.substepComboBox, SIGNAL('currentIndexChanged(int)'), self.on_plot) self.connect(self.keywordComboBox, SIGNAL('currentIndexChanged(int)'), self.on_keyword) self.connect(self.plotStyleComboBox, SIGNAL('currentIndexChanged(int)'), self.on_plotStyle) self.connect(self.showSubstepsCheckBox, SIGNAL('stateChanged(int)'), self.on_showSubsteps) self.connect(self.showIndividualCheckBox, SIGNAL('stateChanged(int)'), self.on_individualSteps) self.connect(self.subbandComboBox, SIGNAL('currentIndexChanged(int)'), self.on_subband) self.connect(self.plotButton, SIGNAL('clicked()'), self.on_plot) #************************************** # # Event handlers # #************************************** # Load Kernellog file dialog # def on_loadfile(self): #print "on_loadfile()" # DEBUG # Customization: check if ~/Cluster/SolutionTests exists if os.path.exists('/Users/duscha/Desktop/'): setDir = QString('/Users/duscha/Desktop/') else: setDir = QString('') path = str(QFileDialog.getOpenFileName(self, 'Load Kernellog', setDir)) path = str( path) # Convert to string so that it can be used by load table if path: self.parent.readLogfile(path) else: print("load_table: invalid path") # On step combobox event # def on_step(self): print("on_step()") # DEBUG #step=str(self.stepComboBox.currentText()) self.on_plot() # On substep combobox event # def on_substep(self): print("on_substep()") # DEBUG #step=str(self.stepComboBox.currentText()) self.on_plot() # On toggle individual treatment of counted steps # def on_individualSteps(self): print("on_individualSteps()") # DEBUG self.fillSteps() # update steps combobox self.on_showSubsteps() # also update substeps combobox #step=str(self.stepComboBox.currentText()) self.on_plot() # On selection of different subbands # def on_subband(self): print("on_subband()") # DEBUG self.fillSteps() # update steps combobox self.on_showSubsteps() # also update substeps combobox self.on_plot() # On toggling of show substeps # def on_showSubsteps(self): print("on_substeps()") # DEBUG if self.showSubstepsCheckBox.isChecked() == True: self.showSubSteps = True self.substepComboBox.show() self.fillSubsteps() else: self.showSubSteps = False self.substepComboBox.hide() self.substepComboBox.clear() # On keyword combobox event # def on_keyword(self): print("on_keyword()") # DEBUG self.on_plot() # On change of plot style # def on_plotStyle(self): print("on_plotStyle()") # DEBUG self.plotStyle = self.plotStyleComboBox.currentText( ) # change class attribute # On plot button action # def on_plot(self): self.fig.clf() # clear the figure print("on_plot()") step = str(self.stepComboBox.currentText()) self.plot(step) """ step=str(self.stepComboBox.currentText()) # If we have all steps selected: if step=="ALL" or step=="all": for i in range(0, self.stepComboBox.count()): # loop over all steps currentStep=self.stepComboBox.itemText(i) # get the step name from QComboBox print "on_plot() currentStep = ", currentStep self.plot(currentStep) # plot it else: #print "foo" self.plot(step) # replot with new plotstyle """ # Replot diagram # def plot(self, step): print("plot()") # DEBUG width = 0.25 # width of bar plots # Get the data according to GUI settings step = str(step) substep = str(self.substepComboBox.currentText()) keyword = str(self.keywordComboBox.currentText()) style = str(self.plotStyleComboBox.currentText()) print("plot() step = ", step, "substep = ", substep, "keyword = ", keyword, "style = ", style) # DEBUG self.axes = self.fig.add_subplot(111) # add 1 subplot to the canvas result = [] # TODO: plot all substeps if we get multiple in results if step == "all" or step == "ALL": if self.showIndividualCheckBox.isChecked(): steps = self.parent.timedStepsCount else: steps = self.parent.timedSteps print("plot() steps = ", steps) # DEBUG for i in range(0, len(steps)): #print "plot()", self.parent.getSubStepValue(str(steps[i]), substep, keyword) result.append(self.parent.getStepFinal(str(steps[i]), keyword)) #print "len(result) = ", len(result) print("plot() result[" + str(i) + "] = " + str(result[i])) #self.axes.bar(i, result[i], width) # If we want to see all steps, but not for individual substeps elif step == "all" or step == "ALL" and (substep == None or substep == ""): if self.showIndividualCheckBox.isChecked(): steps = self.parent.getSubsteps(step, keyword) else: steps = self.parent.timedSteps print("steps = ", steps) #steps.append(self.parent.timedSteps) newsteps = [] if isinstance(steps, list): for i in range(0, len(steps)): # overplot them in one plot newsteps.append(steps[i]) result = newsteps elif substep == "all" or substep == "ALL": print("plot(): substep=all") result = (self.parent.getSubStepValue(step, keyword)) elif substep == None or substep == "": result = (self.parent.getStepFinal(step, keyword)) else: result = (self.parent.getSubStepValue(step, substep, keyword)) #if isinstance(result[0], list): # result=self.linearizeList(result) if isinstance(result, list): print("plot() len(result) = ", len(result)) # DEBUG print("plot() result = ", result) # DEBUG #print "plot() result[1] = ", result[1] # DEBUG # # Plot on canvas # ind = [] if isinstance(result, float) or isinstance(result, int): ind = 0 elif isinstance(result, bool): print("plot() invalid result returned") else: maxInd = len(result) for i in range(0, maxInd): ind.append(width * 1.1 * i) # Decide on plotstyle which plotting to do if self.currentPlotStyle == "bar": print("ind = ", ind) # DEBUG print("result = ", result) # DEBUG rects1 = self.axes.bar(ind, result, width, color='r') elif self.currentPlotStyle == "colorbar": print("plot() colorbar") else: print("plot() lines") self.axes.scatter(0, result) # # Set axes labels according to selected keyword on y-axis and # for each plotted step/substep identifier on the x-axis # ylabel = str(self.keywordComboBox.currentText()) if self.keywordComboBox.currentText( ) == "total" or self.keywordComboBox.currentText() == "avg": ylabel = ylabel + " s" self.axes.set_ylabel(ylabel) self.canvas.draw() #****************************************************** # # Helper functions # #******************************************************* def linearizeList(self, reorderlist): print("linearizeList()") # DEBUG newlist = [] if isinstance(reorderlist, list): Nlists = len(reorderlist) for i in range(Nlists): if isinstance(reorderlist[i], list): for j in len(reorderlist[i]): newlist.append(reorderlist[i][j]) else: newlist.append(reorderlist[i]) return newlist #****************************************************** # # Update GUI Widgets on loading a new Kernellog file # #******************************************************* # Update the Kernel log dependent widgets, i.e. deleting # and recreating them # def updateWidgets(self): print("updateWidgets()") # DEBUG self.deleteWidgets() self.createWidgets() # Delete GUI Widgets that are created dynamically from the log # def deleteWidgets(self): # DEBUG print("deleteWidgets()") self.stepComboBox.deleteLater() self.keywordComboBox.deleteLater() self.plotstyleComboBox.deleteLater() self.stepComboBox.deleteLater()
class PlotWindow(QFrame): # Init the class: create plot window and canvas layout (and corresponding buttons) # Steps contains a dictionary of dictionaries with the identified steps # def __init__(self, parent): #QFrame.__init__(self) QMainWindow.__init__(self, None) self.setWindowTitle('BBS timing statistics') self.parent=parent # Parent: BBSTiming class self.currentPlotStyle="bar" # current style of plot: bar, colorbar, lines self.plotStyles=["bar", "colorbar", "line"] # supported plot styles # self.summation=False # show "individual" execution times or "summation" self.fig=None # figure self.axes=None # plot axes self.create_main_frame() self.createWidgets() self.createLayouts() self.createConnections() self.setMinimumWidth(700) self.setMinimumHeight(400) # Create a main frame # def create_main_frame(self): self.main_frame = QWidget() self.dpi = 75 self.setMinimumWidth(300) self.setMinimumHeight(300) # We want matplotlib export functionality, so include toolbar # MPL Canvas and Toolbar # Create canvas for plotting self.fig = Figure((5, 4), dpi=75) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self) self.fig.subplots_adjust(left=0.1, right=0.96, top=0.94, bottom=0.06) # set a small rim self.mpl_toolbar = NavigationToolbar(self.canvas, self) self.mpl_toolbar.show() # first hide the toolbar # Create the layouts for the widgets # def createLayouts(self): # Layouts self.buttonLayout=QVBoxLayout() self.canvasLayout=QVBoxLayout() self.mainLayout=QHBoxLayout() # Add Widgets to the layout self.buttonLayout.addWidget(self.loadButton) self.buttonLayout.addWidget(self.quitButton) self.buttonLayout.insertStretch(-1) self.subStepsLayout=QHBoxLayout() self.subStepsLayout.addWidget(self.showSubstepsCheckBox) self.subStepsLayout.addWidget(self.showSubstepsLabel) self.buttonLayout.addLayout(self.subStepsLayout) self.showIndividualStepsLayout=QHBoxLayout() self.showIndividualStepsLayout.addWidget(self.showIndividualCheckBox) self.showIndividualStepsLayout.addWidget(self.showIndividualLabel) self.buttonLayout.addLayout(self.showIndividualStepsLayout) self.buttonLayout.addWidget(self.stepComboBox) #self.buttonLayout.addWidget(self.stepListView) self.buttonLayout.addWidget(self.substepComboBox) self.buttonLayout.addWidget(self.keywordComboBox) self.buttonLayout.addWidget(self.plotStyleComboBox) self.buttonLayout.addWidget(self.stepComboBox) self.buttonLayout.addWidget(self.plotButton) self.buttonLayout.insertStretch(-1) self.canvasLayout.addWidget(self.canvas) self.canvasLayout.addWidget(self.mpl_toolbar) self.mainLayout.addLayout(self.buttonLayout) self.mainLayout.addLayout(self.canvasLayout) self.setLayout(self.mainLayout) # Create GUI widgets # def createWidgets(self): #print "createWidgets()" # DEBUG self.loadButton=QPushButton("Load logfile") self.loadButton.setToolTip('load a BBS kernellog file') self.loadButton.setMaximumWidth(200) self.quitButton=QPushButton("Quit") self.quitButton.setMaximumWidth(200) self.quitButton.setToolTip('Quit the application') self.quitButton.setMaximumWidth(200) self.plotButton=QPushButton("Plot") self.plotButton.setToolTip('force a replot') self.showSubstepsCheckBox=QCheckBox() self.showSubstepsLabel=QLabel("Show substeps") self.showSubstepsCheckBox.setToolTip("Show also substeps in timing") self.showSubstepsCheckBox.setCheckState(Qt.Unchecked) # Default: False self.showSubstepsCheckBox.show() self.showSubstepsLabel.show() self.showIndividualCheckBox=QCheckBox() self.showIndividualLabel=QLabel("Numbered steps") self.showIndividualCheckBox.setToolTip("Show individually numbered steps") self.showIndividualCheckBox.setCheckState(Qt.Unchecked) # Default: False self.showIndividualCheckBox.show() self.showIndividualLabel.show() # GUI Widgets depending on log file self.createStepComboBox() # Selector for Step self.createKeywordComboBox() # Selector for: total, count, avg # Selector for plot type: bar, line, multibar self.createPlotstyleComboBox() self.createStepComboBox() #self.createStepListView() # This is now done in a function, too # self.substepComboBox=QComboBox() # we create this here once # self.substepComboBox.hide() # self.substepComboBox.setToolTip('Substeps of step') # self.substepComboBox.setMaximumWidth(200) self.createSubbandComboBox() # Create the step combobox containing the timed steps # This should be a multi-selection box to plot multiple # steps # def createStepComboBox(self): #print "createStepComboBox()" # DEBUG self.stepComboBox=QComboBox() for step in self.parent.timedSteps: self.stepComboBox.addItem(step) self.stepComboBox.addItem("all") self.stepComboBox.show() self.stepComboBox.setMaximumWidth(200) def createSubstepComboBox(self): print "createSubstepComboBox()" # DEBUG self.substepComboBox=QComboBox() # we create this here once self.substepComboBox.hide() self.substepComboBox.setToolTip('Substeps of step') self.substepComboBox.setMaximumWidth(200) # Fill step Checkbox with step names, either these are # grouped by their common name, or shown as individually # numbered steps # def fillSteps(self): print "fillSteps()" # DEBUG self.stepComboBox.clear() # Decide if we want the steps grouped or individually numbered if self.showIndividualCheckBox.isChecked()==True: steps=self.parent.timedStepsCount else: steps=self.parent.timedSteps #print "fillSteps() steps = ", steps for step in steps: # Check if that substep is already in there, avoid duplicates if self.stepComboBox.findData(step) == -1: self.stepComboBox.addItem(step) self.stepComboBox.addItem("all") # we again have to add our "all" option # Get the corresponding substeps for a step # def fillSubsteps(self): print "fillSubsteps()" # DEBUG # Get substeps for currently selected step (or all if "all") step=str(self.stepComboBox.currentText()) self.substepComboBox.clear() # first clear substeps comboBox if step != "all" and step!="ALL": substeps=self.parent.getSubsteps(step) #print "fillSubsteps() substeps = ", substeps # DEBUG for substep in substeps: # Check if that substep is already in there, avoid duplicates if self.substepComboBox.findData(substep) == -1: self.substepComboBox.addItem(substep) else: self.substepComboBox.clear() # First remove existing substeps index=0 while index < self.stepComboBox.count(): # loop over all steps # TODO: Might not be supported to show substeps for ALL steps... #substeps=str(self.stepComboBox.itemText(index)) #print "fillSubsteps() substeps = ", substeps #print "fillSubsteps() index = ", index, "maxCount = ", self.stepComboBox.count() step=str(self.stepComboBox.itemText(index)) print "fillSubsteps() step = ", step if step != "all" and step != "ALL": substeps=self.parent.getSubsteps(step) keys=substeps.keys() #print "keys = ", keys for j in range(len(substeps)-1): #print "fillSubsteps() substeps = ", substeps substep=keys[j] if substep != "all" and substep != "ALL": self.substepComboBox.addItem(substep) j=j+1 index=index+1 self.substepComboBox.addItem("ALL") # we need to add an "ALL" """ # Alternative view, displaying all the steps # in a list view that then can be selected for # plotting # def createStepListView(self): print "createStepListBox()" # DEBUG self.stepListView=QListView() for step in self.parent.timedSteps: self.stepListView.insertStringList(step) self.stepListView.show() step.stepListView.setMaximumWidth(200) """ # On timing combobox event # def createKeywordComboBox(self): print "createTimingComboBox()" # DEBUG self.keywordComboBox=QComboBox() for key in self.parent.keywords: self.keywordComboBox.addItem(key) self.keywordComboBox.show() self.keywordComboBox.setMaximumWidth(200) # Create a comboBox offering different Matplotlib styles # def createPlotstyleComboBox(self): print "createPlotstyleComboBox()" # DEBUG self.plotStyleComboBox=QComboBox() for style in self.plotStyles: self.plotStyleComboBox.addItem(style) self.plotStyleComboBox.show() self.plotStyleComboBox.setMaximumWidth(200) # Create subbands comboBox which allows selection of an individual subband # from a pipeline.log def createSubbandComboBox(self): print "createSubbandComboBox()" # DEBUG self.subbandComboBox=QComboBox() for sub in self.parent.subbands: self.subbandComboBox.addItem(sub) self.subbandComboBox.show() self.subbandComboBox.setMaximumWidth(200) #************************************** # # Create connections # #************************************** def createConnections(self): print "createConnections()" # DEBUG self.connect(self.loadButton, SIGNAL('clicked()'), self.on_loadfile) self.connect(self.quitButton, SIGNAL('clicked()'), self, SLOT('close()')) self.connect(self.stepComboBox, SIGNAL('currentIndexChanged(int)'), self.on_step) self.connect(self.stepComboBox, SIGNAL('currentIndexChanged(int)'), self.on_showSubsteps) #self.connect(self.substepComboBox, SIGNAL('currentIndexChanged(int)'), self.on_step) self.connect(self.substepComboBox, SIGNAL('currentIndexChanged(int)'), self.on_plot) self.connect(self.keywordComboBox, SIGNAL('currentIndexChanged(int)'), self.on_keyword) self.connect(self.plotStyleComboBox, SIGNAL('currentIndexChanged(int)'), self.on_plotStyle) self.connect(self.showSubstepsCheckBox, SIGNAL('stateChanged(int)'), self.on_showSubsteps) self.connect(self.showIndividualCheckBox, SIGNAL('stateChanged(int)'), self.on_individualSteps) self.connect(self.subbandComboBox, SIGNAL('currentIndexChanged(int)'), self.on_subband) self.connect(self.plotButton, SIGNAL('clicked()'), self.on_plot) #************************************** # # Event handlers # #************************************** # Load Kernellog file dialog # def on_loadfile(self): #print "on_loadfile()" # DEBUG # Customization: check if ~/Cluster/SolutionTests exists if os.path.exists('/Users/duscha/Desktop/'): setDir=QString('/Users/duscha/Desktop/') else: setDir=QString('') path = unicode(QFileDialog.getOpenFileName(self, 'Load Kernellog', setDir)) path=str(path) # Convert to string so that it can be used by load table if path: self.parent.readLogfile(path) else: print "load_table: invalid path" # On step combobox event # def on_step(self): print "on_step()" # DEBUG #step=str(self.stepComboBox.currentText()) self.on_plot() # On substep combobox event # def on_substep(self): print "on_substep()" # DEBUG #step=str(self.stepComboBox.currentText()) self.on_plot() # On toggle individual treatment of counted steps # def on_individualSteps(self): print "on_individualSteps()" # DEBUG self.fillSteps() # update steps combobox self.on_showSubsteps() # also update substeps combobox #step=str(self.stepComboBox.currentText()) self.on_plot() # On selection of different subbands # def on_subband(self): print "on_subband()" # DEBUG self.fillSteps() # update steps combobox self.on_showSubsteps() # also update substeps combobox self.on_plot() # On toggling of show substeps # def on_showSubsteps(self): print "on_substeps()" # DEBUG if self.showSubstepsCheckBox.isChecked()==True: self.showSubSteps=True self.substepComboBox.show() self.fillSubsteps() else: self.showSubSteps=False self.substepComboBox.hide() self.substepComboBox.clear() # On keyword combobox event # def on_keyword(self): print "on_keyword()" # DEBUG self.on_plot() # On change of plot style # def on_plotStyle(self): print "on_plotStyle()" # DEBUG self.plotStyle=self.plotStyleComboBox.currentText() # change class attribute # On plot button action # def on_plot(self): self.fig.clf() # clear the figure print "on_plot()" step=str(self.stepComboBox.currentText()) self.plot(step) """ step=str(self.stepComboBox.currentText()) # If we have all steps selected: if step=="ALL" or step=="all": for i in range(0, self.stepComboBox.count()): # loop over all steps currentStep=self.stepComboBox.itemText(i) # get the step name from QComboBox print "on_plot() currentStep = ", currentStep self.plot(currentStep) # plot it else: #print "foo" self.plot(step) # replot with new plotstyle """ # Replot diagram # def plot(self, step): print "plot()" # DEBUG width=0.25 # width of bar plots # Get the data according to GUI settings step=str(step) substep=str(self.substepComboBox.currentText()) keyword=str(self.keywordComboBox.currentText()) style=str(self.plotStyleComboBox.currentText()) print "plot() step = ", step, "substep = ", substep, "keyword = ", keyword, "style = ", style # DEBUG self.axes=self.fig.add_subplot(111) # add 1 subplot to the canvas result=[] # TODO: plot all substeps if we get multiple in results if step=="all" or step=="ALL": if self.showIndividualCheckBox.isChecked(): steps=self.parent.timedStepsCount else: steps=self.parent.timedSteps print "plot() steps = ", steps # DEBUG for i in range(0, len(steps)): #print "plot()", self.parent.getSubStepValue(str(steps[i]), substep, keyword) result.append(self.parent.getStepFinal(str(steps[i]), keyword)) #print "len(result) = ", len(result) print "plot() result[" + str(i) + "] = " + str(result[i]) #self.axes.bar(i, result[i], width) # If we want to see all steps, but not for individual substeps elif step=="all" or step=="ALL" and (substep==None or substep==""): if self.showIndividualCheckBox.isChecked(): steps=self.parent.getSubsteps(step, keyword) else: steps=self.parent.timedSteps print "steps = ", steps #steps.append(self.parent.timedSteps) newsteps=[] if isinstance(steps, list): for i in range(0, len(steps)): # overplot them in one plot newsteps.append(steps[i]) result=newsteps elif substep=="all" or substep=="ALL": print "plot(): substep=all" result=(self.parent.getSubStepValue(step, keyword)) elif substep==None or substep=="": result=(self.parent.getStepFinal(step, keyword)) else: result=(self.parent.getSubStepValue(step, substep, keyword)) #if isinstance(result[0], list): # result=self.linearizeList(result) if isinstance(result, list): print "plot() len(result) = ", len(result) # DEBUG print "plot() result = ", result # DEBUG #print "plot() result[1] = ", result[1] # DEBUG # # Plot on canvas # ind=[] if isinstance(result, float) or isinstance(result, int): ind=0 elif isinstance(result, bool): print "plot() invalid result returned" else: maxInd=len(result) for i in range(0, maxInd): ind.append(width*1.1*i) # Decide on plotstyle which plotting to do if self.currentPlotStyle=="bar": print "ind = ", ind # DEBUG print "result = ", result # DEBUG rects1 = self.axes.bar(ind, result, width, color='r') elif self.currentPlotStyle=="colorbar": print "plot() colorbar" else: print "plot() lines" self.axes.scatter(0, result) # # Set axes labels according to selected keyword on y-axis and # for each plotted step/substep identifier on the x-axis # ylabel=str(self.keywordComboBox.currentText()) if self.keywordComboBox.currentText() == "total" or self.keywordComboBox.currentText() == "avg": ylabel=ylabel + " s" self.axes.set_ylabel(ylabel) self.canvas.draw() #****************************************************** # # Helper functions # #******************************************************* def linearizeList(self, reorderlist): print "linearizeList()" # DEBUG newlist=[] if isinstance(reorderlist, list): Nlists=len(reorderlist) for i in range(Nlists): if isinstance(reorderlist[i], list): for j in len(reorderlist[i]): newlist.append(reorderlist[i][j]) else: newlist.append(reorderlist[i]) return newlist #****************************************************** # # Update GUI Widgets on loading a new Kernellog file # #******************************************************* # Update the Kernel log dependent widgets, i.e. deleting # and recreating them # def updateWidgets(self): print "updateWidgets()" # DEBUG self.deleteWidgets() self.createWidgets() # Delete GUI Widgets that are created dynamically from the log # def deleteWidgets(self): # DEBUG print "deleteWidgets()" self.stepComboBox.deleteLater() self.keywordComboBox.deleteLater() self.plotstyleComboBox.deleteLater() self.stepComboBox.deleteLater()