Example #1
0
def matplotlib_figure(width, height):
    """Create a Matplotlib figure with specified width and height for rendering.

  w
    Width of desired plot.
  h
    Height of desired plot.

  return
    A Matplotlib figure.
  """
    try:
        from matplotlib.backends.backend_agg import FigureCanvasAgg
    except:
        paraview.print_error(
            "Error: Cannot import matplotlib.backends.backend_agg.FigureCanvasAgg"
        )
    try:
        from matplotlib.figure import Figure
    except:
        paraview.print_error("Error: Cannot import matplotlib.figure.Figure")

    figure = Figure()
    figureCanvas = FigureCanvasAgg(figure)
    figure.set_dpi(72)
    figure.set_size_inches(float(width) / 72.0, float(height) / 72.0)

    return figure
Example #2
0
  def canvas(self):
    type = self.get("imageType", "png")
    fig = Figure()
    if type == "png":
      canvas = FigureCanvasAgg(fig)
      (self.file, self.filename) = mkstemp(".%s" % type)
    elif type == "svg":
      canvas = FigureCanvasSVG(fig)
      (self.file, self.filename) = mkstemp(".%s" % type)
    elif type == "pdf":
      canvas = FigureCanvasPdf(fig)
      (self.file, self.filename) = mkstemp(".%s" % type)
    elif type == "ps" or type == "eps":
      canvas = FigureCanvasPS(fig)
      (self.file, self.filename) = mkstemp(".%s" % type)
    else:
      raise "Invalid render target requested"

    # Set basic figure parameters
    dpi = float(self.get('dpi'))
    (w, h) = (float(self.get('width')), float(self.get('height')))
    (win, hin) = (w/dpi, h/dpi)
    fig.set_size_inches(win, hin)
    fig.set_dpi(dpi)
    fig.set_facecolor('white')
    return (fig, canvas, w, h)
Example #3
0
def matplotlib_figure(width, height):
  """Create a Matplotlib figure with specified width and height for rendering.

  w
    Width of desired plot.
  h
    Height of desired plot.

  return
    A Matplotlib figure.
  """
  try:
    from matplotlib.backends.backend_agg import FigureCanvasAgg
  except:
    paraview.print_error("Error: Cannot import matplotlib.backends.backend_agg.FigureCanvasAgg")
  try:
    from matplotlib.figure import Figure
  except:
    paraview.print_error("Error: Cannot import matplotlib.figure.Figure")

  figure = Figure()
  figureCanvas = FigureCanvasAgg(figure)
  figure.set_dpi(72)
  figure.set_size_inches(float(width)/72.0, float(height)/72.0)

  return figure
Example #4
0
 def __get_column_width(self):
 
   max_length = 0
   max_column_text = ''
   flag = self.prefs.get('legend_numbers',True)
   unit = self.prefs.get('legend_unit',False)
   for label,num in self.labels:      
     if not flag: num = None
     if num is not None:
       column_length = len(str(label)+str(num)) + 1
     else:
       column_length = len(str(label)) + 1  
     if column_length > max_length:
       max_length = column_length
       if flag:
         if type(num) == types.IntType or type(num) == types.LongType:
           numString = str(num)
         else:
           numString = "%.1f" % float(num)  
         max_column_text = '%s  %s' % (str(label),numString)
         if unit:
           max_column_text += "%"
       else:
         max_column_text = '%s   ' % str(label)  
                        
   figure = Figure()   
   canvas = FigureCanvasAgg(figure) 
   dpi = self.prefs['dpi']
   figure.set_dpi( dpi ) 
   l_size,l_padding = self.__get_legend_text_size()    
   self.text_size = pixelToPoint(l_size,dpi)           
   text = Text(0.,0.,text=max_column_text,size=self.text_size)
   text.set_figure(figure)
   bbox = text.get_window_extent(canvas.get_renderer())
   self.column_width = bbox.width+6*l_size
Example #5
0
class PlotCanvas(tk.Frame):
    """ the canvas class for drawing the Nelder plot design """
    
    borderpoint_color = "black"
    datapoint_color = ("red", "blue", "green")
    wheel_color = "black"
    spoke_color = "black"
    defaul_dpi = 100
        
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.figure = Figure(figsize=(5,5), dpi=self.defaul_dpi, tight_layout = True)
        self.plot = self.figure.add_subplot(111)
        self.plot.axis('scaled')
        self.plot.set_axis_off()
        self.canvas = FigureCanvasTkAgg(self.figure, self)
        self.canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
        self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        self.nelder_plot = None
            
    def updatePlotSize(self):
        """ redraw the plot when the size changes """
        if self.nelder_plot.width > 0 and self.nelder_plot.height > 0:
            self.plot.axis([0,self.nelder_plot.width,0,self.nelder_plot.height])
            self.plot.set_axis_on()
        else:
            self.plot.set_axis_off()
                 
    def setNelderPlot(self, nelder_plot: NelderPlot):
        """ define the Nelder plot object to be drawn """
        self.plot.clear()
        self.nelder_plot = nelder_plot
        self.updatePlotSize()
        if not nelder_plot.isValid(): 
            self.canvas.draw()
            return
        for w in nelder_plot.wheels.values():
            wheel = Wedge((w.center_point.x, w.center_point.y), w.radius, 0, 360, linewidth=0.5, width = 0, 
                           edgecolor = self.wheel_color, alpha = 0.5, linestyle = (0, (4, 8)))
            self.plot.add_patch(wheel)
        for l in nelder_plot.spokes:
            line = Line2D([l.intersect_point.x, l.end_point.x], [l.intersect_point.y, l.end_point.y], linewidth=0.5,
                              color = self.spoke_color, alpha = 0.5, linestyle = ":")
            self.plot.add_line(line) 
        p_size = min(self.nelder_plot.width, self.nelder_plot.height)/120        
        for p in nelder_plot.datapoints:
            point = Circle((p.x, p.y), p_size, facecolor = self.datapoint_color[p.group_id])
            if p.is_border: 
                point.set_edgecolor(self.borderpoint_color)
                point.set_radius(p_size * 0.9)
            self.plot.add_patch(point)
        self.canvas.draw()
    
    def saveImage(self, fileName, dpi = defaul_dpi):
        """ save the image to the file and size (DPI) defined """
        self.figure.set_dpi(dpi)
        self.figure.savefig(fileName)
        self.figure.set_dpi(self.defaul_dpi)
Example #6
0
 def __init__(self, parent=None, width=8, height=8, dpi=100):
     fig = Figure(figsize=(width, height),
                  dpi=200)  # 创建一个Figure,注意:该Figure为matplotlib下的figure,不是matplotlib.pyplot下面的figure
     pdf = camelot.read_pdf(r"C:\Users\localhost\Desktop\石家庄市2018年市本级和全市财政总决算报表.pdf", flavor='stream', pages='5')
     if pdf:
         fig = camelot.plot(pdf[0], kind='textedge')
     fig.set_dpi(150)
     axis('tight')
     FigureCanvas.__init__(self, fig)  # 初始化父类
     self.setParent(parent)
Example #7
0
def save_plot(portrait, points, name, out_dir="./"):
    fig = Figure()
    fig.set_dpi(50)
    fig.set_size_inches(12, 16)
    canvas = FigureCanvas(fig)
    ax = fig.add_subplot(111)
    ax.axis('off')
    ax.imshow(portrait)
    ax.scatter(points[:, 0], points[:, 1], s=50)
    out_path = out_dir + name + "_points.png"
    fig.savefig(out_path, bbox_inches='tight', pad_inches=0)
Example #8
0
 def on_paint_request(self, printer):
     from matplotlib.figure import Figure
     from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
     rect = printer.pageRect( QtGui.QPrinter.Inch )
     dpi = printer.resolution()
     fig = Figure( facecolor='#ffffff')
     fig.set_figsize_inches( (rect.width(),rect.height()) )
     fig.set_dpi( dpi )
     self._value.plot_on_figure( fig )
     canvas = FigureCanvas(fig)
     canvas.render( printer )
Example #9
0
 def print_(self, printer):
     from matplotlib.figure import Figure
     from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
     rect = printer.pageRect(QtPrintSupport.QPrinter.Inch)
     dpi = printer.resolution()
     fig = Figure(facecolor='#ffffff')
     fig.set_size_inches((rect.width(), rect.height()))
     fig.set_dpi(dpi)
     self.chart.plot_on_figure(fig)
     canvas = FigureCanvas(fig)
     canvas.render(printer)
Example #10
0
File: widgets.py Project: e-sr/KG
 def alg_results(cls, obs, algorithm):
     wavPath = obs.export_to_wav()
     # Canvas
     micSn = kg.MicSignal.from_Obs(obs)
     fig = Figure((15, 10))
     fig.set_dpi(110)
     results = algorithm.plot_alg(fig, micSn)
     mpl = {str(algorithm): {'canvas': FigureCanvas(fig),
                             'axHandle': [Bar(ax) for ax in fig.get_axes()],
                             'setTime':True,
                             'animate':True
                             }}
     obj =  cls(setup=True, wavPath=wavPath, t0=micSn.get_t0(), mpl=mpl)
     #obj.timer.start()
     return obj
Example #11
0
def spectro(file_name, offset):
    clip = get_clip(file_name, offset)
    y, sr = librosa.load(clip)
    S = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=128, fmax=8000)
    S_dB = librosa.power_to_db(S, ref=np.max)
    fig = Figure()
    fig.set_dpi(60)
    canvas = FigureCanvas(fig)
    ax = fig.add_subplot(1, 1, 1)
    lrd.specshow(S_dB, ax=ax, x_axis='time', y_axis='mel', sr=sr, fmax=8000)
    fig.colorbar(ax.collections[0], format='%+2.0f dB')
    out_f = io.BytesIO()
    canvas.print_png(out_f)
    response = Response(out_f.getvalue(), mimetype='image/png')
    return response
Example #12
0
def main():
    fig = Figure()
    canvas = FigureCanvas(fig)
    ax = fig.add_subplot(111)
    data = eval(open('data.py').read())
    colors = {
        'terrible': '#ff5555',
        'bad': '#aa0000',
        'moderate': '#ff00ff',
        'good': '#5555ff',
    }
    for f, T, key in data:
        ax.plot(float(f), float(T), marker='.', color=colors[key])
    ax.plot(*approx())
    fig.set_dpi(270)
    canvas.print_png('plot.png')
Example #13
0
def main(fn: str):
    infile = Path(f'{fn}')
    outfile = infile.parent.joinpath(infile.stem + '.pdf')
    outfilebw = infile.parent.joinpath(infile.stem + '.pdf.bw.txt')
    topo = json.loads(infile.read_text())
    nxg = nx_graph_from_topo(topo)
    pos = spring_layout(nxg, iterations=4000)
    fig = Figure()
    fig.set_dpi(300)
    ax = fig.add_subplot(111)
    ax.axis('off')
    labels = dict()
    for edge in nxg.edges:
        bw = nxg.get_edge_data(edge[0], edge[1], dict()).get('bw', None)
        bw = '' if bw is None else '%.1f mbps' % (bw, )
        labels[edge] = bw
    if len(set(labels.values())) > 1:
        draw_networkx_edge_labels(nxg,
                                  pos,
                                  ax=ax,
                                  edge_labels=labels,
                                  bbox=dict(facecolor='#FFFFFF88',
                                            edgecolor='none'),
                                  font_size='x-small')
    else:
        sbw = next(iter(set(labels.values())))
        outfilebw.write_text(sbw)
    draw_networkx_edges(nxg,
                        pos,
                        ax=ax,
                        edgelist=nxg.edges,
                        edge_color='black')
    draw_networkx_nodes(nxg,
                        pos,
                        ax=ax,
                        nodelist=topo[0],
                        node_color='lightgreen',
                        edgecolors="green")
    draw_networkx_nodes(nxg,
                        pos,
                        ax=ax,
                        nodelist=topo[1],
                        node_color='cyan',
                        edgecolors="darkcyan")
    draw_networkx_labels(nxg, pos, ax=ax, font_size='small')
    fig.savefig(str(outfile))
Example #14
0
    def __get_column_width(self):

        max_length = 0
        max_column_text = ""
        flag = self.prefs.get("legend_numbers", True)
        unit = self.prefs.get("legend_unit", False)
        for label, num in self.labels:
            if not flag:
                num = None
            if num is not None:
                column_length = len(str(label) + str(num)) + 1
            else:
                column_length = len(str(label)) + 1
            if column_length > max_length:
                max_length = column_length
                if flag:
                    if isinstance(num, six.integer_types):
                        numString = str(num)
                    else:
                        numString = "%.1f" % float(num)
                    max_column_text = "%s  %s" % (str(label), numString)
                    if unit:
                        max_column_text += "%"
                else:
                    max_column_text = "%s   " % str(label)

        figure = Figure()
        canvas = FigureCanvasAgg(figure)
        dpi = self.prefs["dpi"]
        figure.set_dpi(dpi)
        l_size, _ = self.__get_legend_text_size()
        self.text_size = pixelToPoint(l_size, dpi)
        text = Text(0.0, 0.0, text=max_column_text, size=self.text_size)
        text.set_figure(figure)
        bbox = text.get_window_extent(canvas.get_renderer())
        columnwidth = bbox.width + 6 * l_size
        # make sure the legend fit in the box
        self.column_width = (columnwidth
                             if columnwidth <= self.prefs["legend_width"] else
                             self.prefs["legend_width"] - 6 * l_size)
Example #15
0
    def __get_column_width(self):

        max_length = 0
        max_column_text = ''
        flag = self.prefs.get('legend_numbers', True)
        unit = self.prefs.get('legend_unit', False)
        for label, num in self.labels:
            if not flag: num = None
            if num is not None:
                column_length = len(str(label) + str(num)) + 1
            else:
                column_length = len(str(label)) + 1
            if column_length > max_length:
                max_length = column_length
                if flag:
                    if type(num) == types.IntType or type(
                            num) == types.LongType:
                        numString = str(num)
                    else:
                        numString = "%.1f" % float(num)
                    max_column_text = '%s  %s' % (str(label), numString)
                    if unit:
                        max_column_text += "%"
                else:
                    max_column_text = '%s   ' % str(label)

        figure = Figure()
        canvas = FigureCanvasAgg(figure)
        dpi = self.prefs['dpi']
        figure.set_dpi(dpi)
        l_size, _ = self.__get_legend_text_size()
        self.text_size = pixelToPoint(l_size, dpi)
        text = Text(0., 0., text=max_column_text, size=self.text_size)
        text.set_figure(figure)
        bbox = text.get_window_extent(canvas.get_renderer())
        columnwidth = bbox.width + 6 * l_size
        self.column_width = columnwidth if columnwidth <= self.prefs[
            'legend_width'] else self.prefs[
                'legend_width'] - 6 * l_size  #make sure the legend fit in the box
Example #16
0
    def print_result(self, print_context, render=True):
        figure = Figure(facecolor='white', figsize=(6, 4.5))
        figure.set_dpi(72)
        # Don't draw the frame, please.
        figure.set_frameon(False)

        canvas = _PlotResultCanvas(figure)

        axes = figure.add_subplot(111)
        self._replay(axes)

        width, height = figure.bbox.width, figure.bbox.height

        if render:
            cr = print_context.get_cairo_context()

            renderer = RendererCairo(figure.dpi)
            renderer.set_width_height(width, height)
            if hasattr(renderer, 'gc'):
                # matplotlib-0.99 and newer
                renderer.gc.ctx = cr
            else:
                # matplotlib-0.98

                # RendererCairo.new_gc() does a restore to get the context back
                # to its original state after changes
                cr.save()
                renderer.ctx = cr

            figure.draw(renderer)

            if not hasattr(renderer, 'gc'):
                # matplotlib-0.98
                # Reverse the save() we did before drawing
                cr.restore()

        return height
Example #17
0
    def print_result(self, print_context, render=True):
        figure = Figure(facecolor='white', figsize=(6,4.5))
        figure.set_dpi(72)
        # Don't draw the frame, please.
        figure.set_frameon(False)

        canvas = _PlotResultCanvas(figure)

        axes = figure.add_subplot(111)
        self._replay(axes)

        width, height = figure.bbox.width, figure.bbox.height

        if render:
            cr = print_context.get_cairo_context()

            renderer = RendererCairo(figure.dpi)
            renderer.set_width_height(width, height)
            if hasattr(renderer, 'gc'):
                # matplotlib-0.99 and newer
                renderer.gc.ctx = cr
            else:
                # matplotlib-0.98

                # RendererCairo.new_gc() does a restore to get the context back
                # to its original state after changes
                cr.save()
                renderer.ctx = cr

            figure.draw(renderer)

            if not hasattr(renderer, 'gc'):
                # matplotlib-0.98
                # Reverse the save() we did before drawing
                cr.restore()

        return height
Example #18
0
def listsize():
    """
    [DEPRECATED]
    Returns info about the inverted index
    """
    import StringIO
    import random

    from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
    from matplotlib.figure import Figure

    fig = Figure()
    fig.set_dpi = 100
    fig.set_size_inches(9, 12)
    fig.set_facecolor('w')
    ax = fig.add_subplot(211)
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.get_xaxis().tick_bottom()
    ax.get_yaxis().tick_left()
    ax.set_title('Inverted list sizes')
    y = index.listsizes(filter_small=False)
    x = range(len(y))
    ax.plot(x, y, '-')

    ax = fig.add_subplot(212)
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.get_xaxis().tick_bottom()
    ax.get_yaxis().tick_left()
    ax.set_xscale('log')
    ax.set_yscale('log')
    ax.set_title('Inverted list sizes (log scale)')
    y = index.listsizes(filter_small=False)
    x = range(len(y))
    ax.plot(x, y, '-')

    canvas = FigureCanvas(fig)
    png_output = StringIO.StringIO()
    canvas.print_png(png_output)
    response = make_response(png_output.getvalue())
    response.headers['Content-Type'] = 'image/png'
    return response
Example #19
0
def listsize():
    """
    [DEPRECATED]
    Returns info about the inverted index
    """
    import StringIO
    import random

    from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
    from matplotlib.figure import Figure

    fig = Figure()
    fig.set_dpi = 100
    fig.set_size_inches(9, 12)
    fig.set_facecolor('w')
    ax = fig.add_subplot(211)
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.get_xaxis().tick_bottom()
    ax.get_yaxis().tick_left()
    ax.set_title('Inverted list sizes')
    y = index.listsizes(filter_small=False)
    x = range(len(y))
    ax.plot(x, y, '-')

    ax = fig.add_subplot(212)
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.get_xaxis().tick_bottom()
    ax.get_yaxis().tick_left()
    ax.set_xscale('log')
    ax.set_yscale('log')
    ax.set_title('Inverted list sizes (log scale)')
    y = index.listsizes(filter_small=False)
    x = range(len(y))
    ax.plot(x, y, '-')

    canvas = FigureCanvas(fig)
    png_output = StringIO.StringIO()
    canvas.print_png(png_output)
    response = make_response(png_output.getvalue())
    response.headers['Content-Type'] = 'image/png'
    return response
class Canvas_sourceImage:
    def __init__(self, ui, W_matrix, N):

        # tab
        ui.list_of_tabs.append(QtWidgets.QWidget())
        ui.list_of_tabs[-1].setObjectName("tab_plotSourceImage")

        # gridlayout TAB SourceImag
        ui.list_grid_tabs.append(
            QtWidgets.QGridLayout(self.tab_plotSourceImage))
        ui.list_grid_tabs[-1].setObjectName("gridLayout_TabSourceImage")

        # Scroll Area Source Image
        ui.scrollArea_sourceImage = QtWidgets.QScrollArea(
            ui.tab_plotSourceImage)
        ui.scrollArea_sourceImage.setPalette(palette_scrollPlotProp)
        ui.scrollArea_sourceImage.setWidgetResizable(True)
        ui.scrollArea_sourceImage.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                                QtWidgets.QSizePolicy.Minimum)
        ui.scrollArea_sourceImage.setObjectName("scrollArea_sourceImage")

        # Scroll Area Options Source
        ui.scrollArea_sourceImageOpt = QtWidgets.QScrollArea(
            ui.tab_plotSourceImage)
        ui.scrollArea_sourceImageOpt.setWidgetResizable(True)
        ui.scrollArea_sourceImageOpt.setObjectName("scrollArea_sourceImageOpt")
        ui.scrollArea_sourceImageOpt.setPalette(palette_scrollPlotProp)

        ui.scrollAreaWidgetContents_sourceImageOpt = QtWidgets.QWidget()
        ui.scrollAreaWidgetContents_sourceImageOpt.setObjectName(
            "scrollAreaWidgetContents_sourceImageOpt")
        ui.scrollArea_sourceImageOpt.setWidget(
            ui.scrollAreaWidgetContents_sourceImageOpt)

        ui.gridLayout_sourceImageOpt = QtWidgets.QGridLayout(
            ui.scrollAreaWidgetContents_sourceImageOpt)
        ui.gridLayout_sourceImageOpt.setObjectName("gridLayout_sourceImageOpt")

        ui.gridLayout_TabSourceImage.addWidget(ui.scrollArea_sourceImage, 1, 0,
                                               1, 1)
        ui.gridLayout_TabSourceImage.addWidget(ui.scrollArea_sourceImageOpt, 3,
                                               0, 1, 1)

        #=======================================================================
        # Parameters
        #=======================================================================
        # User interface
        self.ui = ui

        # parent
        self.parent = ui.scrollArea_sourceImage

        # parent optioncs
        self.parentOptions = ui.scrollArea_sourceImageOpt

        # grid parent options
        self.gridOptions = ui.gridLayout_sourceImageOpt
        #_______________________________________________________________________

        self.build_fig(W_matrix, N)

    def build_fig(self, W_matrix, N):

        #=======================================================================
        # Create the mpl Figure and FigCanvas objects.
        #=======================================================================
        self.dpi = 100
        self.fig = Figure((5.0, 4.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)

        # 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.
        #
        self.axes = self.fig.add_subplot(111)
        #_______________________________________________________________________

        #=======================================================================
        # Plotting 2D figure and configuring
        #=======================================================================
        #
        # creating image source
        image_source = zeros((N, N))
        for i in range(0, N):
            for j in range(0, N):
                image_source[i, j] = W_matrix[i, j, i, j].real

        # PLOT
        self.im = self.axes.pcolormesh(image_source)
        self.cbar = self.fig.colorbar(self.im)

        # font size
        self.fsize = 12

        # x,y Labels
        self.axes.set_xlabel("x (m)", fontsize=self.fsize)
        self.axes.set_ylabel("y (m)", fontsize=self.fsize)
        #_______________________________________________________________________

        #=======================================================================
        # Tool bar
        #=======================================================================

        # Bind the 'pick' event for clicking on one of the bars
        self.canvas.mpl_connect(
            'pick_event', self.ui.on_pick
        )  #self.canvas.mpl_connect("scroll_event", ui.scrolling)

        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.parent)

        #ui.gridLayout_TabSourceImage.addWidget(self.mpl_toolbar, 2, 0, 1, 3)
        self.ui.gridLayout_TabSourceImage.addWidget(self.mpl_toolbar, 2, 0, 1,
                                                    3)
        #_______________________________________________________________________

        #=======================================================================
        # Canvas in Scroll Area
        #=======================================================================
        self.label_opt = QtWidgets.QLabel()
        self.label_opt.setObjectName("label_opt")
        self.label_opt.setText("Plot Options:")
        #self.gridOptions.addWidget(self.label_opt, 3, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        #self.canvas.draw()
        #self.canvas.setParent(parent)
        self.canvas.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                  QtWidgets.QSizePolicy.Minimum)

        # Container for VBOX
        self.containerGraph = QWidget(self.parent)
        self.containerGraph.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                          QtWidgets.QSizePolicy.Minimum)

        self.containerGraph.setMinimumWidth(self.canvas.width())
        self.containerGraph.setMinimumHeight(self.canvas.height())

        self.containerGraph.setMaximumWidth(self.canvas.width() + 5)
        self.containerGraph.setMaximumHeight(self.canvas.height() + 5)

        # VBOX for canvas
        self.vbox = QVBoxLayout(self.containerGraph)
        #self.vbox.setGeometry(QRect(0, 0, self.canvas.width(), self.canvas.height()))
        self.vbox.addWidget(self.canvas)

        self.parent.setWidget(self.containerGraph)
        #_______________________________________________________________________

        #=======================================================================
        # Figure Options
        #=======================================================================

        # Options
        """
        self.label_opt = QtWidgets.QLabel(self.parentOptions)
        self.label_opt.setObjectName("label_opt")
        self.label_opt.setText("Plot Options:")
        self.gridOptions.addWidget(self.label_opt, 3, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)
        """

        # label title
        self.label_title = QtWidgets.QLabel(self.parentOptions)
        self.label_title.setObjectName("label_title")
        self.label_title.setText("Title")
        self.gridOptions.addWidget(self.label_title,
                                   4,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit title label
        self.lineEdit_title = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_title.setObjectName("lineEdit_title")
        self.lineEdit_title.textChanged.connect(self.change_title)
        self.gridOptions.addWidget(self.lineEdit_title,
                                   4,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.change_title()
        self.lineEdit_title.setText("Source Image")

        # label x
        self.label_x = QtWidgets.QLabel(self.parentOptions)
        self.label_x.setObjectName("label_x")
        self.label_x.setText("Label x-axis")
        self.gridOptions.addWidget(self.label_x,
                                   6,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit x label
        self.lineEdit_xLabel = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_xLabel.setObjectName("lineEdit_xlabel")
        self.lineEdit_xLabel.textChanged.connect(self.change_labelx)
        self.gridOptions.addWidget(self.lineEdit_xLabel,
                                   6,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.change_labelx()
        self.lineEdit_xLabel.setText("x")

        # label y
        self.label_y = QtWidgets.QLabel(self.parentOptions)
        self.label_y.setObjectName("label_y")
        self.label_y.setText("Label y-axis")
        self.gridOptions.addWidget(self.label_y,
                                   8,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit y label
        self.lineEdit_yLabel = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_yLabel.setObjectName("lineEdit_ylabel")
        self.lineEdit_yLabel.textChanged.connect(self.change_labely)
        self.gridOptions.addWidget(self.lineEdit_yLabel,
                                   8,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.change_labely()
        self.lineEdit_yLabel.setText("y")

        # label xlim
        self.label_xlim = QtWidgets.QLabel(self.parentOptions)
        self.label_xlim.setObjectName("label_xlim")
        self.label_xlim.setText("xlim")
        self.gridOptions.addWidget(self.label_xlim,
                                   10,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit xlim
        self.lineEdit_xlim = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_xlim.setObjectName("lineEdit_ylabel")
        self.lineEdit_xlim.textChanged.connect(self.change_xlim)
        self.gridOptions.addWidget(self.lineEdit_xlim,
                                   10,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_xlim.setText("(_,_)")
        self.change_xlim()

        # label ylim
        self.label_ylim = QtWidgets.QLabel(self.parentOptions)
        self.label_ylim.setObjectName("label_ylim")
        self.label_ylim.setText("ylim")
        self.gridOptions.addWidget(self.label_ylim,
                                   12,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit ylim
        self.lineEdit_ylim = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_ylim.setObjectName("lineEdit_ylabel")
        self.lineEdit_ylim.textChanged.connect(self.change_ylim)
        self.gridOptions.addWidget(self.lineEdit_ylim,
                                   12,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_ylim.setText("(_,_)")
        self.change_ylim()

        # label cmap
        self.label_cmap = QtWidgets.QLabel(self.parentOptions)
        self.label_cmap.setObjectName("label_cmap")
        self.label_cmap.setText("Color Map")
        self.gridOptions.addWidget(self.label_cmap,
                                   18,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit cmap
        self.lineEdit_cmap = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_cmap.setObjectName("lineEdit_cmap")
        self.lineEdit_cmap.textChanged.connect(self.change_cmap)
        self.gridOptions.addWidget(self.lineEdit_cmap,
                                   18,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_cmap.setText("hot")
        self.change_cmap()

        # label Font Size
        self.label_fsize = QtWidgets.QLabel(self.parentOptions)
        self.label_fsize.setObjectName("label_fsize")
        self.label_fsize.setText("Font Size")
        self.gridOptions.addWidget(self.label_fsize,
                                   20,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit font size
        self.lineEdit_fsize = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_fsize.setObjectName("label_fsize")
        self.lineEdit_fsize.textChanged.connect(self.change_fsize)
        self.gridOptions.addWidget(self.lineEdit_fsize,
                                   20,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_fsize.setText(str(self.fsize))
        self.change_fsize()

        # label DPI
        self.label_dpi = QtWidgets.QLabel(self.parentOptions)
        self.label_dpi.setObjectName("label_dpi")
        self.label_dpi.setText("dpi (100-500)")
        self.gridOptions.addWidget(self.label_dpi,
                                   22,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit DPI
        self.lineEdit_dpi = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_dpi.setObjectName("label_dpi")
        self.lineEdit_dpi.textChanged.connect(self.change_dpi)
        self.gridOptions.addWidget(self.lineEdit_dpi,
                                   22,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_dpi.setText(str(self.dpi))
        self.change_fsize()

    def update_draw(self):
        self.canvas.draw()
        self.canvas.updateGeometry()

    def change_dpi(self):
        try:
            new = int(self.lineEdit_dpi.text())
            if new >= 100 and new <= 500:
                self.dpi = new
                self.fig.set_dpi(new)
                self.update_draw()
        except:
            pass

    def change_fsize(self):
        try:
            self.fsize = int(self.lineEdit_fsize.text())
            self.change_title()
            self.change_labelx()
            self.change_labely()
            self.update_draw()
            print(self.fsize)

        except Exception as error:
            pass  #self.ui.update_outputText(error)

    def change_cmap(self):
        try:
            self.im.set_cmap(self.lineEdit_cmap.text())
            self.canvas.draw()
        except Exception as error:
            pass
            #self.ui.update_outputText(error)

    def change_xlim(self):
        try:
            temp_txt = self.lineEdit_xlim.text()
            Ntxt = len(temp_txt)
            numList = []
            if temp_txt[0] == "(" and temp_txt[-1] == ")":
                actual = ""
                for i in range(1, Ntxt - 1):
                    if temp_txt[i] == ",":
                        numList.append(float(actual))
                        actual = ""
                    elif i == Ntxt - 2:
                        actual += temp_txt[i]
                        numList.append(float(actual))
                    else:
                        actual += temp_txt[i]
            self.axes.set_xlim(numList[0], numList[1])
        except Exception as error:
            pass
            #self.ui.update_outputText(error)

    def change_ylim(self):
        try:
            temp_txt = self.lineEdit_ylim.text()
            Ntxt = len(temp_txt)
            numList = []
            if temp_txt[0] == "(" and temp_txt[-1] == ")":
                actual = ""
                for i in range(1, Ntxt - 1):
                    if temp_txt[i] == ",":
                        numList.append(float(actual))
                        actual = ""
                    elif i == Ntxt - 2:
                        actual += temp_txt[i]
                        numList.append(float(actual))
                    else:
                        actual += temp_txt[i]
            self.axes.set_ylim(numList[0], numList[1])
            self.canvas.draw()
        except Exception as error:
            pass
            #self.ui.update_outputText(error)

    def change_title(self):
        try:
            self.axes.set_title(self.lineEdit_title.text(),
                                fontsize=self.fsize)
            self.canvas.draw()
        except:
            pass

    def change_labelx(self):
        if self.lineEdit_xLabel.text() == "":
            self.axes.set_xlabel("")
        else:
            try:
                self.axes.set_xlabel(self.lineEdit_xLabel.text(),
                                     fontsize=self.fsize)
                self.canvas.draw()
            except:
                pass
                #self.ui.update_outputText("Unable to update x-label.")

    def change_labely(self):
        if self.lineEdit_yLabel.text() == "":
            self.axes.set_ylabel("")
        else:
            try:
                self.axes.set_ylabel(self.lineEdit_yLabel.text(),
                                     fontsize=self.fsize)
                self.canvas.draw()
            except:
                pass
Example #21
0
class Canvas_propSDC2D:
    def __init__(self, ui, W_matrix, N):

        # Scroll Area Propagation SDC
        ui.scrollArea_propSDC = QtWidgets.QScrollArea(ui.tab_plotPropSDC2D)
        ui.scrollArea_propSDC.setPalette(palette_scrollPlotProp)
        ui.scrollArea_propSDC.setWidgetResizable(True)
        ui.scrollArea_propSDC.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                            QtWidgets.QSizePolicy.Minimum)
        ui.scrollArea_propSDC.setObjectName("scrollArea_propSDC")

        # Scroll Area Options prop
        ui.scrollArea_propSDCOpt = QtWidgets.QScrollArea(ui.tab_plotPropSDC2D)
        ui.scrollArea_propSDCOpt.setWidgetResizable(True)
        ui.scrollArea_propSDCOpt.setObjectName("scrollArea_propImageOpt")
        ui.scrollArea_propSDCOpt.setPalette(palette_scrollPlotProp)

        ui.scrollAreaWidgetContents_propSDCOpt = QtWidgets.QWidget()
        ui.scrollAreaWidgetContents_propSDCOpt.setObjectName(
            "scrollAreaWidgetContents_propSDCOpt")
        ui.scrollArea_propSDCOpt.setWidget(
            ui.scrollAreaWidgetContents_propSDCOpt)

        ui.gridLayout_propSDCOpt = QtWidgets.QGridLayout(
            ui.scrollAreaWidgetContents_propSDCOpt)
        ui.gridLayout_propSDCOpt.setObjectName("gridLayout_propSDCOpt")

        ui.gridLayout_TabPropSDC2D.addWidget(ui.scrollArea_propSDC, 3, 0, 1, 1)
        ui.gridLayout_TabPropSDC2D.addWidget(ui.scrollArea_propSDCOpt, 10, 0,
                                             1, 1)

        # Scroll Area Propagation SDC Phase
        ui.scrollArea_propSDC_phase = QtWidgets.QScrollArea(
            ui.tab_plotPropSDC2D)
        ui.scrollArea_propSDC_phase.setPalette(palette_scrollPlotProp)
        ui.scrollArea_propSDC_phase.setWidgetResizable(True)
        ui.scrollArea_propSDC_phase.setSizePolicy(
            QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        ui.scrollArea_propSDC_phase.setObjectName("scrollArea_propSDC_phase")

        # Scroll Area Options Propagation SDC Phase
        ui.scrollArea_propSDCOpt_phase = QtWidgets.QScrollArea(
            ui.tab_plotPropSDC2D)
        ui.scrollArea_propSDCOpt_phase.setWidgetResizable(True)
        ui.scrollArea_propSDCOpt_phase.setObjectName(
            "scrollArea_propImageOpt_phase")
        ui.scrollArea_propSDCOpt_phase.setPalette(palette_scrollPlotProp)

        ui.scrollAreaWidgetContents_propSDCOpt_phase = QtWidgets.QWidget()
        ui.scrollAreaWidgetContents_propSDCOpt_phase.setObjectName(
            "scrollAreaWidgetContents_propSDCOpt_phase")
        ui.scrollArea_propSDCOpt_phase.setWidget(
            ui.scrollAreaWidgetContents_propSDCOpt_phase)

        ui.gridLayout_propSDCOpt_phase = QtWidgets.QGridLayout(
            ui.scrollAreaWidgetContents_propSDCOpt_phase)
        ui.gridLayout_propSDCOpt_phase.setObjectName(
            "gridLayout_propSDCOpt_phase")

        ui.gridLayout_TabPropSDC2D.addWidget(ui.scrollArea_propSDC_phase, 3, 1,
                                             1, 1)
        ui.gridLayout_TabPropSDC2D.addWidget(ui.scrollArea_propSDCOpt_phase,
                                             10, 1, 1, 1)
        #_______________________________________________________________________

        #=======================================================================
        # Parameters
        #=======================================================================
        # N
        self.N = N

        # W matrix
        self.W_matrix = W_matrix

        # User interface
        self.ui = ui

        # parent
        self.parent = ui.scrollArea_propSDC
        self.parent_phase = ui.scrollArea_propSDC_phase

        # parent optioncs
        self.parentOptions = ui.scrollArea_propSDCOpt
        self.parentOptions_phase = ui.scrollArea_propSDCOpt_phase

        # grid parent options
        self.gridOptions = ui.gridLayout_propSDCOpt
        self.gridOptions_phase = ui.gridLayout_propSDCOpt_phase

        # first plot
        self.first_plot = False
        #_______________________________________________________________________

        # Initial points (middle)
        self.P1x = int(N / 2)
        self.P1y = int(N / 2)

        self.build_fig()

    def build_fig(self):

        #=======================================================================
        # Create the mpl Figure and FigCanvas objects.
        #=======================================================================
        # magnitude
        self.dpi = 100
        self.fig = Figure((5.0, 4.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)

        # phase
        self.dpi_phase = 100
        self.fig_phase = Figure((5.0, 4.0), dpi=self.dpi_phase)
        self.canvas_phase = FigureCanvas(self.fig_phase)

        # axes
        self.axes = self.fig.add_subplot(111)
        self.axes_phase = self.fig_phase.add_subplot(111)
        #_______________________________________________________________________

        #=======================================================================
        # Plotting 2D figure and configuring
        #=======================================================================

        # creating image prop
        self.propSDC_mag = sqrt(self.W_matrix[self.P1x, self.P1y].real**2 +
                                self.W_matrix[self.P1x, self.P1y].imag**2)
        self.propSDC_phase = angle(self.W_matrix[self.P1y, self.P1y])

        # PLOT magnitude
        self.im = self.axes.imshow(self.propSDC_mag)
        self.cbar = self.fig.colorbar(self.im)

        # PLOT phase
        self.im_phase = self.axes_phase.imshow(self.propSDC_phase)
        self.cbar_phase = self.fig_phase.colorbar(self.im_phase)

        # font size
        self.fsize = 12
        self.fsize_phase = 12

        # x,y Labels
        self.axes.set_xlabel("x (m)", fontsize=self.fsize)
        self.axes.set_ylabel("y (m)", fontsize=self.fsize)
        #_______________________________________________________________________

        #=======================================================================
        # Tool bar
        #=======================================================================

        # Bind the 'pick' event for clicking on one of the bars
        self.canvas.mpl_connect(
            'pick_event', self.ui.on_pick
        )  #self.canvas.mpl_connect("scroll_event", ui.scrolling)
        # Bind the 'pick' event for clicking on one of the bars
        self.canvas_phase.mpl_connect(
            'pick_event', self.ui.on_pick
        )  #self.canvas.mpl_connect("scroll_event", ui.scrolling)

        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.parent)
        self.mpl_toolbar_phase = NavigationToolbar(self.canvas_phase,
                                                   self.parent_phase)

        #ui.gridLayout_TabPropImage.addWidget(self.mpl_toolbar, 2, 0, 1, 3)
        self.ui.gridLayout_TabPropSDC2D.addWidget(
            self.mpl_toolbar, 8, 0, 1, 3, alignment=QtCore.Qt.AlignLeft)
        self.ui.gridLayout_TabPropSDC2D.addWidget(
            self.mpl_toolbar_phase, 8, 1, 1, 3, alignment=QtCore.Qt.AlignLeft)

        #_______________________________________________________________________

        #=======================================================================
        # Canvas in Scroll Area - magnitude
        #=======================================================================

        #self.canvas.draw()
        #self.canvas.setParent(parent)
        self.canvas.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                  QtWidgets.QSizePolicy.Minimum)

        # Container for VBOX
        self.containerGraph = QWidget(self.parent)
        self.containerGraph.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                          QtWidgets.QSizePolicy.Minimum)

        self.containerGraph.setMinimumWidth(self.canvas.width())
        self.containerGraph.setMinimumHeight(self.canvas.height())

        self.containerGraph.setMaximumWidth(self.canvas.width() + 5)
        self.containerGraph.setMaximumHeight(self.canvas.height() + 5)

        # VBOX for canvas
        self.vbox = QVBoxLayout(self.containerGraph)
        #self.vbox.setGeometry(QRect(0, 0, self.canvas.width(), self.canvas.height()))
        self.vbox.addWidget(self.canvas)

        self.parent.setWidget(self.containerGraph)

        #_______________________________________________________________________

        #=======================================================================
        # Canvas in Scroll Area - phase
        #=======================================================================
        self.canvas_phase.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                        QtWidgets.QSizePolicy.Minimum)

        # Container for VBOX
        self.containerGraph_phase = QWidget(self.parent_phase)
        self.containerGraph_phase.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                                QtWidgets.QSizePolicy.Minimum)

        self.containerGraph_phase.setMinimumWidth(self.canvas_phase.width())
        self.containerGraph_phase.setMinimumHeight(self.canvas_phase.height())

        self.containerGraph_phase.setMaximumWidth(self.canvas_phase.width() +
                                                  5)
        self.containerGraph_phase.setMaximumHeight(self.canvas_phase.height() +
                                                   5)

        # VBOX for canvas
        self.vbox_phase = QVBoxLayout(self.containerGraph_phase)
        #self.vbox.setGeometry(QRect(0, 0, self.canvas.width(), self.canvas.height()))
        self.vbox_phase.addWidget(self.canvas_phase)

        self.parent_phase.setWidget(self.containerGraph_phase)
        #_______________________________________________________________________

        if not self.first_plot:
            self.figure_options()
            self.figure_options_phase()
            self.first_plot = True

    def figure_options(self):

        # label Point P1x
        self.label_P1x = QtWidgets.QLabel(self.parentOptions)
        self.label_P1x.setObjectName("label_P1x")
        self.label_P1x.setText("Point ")
        self.gridOptions.addWidget(self.label_P1x,
                                   2,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit Point P1x
        self.lineEdit_P1x = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_P1x.setObjectName("lineEdit_P1x")
        self.gridOptions.addWidget(self.lineEdit_P1x,
                                   2,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_P1x.setText(str(int(self.N / 2)))
        self.lineEdit_P1x.textChanged.connect(self.change_P1x)

        # label Point P1y
        self.label_P1y = QtWidgets.QLabel(self.parentOptions)
        self.label_P1y.setObjectName("label_P1y")
        self.label_P1y.setText('$Point$')
        self.gridOptions.addWidget(self.label_P1y,
                                   4,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit Point P1x
        self.lineEdit_P1y = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_P1y.setObjectName("lineEdit_P1y")
        self.gridOptions.addWidget(self.lineEdit_P1y,
                                   4,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_P1y.setText(str(int(self.N / 2)))
        self.lineEdit_P1y.textChanged.connect(self.change_P1y)

        # label title
        self.label_title = QtWidgets.QLabel(self.parentOptions)
        self.label_title.setObjectName("label_title")
        self.label_title.setText("Title")
        self.gridOptions.addWidget(self.label_title,
                                   6,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit title label
        self.lineEdit_title = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_title.setObjectName("lineEdit_title")
        self.lineEdit_title.textChanged.connect(self.change_title)
        self.gridOptions.addWidget(self.lineEdit_title,
                                   6,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.change_title()
        self.lineEdit_title.setText("Propagation SDC")

        # label x
        self.label_x = QtWidgets.QLabel(self.parentOptions)
        self.label_x.setObjectName("label_x")
        self.label_x.setText("Label x-axis")
        self.gridOptions.addWidget(self.label_x,
                                   8,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit x label
        self.lineEdit_xLabel = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_xLabel.setObjectName("lineEdit_xlabel")
        self.lineEdit_xLabel.textChanged.connect(self.change_labelx)
        self.gridOptions.addWidget(self.lineEdit_xLabel,
                                   8,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.change_labelx()
        self.lineEdit_xLabel.setText("x")

        # label y
        self.label_y = QtWidgets.QLabel(self.parentOptions)
        self.label_y.setObjectName("label_y")
        self.label_y.setText("Label y-axis")
        self.gridOptions.addWidget(self.label_y,
                                   10,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit y label
        self.lineEdit_yLabel = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_yLabel.setObjectName("lineEdit_ylabel")
        self.lineEdit_yLabel.textChanged.connect(self.change_labely)
        self.gridOptions.addWidget(self.lineEdit_yLabel,
                                   10,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.change_labely()
        self.lineEdit_yLabel.setText("y")

        # label xlim
        self.label_xlim = QtWidgets.QLabel(self.parentOptions)
        self.label_xlim.setObjectName("label_xlim")
        self.label_xlim.setText("xlim")
        self.gridOptions.addWidget(self.label_xlim,
                                   12,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit xlim
        self.lineEdit_xlim = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_xlim.setObjectName("lineEdit_ylabel")
        self.lineEdit_xlim.textChanged.connect(self.change_xlim)
        self.gridOptions.addWidget(self.lineEdit_xlim,
                                   12,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_xlim.setText("(_,_)")
        self.change_xlim()

        # label ylim
        self.label_ylim = QtWidgets.QLabel(self.parentOptions)
        self.label_ylim.setObjectName("label_ylim")
        self.label_ylim.setText("ylim")
        self.gridOptions.addWidget(self.label_ylim,
                                   14,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit ylim
        self.lineEdit_ylim = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_ylim.setObjectName("lineEdit_ylabel")
        self.lineEdit_ylim.textChanged.connect(self.change_ylim)
        self.gridOptions.addWidget(self.lineEdit_ylim,
                                   14,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_ylim.setText("(_,_)")
        self.change_ylim()

        # label cmap
        self.label_cmap = QtWidgets.QLabel(self.parentOptions)
        self.label_cmap.setObjectName("label_cmap")
        self.label_cmap.setText("Color Map")
        self.gridOptions.addWidget(self.label_cmap,
                                   20,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit cmap
        self.lineEdit_cmap = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_cmap.setObjectName("lineEdit_cmap")
        self.lineEdit_cmap.textChanged.connect(self.change_cmap)
        self.gridOptions.addWidget(self.lineEdit_cmap,
                                   20,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_cmap.setText("hot")
        self.change_cmap()

        # label Font Size
        self.label_fsize = QtWidgets.QLabel(self.parentOptions)
        self.label_fsize.setObjectName("label_fsize")
        self.label_fsize.setText("Font Size")
        self.gridOptions.addWidget(self.label_fsize,
                                   22,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit font size
        self.lineEdit_fsize = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_fsize.setObjectName("label_fsize")
        self.lineEdit_fsize.textChanged.connect(self.change_fsize)
        self.gridOptions.addWidget(self.lineEdit_fsize,
                                   22,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_fsize.setText(str(self.fsize))
        self.change_fsize()

        # label DPI
        self.label_dpi = QtWidgets.QLabel(self.parentOptions)
        self.label_dpi.setObjectName("label_dpi")
        self.label_dpi.setText("dpi (100-500)")
        self.gridOptions.addWidget(self.label_dpi,
                                   24,
                                   0,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)

        # line edit DPI
        self.lineEdit_dpi = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_dpi.setObjectName("label_dpi")
        self.lineEdit_dpi.textChanged.connect(self.change_dpi)
        self.gridOptions.addWidget(self.lineEdit_dpi,
                                   24,
                                   1,
                                   1,
                                   1,
                                   alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_dpi.setText(str(self.dpi))
        self.change_fsize()
        #_______________________________________________________________________

    def figure_options_phase(self):
        try:
            # label title_phase
            self.label_title_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_title_phase.setObjectName("label_title")
            self.label_title_phase.setText("Title")
            self.gridOptions_phase.addWidget(self.label_title_phase,
                                             6,
                                             0,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)

            # line edit title label_phase
            self.lineEdit_title_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_title_phase.setObjectName("lineEdit_title_phase")
            self.lineEdit_title_phase.textChanged.connect(
                self.change_title_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_title_phase,
                                             6,
                                             1,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_title_phase.setText("Prop SDC Phase")
            self.change_title_phase()

            # label x_phase
            self.label_x_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_x_phase.setObjectName("label_xv")
            self.label_x_phase.setText("Label x-axis")
            self.gridOptions_phase.addWidget(self.label_x_phase,
                                             8,
                                             0,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)

            # line edit x label_phase_phase
            self.lineEdit_xLabel_phase = QtWidgets.QLineEdit(
                self.parentOptions)
            self.lineEdit_xLabel_phase.setObjectName("lineEdit_xlabel_phase")
            self.lineEdit_xLabel_phase.textChanged.connect(
                self.change_labelx_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_xLabel_phase,
                                             8,
                                             1,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)
            self.change_labelx_phase()
            self.lineEdit_xLabel_phase.setText("x")

            # label y_phase
            self.label_y_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_y_phase.setObjectName("label_y_phase")
            self.label_y_phase.setText("Label y-axis")
            self.gridOptions_phase.addWidget(self.label_y_phase,
                                             10,
                                             0,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)

            # line edit y label_phase
            self.lineEdit_yLabel_phase = QtWidgets.QLineEdit(
                self.parentOptions)
            self.lineEdit_yLabel_phase.setObjectName("lineEdit_ylabel_phase")
            self.lineEdit_yLabel_phase.textChanged.connect(
                self.change_labely_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_yLabel_phase,
                                             10,
                                             1,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)
            self.change_labely_phase()
            self.lineEdit_yLabel_phase.setText("y")

            # label xlim_phase
            self.label_xlim_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_xlim_phase.setObjectName("label_xlim_phase")
            self.label_xlim_phase.setText("xlim")
            self.gridOptions_phase.addWidget(self.label_xlim_phase,
                                             12,
                                             0,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)

            # line edit xlim_phase
            self.lineEdit_xlim_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_xlim_phase.setObjectName("lineEdit_ylabel_phase")
            self.lineEdit_xlim_phase.textChanged.connect(
                self.change_xlim_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_xlim_phase,
                                             12,
                                             1,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_xlim_phase.setText("(_,_)")
            self.change_xlim_phase()

            # label ylim_phase
            self.label_ylim_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_ylim_phase.setObjectName("label_ylim_phase")
            self.label_ylim_phase.setText("ylim")
            self.gridOptions_phase.addWidget(self.label_ylim_phase,
                                             14,
                                             0,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)

            # line edit ylim_phase
            self.lineEdit_ylim_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_ylim_phase.setObjectName("lineEdit_ylabel_phase")
            self.lineEdit_ylim_phase.textChanged.connect(
                self.change_ylim_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_ylim_phase,
                                             14,
                                             1,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_ylim_phase.setText("(_,_)")
            self.change_ylim_phase()

            # label cmap_phase
            self.label_cmap_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_cmap_phase.setObjectName("label_cmap_phase")
            self.label_cmap_phase.setText("Color Map")
            self.gridOptions_phase.addWidget(self.label_cmap_phase,
                                             20,
                                             0,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)

            # line edit cmap_phase
            self.lineEdit_cmap_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_cmap_phase.setObjectName("lineEdit_cmap_phase")
            self.lineEdit_cmap_phase.textChanged.connect(
                self.change_cmap_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_cmap_phase,
                                             20,
                                             1,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_cmap_phase.setText("hot")
            self.change_cmap_phase()

            # label Font Size_phase
            self.label_fsize_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_fsize_phase.setObjectName("label_fsize")
            self.label_fsize_phase.setText("Font Size")
            self.gridOptions_phase.addWidget(self.label_fsize_phase,
                                             22,
                                             0,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)

            # line edit font size_phase
            self.lineEdit_fsize_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_fsize_phase.setObjectName("label_fsize_phase")
            self.lineEdit_fsize_phase.textChanged.connect(self.change_fsize)
            self.gridOptions_phase.addWidget(self.lineEdit_fsize_phase,
                                             22,
                                             1,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_fsize_phase.setText(str(self.fsize))
            self.change_fsize_phase()

            # label DPI_phase
            self.label_dpi_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_dpi_phase.setObjectName("label_dpi_phase")
            self.label_dpi_phase.setText("dpi (100-500)")
            self.gridOptions_phase.addWidget(self.label_dpi_phase,
                                             24,
                                             0,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)

            # line edit DPI_phase
            self.lineEdit_dpi_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_dpi_phase.setObjectName("label_dpi_phase")
            self.lineEdit_dpi_phase.textChanged.connect(self.change_dpi_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_dpi_phase,
                                             24,
                                             1,
                                             1,
                                             1,
                                             alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_dpi_phase.setText(str(self.dpi_phase))
            self.change_fsize_phase()
            #_______________________________________________________________________

        except Exception as error:
            self.ui.update_outputText(str(error))

    def change_P1x(self):
        try:
            temp = self.lineEdit_P1x.text()
            if temp != "":
                new = int(temp)
                if new >= 0 and new < self.N:
                    self.P1x = new
                    self.update_pcolor()
                    self.update_draw()
        except Except as error:
            self.ui.update_outputText(str(error))

    def change_P1y(self):
        try:
            temp = self.lineEdit_P1y.text()
            if temp != "":
                new = int(temp)
                if new >= 0 and new < self.N:
                    self.P1y = new
                    self.update_pcolor()
                    self.update_draw()
        except Except as error:
            self.ui.update_outputText(str(error))

    def update_pcolor(self):
        try:
            # creating image prop
            self.propSDC_mag = sqrt(self.W_matrix[self.P1x, self.P1y].real**2 +
                                    self.W_matrix[self.P1x, self.P1y].imag**2)
            self.propSDC_phase = angle(self.W_matrix[self.P1y, self.P1y])

            self.im.set_array(self.propSDC_mag)
            self.im_phase.set_array(self.propSDC_phase)

        except Exception as error:
            self.ui.update_outputText(str(error))

    def update_draw(self):
        self.canvas.draw()
        self.canvas.updateGeometry()
        self.canvas_phase.draw()
        self.canvas_phase.updateGeometry()

    #===========================================================================
    # Magnitude
    #===========================================================================
    def change_dpi(self):
        try:
            new = int(self.lineEdit_dpi.text())
            if new >= 100 and new <= 500:
                self.dpi = new
                self.fig.set_dpi(new)
                self.update_draw()
        except:
            pass

    def change_fsize(self):
        try:
            self.fsize = int(self.lineEdit_fsize.text())
            self.change_title()
            self.change_labelx()
            self.change_labely()
            self.update_draw()
            print(self.fsize)

        except Exception as error:
            pass  #self.ui.update_outputText(error)

    def change_cmap(self):
        try:
            self.im.set_cmap(self.lineEdit_cmap.text())
            self.canvas.draw()
        except Exception as error:
            pass
            #self.ui.update_outputText(error)

    def change_xlim(self):
        try:
            temp_txt = self.lineEdit_xlim.text()
            Ntxt = len(temp_txt)
            numList = []
            if temp_txt[0] == "(" and temp_txt[-1] == ")":
                actual = ""
                for i in range(1, Ntxt - 1):
                    if temp_txt[i] == ",":
                        numList.append(float(actual))
                        actual = ""
                    elif i == Ntxt - 2:
                        actual += temp_txt[i]
                        numList.append(float(actual))
                    else:
                        actual += temp_txt[i]
            self.axes.set_xlim(numList[0], numList[1])
        except Exception as error:
            pass
            #self.ui.update_outputText(error)

    def change_ylim(self):
        try:
            temp_txt = self.lineEdit_ylim.text()
            Ntxt = len(temp_txt)
            numList = []
            if temp_txt[0] == "(" and temp_txt[-1] == ")":
                actual = ""
                for i in range(1, Ntxt - 1):
                    if temp_txt[i] == ",":
                        numList.append(float(actual))
                        actual = ""
                    elif i == Ntxt - 2:
                        actual += temp_txt[i]
                        numList.append(float(actual))
                    else:
                        actual += temp_txt[i]
            self.axes.set_ylim(numList[0], numList[1])
            self.canvas.draw()
        except Exception as error:
            pass
            #self.ui.update_outputText(error)

    def change_title(self):
        try:
            self.axes.set_title(self.lineEdit_title.text(),
                                fontsize=self.fsize)
            self.canvas.draw()
        except:
            pass

    def change_labelx(self):
        if self.lineEdit_xLabel.text() == "":
            self.axes.set_xlabel("")
        else:
            try:
                self.axes.set_xlabel(self.lineEdit_xLabel.text(),
                                     fontsize=self.fsize)
                self.canvas.draw()
            except Exception as error:

                self.ui.update_outputText(str(error))

    def change_labely(self):
        if self.lineEdit_yLabel.text() == "":
            self.axes.set_ylabel("")
        else:
            try:
                self.axes.set_ylabel(self.lineEdit_yLabel.text(),
                                     fontsize=self.fsize)
                self.canvas.draw()
            except:
                pass
                #self.ui.update_outputText("Unable to update y-label.")

    #___________________________________________________________________________

    #===========================================================================
    # Phase
    #===========================================================================
    try:

        def change_dpi_phase(self):
            try:
                new = int(self.lineEdit_dpi_phase.text())
                if new >= 100 and new <= 500:
                    self.dpi_phase = new
                    self.fig_phase.set_dpi(new)
                    self.update_draw()
            except:
                pass

        def change_fsize_phase(self):
            try:
                self.fsize_phase = int(self.lineEdit_fsize.text())
                self.change_title_phase()
                self.change_labelx_phase()
                self.change_labely_phase()
                self.update_draw()

            except Exception as error:
                pass  #self.ui.update_outputText(error)

        def change_cmap_phase(self):
            try:
                self.im_phase.set_cmap(self.lineEdit_cmap_phase.text())
                self.canvas_phase.draw()
            except Exception as error:
                pass
                #self.ui.update_outputText(error)

        def change_xlim_phase(self):
            try:
                temp_txt = self.lineEdit_xlim_phase.text()
                Ntxt = len(temp_txt)
                numList = []
                if temp_txt[0] == "(" and temp_txt[-1] == ")":
                    actual = ""
                    for i in range(1, Ntxt - 1):
                        if temp_txt[i] == ",":
                            numList.append(float(actual))
                            actual = ""
                        elif i == Ntxt - 2:
                            actual += temp_txt[i]
                            numList.append(float(actual))
                        else:
                            actual += temp_txt[i]
                self.axes_phase.set_xlim(numList[0], numList[1])
            except Exception as error:
                pass
                #self.ui.update_outputText(error)

        def change_ylim_phase(self):
            try:
                temp_txt = self.lineEdit_ylim_phase.text()
                Ntxt = len(temp_txt)
                numList = []
                if temp_txt[0] == "(" and temp_txt[-1] == ")":
                    actual = ""
                    for i in range(1, Ntxt - 1):
                        if temp_txt[i] == ",":
                            numList.append(float(actual))
                            actual = ""
                        elif i == Ntxt - 2:
                            actual += temp_txt[i]
                            numList.append(float(actual))
                        else:
                            actual += temp_txt[i]
                self.axes_phase.set_ylim(numList[0], numList[1])
                self.canvas.draw()
            except Exception as error:
                pass
                #self.ui.update_outputText(error)

        def change_title_phase(self):
            try:
                self.axes_phase.set_title(self.lineEdit_title_phase.text(),
                                          fontsize=self.fsize_phase)
                self.canvas_phase.draw()
            except:
                pass

        def change_labelx_phase(self):
            if self.lineEdit_xLabel_phase.text() == "":
                self.axes_phase.set_xlabel("")
            else:
                try:
                    self.axes_phase.set_xlabel(
                        self.lineEdit_xLabel_phase.text(),
                        fontsize=self.fsize_phase)
                    self.canvas_phase.draw()
                except Exception as error:
                    self.ui.update_outputText(str(error))

        def change_labely_phase(self):
            if self.lineEdit_yLabel_phase.text() == "":
                self.axes_phase.set_ylabel("")
            else:
                try:
                    self.axes_phase.set_ylabel(
                        self.lineEdit_yLabel_phase.text(),
                        fontsize=self.fsize_phase)
                    self.canvas_phase.draw()
                except:
                    pass
                    #self.ui.update_outputText("Unable to update y-label.")

    except Exception as error:
        self.ui.update_outputText(error)
Example #22
0
class CalibPH(tk.Frame):
    def __init__(self, parent, controller, ChannelID, channelName):
        tk.Frame.__init__(self, parent)

        defs_common.logtoconsole("Initializing CalibPH...",
                                 fg="YELLOW",
                                 bg="MAGENTA",
                                 style="BRIGHT")

        self.controller = controller
        self.parent = parent
        self.ChannelID = ChannelID
        self.ChannelName = channelName

        # registering validation command
        #self.vldt_ifnum_cmd = (self.register(self.ValidateIfNum),'%s', '%S')

        self.isCalRunning = False
        self.calType = "none"
        self.calPoints = []
        self.currentDVlistCounter = 0
        self.currentDVlist = []

        strHeadLabel = "Channel " + str(self.ChannelID) + " [" + str(
            self.ChannelName) + "]"
        headlabel = tk.Label(self, text=strHeadLabel, font=LARGE_FONT)
        headlabel.grid(row=0, column=0, pady=10, sticky=W, columnspan=3)

        lbl_calPoint = headlabel = tk.Label(self, text="Cal Point")
        lbl_calPoint.grid(row=1, column=0, padx=10)
        lbl_refVal = headlabel = tk.Label(self, text="PH Reference")
        lbl_refVal.grid(row=1, column=1, padx=10)
        lbl_digVal = headlabel = tk.Label(self, text="Digital Value")
        lbl_digVal.grid(row=1, column=2, padx=10)

        # we want to underline the header, so:
        # clone the font, set the underline attribute,
        # and assign it to our widget
        f = font.Font(lbl_calPoint, lbl_calPoint.cget("font"))
        f.configure(underline=True)
        lbl_calPoint.configure(font=f)
        lbl_refVal.configure(font=f)
        lbl_digVal.configure(font=f)

        # read values from config file
        # Low Val
        lbl_pointLow = tk.Label(self, text="Low")
        lbl_pointLow.grid(row=2, column=0)
        lbl_phrefLow = tk.Label(self, text="4.0")
        lbl_phrefLow.grid(row=2, column=1)
        strval = "ch" + str(ChannelID) + "_ph_low"
        val = self.controller.controller.controller.controller.downloadsettings(
            "mcp3008", strval, "900")
        self.lbl_low_val = tk.Label(self, text=val)
        self.lbl_low_val.grid(row=2, column=2)
        btn_LowCalStart = Button(self,
                                 text="Start Low Calibration",
                                 command=lambda: self.startCalLoop('low'))
        btn_LowCalStart.grid(row=2, column=3, sticky=EW)
        # Med Val
        lbl_pointMed = tk.Label(self, text="Mid")
        lbl_pointMed.grid(row=3, column=0)
        lbl_phrefMed = tk.Label(self, text="7.0")
        lbl_phrefMed.grid(row=3, column=1)
        strval = "ch" + str(ChannelID) + "_ph_med"
        val = self.controller.controller.controller.controller.downloadsettings(
            "mcp3008", strval, "800")
        self.lbl_med_val = tk.Label(self, text=val)
        self.lbl_med_val.grid(row=3, column=2)
        btn_MedCalStart = Button(self,
                                 text="Start Mid Calibration",
                                 command=lambda: self.startCalLoop('med'))
        btn_MedCalStart.grid(row=3, column=3, sticky=EW)
        # High Val
        lbl_pointHigh = tk.Label(self, text="High")
        lbl_pointHigh.grid(row=4, column=0)
        lbl_phrefHigh = tk.Label(self, text="10.0")
        lbl_phrefHigh.grid(row=4, column=1)
        strval = "ch" + str(ChannelID) + "_ph_high"
        val = self.controller.controller.controller.controller.downloadsettings(
            "mcp3008", strval, "700")
        self.lbl_high_val = tk.Label(self, text=val)
        self.lbl_high_val.grid(row=4, column=2)
        btn_HighCalStart = Button(self,
                                  text="Start High Calibration",
                                  command=lambda: self.startCalLoop('high'))
        btn_HighCalStart.grid(row=4, column=3, sticky=EW)

        # Show current PH and DV val
        frame_LiveData = LabelFrame(self, text="Live Data")
        frame_LiveData.grid(row=5, column=0, columnspan=4, sticky=EW)
        lbl_curPH = tk.Label(frame_LiveData, text="Current PH:")
        lbl_curPH.grid(row=5, column=0, sticky=E, columnspan=2)
        self.lbl_curPHval = tk.Label(frame_LiveData, text="waiting...")
        self.lbl_curPHval.grid(row=5, column=2, sticky=W, padx=20)
        lbl_curDV = tk.Label(frame_LiveData, text="Current Digital Value:")
        lbl_curDV.grid(row=6, column=0, sticky=E, columnspan=2)
        self.lbl_curDVval = tk.Label(frame_LiveData, text="waiting...")
        self.lbl_curDVval.grid(row=6, column=2, sticky=W, padx=20, pady=10)

        # calibration data
        frame_CalData = LabelFrame(self, text="Calibration Data")
        frame_CalData.grid(row=7, column=0, columnspan=4, sticky=EW)

        # cal label
        self.calLabel = Label(frame_CalData, text=" ", font=LARGE_FONT_BOLD)
        self.calLabel.grid(row=0,
                           column=0,
                           columnspan=4,
                           padx=5,
                           pady=4,
                           sticky=W)

        # progress bar
        self.calprogress = ttk.Progressbar(frame_CalData,
                                           orient='horizontal',
                                           mode='determinate',
                                           maximum=NUMCALPOINTS,
                                           length=450)
        self.calprogress.grid(row=1,
                              column=0,
                              sticky=EW,
                              pady=10,
                              padx=5,
                              columnspan=6)

        # data points plot
        style.use("ggplot")
        self.figprobe = Figure(figsize=(6, 2.5), dpi=100)
        self.figprobe.set_facecolor("gainsboro")
        self.aniprobe = self.figprobe.add_subplot(111)
        self.aniprobe.set_title("Data Points")

        self.canvasprobe = FigureCanvasTkAgg(self.figprobe, frame_CalData)

        self.canvasprobe.show()
        self.canvasprobe.get_tk_widget().grid(sticky=EW,
                                              row=2,
                                              column=2,
                                              columnspan=4)

        # histogram plot
        ##        self.fighist, self.axhist = plt.subplots()
        ##        plt.title("Histogram")
        self.fighist = Figure(figsize=(6, 2.5), dpi=100)
        self.axhist = self.fighist.add_subplot(111)
        self.axhist.set_title("Histogram")
        self.fighist.set_facecolor("gainsboro")
        self.fighist.set_size_inches(6, 2.5)
        self.fighist.set_dpi(100)
        self.axhist.axes.tick_params(axis='x', labelsize=8)
        self.axhist.axes.tick_params(axis='y', labelsize=8)
        self.axhist.axes.set_xlim([0, 1023])

        self.canvashist = FigureCanvasTkAgg(self.fighist, frame_CalData)
        self.canvashist.show()
        self.canvashist.get_tk_widget().grid(sticky=EW,
                                             row=3,
                                             column=2,
                                             columnspan=4)

        ani = animation.FuncAnimation(self.figprobe,
                                      self.animate_probe,
                                      interval=1000)

        # scrolled textbox for calibration values
        self.txt_calPoints = tkst.ScrolledText(frame_CalData,
                                               width=15,
                                               height=10,
                                               wrap='word')
        self.txt_calPoints.grid(row=2,
                                column=0,
                                sticky=NSEW,
                                padx=5,
                                columnspan=2)

        # results area
        self.frame_Results = LabelFrame(frame_CalData, text="Results")
        self.frame_Results.grid(row=3, column=0, sticky=NSEW, columnspan=2)

        self.lbl_num_Samples = Label(self.frame_Results, text="Num. Samples:")
        self.lbl_num_Samples.grid(row=0, column=0, sticky=E)
        self.lbl_num_SamplesVal = Label(self.frame_Results, text="", width=10)
        self.lbl_num_SamplesVal.grid(row=0, column=1, sticky=EW)

        self.lbl_resultMin = Label(self.frame_Results, text="Min:")
        self.lbl_resultMin.grid(row=1, column=0, sticky=E)
        self.lbl_resultMinVal = Label(self.frame_Results, text="", width=10)
        self.lbl_resultMinVal.grid(row=1, column=1, sticky=EW)

        self.lbl_resultMax = Label(self.frame_Results, text="Max:")
        self.lbl_resultMax.grid(row=2, column=0, sticky=E)
        self.lbl_resultMaxVal = Label(self.frame_Results, text="", width=10)
        self.lbl_resultMaxVal.grid(row=2, column=1, sticky=EW)

        self.lbl_resultMean = Label(self.frame_Results, text="Mean:")
        self.lbl_resultMean.grid(row=3, column=0, sticky=E)
        self.lbl_resultMeanVal = Label(self.frame_Results, text="", width=10)
        self.lbl_resultMeanVal.grid(row=3, column=1, sticky=EW)

        self.lbl_resultStdDev = Label(self.frame_Results,
                                      text="Std. Deviation:")
        self.lbl_resultStdDev.grid(row=4, column=0, sticky=E)
        self.lbl_resultStdDevVal = Label(self.frame_Results, text="", width=10)
        self.lbl_resultStdDevVal.grid(row=4, column=1, sticky=EW)

        self.lbl_resultCalval = Label(self.frame_Results,
                                      text="Calibration Value:")
        self.lbl_resultCalval.grid(row=5, column=0, sticky=E)
        self.lbl_resultCalvalVal = Label(self.frame_Results,
                                         text="",
                                         width=10,
                                         font=LARGE_FONT_BOLD)
        self.lbl_resultCalvalVal.grid(row=5, column=1, sticky=EW, pady=20)

        self.btn_ApplyCal = Button(self.frame_Results,
                                   text="Apply Calibration Value",
                                   command=self.ApplyCal)
        self.btn_ApplyCal.grid(row=6, column=0, columnspan=2, sticky=EW)

        self.currentADCLoop(self.ChannelID)

    def startCalLoop(self, calPoint):

        self.isCalRunning = True

        #reset stats
        self.calprogress['value'] = 0
        self.txt_calPoints.delete(1.0, END)
        self.lbl_resultMeanVal.config(text="")
        self.lbl_num_SamplesVal.config(text="")
        self.lbl_resultStdDevVal.config(text="")
        self.lbl_resultMinVal.config(text="")
        self.lbl_resultMaxVal.config(text="")
        self.lbl_resultCalvalVal.config(text="")

        #clear old data plot
        self.aniprobe.cla()
        #remove old histogram if exists
        try:
            t = [b.remove() for b in self.patches]
            print(t)
            self.canvashist.show()
        except:
            print("no bars")

        self.calPoints.clear()

        if calPoint == 'low':
            print("calLoop low")
            self.caltype = "low"
            self.calLabel['text'] = "Low Calibration: In Progress..."
        if calPoint == 'med':
            print("calLoop med")
            self.caltype = "med"
            self.calLabel['text'] = "Mid Calibration: In Progress..."
        if calPoint == 'high':
            print("calLoop high")
            self.caltype = "high"
            self.calLabel['text'] = "High Calibration: In Progress..."

    def currentADCLoop(self, chnum):
        try:
            # get setting value from server
            request = {
                "rpc_req": "get_ADCfromMCP3008",
                "ch_num": str(chnum),
            }
            request = json.dumps(request)
            val = self.controller.controller.controller.controller.rpc_call(
                request, "rpc_queue")
            val = val.decode()
            val = json.loads(val)
            val = val.get("dv")

            print(val)
            #self.lbl_curDVval.configure(text=val)

            # buffer for current PH vals
            if self.currentDVlistCounter < 9:
                self.currentDVlistCounter = self.currentDVlistCounter + 1
            else:
                self.currentDVlistCounter = 0

            if len(self.currentDVlist) < 10:
                self.currentDVlist.append(val)
                #print("in")
            else:
                self.currentDVlist[self.currentDVlistCounter] = val
                #print("out")
            print("counter = " + str(self.currentDVlistCounter))
            print("Current DV list: = " + str(self.currentDVlist))
            phVal = ph_sensor.dv2ph(int(mean(self.currentDVlist)),
                                    self.ChannelID,
                                    self.lbl_low_val.cget("text"),
                                    self.lbl_med_val.cget("text"),
                                    self.lbl_high_val.cget("text"))
            print('{0:.2f}'.format(float(phVal)))
            self.lbl_curPHval.configure(text='{0:.2f}'.format(float(phVal)),
                                        font=LARGE_FONT_BOLD)
            self.lbl_curDVval.configure(text=str(self.currentDVlist))

            if self.isCalRunning == True:
                print("cal in progress")
                self.calPoints.append(val)
                print(self.calPoints)
                self.calprogress['value'] = len(self.calPoints)

                strVal = str(len(self.calPoints)) + ":" + str(val)
                self.txt_calPoints.insert(END, str(strVal) + '\n')
                self.txt_calPoints.see('end')

                #plot new point
                #self.animate_probe(self.figprobe)

                calPtArray = numpy.array(self.calPoints)
                stdDev = numpy.std(calPtArray, axis=0)
                meanDV = mean(self.calPoints)
                minDV = min(self.calPoints)
                maxDV = max(self.calPoints)
                print("std dev = " + str(stdDev))
                print(meanDV + stdDev)
                self.lbl_resultMeanVal.config(
                    text=str('{:.2f}'.format(meanDV)))
                self.lbl_num_SamplesVal.config(text=str(len(self.calPoints)))
                self.lbl_resultStdDevVal.config(
                    text=str('{:.2f}'.format(stdDev)))
                self.lbl_resultMinVal.config(text=str(minDV))
                self.lbl_resultMaxVal.config(text=str(maxDV))

                if len(self.calPoints) >= NUMCALPOINTS:
                    print("mean = " + str(mean(self.calPoints)))

                    if self.caltype == 'low':
                        #self.lbl_low_val.config(text=int(mean(self.calPoints)))
                        self.calLabel[
                            'text'] = "Low Calibration: Aquisition Complete"
                    elif self.caltype == 'med':
                        #self.lbl_med_val.config(text=int(mean(self.calPoints)))
                        self.calLabel[
                            'text'] = "Mid Calibration: Aquisition Complete"
                    elif self.caltype == 'high':
                        #self.lbl_high_val.config(text=int(mean(self.calPoints)))
                        self.calLabel[
                            'text'] = "High Calibration: Aquisition Complete"

                    FilteredCountList = [
                        x for x in self.calPoints
                        if (x >= meanDV - ph_Sigma * stdDev)
                    ]
                    FilteredCountList = [
                        x for x in FilteredCountList
                        if (x <= meanDV + ph_Sigma * stdDev)
                    ]

                    print("Cal point = " + str(int(mean(FilteredCountList))))

                    self.lbl_resultCalvalVal.config(
                        text=str(int(math.ceil(mean(FilteredCountList)))))

                    self.plot_hist()
                    self.isCalRunning = False

            self.after(1000, self.currentADCLoop, chnum)

            #return val
        except Exception as e:
            print(e)
            pass

    def getADCval(self, chnum):
        # get setting value from server
        request = {
            "rpc_req": "get_ADCfromMCP3008",
            "ch_num": str(chnum),
        }
        request = json.dumps(request)
        val = self.controller.controller.controller.controller.rpc_call(
            request, "rpc_queue")
        val = val.decode()
        val = json.loads(val)
        val = val.get("dv")

        print(val)

        return val

    # plot calibration data
    def animate_probe(self, i):
        if self.isCalRunning == True:
            self.aniprobe.clear()
            chartData = self.calPoints
            dim = numpy.arange(1, len(chartData) + 1)
            #print(dim)
            #print(chartData)
            self.aniprobe.set_title("Data Points")
            try:
                self.aniprobe.plot(dim, chartData, "-", color='GREEN')
                self.aniprobe.axes.tick_params(axis='x', labelsize=8)
                self.aniprobe.axes.tick_params(axis='y', labelsize=8)
                self.aniprobe.axes.set_xlim([1, None])

            except:
                print("Error plotting data")
                pass
            if len(chartData) > 1:
                meanDV = mean(self.calPoints)
                calPtArray = numpy.array(chartData)
                stdDev = numpy.std(calPtArray, axis=0)

                FilteredCountList = [
                    x for x in self.calPoints
                    if (x >= meanDV - ph_Sigma * stdDev)
                ]
                FilteredCountList = [
                    x for x in FilteredCountList
                    if (x <= meanDV + ph_Sigma * stdDev)
                ]
                targetMeanDV = mean(FilteredCountList)
                targetDV = int(math.ceil(targetMeanDV))
                self.aniprobe.axhline(y=(targetDV), color='red')
                #self.aniprobe.axhline(y=(meanDV), color='red')

                self.aniprobe.axhline(y=math.ceil(meanDV + stdDev),
                                      color='black',
                                      linestyle='-.')
                self.aniprobe.axhline(y=math.ceil(meanDV - stdDev),
                                      color='black',
                                      linestyle='-.')

                t = self.aniprobe.text(1, targetDV, str(targetDV), fontsize=24)
                #t = self.aniprobe.text(1, meanDV, str("{:.2f}".format(meanDV)), fontsize=24)
                t.set_bbox(
                    dict(facecolor='white', alpha=0.5, edgecolor='black'))
            return

    # plot calibration histogram
    def plot_hist(self):

        try:
            # lets plot the histogram
            bins = range(0, 1023, binsize)  # set up bins for histogram
            n, dvbins, self.patches = self.axhist.hist(self.calPoints,
                                                       bins,
                                                       color="royalblue",
                                                       ec="royalblue")

            self.canvashist.show()
        except:
            print("Error plotting histogram")
            pass

        return

    def ApplyCal(self):
        self.running = 0
        try:
            calVal = self.lbl_resultCalvalVal.cget("text")
            if self.caltype == 'low':
                self.lbl_low_val.config(text=int(calVal))
            elif self.caltype == 'med':
                self.lbl_med_val.config(text=int(calVal))
            elif self.caltype == 'high':
                self.lbl_high_val.config(text=int(calVal))
        except Exception as e:
            print(e)
Example #23
0
class Chart(object):
    """
    Simple and clean facade to Matplotlib's plotting API.
    
    A chart instance abstracts a plotting device, on which one or
    multiple related plots can be drawn. Charts can be exported as images, or
    visualized interactively. Each chart instance will always open in its own
    GUI window, and this window will never block the execution of the rest of
    the program, or interfere with other L{Chart}s.
    The GUI can be safely opened in the background and closed infinite number
    of times, as long as the client program is still running.
    
    By default, a chart contains a single plot:
    
    >>> chart.plot
    matplotlib.axes.AxesSubplot
    >>> chart.plot.hist(...)
    
    If C{rows} and C{columns} are defined, the chart will contain
    C{rows} x C{columns} number of plots (equivalent to MPL's sub-plots).
    Each plot can be assessed by its index:
    
    >>> chart.plots[0]
    first plot
    
    or by its position in the grid:
    
    >>> chart.plots[0, 1]
    plot at row=0, column=1
    
    @param number: chart number; by default this a L{Chart.AUTONUMBER}
    @type number: int or None
    @param title: chart master title
    @type title: str
    @param rows: number of rows in the chart window
    @type rows: int
    @param columns: number of columns in the chart window
    @type columns: int
    
    @note: additional arguments are passed directly to Matplotlib's Figure
           constructor. 
    """

    AUTONUMBER = None

    _serial = 0

    def __init__(self,
                 number=None,
                 title='',
                 rows=1,
                 columns=1,
                 backend=Backends.WX_WIDGETS,
                 *fa,
                 **fk):

        if number == Chart.AUTONUMBER:
            Chart._serial += 1
            number = Chart._serial

        if rows < 1:
            rows = 1
        if columns < 1:
            columns = 1

        self._rows = int(rows)
        self._columns = int(columns)
        self._number = int(number)
        self._title = str(title)
        self._figure = Figure(*fa, **fk)
        self._figure._figure_number = self._number
        self._figure.suptitle(self._title)
        self._beclass = backend
        self._hasgui = False
        self._plots = PlotsCollection(self._figure, self._rows, self._columns)
        self._canvas = FigureCanvasAgg(self._figure)

        formats = [(f.upper(), f)
                   for f in self._canvas.get_supported_filetypes()]
        self._formats = csb.core.Enum.create('OutputFormats', **dict(formats))

    def __getitem__(self, i):
        if i in self._plots:
            return self._plots[i]
        else:
            raise KeyError('No such plot number: {0}'.format(i))

    def __enter__(self):
        return self

    def __exit__(self, *a, **k):
        self.dispose()

    @property
    def _backend(self):
        return Backend.get(self._beclass, started=True)

    @property
    def _backend_started(self):
        return Backend.query(self._beclass)

    @property
    def title(self):
        """
        Chart title
        @rtype: str
        """
        return self._title

    @property
    def number(self):
        """
        Chart number
        @rtype: int
        """
        return self._number

    @property
    def plots(self):
        """
        Index-based access to the plots in this chart
        @rtype: L{PlotsCollection}
        """
        return self._plots

    @property
    def plot(self):
        """
        First plot
        @rtype: matplotlib.AxesSubplot
        """
        return self._plots[0]

    @property
    def rows(self):
        """
        Number of rows in this chart
        @rtype: int
        """
        return self._rows

    @property
    def columns(self):
        """
        Number of columns in this chart
        @rtype: int
        """
        return self._columns

    @property
    def width(self):
        """
        Chart's width in inches
        @rtype: int
        """
        return self._figure.get_figwidth()

    @width.setter
    def width(self, inches):
        self._figure.set_figwidth(inches)
        if self._backend_started:
            self._backend.resize(self._figure)

    @property
    def height(self):
        """
        Chart's height in inches
        @rtype: int
        """
        return self._figure.get_figheight()

    @height.setter
    def height(self, inches):
        self._figure.set_figheight(inches)
        if self._backend_started:
            self._backend.resize(self._figure)

    @property
    def dpi(self):
        """
        Chart's DPI
        @rtype: int
        """
        return self._figure.get_dpi()

    @dpi.setter
    def dpi(self, dpi):
        self._figure.set_dpi(dpi)
        self._backend.resize(self._figure)

    @property
    def formats(self):
        """
        Supported output file formats
        @rtype: L{csb.core.enum}
        """
        return self._formats

    def show(self):
        """
        Show the GUI window (non-blocking).
        """
        if not self._hasgui:
            self._backend.add(self._figure)
            self._hasgui = True

        self._backend.show(self._figure)

    def hide(self):
        """
        Hide (but do not dispose) the GUI window.
        """
        self._backend.hide(self._figure)

    def dispose(self):
        """
        Dispose the GUI interface. Must be called at the end if any
        chart.show() calls have been made. Automatically called if using
        the chart in context manager ("with" statement).
        
        @note: Failing to call this method if show() has been called at least
        once may cause backend-related errors.
        """
        if self._backend_started:

            service = self._backend

            if service and service.running:
                service.destroy(self._figure, wait=True)
                service.client_disposed(self)

    def save(self, file, format='png', crop=False, dpi=None, *a, **k):
        """
        Save all plots to an image.
        
        @param file: destination file name
        @type file: str
        @param format: output image format; see C{chart.formats} for enumeration
        @type format: str or L{csb.core.EnumItem}
        @param crop: if True, crop the image (equivalent to MPL's bbox=tight)
        @type crop: bool
                
        @note: additional arguments are passed directly to MPL's savefig method
        """
        if 'bbox_inches' in k:
            bbox = k['bbox_inches']
            del k['bbox_inches']
        else:
            if crop:
                bbox = 'tight'
            else:
                bbox = None

        self._canvas.print_figure(file,
                                  format=str(format),
                                  bbox_inches=bbox,
                                  dpi=dpi,
                                  *a,
                                  **k)
Example #24
0
    def calculateWallMap(self,
                         resolution=0.1,
                         level=0,
                         zlim=(0.15, 1.50),
                         xlim=None,
                         ylim=None,
                         roomIds=None):

        figSize = (10, 10)
        fig = Figure(figsize=figSize, dpi=100, frameon=False)
        canvas = FigureCanvas(fig)
        ax = fig.add_subplot(111, aspect='equal')
        fig.subplots_adjust(left=0,
                            bottom=0,
                            right=1,
                            top=1,
                            wspace=0,
                            hspace=0)
        ax.axis('off')
        ax.set_aspect('equal')

        floorZ = self._getFloorReferenceZ(level)
        zlim = np.array(zlim) + floorZ

        if roomIds is not None:
            layoutModels = []
            for roomId in roomIds:
                layoutModels.extend([
                    model for model in self.scene.scene.findAllMatches(
                        '**/level-%d/room-%s/layouts/object-*/+ModelNode' %
                        (level, roomId))
                ])
        else:
            layoutModels = [
                model for model in self.scene.scene.findAllMatches(
                    '**/level-%d/**/layouts/object-*/+ModelNode' % level)
            ]

        # Loop for all walls in the scene:
        for model in layoutModels:
            modelId = model.getNetTag('model-id')

            if not modelId.endswith('w'):
                continue

            addModelTriangles(ax, model, zlim=zlim)

        if xlim is not None and ylim is not None:
            ax.set_xlim(xlim)
            ax.set_ylim(ylim)
        else:
            ax.autoscale(True)
            set_axes_equal(ax)

        xlim, ylim = ax.get_xlim(), ax.get_ylim()
        xrange = xlim[1] - xlim[0]
        yrange = ylim[1] - ylim[0]
        assert np.allclose(xrange, yrange, atol=1e-6)
        dpi = (xrange / resolution) / figSize[0]
        fig.set_dpi(dpi)

        wallMap = canvas2image(canvas)
        plt.close(fig)

        # RGB to binary
        wallMap = np.round(np.mean(wallMap[:, :], axis=-1))

        # NOTE: inverse image so that obstacle areas are shown in white
        wallMap = 1.0 - wallMap

        return wallMap, xlim, ylim
Example #25
0
def do_it(cfg):
    DPI = 96

    fig = Figure()
    FigureCanvasAgg(fig)
    ax: Axes = fig.subplots(
        1,
        1,
        subplot_kw=dict(xticks=[], yticks=[]),
        gridspec_kw=dict(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0),
    )
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    ax.set_axis_off()
    ax.set_xlim(-1, 1)
    ax.set_ylim(-1, 1)

    fig.set_dpi(DPI)
    fig.set_size_inches(cfg.dim / DPI, cfg.dim / DPI)

    # params
    tau = 2 * np.pi
    NPOINTS = 1000
    XMAX = 1
    FREQ = 1.3

    def lerp(x, y, a: float):
        return x * (1 - a) + y * a

    def sintau(x):
        return np.sin(tau * x)

    def costau(x):
        return np.cos(tau * x)

    gauss = lambda xs, W: np.exp(-(xs / W)**2)
    cos_win = lambda xs: costau(xs / 4)

    def win(xs):
        assert xs[0] == -1
        assert xs[-1] == 1

        W = 0.6
        e = 1
        return gauss(xs, W) * cos_win(xs)**e

    # plot
    xs = np.linspace(-XMAX, XMAX, NPOINTS)

    def sinusoid(dx, freq=1, yscale=1):
        # sintau
        # x: compress=freq, shift=dx
        # y: mul=yscale
        return lambda xs: sintau((xs - dx) * freq) * yscale

    def plot_sinusoid(dx, freq, yscale, alpha, color=None):
        func = sinusoid(dx, freq, yscale)
        ax.plot(xs,
                func(xs) * win(xs),
                alpha=alpha,
                color=color,
                linewidth=cfg.line_width)

    top = "narrow"
    blue = "narrow"

    top_blue = top == blue
    if top_blue:
        i = cfg.nline - 1
        di = -1
    else:
        i = 0
        di = 1

    freqs = np.geomspace(0.2, 1, cfg.nline)
    if top == "wide":
        freqs = freqs[::-1]

    e = 0

    for freq in freqs:
        plot_sinusoid(0, freq=freq, yscale=freq**e, alpha=1, color=cmap(i))
        i += di

    fig.savefig(f"{cfg.dim}.png", transparent=True)
Example #26
0
class PlotSettings(object):

    """
    The PlotSettings-class initializes the default values for the plot.

    The class can return those values to the main window and the plot-settings
    dialog. The plot-settings dialog will call the instance of this class to
    change the different settings. This class also stores the figure and can
    return different subplot-layouts. This class also stores the normal and
    inverse transformations of the stereonet, and will return the correct
    one for either the Schmidt- or Wulff-Net.
    """

    def __init__(self, testing):
        """
        Initalizes the default values, colors and the matplotlib-figure.

        Initializes and stores the default settings. Initializes the
        matplotlib-figure, a folder-icon for the group-layers of the layer-view.
        """
        self.folder_icon = Gtk.IconTheme.get_default().load_icon(
            "folder", 16, 0)
        self.props = OrderedDict(sorted({"draw_grid": True,
                      "equal_area_projection": True,
                      "minor_grid_spacing": 2,
                      "major_grid_spacing": 10,
                      "grid_cutoff_lat": 80,
                      "show_north": True,
                      "show_cross": True,
                      "pixel_density": 75,
                      "grid_linestyle": "--",
                      "grid_color": "#787878",
                      "grid_width": 0.4,
                      "draw_legend": True,
                      "canvas_color": "#bfbfbf",
                      "highlight": False
                      }.items()))
        self.night_mode = False
        self.fig = Figure(dpi=self.props["pixel_density"])
        if testing == False:
            try:
                self.g_settings = Gio.Settings.new("org.gtk.innstereo")
                self.get_defaults()
            except:
                pass

    def get_defaults(self):
        """
        Gets the defaults from the Gio.Settings.
        """
        self.props["draw_legend"] = self.g_settings.get_boolean("show-legend")
        self.props["draw_grid"] = self.g_settings.get_boolean("draw-grid")
        self.props["equal_area_projection"] = self.g_settings.get_boolean("stereonet-projection")
        self.props["show_cross"] = self.g_settings.get_boolean("center-cross")
        self.night_mode = self.g_settings.get_boolean("night-mode")
        self.props["pixel_density"] = self.g_settings.get_value("pixel-density").get_int32()
        self.props["highlight"] = self.g_settings.get_boolean("highlight-mode")

    def get_fig(self):
        """
        Returns the Matplotlib-Figure.

        Returns the figure that is stored by this class. The MainWindow class
        calls this function once during initialization to add the figure to
        the FigureCanvas.
        """
        return self.fig

    def get_inverse_transform(self):
        """
        Returns the inverse transform for the current stereonet projection.

        If the projection is equal are (True) the function returns the
        InvertedLambertTransform- or else the
        InvertedSterreographicTransform-class.
        """
        if self.props["equal_area_projection"] is True:
            return mplstereonet.stereonet_transforms.\
                        InvertedLambertTransform(0, 0,
                        self.props["pixel_density"])
        else:
            return mplstereonet.stereonet_transforms.\
                        InvertedStereographicTransform(0, 0,
                        self.props["pixel_density"])

    def get_transform(self):
        """
        Returns the normal transform for the current stereonet projection.

        If the projection is equal are (True) the function returns the
        LambertTransform- or else the SterreographicTransform-class.
        """
        if self.props["equal_area_projection"] is True:
            return mplstereonet.stereonet_transforms.\
                        LambertTransform(0, 0,
                        self.props["pixel_density"])
        else:
            return mplstereonet.stereonet_transforms.\
                        StereographicTransform(0, 0,
                        self.props["pixel_density"])

    def get_draw_grid_state(self):
        """
        Returns if the grid should be drawn for the stereonet.

        Returns a boolean. True mean that a grid should be drawn. False means
        that no grid should be drawn. This method is called by the MainWindow-
        redraw_plot-method.
        """
        return self.props["draw_grid"]

    def set_draw_grid_state(self, new_state):
        """
        Sets if the grid should be drawn for the stereonet.

        Expects a boolean. True mean that a grid should be drawn. False means
        that no grid should be drawn. This method is called by the
        LayerProperties-dialog when the setting is changed.
        """
        self.props["draw_grid"] = new_state

    def get_folder_icon(self):
        """
        Returns the folder icon used for the group-layer pixbuf.

        Always returns the "folder" icon from the Gtk.IconTheme. The folder
        will therefore match the desktop-theme set by the user. This method is
        called by the MainWindow "on_toolbutton_create_group_layer_clicked"-
        method.
        """
        return self.folder_icon

    def get_pixel_density(self):
        """
        Returns the pixel density the plot is using.

        The pixel density is an int and the default value is 75. This method
        is called by the LayerProperties-dialog so it can display the current
        value.
        """
        return self.props["pixel_density"]

    def set_pixel_density(self, new_pixel_density):
        """
        Sets a new pixel density for the plot.

        Expects an int. This method is called by the LayerProperties-dialog.
        The new value will be used when the plot redraws when the settings
        in the dialog are applied.
        """
        self.props["pixel_density"] = new_pixel_density

    def get_projection(self):
        """
        Returns the projection currently used by the stereonet.

        Returns one of two strings that MPLStereonet uses to distinguish
        between the equal-area and equal-angle projection. This method is only
        called from this class when the view is switched.
        """
        if self.props["equal_area_projection"] is True:
            return "equal_area_stereonet"
        else:
            return "equal_angle_stereonet"

    def get_projection_state(self):
        """
        Returns the projection state for the stereonet.

        Returns a boolean. True means that the stereonet should be drawn
        with equal-area. False mean equal-angle. This method is called by the
        StereonetProperties-dialog to load the current setting.
        """
        return self.props["equal_area_projection"]

    def set_projection_state(self, new_state):
        """
        Sets a new projection state.

        Expects a boolean. True means that the projection will be equal-area,
        False means equal-angle. This method is called by the
        StereonetProperties-dialog when a new setting for the projection is
        applied.
        """
        self.props["equal_area_projection"] = new_state

    def get_grid_linestyle(self):
        """
        Returns the linestyle of the grid.

        The linestyle is returned as a string. Default is "--" (dashed). This
        method is called by the MainWindow "redraw_plot"-method.
        """
        return self.props["grid_linestyle"]

    def get_grid_color(self):
        """
        Returns the color of the grid.

        Returns the color as a hex-triplet. The default is "#787878". This
        method is called by the MainWindow "redraw_plot"-method.
        """
        return self.props["grid_color"]

    def get_grid_width(self):
        """
        Returns the width of the grid lines.

        The width of the grid lines is returned as a float or int. The default
        is "0.4". This method is called by the MainWindow "redraw_plot"-method.
        """
        return self.props["grid_width"]

    def get_draw_legend(self):
        """
        Returns if the legend should be drawn as a boolean.

        The returned value is either True if a legend should be drawn, or False
        if no legend should be drawn. This method is called by the MainWindow
        "redraw_plot"-method and the StereonetProperties-dialog.
        """
        return self.props["draw_legend"]

    def set_draw_legend(self, new_state):
        """
        Sets a new state for whether the legend should be drawn.

        Expects a boolean. True means that the legend should be drawn. False
        means that no legend should be drawn. This method is called by the
        StereonetProperties-dialog when a new setting is applied.
        """
        self.props["draw_legend"] = new_state

    def get_canvas_rgba(self):
        """
        Returns the canvas color as a Gdk.RGBA.

        This method is called by the StereonetProperties-dialog to apply the
        current canvas color to the ColorButton.
        """
        rgba = Gdk.RGBA()
        rgba.parse(self.props["canvas_color"])
        return rgba.to_color()

    def set_canvas_color(self, new_color):
        """
        Sets a new canvas color.

        Expects a hex-triplet string (e.g. "#bfbfbf"). This method is called
        by the StereonetProperties-dialog when a new color is applied to the
        canvas.
        """
        self.props["canvas_color"] = new_color

    def get_stereonet(self):
        """
        Resets the figure and returns the stereonet axis.

        When the view in the main window is changed to only stereoent. The
        figure is reset. Then the current settings are applied and one subplot
        for the stereonet is created. This method is called when the
        MainWindow "__init__"-method and the "redraw_plot"-method. 
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.props["canvas_color"])
        self.fig.set_dpi(self.props["pixel_density"])
        gridspec = GridSpec(2, 3)
        sp_stereo = gridspec.new_subplotspec((0, 0), rowspan=2, colspan=2)
        sp_cbar = gridspec.new_subplotspec((1, 2), rowspan=1, colspan=1)
        ax_stereo = self.fig.add_subplot(sp_stereo,
                                         projection=self.get_projection())
        ax_cbar = self.fig.add_subplot(sp_cbar)
        ax_cbar.axis("off")
        ax_cbar.set_aspect(8)
        return ax_stereo, ax_cbar

    def get_stereo_rose(self):
        """
        Resets the figure and returns a stereonet and rose diagram axis.

        When the view in the main window is changed to stereonet and rose
        diagram, the figure is reset. The current settings are applied and
        two subplots for the stereonet and rose diagram are created. The
        axis of the stereonet and rose diagram are returned. This method is
        called by the MainWindow "redraw_plot"-method.
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.props["canvas_color"])
        self.fig.set_dpi(self.props["pixel_density"])
        gridspec = GridSpec(2, 5)
        sp_stereo = gridspec.new_subplotspec((0, 0),
                                             rowspan=2, colspan=2)
        sp_cbar = gridspec.new_subplotspec((1, 2), rowspan=1, colspan=1)
        sp_rose = gridspec.new_subplotspec((0, 3),
                                           rowspan=2, colspan=2)
        ax_stereo = self.fig.add_subplot(sp_stereo,
                                         projection=self.get_projection())
        ax_rose = self.fig.add_subplot(sp_rose, projection="northpolar")

        ax_cbar = self.fig.add_subplot(sp_cbar)
        ax_cbar.axis("off")
        ax_cbar.set_aspect(8)
        return ax_stereo, ax_rose, ax_cbar

    def get_stereo_two_rose(self):
        """
        Resets the figure and returns a stereonet two rose diagrams axis.

        When the view in the main window is changed to this setting, this
        function is called and sets up a plot with a stereonet and two
        rose diagram axis. One axis is for azimuth, the other one for
        dip.
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.props["canvas_color"])
        self.fig.set_dpi(self.props["pixel_density"])
        gridspec = GridSpec(2, 4)
        sp_stereo = gridspec.new_subplotspec((0, 0),
                                             rowspan=2, colspan=2)
        sp_cbar = gridspec.new_subplotspec((1, 2), rowspan=1, colspan=1)
        sp_rose = gridspec.new_subplotspec((0, 3),
                                           rowspan=1, colspan=1)
        sp_drose = gridspec.new_subplotspec((1, 3),
                                           rowspan=1, colspan=1)
        ax_stereo = self.fig.add_subplot(sp_stereo,
                                         projection=self.get_projection())
        ax_rose = self.fig.add_subplot(sp_rose, projection="northpolar")
        ax_drose = self.fig.add_subplot(sp_drose, projection="dippolar")
        ax_cbar = self.fig.add_subplot(sp_cbar)
        ax_cbar.axis("off")
        ax_cbar.set_aspect(8)
        return ax_stereo, ax_rose, ax_drose, ax_cbar

    def get_rose_diagram(self):
        """
        Resets the figure and returns the rose diagram axis.

        When the view in the main window is changed to rose-diagram-only the
        figure is reset. The current settings are applied and one subplot
        for the rose diagram is created. The axis of the rose-diagram is
        returned. This method is called by the MainWindow "redraw_plot"-method.
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.props["canvas_color"])
        self.fig.set_dpi(self.props["pixel_density"])
        gridspec = GridSpec(1, 1)
        sp_rose = gridspec.new_subplotspec((0, 0))
        ax_rose = self.fig.add_subplot(sp_rose, projection="northpolar")
        return ax_rose

    def get_pt_view(self):
        """
        Resets the canvas and returns the 3 axis of the paleostress view.

        When the view in the main window is changed to paleostress the figure
        is reset. The current settings are applied and 3 subplots are created.
        The 3 axis of the subplots are returned. This method is called by the
        MainWindow "redraw_plot"-method when the view has been changed.
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.props["canvas_color"])
        self.fig.set_dpi(self.props["pixel_density"])
        gridspec = GridSpec(2, 5)
        sp_stereo = gridspec.new_subplotspec((0, 0), colspan=3, rowspan=2)
        sp_fluc = gridspec.new_subplotspec((0, 3), colspan=2)
        sp_mohr = gridspec.new_subplotspec((1, 3), colspan=2)
        ax_stereo = self.fig.add_subplot(sp_stereo,
                                         projection=self.get_projection())
        ax_fluc = self.fig.add_subplot(sp_fluc, aspect="equal")
        ax_mohr = self.fig.add_subplot(sp_mohr, aspect="equal")
        return ax_stereo, ax_fluc, ax_mohr

    def get_show_north(self):
        """
        Returns if the stereonet should show the North symbol or degrees

        Returns True if the North symbol should be drawn (the default value),
        or False in which case numbers will be drawn for different degrees.
        """
        return self.props["show_north"]

    def set_show_north(self, new_state):
        """
        Sets a new state for whether the North symbol should be drawn.

        Expects a boolean. True means the North symbol will be drawn. False
        means that the stereonet will show different degrees along the outside.
        """
        self.props["show_north"] = new_state

    def get_show_cross(self):
        """
        Returns if the stereonet should draw a cross at the center.

        Returns True if the cross should be drawn (the default value) or False
        if the cross should not be drawn.
        """
        return self.props["show_cross"]

    def set_show_cross(self, new_state):
        """
        Sets a new state for whether the center cross should be drawn.

        Expects a boolean. True means the center cross will be drawn. False
        means it will not be drawn.
        """
        self.props["show_cross"] = new_state

    def get_properties(self):
        """
        Returns the current plot properties in a dictionary.

        The plot properties are stored in a dictionary. For loading and saving
        the dict is requested by the main window.
        """
        return self.props

    def set_properties(self, new_props):
        """
        Sets the properties to those passed in a dictionary.

        Loading a file will also set the plot properties to the saved state.
        The properties are appllied to this plot.
        """
        for key in new_props:
            self.props[key] = new_props[key]

    def get_highlight(self):
        """
        Gets the state of selection highlighting.

        Default is False.
        """
        return self.props["highlight"]

    def set_highlight(self, new_state):
        """
        Sets a new state for highlighting.

        Expects a boolean.
        """
        self.props["highlight"] = new_state

    def get_night_mode(self):
        """
        Gets the state of the night mode.

        Default is False, which is usually a lighter interface color.
        """
        return self.night_mode

    def set_night_mode(self, new_state):
        """
        Sets a new state for the night mode.

        Expects a boolean.
        """
        self.night_mode = new_state
Example #27
0
class matplotsink(wx.Panel):
  
    def __init__(self, parent, title, queue,gsz,zoom):
         wx.Panel.__init__(self, parent, wx.SIMPLE_BORDER)
        
	 self.gsz = gsz
         self.parent = parent
         self.title = title
         self.q = queue
	 self.zoom=zoom
         self.paused = False
       
#        self.create_menu()
#        self.create_status_bar()
         self.create_main_panel()
	 

    def create_menu(self):
        self.menubar = wx.MenuBar()
        
        menu_file = wx.Menu()
        m_expt = menu_file.Append(-1, "&Save plot\tCtrl-S", "Save plot to file")
        self.Bind(wx.EVT_MENU, self.on_save_plot, m_expt)
        menu_file.AppendSeparator()
        m_exit = menu_file.Append(-1, "E&xit\tCtrl-X", "Exit")
        self.Bind(wx.EVT_MENU, self.on_exit, m_exit)
        self.menubar.Append(menu_file, "&File")
        self.SetMenuBar(self.menubar)


    def create_main_panel(self):
        self.panel = self

        self.init_plot()
        self.canvas = FigCanvas(self.panel, -1, self.fig)
	self.scroll_range = 400
	self.canvas.SetScrollbar(wx.HORIZONTAL,0,5,self.scroll_range)
	self.canvas.Bind(wx.EVT_SCROLLWIN,self.OnScrollEvt)
	
        
        self.pause_button = wx.Button(self.panel, -1, "Pause")
        self.Bind(wx.EVT_BUTTON, self.on_pause_button, self.pause_button)
        self.Bind(wx.EVT_UPDATE_UI, self.on_update_pause_button, self.pause_button)
        
        self.cb_grid = wx.CheckBox(self.panel, -1, 
            "Show Grid",
            style=wx.ALIGN_RIGHT)
        self.Bind(wx.EVT_CHECKBOX, self.on_cb_grid, self.cb_grid)
        self.cb_grid.SetValue(True)
        
        self.cb_xlab = wx.CheckBox(self.panel, -1, 
            "Show X labels",
            style=wx.ALIGN_RIGHT)
        self.Bind(wx.EVT_CHECKBOX, self.on_cb_xlab, self.cb_xlab)        
        self.cb_xlab.SetValue(True)
        
        self.hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        self.hbox1.Add(self.pause_button, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
        self.hbox1.AddSpacer(20)
        self.hbox1.Add(self.cb_grid, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
        self.hbox1.AddSpacer(10)
        self.hbox1.Add(self.cb_xlab, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
        
        
        self.vbox = wx.BoxSizer(wx.VERTICAL)
        self.vbox.Add(self.canvas, 1, flag=wx.LEFT | wx.TOP | wx.GROW)        
        self.vbox.Add(self.hbox1, 0, flag=wx.ALIGN_LEFT | wx.TOP)
        
        self.panel.SetSizer(self.vbox)
        self.vbox.Fit(self)
	self.ani=animation.FuncAnimation(self.fig,self.draw_plot,interval=100)
    
    def OnScrollEvt(self,event):
	self.i_start = event.GetPosition()
	self.i_end =  self.i_window + event.GetPosition()
	self.draw_plot(0)
	
    def create_status_bar(self):
        self.statusbar = self.CreateStatusBar()

    def draw_test(self,event):
	self.xar=np.arange(len(self.q.queue))
        self.yar=np.array(self.q.queue)
	self.axes.plot(self.xar,self.yar)

    def init_plot(self):
        self.dpi = 100
 	self.fig = Figure((3.0, 3.0), dpi=self.dpi)
        self.fig.set_size_inches(7.0,4.0)
        self.fig.set_dpi(self.dpi)

        self.axes = self.fig.add_subplot(111)
        self.axes.set_axis_bgcolor('black')
        self.axes.set_title(self.title, size=12)
        
        pylab.setp(self.axes.get_xticklabels(), fontsize=8)
        pylab.setp(self.axes.get_yticklabels(), fontsize=8)
	self.i_window = self.gsz
	self.i_start = 0
	self.i_end = self.i_start + self.i_window
        # plot the data as a line series, and save the reference 
        # to the plotted line series
        #
        self.plot_data = self.axes.plot(
             [], 
             linewidth=1,
             color=(1, 1, 0),
             )[0]

     
    def draw_plot(self,event):
         """ Redraws the plot
         """
	 if len(list(self.q.queue))>1 and not self.paused:

             if self.zoom:
                 xmax = len(list(self.q.queue)) if len(list(self.q.queue)) > 50 else 50
               
                 xmin = xmax - 50
                 # for ymin and ymax, find the minimal and maximal values
                 # in the data set and add a mininal margin.
                 # 
                 # note that it's easy to change this scheme to the 
                 # minimal/maximal value in the current display, and not
                 # the whole data set.
                 # 
                 ymin = round(min(list(self.q.queue)), 0) - 1
            
                 ymax = round(max(list(self.q.queue)), 0) + 1

                 self.axes.set_xbound(lower=xmin, upper=xmax)
                 self.axes.set_ybound(lower=ymin, upper=ymax)
           
                 # anecdote: axes.grid assumes b=True if any other flag is
                 # given even if b is set to False.
                 # so just passing the flag into the first statement won't
                 # work.
                 #
                 if self.cb_grid.IsChecked():
                     self.axes.grid(True, color='gray')
                 else:
                     self.axes.grid(False)

                 # Using setp here is convenient, because get_xticklabels
                 # returns a list over which one needs to explicitly 
                 # iterate, and setp already handles this.
                 #  
                 pylab.setp(self.axes.get_xticklabels(), 
                 visible=self.cb_xlab.IsChecked())

            
                 self.plot_data.set_xdata(np.arange(len(list(self.q.queue))))
                 self.plot_data.set_ydata(np.array(list(self.q.queue)))
                 self.canvas.draw()
        	
             else: 
    	         if self.cb_grid.IsChecked():
    	             self.axes.grid(True, color='gray')
    	         else:
            	     self.axes.grid(False)

           		 # Using setp here is convenient, because get_xticklabels
            	 # returns a list over which one needs to explicitly 
    	         # iterate, and setp already handles this.

    	         pylab.setp(self.axes.get_xticklabels(), 
            	 visible=self.cb_xlab.IsChecked())
    		 
    	         self.plot_data.set_xdata(np.arange(len(list(self.q.queue)))[self.i_start:self.i_end])
            	 self.plot_data.set_ydata(np.array(list(self.q.queue))[self.i_start:self.i_end])
    		 self.axes.set_xlim(min(np.arange(len(list(self.q.queue)))[self.i_start:self.i_end]),max(np.arange(len(list(self.q.queue)))[self.i_start:self.i_end]))
    #		 if self.zoom:
    	  	 self.axes.set_ylim(min(np.array(list(self.q.queue))),max(np.array(list(self.q.queue))))
    		 
    		 self.canvas.draw()


    
    def on_pause_button(self, event):
        self.paused = not self.paused
    
    def on_update_pause_button(self, event):
        label = "Resume" if self.paused else "Pause"
        self.pause_button.SetLabel(label)
    
    def on_cb_grid(self, event):
        self.draw_plot(0)
    
    def on_cb_xlab(self, event):
        self.draw_plot(0)
    
    def on_save_plot(self, event):
        file_choices = "PNG (*.png)|*.png"
        
        dlg = wx.FileDialog(
            self, 
            message="Save plot as...",
            defaultDir=os.getcwd(),
            defaultFile="plot.png",
            wildcard=file_choices,
            style=wx.SAVE)
        
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.canvas.print_figure(path, dpi=self.dpi)
            self.flash_status_message("Saved to %s" % path)
    
    def on_redraw_timer(self, event):
        # if paused do not add data, but still redraw the plot
        # (to respond to scale modifications, grid change, etc.)
        #
        if not self.paused:
            self.data += self.datagen.next()
        self.draw_plot(0)

    
    def on_exit(self, event):
        self.Destroy()
    
    def flash_status_message(self, msg, flash_len_ms=1500):
        self.statusbar.SetStatusText(msg)
        self.timeroff = wx.Timer(self)
        self.Bind(
            wx.EVT_TIMER, 
            self.on_flash_status_off, 
            self.timeroff)
        self.timeroff.Start(flash_len_ms, oneShot=True)
    
    def on_flash_status_off(self, event):
        self.statusbar.SetStatusText('')
Example #28
0
class Canvas_2DSDC:

    def __init__(self,ui,W_matrix,N,dx,title="Source 2D SDC"):

        #=======================================================================
        # Adding Tab to UI
        #=======================================================================
        ui.list_of_tabs.append(QtWidgets.QWidget())
        ui.list_of_tabs[-1].setObjectName("tab_plotSDC2D")

        # gridlayout TAB SourceImag
        ui.list_grid_tabs.append(QtWidgets.QGridLayout(ui.list_of_tabs[-1]))
        ui.list_grid_tabs[-1].setObjectName("gridLayout_TabSDC2D")
        #_______________________________________________________________________


        #=======================================================================
        # Scroll Area SDC Points
        #=======================================================================
        self.scrollArea_points = QtWidgets.QScrollArea(ui.list_of_tabs[-1])
        self.scrollArea_points.setWidgetResizable(True)
        self.scrollArea_points.setObjectName("scrollArea_points")
        self.scrollArea_points.setPalette(palette_scrollPlotProp)

        self.scrollAreaWidgetContents_points = QtWidgets.QWidget()
        self.scrollAreaWidgetContents_points.setObjectName("scrollAreaWidgetContents_points")
        self.scrollArea_points.setWidget(self.scrollAreaWidgetContents_points)

        self.gridLayout_points = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_points)
        self.gridLayout_points.setObjectName("gridLayout_points")

        ui.list_grid_tabs[-1].addWidget(self.scrollArea_points, 1, 0, 1, 2)
        #_______________________________________________________________________


        #=======================================================================
        # Button update point
        #=======================================================================
        self.pushButton_updatePoint = QtWidgets.QPushButton(ui.list_of_tabs[-1])
        self.pushButton_updatePoint.setPalette(palette_buttonStart)
        self.pushButton_updatePoint.setFont(font_button)
        self.pushButton_updatePoint.setObjectName("pushButton_updatePoint")
        self.gridLayout_points.addWidget(self.pushButton_updatePoint, 2, 8, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.pushButton_updatePoint.setMinimumWidth(ui.rect.width()/8)
        self.pushButton_updatePoint.setText("Update Point")
        self.pushButton_updatePoint.clicked.connect(self.change_point)
        #_______________________________________________________________________


        # Scroll Area Source Image
        self.scrollArea_sourceSDC = QtWidgets.QScrollArea(ui.list_of_tabs[-1])
        self.scrollArea_sourceSDC.setPalette(palette_scrollPlotProp)
        self.scrollArea_sourceSDC.setWidgetResizable(True)
        self.scrollArea_sourceSDC.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtWidgets.QSizePolicy.Minimum)
        self.scrollArea_sourceSDC.setObjectName("scrollArea_sourceSDC2D")

        # Scroll Area Options prop
        self.scrollArea_sourceSDCOpt = QtWidgets.QScrollArea(ui.list_of_tabs[-1])
        self.scrollArea_sourceSDCOpt.setWidgetResizable(True)
        self.scrollArea_sourceSDCOpt.setObjectName("scrollArea_2DSDC")
        self.scrollArea_sourceSDCOpt.setPalette(palette_scrollPlotProp)

        self.scrollAreaWidgetContents_sourceSDCOpt = QtWidgets.QWidget()
        self.scrollAreaWidgetContents_sourceSDCOpt.setObjectName("scrollAreaWidgetContents_sourceSDCOpt")
        self.scrollArea_sourceSDCOpt.setWidget(self.scrollAreaWidgetContents_sourceSDCOpt)

        self.gridLayout_sourceSDCOpt = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_sourceSDCOpt)
        self.gridLayout_sourceSDCOpt.setObjectName("gridLayout_sourceSDCOpt")

        ui.list_grid_tabs[-1].addWidget(self.scrollArea_sourceSDC, 3, 0, 1, 1)
        ui.list_grid_tabs[-1].addWidget(self.scrollArea_sourceSDCOpt, 10, 0, 1, 1)

        # Scroll Area Source SDC Phase
        self.scrollArea_sourceSDC_phase = QtWidgets.QScrollArea(ui.list_of_tabs[-1])
        self.scrollArea_sourceSDC_phase.setPalette(palette_scrollPlotProp)
        self.scrollArea_sourceSDC_phase.setWidgetResizable(True)
        self.scrollArea_sourceSDC_phase.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtWidgets.QSizePolicy.Minimum)
        self.scrollArea_sourceSDC_phase.setObjectName("scrollArea_sourceSDC_phase")

        # Scroll Area Options Source SDC Phase
        self.scrollArea_sourceSDCOpt_phase = QtWidgets.QScrollArea(ui.list_of_tabs[-1])
        self.scrollArea_sourceSDCOpt_phase.setWidgetResizable(True)
        self.scrollArea_sourceSDCOpt_phase.setObjectName("scrollArea_propImageOpt_phase")
        self.scrollArea_sourceSDCOpt_phase.setPalette(palette_scrollPlotProp)

        self.scrollAreaWidgetContents_sourceSDCOpt_phase = QtWidgets.QWidget()
        self.scrollAreaWidgetContents_sourceSDCOpt_phase.setObjectName("scrollAreaWidgetContents_sourceSDCOpt_phase")
        self.scrollArea_sourceSDCOpt_phase.setWidget(self.scrollAreaWidgetContents_sourceSDCOpt_phase)

        self.gridLayout_sourceSDCOpt_phase = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_sourceSDCOpt_phase)
        self.gridLayout_sourceSDCOpt_phase.setObjectName("gridLayout_sourceSDCOpt_phase")

        ui.list_grid_tabs[-1].addWidget(self.scrollArea_sourceSDC_phase, 3, 1, 1, 1)
        ui.list_grid_tabs[-1].addWidget(self.scrollArea_sourceSDCOpt_phase, 10, 1, 1, 1)
        #_______________________________________________________________________


        #=======================================================================
        # Parameters
        #=======================================================================
        # N
        self.N = N

        # spatial resolution
        self.dx = dx

        # W matrix
        self.W_matrix = W_matrix

        # User interface
        self.ui = ui

        # title
        self.title = title

        # parent
        self.parent       = self.scrollArea_sourceSDC
        self.parent_phase = self.scrollArea_sourceSDC_phase

        # parent optioncs
        self.parentOptions       = self.scrollArea_sourceSDCOpt
        self.parentOptions_phase = self.scrollArea_sourceSDCOpt_phase

        # grid parent options
        self.gridOptions       = self.gridLayout_sourceSDCOpt
        self.gridOptions_phase = self.gridLayout_sourceSDCOpt_phase

        # first plot
        self.first_plot = False
        #_______________________________________________________________________

        # Initial points (middle)
        self.P1x = int(N/2)
        self.P1y = int(N/2)

        self.build_fig()


    def build_fig(self):

        #=======================================================================
        # Create the mpl Figure and FigCanvas objects.
        #=======================================================================
        # magnitude
        self.dpi = 100
        self.fig = Figure((5.0, 4.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)

        # phase
        self.dpi_phase = 100
        self.fig_phase = Figure((5.0, 4.0), dpi=self.dpi_phase)
        self.canvas_phase = FigureCanvas(self.fig_phase)

        # axes
        self.axes = self.fig.add_subplot(111)
        self.axes_phase = self.fig_phase.add_subplot(111)
        #_______________________________________________________________________


        #=======================================================================
        # Plotting 2D figure and configuring
        #=======================================================================
        self.SDC2D_real  = self.W_matrix[self.P1x,self.P1y].real
        self.SDC2D_imag  = self.W_matrix[self.P1x,self.P1y].imag

        self.SDC2D_mag = zeros((self.N,self.N),dtype=float)
        S1 = abs(self.W_matrix[self.P1x,self.P1y,self.P1x,self.P1y].real)
        for i in range(0,self.N):
            for j in range(0,self.N):
                if self.W_matrix[self.P1x,self.P1y,self.P1x,self.P1y].real!=0.0 and self.W_matrix[i,j,i,j].real!=0.0:
                    S2 = abs(self.W_matrix[i,j,i,j].real)
                    self.SDC2D_mag[i,j] = sqrt(self.W_matrix[self.P1x,self.P1y,i,j].real**2+self.W_matrix[self.P1x,self.P1y,i,j].imag**2)/(sqrt(S1)*sqrt(S2))
                else:
                    self.SDC2D_mag[i,j]=0.0

        #self.SDC2D_mag = abs(sqrt(temp.real**2+temp.imag**2))

        #self.SDC2D_mag   = sqrt(self.W_matrix[self.P1x,self.P1y].real**2+self.W_matrix[self.P1x,self.P1y].imag**2)

        self.SDC2D_phase = abs(angle(self.W_matrix[self.P1y,self.P1y]))

        # xy array
        self.x_array = arange(0,self.N,1,dtype=float32)
        self.x_array -= int(self.N/2)
        self.x_array *= self.dx

        # PLOT magnitude
        self.im = self.axes.pcolormesh(self.x_array,self.x_array,self.SDC2D_mag,shading="auto")
        self.cbar = self.fig.colorbar(self.im)

        # PLOT phase
        self.im_phase = self.axes_phase.pcolormesh(self.x_array,self.x_array,self.SDC2D_phase,shading="auto")
        self.cbar_phase = self.fig_phase.colorbar(self.im_phase)

        # font size
        self.fsize = 12
        self.fsize_phase = 12

        # x,y Labels
        self.axes.set_xlabel("x (m)",fontsize = self.fsize)
        self.axes.set_ylabel("y (m)",fontsize = self.fsize)
        #_______________________________________________________________________


        #=======================================================================
        # Tool bar
        #=======================================================================

        # Bind the 'pick' event for clicking on one of the bars
        self.canvas.mpl_connect('pick_event', self.ui.on_pick) #self.canvas.mpl_connect("scroll_event", ui.scrolling)
        # Bind the 'pick' event for clicking on one of the bars
        self.canvas_phase.mpl_connect('pick_event', self.ui.on_pick) #self.canvas.mpl_connect("scroll_event", ui.scrolling)

        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.parent)
        self.mpl_toolbar_phase = NavigationToolbar(self.canvas_phase, self.parent_phase)

        #ui.gridLayout_TabPropImage.addWidget(self.mpl_toolbar, 2, 0, 1, 3)
        self.ui.list_grid_tabs[-1].addWidget(self.mpl_toolbar, 8, 0, 1, 3,alignment=QtCore.Qt.AlignLeft)
        self.ui.list_grid_tabs[-1].addWidget(self.mpl_toolbar_phase, 8, 1, 1, 3,alignment=QtCore.Qt.AlignLeft)

        #_______________________________________________________________________


        #=======================================================================
        # Canvas in Scroll Area - magnitude
        #=======================================================================

        #self.canvas.draw()
        #self.canvas.setParent(parent)
        self.canvas.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtWidgets.QSizePolicy.Minimum)

        # Container for VBOX
        self.containerGraph = QWidget(self.parent)
        self.containerGraph.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtWidgets.QSizePolicy.Minimum)

        self.containerGraph.setMinimumWidth(self.canvas.width())
        self.containerGraph.setMinimumHeight(self.canvas.height())

        self.containerGraph.setMaximumWidth(self.canvas.width()+5)
        self.containerGraph.setMaximumHeight(self.canvas.height()+5)

        # VBOX for canvas
        self.vbox = QVBoxLayout(self.containerGraph)
        #self.vbox.setGeometry(QRect(0, 0, self.canvas.width(), self.canvas.height()))
        self.vbox.addWidget(self.canvas)

        self.parent.setWidget(self.containerGraph)

        #_______________________________________________________________________


        #=======================================================================
        # Canvas in Scroll Area - phase
        #=======================================================================
        self.canvas_phase.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtWidgets.QSizePolicy.Minimum)

        # Container for VBOX
        self.containerGraph_phase = QWidget(self.parent_phase)
        self.containerGraph_phase.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtWidgets.QSizePolicy.Minimum)

        self.containerGraph_phase.setMinimumWidth(self.canvas_phase.width())
        self.containerGraph_phase.setMinimumHeight(self.canvas_phase.height())

        self.containerGraph_phase.setMaximumWidth(self.canvas_phase.width()+5)
        self.containerGraph_phase.setMaximumHeight(self.canvas_phase.height()+5)

        # VBOX for canvas
        self.vbox_phase = QVBoxLayout(self.containerGraph_phase)
        #self.vbox.setGeometry(QRect(0, 0, self.canvas.width(), self.canvas.height()))
        self.vbox_phase.addWidget(self.canvas_phase)

        self.parent_phase.setWidget(self.containerGraph_phase)
        #_______________________________________________________________________



        if not self.first_plot:
            self.figure_options()
            self.figure_options_phase()
            self.first_plot = True






    def figure_options(self):

        # label Point P1x
        self.label_P1x = QtWidgets.QLabel(self.parentOptions)
        self.label_P1x.setObjectName("label_P1x")
        self.label_P1x.setText("x_1, y_1:")
        self.gridLayout_points.addWidget(self.label_P1x, 2, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit Point P1x
        self.lineEdit_P1x = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_P1x.setObjectName("lineEdit_P1x")
        self.gridLayout_points.addWidget(self.lineEdit_P1x,2, 2, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_P1x.setText(str(int(self.N/2)))
        #self.lineEdit_P1x.textChanged.connect(self.change_P1x)

        # line edit Point P1x
        self.lineEdit_P1y = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_P1y.setObjectName("lineEdit_P1y")
        self.gridLayout_points.addWidget(self.lineEdit_P1y,2, 4, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_P1y.setText(str(int(self.N/2)))
        #self.lineEdit_P1y.textChanged.connect(self.change_P1y)

        # label title
        self.label_title = QtWidgets.QLabel(self.parentOptions)
        self.label_title.setObjectName("label_title")
        self.label_title.setText("Title")
        self.gridOptions.addWidget(self.label_title, 6, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit title label
        self.lineEdit_title = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_title.setObjectName("lineEdit_title")
        self.lineEdit_title.textChanged.connect(self.change_title)
        self.gridOptions.addWidget(self.lineEdit_title,6, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_title.setText(self.title+" Magnitude")
        self.change_title()

        # label x
        self.label_x = QtWidgets.QLabel(self.parentOptions)
        self.label_x.setObjectName("label_x")
        self.label_x.setText("Label x-axis")
        self.gridOptions.addWidget(self.label_x, 8, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit x label
        self.lineEdit_xLabel = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_xLabel.setObjectName("lineEdit_xlabel")
        self.lineEdit_xLabel.textChanged.connect(self.change_labelx)
        self.gridOptions.addWidget(self.lineEdit_xLabel,8, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.change_labelx()
        self.lineEdit_xLabel.setText("x")

        # label y
        self.label_y = QtWidgets.QLabel(self.parentOptions)
        self.label_y.setObjectName("label_y")
        self.label_y.setText("Label y-axis")
        self.gridOptions.addWidget(self.label_y, 10, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit y label
        self.lineEdit_yLabel = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_yLabel.setObjectName("lineEdit_ylabel")
        self.lineEdit_yLabel.textChanged.connect(self.change_labely)
        self.gridOptions.addWidget(self.lineEdit_yLabel,10, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.change_labely()
        self.lineEdit_yLabel.setText("y")

        # label xlim
        self.label_xlim = QtWidgets.QLabel(self.parentOptions)
        self.label_xlim.setObjectName("label_xlim")
        self.label_xlim.setText("xlim")
        self.gridOptions.addWidget(self.label_xlim, 12, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit xlim
        self.lineEdit_xlim = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_xlim.setObjectName("lineEdit_ylabel")
        self.lineEdit_xlim.textChanged.connect(self.change_xlim)
        self.gridOptions.addWidget(self.lineEdit_xlim,12, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_xlim.setText("(_,_)")
        self.change_xlim()

        # label ylim
        self.label_ylim = QtWidgets.QLabel(self.parentOptions)
        self.label_ylim.setObjectName("label_ylim")
        self.label_ylim.setText("ylim")
        self.gridOptions.addWidget(self.label_ylim, 14, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit ylim
        self.lineEdit_ylim = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_ylim.setObjectName("lineEdit_ylabel")
        self.lineEdit_ylim.textChanged.connect(self.change_ylim)
        self.gridOptions.addWidget(self.lineEdit_ylim,14, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_ylim.setText("(_,_)")
        self.change_ylim()

        # label cmap
        self.label_cmap = QtWidgets.QLabel(self.parentOptions)
        self.label_cmap.setObjectName("label_cmap")
        self.label_cmap.setText("Color Map")
        self.gridOptions.addWidget(self.label_cmap, 20, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit cmap
        self.lineEdit_cmap = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_cmap.setObjectName("lineEdit_cmap")
        self.lineEdit_cmap.textChanged.connect(self.change_cmap)
        self.gridOptions.addWidget(self.lineEdit_cmap,20, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_cmap.setText("hot")
        self.change_cmap()

        # label Font Size
        self.label_fsize = QtWidgets.QLabel(self.parentOptions)
        self.label_fsize.setObjectName("label_fsize")
        self.label_fsize.setText("Font Size")
        self.gridOptions.addWidget(self.label_fsize, 22, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit font size
        self.lineEdit_fsize = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_fsize.setObjectName("label_fsize")
        self.lineEdit_fsize.textChanged.connect(self.change_fsize)
        self.gridOptions.addWidget(self.lineEdit_fsize,22, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_fsize.setText(str(self.fsize))
        self.change_fsize()

        # label DPI
        self.label_dpi = QtWidgets.QLabel(self.parentOptions)
        self.label_dpi.setObjectName("label_dpi")
        self.label_dpi.setText("dpi (100-500)")
        self.gridOptions.addWidget(self.label_dpi, 24, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit DPI
        self.lineEdit_dpi = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_dpi.setObjectName("label_dpi")
        self.lineEdit_dpi.textChanged.connect(self.change_dpi)
        self.gridOptions.addWidget(self.lineEdit_dpi,24, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_dpi.setText(str(self.dpi))
        self.change_fsize()
        #_______________________________________________________________________




    def figure_options_phase(self):
        try:
            # label title_phase
            self.label_title_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_title_phase.setObjectName("label_title")
            self.label_title_phase.setText("Title")
            self.gridOptions_phase.addWidget(self.label_title_phase, 6, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

            # line edit title label_phase
            self.lineEdit_title_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_title_phase.setObjectName("lineEdit_title_phase")
            self.lineEdit_title_phase.textChanged.connect(self.change_title_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_title_phase,6, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_title_phase.setText(self.title+" Phase")
            self.change_title_phase()

            # label x_phase
            self.label_x_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_x_phase.setObjectName("label_xv")
            self.label_x_phase.setText("Label x-axis")
            self.gridOptions_phase.addWidget(self.label_x_phase, 8, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

            # line edit x label_phase_phase
            self.lineEdit_xLabel_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_xLabel_phase.setObjectName("lineEdit_xlabel_phase")
            self.lineEdit_xLabel_phase.textChanged.connect(self.change_labelx_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_xLabel_phase,8, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
            self.change_labelx_phase()
            self.lineEdit_xLabel_phase.setText("x")

            # label y_phase
            self.label_y_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_y_phase.setObjectName("label_y_phase")
            self.label_y_phase.setText("Label y-axis")
            self.gridOptions_phase.addWidget(self.label_y_phase, 10, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

            # line edit y label_phase
            self.lineEdit_yLabel_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_yLabel_phase.setObjectName("lineEdit_ylabel_phase")
            self.lineEdit_yLabel_phase.textChanged.connect(self.change_labely_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_yLabel_phase,10, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
            self.change_labely_phase()
            self.lineEdit_yLabel_phase.setText("y")

            # label xlim_phase
            self.label_xlim_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_xlim_phase.setObjectName("label_xlim_phase")
            self.label_xlim_phase.setText("xlim")
            self.gridOptions_phase.addWidget(self.label_xlim_phase, 12, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

            # line edit xlim_phase
            self.lineEdit_xlim_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_xlim_phase.setObjectName("lineEdit_ylabel_phase")
            self.lineEdit_xlim_phase.textChanged.connect(self.change_xlim_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_xlim_phase,12, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_xlim_phase.setText("(_,_)")
            self.change_xlim_phase()

            # label ylim_phase
            self.label_ylim_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_ylim_phase.setObjectName("label_ylim_phase")
            self.label_ylim_phase.setText("ylim")
            self.gridOptions_phase.addWidget(self.label_ylim_phase, 14, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

            # line edit ylim_phase
            self.lineEdit_ylim_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_ylim_phase.setObjectName("lineEdit_ylabel_phase")
            self.lineEdit_ylim_phase.textChanged.connect(self.change_ylim_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_ylim_phase,14, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_ylim_phase.setText("(_,_)")
            self.change_ylim_phase()

            # label cmap_phase
            self.label_cmap_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_cmap_phase.setObjectName("label_cmap_phase")
            self.label_cmap_phase.setText("Color Map")
            self.gridOptions_phase.addWidget(self.label_cmap_phase, 20, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

            # line edit cmap_phase
            self.lineEdit_cmap_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_cmap_phase.setObjectName("lineEdit_cmap_phase")
            self.lineEdit_cmap_phase.textChanged.connect(self.change_cmap_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_cmap_phase,20, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_cmap_phase.setText("hot")
            self.change_cmap_phase()

            # label Font Size_phase
            self.label_fsize_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_fsize_phase.setObjectName("label_fsize")
            self.label_fsize_phase.setText("Font Size")
            self.gridOptions_phase.addWidget(self.label_fsize_phase, 22, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

            # line edit font size_phase
            self.lineEdit_fsize_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_fsize_phase.setObjectName("label_fsize_phase")
            self.lineEdit_fsize_phase.textChanged.connect(self.change_fsize)
            self.gridOptions_phase.addWidget(self.lineEdit_fsize_phase,22, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_fsize_phase.setText(str(self.fsize))
            self.change_fsize_phase()

            # label DPI_phase
            self.label_dpi_phase = QtWidgets.QLabel(self.parentOptions)
            self.label_dpi_phase.setObjectName("label_dpi_phase")
            self.label_dpi_phase.setText("dpi (100-500)")
            self.gridOptions_phase.addWidget(self.label_dpi_phase, 24, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

            # line edit DPI_phase
            self.lineEdit_dpi_phase = QtWidgets.QLineEdit(self.parentOptions)
            self.lineEdit_dpi_phase.setObjectName("label_dpi_phase")
            self.lineEdit_dpi_phase.textChanged.connect(self.change_dpi_phase)
            self.gridOptions_phase.addWidget(self.lineEdit_dpi_phase,24, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
            self.lineEdit_dpi_phase.setText(str(self.dpi_phase))
            self.change_fsize_phase()
            #_______________________________________________________________________

        except Exception as error:
            self.ui.update_outputText(str(error))


    def change_point(self):

        try:
            P1x = int(self.lineEdit_P1x.text())
            P1y = int(self.lineEdit_P1y.text())

            if P1x>=0 and P1x<self.N:
                if P1y>=0 and P1y<self.N:
                    # defining points
                    self.P1x = P1x
                    self.P1y = P1y

                    self.update_pcolor()
                    self.update_draw()
                    #self.fig.canvas.flush_events()


        except Except as error:
            self.ui.update_outputText("Insert valid points.")
            #if debug:
                #self.ui.update_outputText(str(error)+" at <windowPlot_propSDC> in <change_point> function.")



    def update_pcolor(self):
        try:
            # creating image prop
            #self.SDC2D_mag   = sqrt(self.W_matrix[self.P1x,self.P1y].real**2+self.W_matrix[self.P1x,self.P1y].imag**2)

            self.SDC2D_mag = zeros((self.N,self.N),dtype=float)
            S1 = abs(self.W_matrix[self.P1x,self.P1y,self.P1x,self.P1y].real)

            for i in range(0,self.N):
                for j in range(0,self.N):
                    if self.W_matrix[self.P1x,self.P1y,self.P1x,self.P1y].real!=0.0 and self.W_matrix[i,j,i,j].real!=0.0:
                        S2 = abs(self.W_matrix[i,j,i,j].real)
                        self.SDC2D_mag[i,j] = sqrt(self.W_matrix[self.P1x,self.P1y,i,j].real**2+self.W_matrix[self.P1x,self.P1y,i,j].imag**2)/sqrt(S1*S2)
                    else:
                        self.SDC2D_mag[i,j]=0.0



            self.SDC2D_phase = abs(angle(self.W_matrix[self.P1y,self.P1y]))


            self.im.set_array(self.SDC2D_mag[:-1,:-1].ravel())
            self.im_phase.set_array(self.SDC2D_phase[:-1,:-1].ravel())
            self.update_draw()

        except Exception as error:
            self.ui.update_outputText(str(error))

    def update_draw(self):
        self.canvas.draw()
        self.canvas.updateGeometry()
        self.canvas_phase.draw()
        self.canvas_phase.updateGeometry()




    #===========================================================================
    # Magnitude
    #===========================================================================
    def change_dpi(self):
        try:
            new = int(self.lineEdit_dpi.text())
            if new>=100 and new<=500:
                self.dpi = new
                self.fig.set_dpi(new)
                self.update_draw()
        except:
            pass

    def change_fsize(self):
        try:
            self.fsize = int(self.lineEdit_fsize.text())
            self.change_title()
            self.change_labelx()
            self.change_labely()
            self.update_draw()

        except Exception as error:
            pass #self.ui.update_outputText(error)


    def change_cmap(self):
        try:
            self.im.set_cmap(self.lineEdit_cmap.text())
            self.canvas.draw()
        except Exception as error:
            pass
            #self.ui.update_outputText(error)


    def change_xlim(self):
        try:
            temp_txt = self.lineEdit_xlim.text()
            Ntxt     = len(temp_txt)
            numList = []
            if temp_txt[0]=="(" and temp_txt[-1]==")":
                actual=""
                for i in range(1,Ntxt-1):
                    if temp_txt[i] == ",":
                        numList.append(float(actual))
                        actual = ""
                    elif i==Ntxt-2:
                        actual+=temp_txt[i]
                        numList.append(float(actual))
                    else:
                        actual+=temp_txt[i]
            self.axes.set_xlim(numList[0],numList[1])
        except Exception as error:
            pass
            #self.ui.update_outputText(error)

    def change_ylim(self):
        try:
            temp_txt = self.lineEdit_ylim.text()
            Ntxt     = len(temp_txt)
            numList = []
            if temp_txt[0]=="(" and temp_txt[-1]==")":
                actual=""
                for i in range(1,Ntxt-1):
                    if temp_txt[i] == ",":
                        numList.append(float(actual))
                        actual = ""
                    elif i==Ntxt-2:
                        actual+=temp_txt[i]
                        numList.append(float(actual))
                    else:
                        actual+=temp_txt[i]
            self.axes.set_ylim(numList[0],numList[1])
            self.canvas.draw()
        except Exception as error:
            pass
            #self.ui.update_outputText(error)

    def change_title(self):
        try:
            self.axes.set_title(self.lineEdit_title.text(),fontsize = self.fsize)
            self.canvas.draw()
            ##self.title = str(self.lineEdit_title.text())
        except:
            pass

    def change_labelx(self):
        if self.lineEdit_xLabel.text()=="":
            self.axes.set_xlabel("")
        else:
            try:
                self.axes.set_xlabel(self.lineEdit_xLabel.text(),fontsize = self.fsize)
                self.canvas.draw()
            except Exception as error:

                self.ui.update_outputText(str(error))

    def change_labely(self):
        if self.lineEdit_yLabel.text()=="":
            self.axes.set_ylabel("")
        else:
            try:
                self.axes.set_ylabel(self.lineEdit_yLabel.text(),fontsize = self.fsize)
                self.canvas.draw()
            except:
                pass
                #self.ui.update_outputText("Unable to update y-label.")

    #___________________________________________________________________________


    #===========================================================================
    # Phase
    #===========================================================================
    try:
        def change_dpi_phase(self):
            try:
                new = int(self.lineEdit_dpi_phase.text())
                if new>=100 and new<=500:
                    self.dpi_phase = new
                    self.fig_phase.set_dpi(new)
                    self.update_draw()
            except:
                pass

        def change_fsize_phase(self):
            try:
                self.fsize_phase = int(self.lineEdit_fsize.text())
                self.change_title_phase()
                self.change_labelx_phase()
                self.change_labely_phase()
                self.update_draw()

            except Exception as error:
                pass #self.ui.update_outputText(error)


        def change_cmap_phase(self):
            try:
                self.im_phase.set_cmap(self.lineEdit_cmap_phase.text())
                self.canvas_phase.draw()
            except Exception as error:
                pass
                #self.ui.update_outputText(error)


        def change_xlim_phase(self):
            try:
                temp_txt = self.lineEdit_xlim_phase.text()
                Ntxt     = len(temp_txt)
                numList = []
                if temp_txt[0]=="(" and temp_txt[-1]==")":
                    actual=""
                    for i in range(1,Ntxt-1):
                        if temp_txt[i] == ",":
                            numList.append(float(actual))
                            actual = ""
                        elif i==Ntxt-2:
                            actual+=temp_txt[i]
                            numList.append(float(actual))
                        else:
                            actual+=temp_txt[i]
                self.axes_phase.set_xlim(numList[0],numList[1])
            except Exception as error:
                pass
                #self.ui.update_outputText(error)

        def change_ylim_phase(self):
            try:
                temp_txt = self.lineEdit_ylim_phase.text()
                Ntxt     = len(temp_txt)
                numList = []
                if temp_txt[0]=="(" and temp_txt[-1]==")":
                    actual=""
                    for i in range(1,Ntxt-1):
                        if temp_txt[i] == ",":
                            numList.append(float(actual))
                            actual = ""
                        elif i==Ntxt-2:
                            actual+=temp_txt[i]
                            numList.append(float(actual))
                        else:
                            actual+=temp_txt[i]
                self.axes_phase.set_ylim(numList[0],numList[1])
                self.canvas.draw()
            except Exception as error:
                pass
                #self.ui.update_outputText(error)

        def change_title_phase(self):
            try:
                self.axes_phase.set_title(self.lineEdit_title_phase.text(),fontsize = self.fsize_phase)
                self.canvas_phase.draw()
            except:
                pass

        def change_labelx_phase(self):
            if self.lineEdit_xLabel_phase.text()=="":
                self.axes_phase.set_xlabel("")
            else:
                try:
                    self.axes_phase.set_xlabel(self.lineEdit_xLabel_phase.text(),fontsize = self.fsize_phase)
                    self.canvas_phase.draw()
                except Exception as error:
                    self.ui.update_outputText(str(error))

        def change_labely_phase(self):
            if self.lineEdit_yLabel_phase.text()=="":
                self.axes_phase.set_ylabel("")
            else:
                try:
                    self.axes_phase.set_ylabel(self.lineEdit_yLabel_phase.text(),fontsize = self.fsize_phase)
                    self.canvas_phase.draw()
                except:
                    pass
                    #self.ui.update_outputText("Unable to update y-label.")

    except Exception as error:
        self.ui.update_outputText(error)
    #___________________________________________________________________________


#===============================================================================
#///////////////////////////////////////////////////////////////////////////////
#===============================================================================
Example #29
0
class BaseVisualizer(object):
    visualizer_name = _('Base Visualizer')

    def __init__(self, canvas_panel, data, parent_frame):
        trigger(events.EVENT_VISUALIZER_DRAW, visualizer=self)
        self.conf = app_config

        # variables section
        self.canvas_panel = canvas_panel
        self.data = data
        self.processed_data = None
        self.frame = parent_frame
        self.events = app_events
        self.plots = []
        self.vline = []

        # calculate data
        self.process()

        # prepare canvas
        self.canvas_width, self.canvas_height = self.canvas_panel.Size
        figsize = (float(self.canvas_width) / self.conf.draw_dpi, self.conf.draw_figure_height * len(self.data))
        self.fig = Figure(
            dpi=self.conf.draw_dpi,
            facecolor=self.conf.draw_facecolor,
            figsize=figsize
        )
        self.canvas = FigCanvas(self.canvas_panel, -1, self.fig)

        # display controls
        self.draw()

        # bind events
        self.canvas_panel.Bind(wx.EVT_SIZE, self.evt_on_resize_panel)
        on(events.EVENT_VISUALIZER_DRAW, self.on_any_visualizer_draw)
        self.conf.on(events.EVENT_CHANGED_PARAMETER_key('draw_*'), self.on_config_changed)
        self.on('button_press_event', self.on_button_press_event)
        self.on('motion_notify_event', self.on_motion_notify_event)

    def create_cursor(self):
        if self.plots:
            self.cursor = MultiCursor(self.fig.canvas, self.plots, color=self.conf.draw_dynamic_cursor_color, lw=1)
            self.cursor.val_texts = []
            for i, plot in enumerate(self.plots):
                val_text = plot.text(0.15, 1.04, '', transform=plot.transAxes, fontsize=9, color=self.conf.draw_dynamic_cursor_color)
                val_text.plot = plot
                val_text.data = self.processed_data[i]
                self.cursor.val_texts.append(val_text)

    def create_vline(self):
        for i, plot in enumerate(self.plots):
            line = plot.axvline(color=self.conf.draw_static_cursor_color)
            line.plot = plot
            line.data = self.processed_data[i]
            line.val_text = plot.text(0.05, 1.04, '', transform=plot.transAxes, fontsize=9, color=self.conf.draw_static_cursor_color)
            self.vline.append(line)

    def on(self, event, func):
        """ Canvas events """
        self.fig.canvas.mpl_connect(event, func)

    def on_any_visualizer_draw(self, visualizer):
        if visualizer is not self:
            self.clear()
            self.conf.off(events.EVENT_CHANGED_PARAMETER_key('draw_*'), [self.on_config_changed])

    def on_config_changed(self, key, value):
        if key in ('draw_position', 'draw_page_size'):
            self.update_plots()
        elif key in ('draw_dpi', 'draw_figure_height', 'draw_facecolor'):
            self.update_figure()
        elif key == 'draw_static_cursor_color':
            for line in self.vline:
                line.set_color(value)
            self.canvas.draw()
        elif key == 'draw_dynamic_cursor_color':
            for line in self.cursor.lines:
                line.set_color(value)
            self.canvas.draw()

    def on_button_press_event(self, event):
        self.update_vline(event)
        if event.inaxes is not None and self.canvas.widgetlock.available(self):
            self.events.trigger(events.EVENT_VISUALIZER_STATIC_CURSOR_CHANGED, plot_event=event, data=self.processed_data)

    def on_motion_notify_event(self, event):
        self.update_cursor_label(event)
        if event.inaxes is not None and self.canvas.widgetlock.available(self):
            self.events.trigger(events.EVENT_VISUALIZER_DYNAMIC_CURSOR_CHANGED, plot_event=event, data=self.processed_data)

    def evt_on_resize_panel(self, event):
        cur_width = self.canvas_panel.Size[0]
        if self.canvas_width != cur_width:
            self.canvas_width = cur_width
            self.fig.set_figwidth(float(self.canvas_width) / self.conf.draw_dpi)
            self.canvas_panel.Refresh()
            self.canvas.draw()

    def _prepare_static_cursor_value(self, data, event):
        return '(%.3f, %.3f)' % (
            data.to_time(event.xdata),
            data.to_value(event.xdata))

    def update_vline(self, event):
        if event.inaxes:
            for line in self.vline:
                line.set_xdata(event.xdata)
                line.val_text.set_text(self._prepare_static_cursor_value(line.data, event))
            self.canvas.draw()

    def _prepare_dynamic_cursor_label(self, data, event):
        return '(%.3f, %.3f)' % (
            data.to_time(event.xdata),
            data.to_value(event.xdata))

    def update_cursor_label(self, event):
        if event.inaxes and False: #disabled
            for text in self.cursor.val_texts:
                text.set_text(self._prepare_dynamic_cursor_label(text.data, event))
            self.canvas.draw()

    def update_plots(self):
        position = self.conf.draw_position
        page_size = self.conf.draw_page_size
        frame = (position - page_size if position > page_size else 0,
                 position if position >= page_size else page_size)
        for plt in self.plots:
            plt.set_xlim(frame)
        self.canvas.draw()

    def update_figure(self):
        self.fig.set_dpi(self.conf.draw_dpi)
        self.fig.set_figheight(self.conf.draw_figure_height * len(self.data))
        self.fig.set_facecolor(self.conf.draw_facecolor)
        self.canvas_panel.SetBackgroundColour(self.conf.draw_facecolor)
        self.canvas_panel.Update()
        self.canvas.draw()

    def create_aux(self):
        self.create_cursor()
        self.create_vline()
        self.canvas.figure.tight_layout()
        self.canvas_panel.update_scroll(self.canvas.Size)

    def draw(self):
        """Visualizes calculated data"""

    def clear(self):
        """Clear canvas"""
        self.canvas.figure.clear()
        self.canvas.draw()

    def process(self):
        """Calculates needed information"""
        self.processed_data = self.data

    def print_figure(self, path):
        """Export canvas into the file ``path``"""
        self.canvas.print_figure(path, dpi=self.conf.draw_dpi)
Example #30
0
      (width_dpi, height_dpi))

# Pixel width and height of a character in the fixed-width font courier.
# Note that two chars gives you exactly twice what one char is.
my_font = tkf.Font(font='monospace', size=10)
pixel_width_per_char = my_font.measure("w")
pixel_height_per_char = my_font.metrics("linespace")

print('Pixel width per character: %f px, Pixel height per character: %f px' %
      (pixel_width_per_char, pixel_height_per_char))

# Figure size in inches
figure_size = (13, 6)

f = Figure()
f.set_dpi(96)
f.set_size_inches(figure_size[0], figure_size[1])

# a.text could add text to the figure.
a = f.add_subplot(111)
frame1 = f.gca()
frame1.axes.get_xaxis().set_visible(False)
frame1.axes.get_yaxis().set_visible(False)

# This we would input from the user, generally.
row_number = 16


def x_chars_to_xu(x_chars: float) -> float:
    """
    This function takes in a number of characters, and returns the
Example #31
0
class Chart(object):
    """
    Simple and clean facade to Matplotlib's plotting API.
    
    A chart instance abstracts a plotting device, on which one or
    multiple related plots can be drawn. Charts can be exported as images, or
    visualized interactively. Each chart instance will always open in its own
    GUI window, and this window will never block the execution of the rest of
    the program, or interfere with other L{Chart}s.
    The GUI can be safely opened in the background and closed infinite number
    of times, as long as the client program is still running.
    
    By default, a chart contains a single plot:
    
    >>> chart.plot
    matplotlib.axes.AxesSubplot
    >>> chart.plot.hist(...)
    
    If C{rows} and C{columns} are defined, the chart will contain
    C{rows} x C{columns} number of plots (equivalent to MPL's sub-plots).
    Each plot can be assessed by its index:
    
    >>> chart.plots[0]
    first plot
    
    or by its position in the grid:
    
    >>> chart.plots[0, 1]
    plot at row=0, column=1
    
    @param number: chart number; by default this a L{Chart.AUTONUMBER}
    @type number: int or None
    @param title: chart master title
    @type title: str
    @param rows: number of rows in the chart window
    @type rows: int
    @param columns: number of columns in the chart window
    @type columns: int
    
    @note: additional arguments are passed directly to Matplotlib's Figure
           constructor. 
    """

    AUTONUMBER = None
    
    _serial = 0
    
    
    def __init__(self, number=None, title='', rows=1, columns=1, backend=Backends.WX_WIDGETS, *fa, **fk):
        
        if number == Chart.AUTONUMBER:
            Chart._serial += 1
            number = Chart._serial
        
        if rows < 1:
            rows = 1
        if columns < 1:
            columns = 1
            
        self._rows = int(rows)
        self._columns = int(columns)
        self._number = int(number)
        self._title = str(title)
        self._figure = Figure(*fa, **fk)
        self._figure._figure_number = self._number
        self._figure.suptitle(self._title)
        self._beclass = backend
        self._hasgui = False
        self._plots = PlotsCollection(self._figure, self._rows, self._columns)        
        self._canvas = FigureCanvasAgg(self._figure)
        
        formats = [ (f.upper(), f) for f in self._canvas.get_supported_filetypes() ]
        self._formats = csb.core.Enum.create('OutputFormats', **dict(formats))
    
    def __getitem__(self, i):
        if i in self._plots:
            return self._plots[i]
        else:
            raise KeyError('No such plot number: {0}'.format(i))
        
    def __enter__(self):
        return self
    
    def __exit__(self, *a, **k):
        self.dispose()
    
    @property
    def _backend(self):
        return Backend.get(self._beclass, started=True)

    @property
    def _backend_started(self):
        return Backend.query(self._beclass)
      
    @property
    def title(self):
        """
        Chart title
        @rtype: str
        """
        return self._title
        
    @property
    def number(self):
        """
        Chart number
        @rtype: int
        """        
        return self._number
    
    @property
    def plots(self):
        """
        Index-based access to the plots in this chart
        @rtype: L{PlotsCollection}
        """
        return self._plots
    
    @property
    def plot(self):
        """
        First plot
        @rtype: matplotlib.AxesSubplot
        """
        return self._plots[0]
    
    @property
    def rows(self):
        """
        Number of rows in this chart
        @rtype: int
        """
        return self._rows
    
    @property
    def columns(self):
        """
        Number of columns in this chart
        @rtype: int
        """        
        return self._columns
    
    @property
    def width(self):
        """
        Chart's width in inches
        @rtype: int
        """
        return self._figure.get_figwidth()
    @width.setter
    def width(self, inches):
        self._figure.set_figwidth(inches)
        if self._backend_started:
            self._backend.resize(self._figure)

    @property
    def height(self):
        """
        Chart's height in inches
        @rtype: int
        """        
        return self._figure.get_figheight()
    @height.setter
    def height(self, inches):
        self._figure.set_figheight(inches)
        if self._backend_started:
            self._backend.resize(self._figure)
                
    @property
    def dpi(self):
        """
        Chart's DPI
        @rtype: int
        """        
        return self._figure.get_dpi()
    @dpi.setter
    def dpi(self, dpi):
        self._figure.set_dpi(dpi)
        self._backend.resize(self._figure)
            
    @property
    def formats(self):
        """
        Supported output file formats
        @rtype: L{csb.core.enum}
        """
        return self._formats
            
    def show(self):
        """
        Show the GUI window (non-blocking).
        """
        if not self._hasgui:
            self._backend.add(self._figure)
            self._hasgui = True
            
        self._backend.show(self._figure)
                
    def hide(self):
        """
        Hide (but do not dispose) the GUI window.
        """
        self._backend.hide(self._figure)
        
    def dispose(self):
        """
        Dispose the GUI interface. Must be called at the end if any
        chart.show() calls have been made. Automatically called if using
        the chart in context manager ("with" statement).
        
        @note: Failing to call this method if show() has been called at least
        once may cause backend-related errors.
        """
        if self._backend_started:
        
            service = self._backend
            
            if service and service.running:
                service.destroy(self._figure, wait=True)
                service.client_disposed(self)    
        
    def save(self, file, format='png', crop=False, dpi=None, *a, **k):
        """
        Save all plots to an image.
        
        @param file: destination file name
        @type file: str
        @param format: output image format; see C{chart.formats} for enumeration
        @type format: str or L{csb.core.EnumItem}
        @param crop: if True, crop the image (equivalent to MPL's bbox=tight)
        @type crop: bool
                
        @note: additional arguments are passed directly to MPL's savefig method
        """
        if 'bbox_inches' in k:
            bbox = k['bbox_inches']
            del k['bbox_inches']
        else:
            if crop:
                bbox = 'tight'
            else:
                bbox = None
            
        self._canvas.print_figure(file, format=str(format), bbox_inches=bbox, dpi=dpi, *a, **k)
Example #32
0
class PlotSettings(object):

    """
    The PlotSettings-class initializes the default values for the plot.

    The class can return those values to the main window and the plot-settings
    dialog. The plot-settings dialog will call the instance of this class to
    change the different settings. This class also stores the figure and can
    return different subplot-layouts. This class also stores the normal and
    inverse transformations of the stereonet, and will return the correct
    one for either the Schmidt- or Wulff-Net.
    """

    def __init__(self):
        """
        Initalizes the default values, colors and the matplotlib-figure.

        Initializes and stores the default settings. Initializes the
        matplotlib-figure, a folder-icon for the group-layers of the layer-view.
        """
        self.folder_icon = Gtk.IconTheme.get_default().load_icon(
            "folder", 16, 0)
        self.draw_grid = True
        self.equal_area_projection = True
        self.minor_grid_spacing = 2
        self.major_grid_spacing = 10
        self.grid_cutoff_lat = 80
        self.show_north = True
        self.show_cross = True
        self.pixel_density = 75
        self.grid_linestyle = "--"
        self.grid_color = "#787878"
        self.grid_width = 0.4
        self.fig = Figure(dpi=self.pixel_density)
        self.draw_legend = True
        self.canvas_color = "#bfbfbf"

    def get_fig(self):
        """
        Returns the Matplotlib-Figure.

        Returns the figure that is stored by this class. The MainWindow class
        calls this function once during initialization to add the figure to
        the FigureCanvas.
        """
        return self.fig

    def get_inverse_transform(self):
        """
        Returns the inverse transform for the current stereonet projection.

        If the projection is equal are (True) the function returns the
        InvertedLambertTransform- or else the
        InvertedSterreographicTransform-class.
        """
        if self.equal_area_projection is True:
            return mplstereonet.stereonet_transforms.\
                        InvertedLambertTransform(0, 0, self.pixel_density)
        else:
            return mplstereonet.stereonet_transforms.\
                        InvertedStereographicTransform(0, 0, self.pixel_density)

    def get_transform(self):
        """
        Returns the normal transform for the current stereonet projection.

        If the projection is equal are (True) the function returns the
        LambertTransform- or else the SterreographicTransform-class.
        """
        if self.equal_area_projection is True:
            return mplstereonet.stereonet_transforms.\
                        LambertTransform(0, 0, self.pixel_density)
        else:
            return mplstereonet.stereonet_transforms.\
                        StereographicTransform(0, 0, self.pixel_density)

    def get_draw_grid_state(self):
        """
        Returns if the grid should be drawn for the stereonet.

        Returns a boolean. True mean that a grid should be drawn. False means
        that no grid should be drawn. This method is called by the MainWindow-
        redraw_plot-method.
        """
        return self.draw_grid

    def set_draw_grid_state(self, new_state):
        """
        Sets if the grid should be drawn for the stereonet.

        Expects a boolean. True mean that a grid should be drawn. False means
        that no grid should be drawn. This method is called by the
        LayerProperties-dialog when the setting is changed.
        """
        self.draw_grid = new_state

    def get_folder_icon(self):
        """
        Returns the folder icon used for the group-layer pixbuf.

        Always returns the "folder" icon from the Gtk.IconTheme. The folder
        will therefore match the desktop-theme set by the user. This method is
        called by the MainWindow "on_toolbutton_create_group_layer_clicked"-
        method.
        """
        return self.folder_icon

    def get_pixel_density(self):
        """
        Returns the pixel density the plot is using.

        The pixel density is an int and the default value is 75. This method
        is called by the LayerProperties-dialog so it can display the current
        value.
        """
        return self.pixel_density

    def set_pixel_density(self, new_pixel_density):
        """
        Sets a new pixel density for the plot.

        Expects an int. This method is called by the LayerProperties-dialog.
        The new value will be used when the plot redraws when the settings
        in the dialog are applied.
        """
        self.pixel_density = new_pixel_density

    def get_projection(self):
        """
        Returns the projection currently used by the stereonet.

        Returns one of two strings that MPLStereonet uses to distinguish
        between the equal-area and equal-angle projection. This method is only
        called from this class when the view is switched.
        """
        if self.equal_area_projection is True:
            return "equal_area_stereonet"
        else:
            return "equal_angle_stereonet"

    def get_projection_state(self):
        """
        Returns the projection state for the stereonet.

        Returns a boolean. True means that the stereonet should be drawn
        with equal-area. False mean equal-angle. This method is called by the
        StereonetProperties-dialog to load the current setting.
        """
        return self.equal_area_projection

    def set_projection_state(self, new_state):
        """
        Sets a new projection state.

        Expects a boolean. True means that the projection will be equal-area,
        False means equal-angle. This method is called by the
        StereonetProperties-dialog when a new setting for the projection is
        applied.
        """
        self.equal_area_projection = new_state

    def get_grid_linestyle(self):
        """
        Returns the linestyle of the grid.

        The linestyle is returned as a string. Default is "--" (dashed). This
        method is called by the MainWindow "redraw_plot"-method.
        """
        return self.grid_linestyle

    def get_grid_color(self):
        """
        Returns the color of the grid.

        Returns the color as a hex-triplet. The default is "#787878". This
        method is called by the MainWindow "redraw_plot"-method.
        """
        return self.grid_color

    def get_grid_width(self):
        """
        Returns the width of the grid lines.

        The width of the grid lines is returned as a float or int. The default
        is "0.4". This method is called by the MainWindow "redraw_plot"-method.
        """
        return self.grid_width

    def get_draw_legend(self):
        """
        Returns if the legend should be drawn as a boolean.

        The returned value is either True if a legend should be drawn, or False
        if no legend should be drawn. This method is called by the MainWindow
        "redraw_plot"-method and the StereonetProperties-dialog.
        """
        return self.draw_legend

    def set_draw_legend(self, new_state):
        """
        Sets a new state for whether the legend should be drawn.

        Expects a boolean. True means that the legend should be drawn. False
        means that no legend should be drawn. This method is called by the
        StereonetProperties-dialog when a new setting is applied.
        """
        self.draw_legend = new_state

    def get_canvas_rgba(self):
        """
        Returns the canvas color as a Gdk.RGBA.

        This method is called by the StereonetProperties-dialog to apply the
        current canvas color to the ColorButton.
        """
        rgba = Gdk.RGBA()
        rgba.parse(self.canvas_color)
        return rgba.to_color()

    def set_canvas_color(self, new_color):
        """
        Sets a new canvas color.

        Expects a hex-triplet string (e.g. "#bfbfbf"). This method is called
        by the StereonetProperties-dialog when a new color is applied to the
        canvas.
        """
        self.canvas_color = new_color

    def get_stereonet(self):
        """
        Resets the figure and returns the stereonet axis.

        When the view in the main window is changed to only stereoent. The
        figure is reset. Then the current settings are applied and one subplot
        for the stereonet is created. This method is called when the
        MainWindow "__init__"-method and the "redraw_plot"-method. 
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.canvas_color)
        self.fig.set_dpi(self.pixel_density)
        gridspec = GridSpec(1, 1)
        sp_stereo = gridspec.new_subplotspec((0, 0))
        ax_stereo = self.fig.add_subplot(sp_stereo,
                                         projection=self.get_projection())
        return ax_stereo

    def get_stereo_rose(self):
        """
        Resets the figure and returns a stereonet and rose diagram axis.

        When the view in the main window is changed to stereonet and rose
        diagram, the figure is reset. The current settings are applied and
        two subplots for the stereonet and rose diagram are created. The
        axis of the stereonet and rose diagram are returned. This method is
        called by the MainWindow "redraw_plot"-method.
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.canvas_color)
        self.fig.set_dpi(self.pixel_density)
        gridspec = GridSpec(1, 2)
        sp_stereo = gridspec.new_subplotspec((0, 0),
                                             rowspan=1, colspan=1)
        sp_rose = gridspec.new_subplotspec((0, 1),
                                           rowspan=1, colspan=1)
        ax_stereo = self.fig.add_subplot(sp_stereo,
                                         projection=self.get_projection())
        ax_rose = self.fig.add_subplot(sp_rose, projection="northpolar")
        return ax_stereo, ax_rose

    def get_rose_diagram(self):
        """
        Resets the figure and returns the rose diagram axis.

        When the view in the main window is changed to rose-diagram-only the
        figure is reset. The current settings are applied and one subplot
        for the rose diagram is created. The axis of the rose-diagram is
        returned. This method is called by the MainWindow "redraw_plot"-method.
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.canvas_color)
        self.fig.set_dpi(self.pixel_density)
        gridspec = GridSpec(1, 1)
        sp_rose = gridspec.new_subplotspec((0, 0))
        ax_rose = self.fig.add_subplot(sp_rose, projection="northpolar")
        return ax_rose

    def get_pt_view(self):
        """
        Resets the canvas and returns the 3 axis of the paleostress view.

        When the view in the main window is changed to paleostress the figure
        is reset. The current settings are applied and 3 subplots are created.
        The 3 axis of the subplots are returned. This method is called by the
        MainWindow "redraw_plot"-method when the view has been changed.
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.canvas_color)
        self.fig.set_dpi(self.pixel_density)
        gridspec = GridSpec(2, 5)
        sp_stereo = gridspec.new_subplotspec((0, 0), colspan=3, rowspan=2)
        sp_fluc = gridspec.new_subplotspec((0, 3), colspan=2)
        sp_mohr = gridspec.new_subplotspec((1, 3), colspan=2)
        ax_stereo = self.fig.add_subplot(sp_stereo,
                                         projection=self.get_projection())
        ax_fluc = self.fig.add_subplot(sp_fluc, aspect="equal")
        ax_mohr = self.fig.add_subplot(sp_mohr, aspect="equal")
        return ax_stereo, ax_fluc, ax_mohr

    def get_show_north(self):
        """
        Returns if the stereonet should show the North symbol or degrees

        Returns True if the North symbol should be drawn (the default value),
        or False in which case numbers will be drawn for different degrees.
        """
        return self.show_north

    def set_show_north(self, new_state):
        """
        Sets a new state for whether the North symbol should be drawn.

        Expects a boolean. True means the North symbol will be drawn. False
        means that the stereonet will show different degrees along the outside.
        """
        self.show_north = new_state

    def get_show_cross(self):
        """
        Returns if the stereonet should draw a cross at the center.

        Returns True if the cross should be drawn (the default value) or False
        if the cross should not be drawn.
        """
        return self.show_cross

    def set_show_cross(self, new_state):
        """
        Sets a new state for whether the center cross should be drawn.

        Expects a boolean. True means the center cross will be drawn. False
        means it will not be drawn.
        """
        self.show_cross = new_state
class PlottingController(object):
    """ Plotting Controller 
    
    This class controlls all the plotting related functionality.
    """
    
    def __init__(self, parameters, defaults):
        """ Constructor """
        v = ParameterValidator(parameters, defaults)
        self.parameters = v.validate()
        self.DPI = 100.0
       
        self.bbox = BBox(parameters["bbox"])
        
        # 1. Retrieve the data
        self.dset = self.__evaluate_datasource_type() (
                                self.parameters["source_url"], \
                                self.bbox, \
                                self.parameters["layers"][0], \
                                self.parameters["time"], \
                                self.parameters["time_index"], \
                                True
                                )
        self.lat = self.dset.get_lats()
        self.lon = self.dset.get_lons()
        self.var = self.dset.get_data()
      
            # 1.1 Normalise data
        self.bbox,self.lon,self.var = \
                self.__transform_lons(self.bbox, \
                                      self.lon, \
                                      self.var)
      
        # 2. Set up figure
        self.bmapuclon = self.bbox.lon_max
        self.bmaplclon = self.bbox.lon_min
        self.bmapuclat = min(90, self.bbox.lat_max)
        self.bmaplclat = max(-90, self.bbox.lat_min)
        
        self.fig = Figure()
        self.canvas = FigureCanvas(self.fig)
      
        # 3. Set up basemap
        ax = self.fig.add_axes( (0,0,1,1), \
                                frame_on = False, \
                                axis_bgcolor = 'k', \
                                alpha = 0 , \
                                visible = False )
                                
        self.m = Basemap( projection = 'cyl', \
                          resolution = 'c' , \
                          llcrnrlon = self.bmaplclon, \
                          llcrnrlat = self.bmaplclat, \
                          urcrnrlon = self.bmapuclon, \
                          urcrnrlat = self.bmapuclat, \
                          suppress_ticks = True, \
                          fix_aspect = False, \
                          ax = ax)
                         
                         
    def get_legend(self):
        """
        Responsible for wrapping the GetLegend request
        
        Returns an image.
        """
        
        #FIXME: Ugly ... replace without having to print map first
        ax = self.fig.add_axes( (0,0,1,1), \
                                frame_on = False, \
                                axis_bgcolor = 'k')
        self.m.ax = ax
        self.__create_contours(pt.ContourPlot)
      
        self.fig = Figure(figsize=(64/self.DPI,256/self.DPI))
        self.canvas = FigureCanvas(self.fig)
        
        self.__create_legend((0,0.1,0.2,0.8))
            
        return self.__create_image()
    
    
    def get_contour(self):
        """ Responsible for wrapping the GetMap request.
        
        Returns an image.
        """
        # Calculate offsets for stuff
        bmaplatmin, bmaplonmin = self.m(self.bbox.lat_min, self.bbox.lon_min)
        bmaplatmax, bmaplonmax = self.m(self.bbox.lat_max, self.bbox.lon_max)
        
        lon_offset1 = abs(self.bmaplclon - bmaplonmin)
        lat_offset1 = abs(self.bmaplclat - bmaplatmin)
        #lon_offset2 = abs(self.bmapuclon - bmaplonmax)
        #lat_offset2 = abs(self.bmapuclat - bmaplatmax)
        
        lon_normstart = lon_offset1 / abs(bmaplonmax - bmaplonmin)
        lat_normstart = lat_offset1 / abs(bmaplatmax - bmaplatmin)
        
        ax_xfrac = abs( self.bmapuclon - self.bmaplclon ) / \
                   abs( bmaplonmax - bmaplonmin )
                   
        ax_yfrac = abs( self.bmapuclat - self.bmaplclat ) / \
                   abs( bmaplatmax - bmaplatmin)
        
        coords = (lon_normstart, lat_normstart, ax_xfrac, ax_yfrac)
        
        #####
        ax = self.fig.add_axes( coords, \
                                frame_on = False, \
                                axis_bgcolor = 'k')
        self.m.ax = ax
        self.__create_contours(self.__evaluate_plot_type())
        return self.__create_image()
    
    
    def get_full_figure(self, n_merid = 5, n_para = 5):
        """ Responsibe for wrapping the GetFullFigure request.
        
        Returns an image.
        
        n_merid: Number of meridians we want to print as an overlay
        n_para: number of parallels we want printed as an overlay
        """
        tick_font_size = 8
        title_font_size = 9
        
        plot_dims = self.__calc_plot_dims()
        ax = self.fig.add_axes( plot_dims, \
                                frame_on = False, \
                                axis_bgcolor = 'k')
        
        self.m.ax = ax
        self.__create_contours(self.__evaluate_plot_type())
        self.__create_legend((0.8,0.1,0.02,plot_dims[3]))
        
        # Creating the overlay
        base = (self.bbox.lon_max - self.bbox.lon_min)/float(n_merid)
        meridians = [ self.bbox.lon_min + i*base for i in range(n_merid)]
        
        base = (self.bbox.lat_max - self.bbox.lat_min)/float(n_para)
        parallels = [ self.bbox.lat_min + i*base for i in range(1,n_para+1)]
        
        self.m.drawcoastlines()
        self.m.drawmeridians(meridians, \
                             labels = [0,1,0,1], \
                             fmt = "%3.1f", \
                             fontsize = tick_font_size)
        self.m.drawparallels(parallels, \
                             labels= [1,0,0,0], \
                             fmt = "%3.1f", \
                             fontsize = tick_font_size)
        self.m.drawparallels([0], \
                             linewidth = 1, \
                             dashes = [1,0], \
                             labels = [0,1,1,1], \
                             fontsize = tick_font_size)
        
        self.fig.text(0.05,0.98,self.__get_plot_title(), \
                      va='top', fontsize=title_font_size)
        
        return self.__create_image(transparent=False)
    
    
    def __create_image(self,transparent=True):
        """ Create image with the given format an returns it. If iamge type is
        not supported, an exception is raised:
        
        transparent: True/False for transparent background
        """
       
        supported_formats = [ 'png', 'svg' ]
        img_format = self.parameters["format"]
        
        if not img_format in supported_formats:
            raise ex.InvalidFormatError(img_format)
       
        img_data = StringIO.StringIO()
       
        self.fig.savefig(img_data, \
                         format = img_format, \
                         transparent=transparent)
        
        value = img_data.getvalue()
        img_data.close()
        
        return value
    
    def __create_contours(self,style_type):
        """
        This class does the actual work, but does not create images. Only
        manipulates the Basemap object.
        
        style_type: The class we have to create
        """
        
        # Set size of the image
        self.fig.set_dpi(self.DPI)
        self.fig.set_size_inches(self.parameters["width"]/self.DPI, \
                                 self.parameters["height"]/self.DPI)
        
        try:
            plot = style_type(self.parameters, \
                              self.m, \
                              self.lon, \
                              self.lat, \
                              self.var, \
                              self.fig )
        except Exception, e:
            raise ex.InvalidParameterValueError(repr(e))
        
        self.main_render = plot.plot()
Example #34
0
File: widgets.py Project: e-sr/KG
    def __init__(self, author, observations, local=True, db=None):
        # init super
        super(CaseCreatorWidget, self).__init__(setup=False)
        self.setWindowTitle('Create Case')
        # set wavepath casepath and local
        self.author = author
        self.local = local
        if self.local:
            self.db = None
            self.wavpath = pathlib.Path().joinpath('wav')
            self.casepath = pathlib.Path().joinpath('test_case').joinpath(self.author)
        else:
            self.db = db
            self.wavpath = pathlib.Path(WAV_PATH)
            self.casepath = pathlib.Path(CASE_FOLDER).joinpath(self.author)
        try:
            self.wavpath.mkdir()
            self.casepath.mkdir()
        except:
            pass

        # init logger
        fn = self.casepath.joinpath('saved_cases.log')
        logging.basicConfig(format='%(asctime)s %(message)s',
                            filename=str(fn),
                            level=logging.DEBUG,  # filemode = 'w+',
                            datefmt='%Y-%m-%d %H:%M:%S')
        logging.captureWarnings(True)
        logging.info('Start case creator session, local: {}.'.format(self.local))

        # set observations and cases to analyzee, dict observatioins contain observation casess ans its metadata
        self.obsKeys = []
        self.observations = {}
        for obs in observations:
            self.init_obs(obs)
        # set current noise
        self.currentNoise = 'Z'
        self.bothVisibles = True

        # Add New Widgets
        # structure:
        #
        #                   main Phonon Widget
        # ------------------------------------------------------
        #                  Figure canvas widget
        # ------------------------------------------------------
        # selectCase GB | selectSOI GB|
        #         set quality GB      | caseinfo GB | save button
        # ------------------------------------------------------

        # Figure Canvas
        plt.ioff()
        fig = Figure((15, 10))
        fig.set_dpi(110)  # default 110
        fig.set_facecolor('#272822')
        # canvas Widget: first fidget
        self.canvas = FigureCanvas(fig)
        # add axes
        self.ax = fig.add_subplot(111)
        # case Selector
        self.minspan = 0.05
        self.CS = CaseSelector(self.ax, self.onselect, self.onclick,
                               nrect=[50, 50], update_on_ext_event=True,
                               minspan=self.minspan)
        self.ca_bar_handle = [self.CS]
        self.ca_widget_handle = [self.CS]
        # add canvas to main vBox
        self.vBox.addWidget(self.canvas)

        # begin second hBox
        # .................
        secondhBox = QtGui.QHBoxLayout()

        # left vBox of second hBox
        leftvBox = QtGui.QVBoxLayout()
        # add first row to left vBox: hBox1
        hBox1 = QtGui.QHBoxLayout()
        # select case combo 
        groupBox = QtGui.QGroupBox('Select observation to analyze ')
        groupBox.setFixedWidth(280)
        self.obsCombo = QtGui.QComboBox()
        self.obsCombo.addItems(self.obsKeys)
        self.saved_obs_to_green()
        hbox1_1 = QtGui.QHBoxLayout()
        hbox1_1.addWidget(self.obsCombo)
        groupBox.setLayout(hbox1_1)
        hBox1.addWidget(groupBox)
        # select noise Type Group
        groupBox = QtGui.QGroupBox('Noise Type to select')
        groupBox.setFixedWidth(220)
        hbox1_2 = QtGui.QHBoxLayout()
        # noise Type combo
        self.SOIcombo = QtGui.QComboBox()
        self.SOIcombo.addItem('Zischen', 'Z')
        self.SOIcombo.setItemData(0, QtGui.QColor('#984ea3'),
                                  QtCore.Qt.BackgroundRole)
        self.SOIcombo.setItemData(0, QtGui.QColor('#f5f5f5'), QtCore.Qt.ForegroundRole)  # change text color
        self.SOIcombo.addItem('Kreischen', 'KG')
        # add backgroundcolor of combo K
        self.SOIcombo.setItemData(1, QtGui.QColor('#ffff33'),
                                  QtCore.Qt.BackgroundRole)
        # change text color
        self.SOIcombo.setItemData(1, QtGui.QColor('#272822'), QtCore.Qt.ForegroundRole)
        hbox1_2.addWidget(self.SOIcombo)
        # visualize both cb
        self.cb = QtGui.QCheckBox('both visible', self)
        self.cb.setChecked(self.bothVisibles)
        hbox1_2.addWidget(self.cb)
        groupBox.setLayout(hbox1_2)
        hBox1.addWidget(groupBox)
        hBox1.addStretch(1)
        leftvBox.addLayout(hBox1)
        # add second row to leftvBox: 
        # quality radios
        groupBox = QtGui.QGroupBox("Select quality: are noise events detectable?")
        groupBox.setFixedWidth(507)
        self.Qradios = [QtGui.QRadioButton(q) for q in ['good', 'medium', 'bad']]
        hbox2_1 = QtGui.QHBoxLayout()
        self.rbG = QtGui.QButtonGroup()
        for rb in self.Qradios:
            self.rbG.addButton(rb)
            hbox2_1.addWidget(rb)
        groupBox.setLayout(hbox2_1)
        # add to leftvBox    
        leftvBox.addWidget(groupBox)
        # add leftvBox to second hBox
        secondhBox.addLayout(leftvBox)

        # centre GB of secondhBox
        # add info Groupbox
        groupBox = QtGui.QGroupBox("case informations")
        # add centre GB to second hBox
        secondhBox.addWidget(groupBox)

        # rigth of second hBox
        # save button
        self.buttonSave = QtGui.QPushButton("save", self)
        # rigth second hBox
        secondhBox.addWidget(self.buttonSave)
        secondhBox.addStretch()
        # end second hBox

        # add second hBox to main vBox
        self.vBox.addLayout(secondhBox)
        # -------------

        # set and centralWidget
        centralWidget = QtGui.QWidget()
        centralWidget.setLayout(self.vBox)
        self.setCentralWidget(centralWidget)

        # add connections
        self.connections()
        self.set_current_obs(0)
Example #35
0
class MainPlotController(object):
    """
        A controller for the main plot canvas.
        Sets up the widgets and has image exporting functionality.
    """
    
    file_filters = ("Portable Network Graphics (PNG)", "*.png"), \
                   ("Scalable Vector Graphics (SVG)", "*.svg"), \
                   ("Portable Document Format (PDF)", "*.pdf")

    _canvas = None
    @property
    def canvas(self):
        if not self._canvas:
            self.setup_figure()
            self.setup_canvas()
            self.setup_content()
        return self._canvas

    # ------------------------------------------------------------
    #      View integration getters
    # ------------------------------------------------------------
    def get_toolbar_widget(self, window):
        return NavigationToolbar(self.canvas, window)

    def get_canvas_widget(self):
        return self.canvas
    
    # ------------------------------------------------------------
    #      Initialization and other internals
    # ------------------------------------------------------------
    def __init__(self, status_callback, marker_callback, *args, **kwargs):
        self.setup_layout_cache()
        self.setup_figure()
        self.setup_canvas()
        self.setup_content(status_callback, marker_callback)

    def setup_layout_cache(self):
        self.position_setup = PositionSetup()
        self.labels = list()
        self.marker_lbls = list()
        self._proxies = dict()
        self.scale = 1.0
        self.stats = False
        self._last_pos = None

    def setup_figure(self):
        self.figure = Figure(dpi=72, facecolor="#FFFFFF", linewidth=0)
        self.figure.subplots_adjust(hspace=0.0, wspace=0.0)

    def setup_canvas(self):
        self._canvas = FigureCanvasGTK(self.figure)

    def setup_content(self, status_callback, marker_callback):
        # Create subplot and add it to the figure:
        self.plot = Subplot(self.figure, 211, facecolor=(1.0, 1.0, 1.0, 0.0))
        self.plot.set_autoscale_on(False)
        self.figure.add_axes(self.plot)

        # Connect events:
        self.canvas.mpl_connect('draw_event', self.fix_after_drawing)
        self.canvas.mpl_connect('resize_event', self.fix_after_drawing)

        self.mtc = MotionTracker(self, status_callback)
        self.cc = ClickCatcher(self, marker_callback)

        #self.update()

    # ------------------------------------------------------------
    #      Update methods
    # ------------------------------------------------------------
    def draw(self):
        self._last_pos = self.fix_before_drawing()
        self.figure.canvas.draw()

    def fix_after_drawing(self, *args):
        _new_pos = self.fix_before_drawing()
        
        if _new_pos != self._last_pos:
            self.figure.canvas.draw()
        self._last_pos = _new_pos

        return False

    def fix_before_drawing(self, *args):
        """
            Fixes alignment issues due to longer labels or smaller windows
            Is executed after an initial draw event, since we can then retrieve
            the actual label dimensions and shift/resize the plot accordingly.
        """
        renderer = get_renderer(self.figure)        
        if not renderer or not self._canvas.get_realized():
            return False
        
        # Fix left side for wide specimen labels:
        if len(self.labels) > 0:
            bbox = self._get_joint_bbox(self.labels, renderer)
            if bbox is not None: 
                self.position_setup.left = self.position_setup.default_left + bbox.width
        # Fix top for high marker labels:
        if len(self.marker_lbls) > 0:
            bbox = self._get_joint_bbox([ label for label, flag, _ in self.marker_lbls if flag ], renderer)
            if bbox is not None: 
                self.position_setup.top = self.position_setup.default_top - bbox.height
        # Fix bottom for x-axis label:
        bottom_label = self.plot.axis["bottom"].label
        if bottom_label is not None:
            bbox = self._get_joint_bbox([bottom_label], renderer)
            if bbox is not None:
                self.position_setup.bottom = self.position_setup.default_bottom + (bbox.ymax - bbox.ymin) * 2.0 # somehow we need this?

        # Calculate new plot position & set it:
        plot_pos = self.position_setup.position
        self.plot.set_position(plot_pos)

        # Adjust specimen label position
        for label in self.labels:
            label.set_x(plot_pos[0] - 0.025)

        # Adjust marker label position
        for label, flag, y_offset in self.marker_lbls:
            if flag:
                newy = plot_pos[1] + plot_pos[3] + y_offset - 0.025
                label.set_y(newy)
        
        _new_pos = self.position_setup.to_string()
        return _new_pos
    
    def update(self, clear=False, project=None, specimens=None):
        """
            Updates the entire plot with the given information.
        """
        if clear: self.plot.cla()

        if project and specimens:
            self.labels, self.marker_lbls = plot_specimens(
                self.plot, self.position_setup, self.cc,
                project, specimens
            )
            # get mixtures for the selected specimens:
            plot_mixtures(self.plot, project, [ mixture for mixture in project.mixtures if any(specimen in mixture.specimens for specimen in specimens) ])

        update_axes(
            self.plot, self.position_setup,
            project, specimens
        )

        self.draw()

    # ------------------------------------------------------------
    #      Plot position and size calculations
    # ------------------------------------------------------------
    def _get_joint_bbox(self, container, renderer):
        bboxes = []
        try:
            for text in container:
                bbox = text.get_window_extent(renderer=renderer)
                # the figure transform goes from relative coords->pixels and we
                # want the inverse of that
                bboxi = bbox.inverse_transformed(self.figure.transFigure)
                bboxes.append(bboxi)
        except (RuntimeError, ValueError):
            logger.exception("Caught unhandled exception when joining boundig boxes")
            return None # don't continue
        # this is the bbox that bounds all the bboxes, again in relative
        # figure coords
        if len(bboxes) > 0:
            bbox = transforms.Bbox.union(bboxes)
            return bbox
        else:
            return None

    # ------------------------------------------------------------
    #      Graph exporting
    # ------------------------------------------------------------
    def save(self, parent=None, current_name="graph", size="auto", num_specimens=1, offset=0.75):
        """
            Displays a save dialog to export an image from the current plot.
        """
        # Parse arguments:
        width, height = 0, 0
        if size == "auto":
            descr, width, height, dpi = settings.OUTPUT_PRESETS[0]
        else:
            width, height, dpi = list(map(float, size.replace("@", "x").split("x")))

        # Load gui:
        builder = Gtk.Builder()
        builder.add_from_file(resource_filename("pyxrd.specimen", "glade/save_graph_size.glade")) # FIXME move this to this namespace!!
        size_expander = builder.get_object("size_expander")
        cmb_presets = builder.get_object("cmb_presets")

        # Setup combo with presets:
        cmb_store = Gtk.ListStore(str, int, int, float)
        for row in settings.OUTPUT_PRESETS:
            cmb_store.append(row)
        cmb_presets.clear()
        cmb_presets.set_model(cmb_store)
        cell = Gtk.CellRendererText()
        cmb_presets.pack_start(cell, True)
        cmb_presets.add_attribute(cell, 'text', 0)
        def on_cmb_changed(cmb, *args):
            itr = cmb.get_active_iter()
            w, h, d = cmb_store.get(itr, 1, 2, 3)
            entry_w.set_text(str(w))
            entry_h.set_text(str(h))
            entry_dpi.set_text(str(d))
        cmb_presets.connect('changed', on_cmb_changed)

        # Setup input boxes:
        entry_w = builder.get_object("entry_width")
        entry_h = builder.get_object("entry_height")
        entry_dpi = builder.get_object("entry_dpi")
        entry_w.set_text(str(width))
        entry_h.set_text(str(height))
        entry_dpi.set_text(str(dpi))

        # What to do when the user wants to save this:
        def on_accept(dialog):
            # Get the width, height & dpi
            width = float(entry_w.get_text())
            height = float(entry_h.get_text())
            dpi = float(entry_dpi.get_text())
            i_width, i_height = width / dpi, height / dpi
            # Save it all right!
            self.save_figure(dialog.filename, dpi, i_width, i_height)

        # Ask the user where, how and if he wants to save:
        DialogFactory.get_save_dialog(
            "Save Graph", parent=parent,
            filters=self.file_filters, current_name=current_name,
            extra_widget=size_expander
        ).run(on_accept)

    def save_figure(self, filename, dpi, i_width, i_height):
        """
            Save the current plot
            
            Arguments:
             filename: the filename to save to (either .png, .pdf or .svg)
             dpi: Dots-Per-Inch resolution
             i_width: the width in inch
             i_height: the height in inch
        """
        # Get original settings:
        original_dpi = self.figure.get_dpi()
        original_width, original_height = self.figure.get_size_inches()
        # Set everything according to the user selection:
        self.figure.set_dpi(dpi)
        self.figure.set_size_inches((i_width, i_height))
        self.figure.canvas.draw() # replot
        bbox_inches = matplotlib.transforms.Bbox.from_bounds(0, 0, i_width, i_height)
        # Save the figure:
        self.figure.savefig(filename, dpi=dpi, bbox_inches=bbox_inches)
        # Put everything back the way it was:
        self.figure.set_dpi(original_dpi)
        self.figure.set_size_inches((original_width, original_height))
        self.figure.canvas.draw() # replot

    pass # end of class
Example #36
0
class MatplotlibRenderer(Renderer):
    """
    Renderer backend which takes data and produces images.
    Does not touch Wave or Channel.

    If __init__ reads cfg, cfg cannot be hotswapped.

    Reasons to hotswap cfg: RendererCfg:
    - GUI preview size
    - Changing layout
    - Changing #smp drawn (samples_visible)
    (see RendererCfg)

        Original OVGen does not support hotswapping.
        It disables changing options during rendering.

    Reasons to hotswap trigger algorithms:
    - changing scan_nsamp (cannot be hotswapped, since correlation buffer is incompatible)
    So don't.
    """
    def __init__(self, *args, **kwargs):
        Renderer.__init__(self, *args, **kwargs)

        dict.__setitem__(matplotlib.rcParams, "lines.antialiased",
                         self.cfg.antialiasing)

        self._fig: "Figure"

        # _axes2d[wave][chan] = Axes
        self._axes2d: List[List["Axes"]]  # set by set_layout()

        # _lines2d[wave][chan] = Line2D
        self._lines2d: List[List[Line2D]] = []
        self._lines_flat: List["Line2D"] = []

    transparent = "#00000000"

    layout: RendererLayout

    def _set_layout(self, wave_nchans: List[int]) -> None:
        """
        Creates a flat array of Matplotlib Axes, with the new layout.
        Opens a window showing the Figure (and Axes).

        Inputs: self.cfg, self.fig
        Outputs: self.nrows, self.ncols, self.axes
        """

        self.layout = RendererLayout(self.lcfg, wave_nchans)

        # Create Axes
        # https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplots.html
        if hasattr(self, "_fig"):
            raise Exception(
                "I don't currently expect to call _set_layout() twice")
            # plt.close(self.fig)

        grid_color = self.cfg.grid_color
        self._fig = Figure()
        FigureCanvasAgg(self._fig)

        # RegionFactory
        def axes_factory(r: RegionSpec) -> "Axes":
            width = 1 / r.ncol
            left = r.col / r.ncol
            assert 0 <= left < 1

            height = 1 / r.nrow
            bottom = (r.nrow - r.row - 1) / r.nrow
            assert 0 <= bottom < 1

            # Disabling xticks/yticks is unnecessary, since we hide Axises.
            ax = self._fig.add_axes([left, bottom, width, height],
                                    xticks=[],
                                    yticks=[])

            if grid_color:
                # Initialize borders
                # Hide Axises
                # (drawing them is very slow, and we disable ticks+labels anyway)
                ax.get_xaxis().set_visible(False)
                ax.get_yaxis().set_visible(False)

                # Background color
                # ax.patch.set_fill(False) sets _fill=False,
                # then calls _set_facecolor(...) "alpha = self._alpha if self._fill else 0".
                # It is no faster than below.
                ax.set_facecolor(self.transparent)

                # Set border colors
                for spine in ax.spines.values():
                    spine.set_color(grid_color)

                def hide(key: str):
                    ax.spines[key].set_visible(False)

                # Hide all axes except bottom-right.
                hide("top")
                hide("left")

                # If bottom of screen, hide bottom. If right of screen, hide right.
                if r.screen_edges & Edges.Bottom:
                    hide("bottom")
                if r.screen_edges & Edges.Right:
                    hide("right")

                # Dim stereo gridlines
                if self.cfg.stereo_grid_opacity > 0:
                    dim_color = matplotlib.colors.to_rgba_array(grid_color)[0]
                    dim_color[-1] = self.cfg.stereo_grid_opacity

                    def dim(key: str):
                        ax.spines[key].set_color(dim_color)

                else:
                    dim = hide

                # If not bottom of wave, dim bottom. If not right of wave, dim right.
                if not r.wave_edges & Edges.Bottom:
                    dim("bottom")
                if not r.wave_edges & Edges.Right:
                    dim("right")

            else:
                ax.set_axis_off()

            return ax

        # Generate arrangement (using self.lcfg, wave_nchans)
        # _axes2d[wave][chan] = Axes
        self._axes2d = self.layout.arrange(axes_factory)

        # Setup figure geometry
        self._fig.set_dpi(DPI)
        self._fig.set_size_inches(self.cfg.width / DPI, self.cfg.height / DPI)

    def render_frame(self, datas: List[np.ndarray]) -> None:
        ndata = len(datas)
        if self.nplots != ndata:
            raise ValueError(
                f"incorrect data to plot: {self.nplots} plots but {ndata} datas"
            )

        # Initialize axes and draw waveform data
        if not self._lines2d:
            assert len(datas[0].shape) == 2, datas[0].shape

            wave_nchans = [data.shape[1] for data in datas]
            self._set_layout(wave_nchans)

            cfg = self.cfg

            # Setup background/axes
            self._fig.set_facecolor(cfg.bg_color)
            for idx, wave_data in enumerate(datas):
                wave_axes = self._axes2d[idx]
                for ax in unique_by_id(wave_axes):
                    max_x = len(wave_data) - 1
                    ax.set_xlim(0, max_x)
                    ax.set_ylim(-1, 1)

                    # Setup midlines (depends on max_x and wave_data)
                    midline_color = cfg.midline_color
                    midline_width = pixels(1)

                    # zorder=-100 still draws on top of gridlines :(
                    kw = dict(color=midline_color, linewidth=midline_width)
                    if cfg.v_midline:
                        ax.axvline(x=max_x / 2, **kw)
                    if cfg.h_midline:
                        ax.axhline(y=0, **kw)

            self._save_background()

            # Plot lines over background
            line_width = pixels(cfg.line_width)

            # Foreach wave
            for wave_idx, wave_data in enumerate(datas):
                wave_axes = self._axes2d[wave_idx]
                wave_lines = []

                # Foreach chan
                for chan_idx, chan_data in enumerate(wave_data.T):
                    ax = wave_axes[chan_idx]
                    line_color = self._line_params[wave_idx].color
                    chan_line: Line2D = ax.plot(chan_data,
                                                color=line_color,
                                                linewidth=line_width)[0]
                    wave_lines.append(chan_line)

                self._lines2d.append(wave_lines)
                self._lines_flat.extend(wave_lines)

        # Draw waveform data
        else:
            # Foreach wave
            for wave_idx, wave_data in enumerate(datas):
                wave_lines = self._lines2d[wave_idx]

                # Foreach chan
                for chan_idx, chan_data in enumerate(wave_data.T):
                    chan_line = wave_lines[chan_idx]
                    chan_line.set_ydata(chan_data)

        self._redraw_over_background()

    bg_cache: Any  # "matplotlib.backends._backend_agg.BufferRegion"

    def _save_background(self) -> None:
        """ Draw static background. """
        # https://stackoverflow.com/a/8956211
        # https://matplotlib.org/api/animation_api.html#funcanimation
        fig = self._fig

        fig.canvas.draw()
        self.bg_cache = fig.canvas.copy_from_bbox(fig.bbox)

    def _redraw_over_background(self) -> None:
        """ Redraw animated elements of the image. """

        canvas: FigureCanvasAgg = self._fig.canvas
        canvas.restore_region(self.bg_cache)

        for line in self._lines_flat:
            line.axes.draw_artist(line)

        # https://bastibe.de/2013-05-30-speeding-up-matplotlib.html
        # thinks fig.canvas.blit(ax.bbox) leaks memory
        # and fig.canvas.update() works.
        # Except I found no memory leak...
        # and update() doesn't exist in FigureCanvasBase when no GUI is present.

        canvas.blit(self._fig.bbox)

    def get_frame(self) -> ByteBuffer:
        """ Returns ndarray of shape w,h,3. """
        canvas = self._fig.canvas

        # Agg is the default noninteractive backend except on OSX.
        # https://matplotlib.org/faq/usage_faq.html
        if not isinstance(canvas, FigureCanvasAgg):
            raise RuntimeError(
                f"oh shit, cannot read data from {type(canvas)} != FigureCanvasAgg"
            )

        w = self.cfg.width
        h = self.cfg.height
        assert (w, h) == canvas.get_width_height()

        buffer_rgb = canvas.tostring_rgb()
        assert len(buffer_rgb) == w * h * RGB_DEPTH

        return buffer_rgb
Example #37
0
    def calculateFloorMap(self,
                          resolution=0.01,
                          level=0,
                          xlim=None,
                          ylim=None,
                          ignoreGround=False,
                          roomIds=None):

        figSize = (10, 10)
        fig = Figure(figsize=figSize, dpi=100, frameon=False)
        canvas = FigureCanvas(fig)
        ax = fig.add_subplot(111, aspect='equal')
        fig.subplots_adjust(left=0,
                            bottom=0,
                            right=1,
                            top=1,
                            wspace=0,
                            hspace=0)
        ax.axis('off')
        ax.set_aspect('equal')

        if roomIds is not None:
            models = []
            for roomId in roomIds:
                models.extend([
                    model for model in self.scene.scene.findAllMatches(
                        '**/level-%d/room-%s/layouts/object-*/+ModelNode' %
                        (level, roomId))
                ])
        else:
            models = [
                model for model in self.scene.scene.findAllMatches(
                    '**/level-%d/**/layouts/object-*/+ModelNode' % level)
            ]

        # Loop for all floors in the scene:
        for model in models:
            modelId = model.getNetTag('model-id')

            if not modelId.endswith('f') or (ignoreGround and 'gd' in modelId):
                continue

            addModelTriangles(ax, model)

        if xlim is not None and ylim is not None:
            ax.set_xlim(xlim)
            ax.set_ylim(ylim)
        else:
            ax.autoscale(True)
            set_axes_equal(ax)

        xlim, ylim = ax.get_xlim(), ax.get_ylim()
        xrange = xlim[1] - xlim[0]
        yrange = ylim[1] - ylim[0]
        assert np.allclose(xrange, yrange, atol=1e-6)
        dpi = (xrange / resolution) / figSize[0]
        fig.set_dpi(dpi)

        floorMap = canvas2image(canvas)
        plt.close(fig)

        # RGB to binary
        floorMap = np.round(np.mean(floorMap[:, :], axis=-1))

        # NOTE: Filter out small gaps that can exist between rooms
        floorMap = ndimage.gaussian_filter(floorMap, sigma=(1, 1), order=0)
        floorMap = np.round(floorMap)

        # NOTE: inverse image so that floor areas are shown in white
        floorMap = 1.0 - floorMap

        return floorMap, xlim, ylim
class Canvas_sourceSpec:

    def __init__(self,ui,CSDA,N):

        # tab
        ui.list_of_tabs.append(QtWidgets.QWidget())  # ui.gridLayout_TabSourceImage
        ui.list_of_tabs[-1].setObjectName("tab_plotSourceSpec")

        #ui.tab_plotSourceSpec = QtWidgets.QWidget()
        #ui.tab_plotSourceSpec.setObjectName("tab_plotSourceSpec")

        # gridlayout TAB Source Spectrum
        ui.list_grid_tabs.append(QtWidgets.QGridLayout(ui.list_of_tabs[-1]))
        ui.list_grid_tabs[-1].setObjectName("gridLayout_TabSourceSpec")
        #ui.gridLayout_TabSourceSpec = QtWidgets.QGridLayout(ui.list_of_tabs[-1])
        #ui.gridLayout_TabSourceSpec.setObjectName("gridLayout_TabSourceSpec")


        # Scroll Area Source Spectrum
        ui.scrollArea_sourceSpec = QtWidgets.QScrollArea(ui.list_of_tabs[-1])
        ui.scrollArea_sourceSpec.setPalette(palette_scrollPlotProp)
        ui.scrollArea_sourceSpec.setWidgetResizable(True)
        ui.scrollArea_sourceSpec.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtWidgets.QSizePolicy.Minimum)
        ui.scrollArea_sourceSpec.setObjectName("scrollArea_sourceSpec")

        # Scroll Area Options Source Spectrum
        ui.scrollArea_sourceSpecOpt = QtWidgets.QScrollArea(ui.list_of_tabs[-1])
        ui.scrollArea_sourceSpecOpt.setWidgetResizable(True)
        ui.scrollArea_sourceSpecOpt.setObjectName("scrollArea_sourceSpecOpt")
        ui.scrollArea_sourceSpecOpt.setPalette(palette_scrollPlotProp)

        ui.scrollAreaWidgetContents_sourceSpecOpt = QtWidgets.QWidget()
        ui.scrollAreaWidgetContents_sourceSpecOpt.setObjectName("scrollAreaWidgetContents_sourceSpecOpt")
        ui.scrollArea_sourceSpecOpt.setWidget(ui.scrollAreaWidgetContents_sourceSpecOpt)

        ui.gridLayout_sourceSpecOpt = QtWidgets.QGridLayout(ui.scrollAreaWidgetContents_sourceSpecOpt)
        ui.gridLayout_sourceSpecOpt.setObjectName("gridLayout_sourceSpecOpt")

        ui.list_grid_tabs[-1].addWidget(ui.scrollArea_sourceSpec, 3, 0, 1, 1)
        ui.list_grid_tabs[-1].addWidget(ui.scrollArea_sourceSpecOpt, 10, 0, 1, 1)


        #_______________________________________________________________________


        #=======================================================================
        # Parameters
        #=======================================================================
        # N
        self.N = N

        # W matrix
        self.CSDA = CSDA

        # User interface
        self.ui = ui

        # parent
        self.parent = ui.scrollArea_sourceSpec

        # parent optioncs
        self.parentOptions = ui.scrollArea_sourceSpecOpt

        # grid parent options
        self.gridOptions = ui.gridLayout_sourceSpecOpt


        # first plot
        self.first_plot = False
        #_______________________________________________________________________

        # Initial points (middle)
        #self.P1x = int(N/2)
        #self.P1y = int(N/2)
        #self.P2x = int(N/2)

        self.build_fig()



    def build_fig(self):

        #=======================================================================
        # Create the mpl Figure and FigCanvas objects.
        #=======================================================================
        # magnitude
        self.dpi = 100
        self.fig = Figure((5.0, 4.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)

        # axes
        self.axes = self.fig.add_subplot(111)
        #_______________________________________________________________________



        #=======================================================================
        # Plotting figure and configuring
        #=======================================================================

        # creating image prop
        spectrum   = self.CSDA.spectrum

        # b array
        b_array=self.CSDA.omega_array

        # PLOT magnitude
        self.im = self.axes.plot(b_array,spectrum,marker="o",linewidth=1.0,label="Source Spectrum")
        #self.cbar = self.fig.colorbar(self.im)
        self.leg = self.axes.legend()

        # font size
        self.fsize = 12

        # x,y Labels
        self.axes.set_xlabel("x (m)",fontsize = self.fsize)
        self.axes.set_ylabel("y (m)",fontsize = self.fsize)


        #_______________________________________________________________________


        #=======================================================================
        # Tool bar
        #=======================================================================

        # Bind the 'pick' event for clicking on one of the bars
        self.canvas.mpl_connect('pick_event', self.ui.on_pick) #self.canvas.mpl_connect("scroll_event", ui.scrolling)

        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.parent)

        #ui.gridLayout_TabPropImage.addWidget(self.mpl_toolbar, 2, 0, 1, 3)
        self.ui.list_grid_tabs[-1].addWidget(self.mpl_toolbar, 8, 0, 1, 3,alignment=QtCore.Qt.AlignLeft)
        #_______________________________________________________________________


        #=======================================================================
        # Canvas in Scroll Area - magnitude
        #=======================================================================

        #self.canvas.draw()
        #self.canvas.setParent(parent)
        self.canvas.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtWidgets.QSizePolicy.Minimum)

        # Container for VBOX
        self.containerGraph = QWidget(self.parent)
        self.containerGraph.setSizePolicy(QtWidgets.QSizePolicy.Minimum,QtWidgets.QSizePolicy.Minimum)

        self.containerGraph.setMinimumWidth(self.canvas.width())
        self.containerGraph.setMinimumHeight(self.canvas.height())

        self.containerGraph.setMaximumWidth(self.canvas.width()+5)
        self.containerGraph.setMaximumHeight(self.canvas.height()+5)

        # VBOX for canvas
        self.vbox = QVBoxLayout(self.containerGraph)
        #self.vbox.setGeometry(QRect(0, 0, self.canvas.width(), self.canvas.height()))
        self.vbox.addWidget(self.canvas)

        self.parent.setWidget(self.containerGraph)
        #_______________________________________________________________________


        if not self.first_plot:
            self.figure_options()
            self.first_plot = True


    def figure_options(self):

        """
        # label Point P1x
        self.label_P1x = QtWidgets.QLabel(self.parentOptions)
        self.label_P1x.setObjectName("label_P1x")
        self.label_P1x.setText("Point ")
        self.gridOptions.addWidget(self.label_P1x, 2, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit Point P1x
        self.lineEdit_P1x = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_P1x.setObjectName("lineEdit_P1x")
        self.gridOptions.addWidget(self.lineEdit_P1x,2, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_P1x.setText(str(int(self.N/2)))
        self.lineEdit_P1x.textChanged.connect(self.change_P1x)

        # label Point P1y
        self.label_P1y = QtWidgets.QLabel(self.parentOptions)
        self.label_P1y.setObjectName("label_P1y")
        self.label_P1y.setText('$Point$')
        self.gridOptions.addWidget(self.label_P1y, 4, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit Point P1x
        self.lineEdit_P1y = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_P1y.setObjectName("lineEdit_P1y")
        self.gridOptions.addWidget(self.lineEdit_P1y,4, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_P1y.setText(str(int(self.N/2)))
        self.lineEdit_P1y.textChanged.connect(self.change_P1y)

        """
        # label title
        self.label_title = QtWidgets.QLabel(self.parentOptions)
        self.label_title.setObjectName("label_title")
        self.label_title.setText("Title")
        self.gridOptions.addWidget(self.label_title, 6, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)


        # line edit title label
        self.lineEdit_title = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_title.setObjectName("lineEdit_title")
        self.lineEdit_title.textChanged.connect(self.change_title)
        self.gridOptions.addWidget(self.lineEdit_title,6, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.change_title()
        self.lineEdit_title.setText("Source Spectrum")

        # label x
        self.label_x = QtWidgets.QLabel(self.parentOptions)
        self.label_x.setObjectName("label_x")
        self.label_x.setText("Label x-axis")
        self.gridOptions.addWidget(self.label_x, 8, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit x label
        self.lineEdit_xLabel = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_xLabel.setObjectName("lineEdit_xlabel")
        self.lineEdit_xLabel.textChanged.connect(self.change_labelx)
        self.gridOptions.addWidget(self.lineEdit_xLabel,8, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.change_labelx()
        self.lineEdit_xLabel.setText(r'$\omega\,(\mathrm{rad\,s^{-1})}$')

        # label y
        self.label_y = QtWidgets.QLabel(self.parentOptions)
        self.label_y.setObjectName("label_y")
        self.label_y.setText("Label y-axis")
        self.gridOptions.addWidget(self.label_y, 10, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit y label
        self.lineEdit_yLabel = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_yLabel.setObjectName("lineEdit_ylabel")
        self.lineEdit_yLabel.textChanged.connect(self.change_labely)
        self.gridOptions.addWidget(self.lineEdit_yLabel,10, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.change_labely()
        self.lineEdit_yLabel.setText("Normalized Spectrum (a.u.)")

        # label xlim
        self.label_xlim = QtWidgets.QLabel(self.parentOptions)
        self.label_xlim.setObjectName("label_xlim")
        self.label_xlim.setText("xlim")
        self.gridOptions.addWidget(self.label_xlim, 12, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit xlim
        self.lineEdit_xlim = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_xlim.setObjectName("lineEdit_ylabel")
        self.lineEdit_xlim.textChanged.connect(self.change_xlim)
        self.gridOptions.addWidget(self.lineEdit_xlim,12, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_xlim.setText("(_,_)")
        self.change_xlim()

        # label ylim
        self.label_ylim = QtWidgets.QLabel(self.parentOptions)
        self.label_ylim.setObjectName("label_ylim")
        self.label_ylim.setText("ylim")
        self.gridOptions.addWidget(self.label_ylim, 14, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit ylim
        self.lineEdit_ylim = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_ylim.setObjectName("lineEdit_ylabel")
        self.lineEdit_ylim.textChanged.connect(self.change_ylim)
        self.gridOptions.addWidget(self.lineEdit_ylim,14, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_ylim.setText("(_,_)")
        self.change_ylim()


        # label Font Size
        self.label_fsize = QtWidgets.QLabel(self.parentOptions)
        self.label_fsize.setObjectName("label_fsize")
        self.label_fsize.setText("Font Size")
        self.gridOptions.addWidget(self.label_fsize, 22, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit font size
        self.lineEdit_fsize = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_fsize.setObjectName("label_fsize")
        self.lineEdit_fsize.textChanged.connect(self.change_fsize)
        self.gridOptions.addWidget(self.lineEdit_fsize,22, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_fsize.setText(str(self.fsize))
        self.change_fsize()

        # label DPI
        self.label_dpi = QtWidgets.QLabel(self.parentOptions)
        self.label_dpi.setObjectName("label_dpi")
        self.label_dpi.setText("dpi (100-500)")
        self.gridOptions.addWidget(self.label_dpi, 24, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit DPI
        self.lineEdit_dpi = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_dpi.setObjectName("label_dpi")
        self.lineEdit_dpi.textChanged.connect(self.change_dpi)
        self.gridOptions.addWidget(self.lineEdit_dpi,24, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_dpi.setText(str(self.dpi))
        self.change_fsize()

        # checkbox grid
        self.checkBox_grid = QtWidgets.QCheckBox(self.parentOptions)
        self.checkBox_grid.setObjectName("Grid")
        self.gridOptions.addWidget(self.checkBox_grid, 30, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.checkBox_grid.setText("Grid")
        self.checkBox_grid.stateChanged.connect(self.change_grid)
        self.checkBox_grid.setChecked(True)

        # checkbox legend
        self.checkBox_legend = QtWidgets.QCheckBox(self.parentOptions)
        self.checkBox_legend.setObjectName("legend")
        self.gridOptions.addWidget(self.checkBox_legend, 32, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.checkBox_legend.setText("Legend")
        self.checkBox_legend.stateChanged.connect(self.change_legend)
        self.checkBox_legend.setChecked(True)

        # label legend font size
        self.label_legendFS = QtWidgets.QLabel(self.parentOptions)
        self.label_legendFS.setObjectName("label_legendFS")
        self.label_legendFS.setText("Legend Font Size")
        self.gridOptions.addWidget(self.label_legendFS, 34, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit legend font size
        self.lineEdit_legendFS = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_legendFS.setObjectName("label_legendFS")
        self.lineEdit_legendFS.textChanged.connect(self.change_legendFS)
        self.gridOptions.addWidget(self.lineEdit_legendFS,34, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_legendFS.setText(str(self.fsize))

        # label legend loc
        self.label_legendLOC = QtWidgets.QLabel(self.parentOptions)
        self.label_legendLOC.setObjectName("label_legendLOC")
        self.label_legendLOC.setText("Legend Location (1-10)")
        self.gridOptions.addWidget(self.label_legendLOC, 36, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit legend loc
        self.lineEdit_legendLOC = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_legendLOC.setObjectName("label_legendLOC")
        self.lineEdit_legendLOC.textChanged.connect(self.change_legendLOC)
        self.gridOptions.addWidget(self.lineEdit_legendLOC,36, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_legendLOC.setText(str(self.fsize))

        # label legend Text
        self.label_legendText = QtWidgets.QLabel(self.parentOptions)
        self.label_legendText.setObjectName("label_legendText")
        self.label_legendText.setText("Legend Text")
        self.gridOptions.addWidget(self.label_legendText, 37, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit legend Text
        self.lineEdit_legendText = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_legendText.setObjectName("label_legendText")
        self.lineEdit_legendText.textChanged.connect(self.change_legendText)
        self.gridOptions.addWidget(self.lineEdit_legendText,37, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_legendText.setText(str("Spectrum"))
        self.change_legendText()

        # label combobox markers
        self.label_markerStyle = QtWidgets.QLabel(self.parentOptions)
        self.label_markerStyle.setObjectName("label_markerStyle")
        self.label_markerStyle.setText("Marker Style")
        self.gridOptions.addWidget(self.label_markerStyle, 38, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # combobox markers
        self.markers_dict = {"None":0, "o":1, ".":2, ",":3, "v":4, "^":5, "<":6, ">":7, "1":8, "2":9, "3":10, "4":11, "8":12, "s":13, "p":14, "P":15, "*":16, "h":17, "H":18, "+":19, "x": 20, "X":21, "D":22, "d":23, "|":24, "_":25}
        self.comboBox_markers = QtWidgets.QComboBox(self.parentOptions)
        self.comboBox_markers.setObjectName("comboBox_markers")
        self.comboBox_markers.addItems(self.markers_dict)
        self.gridOptions.addWidget(self.comboBox_markers, 38, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.comboBox_markers.currentIndexChanged.connect(self.change_markers)
        #self.change_markers()

        # label Marker Size
        self.label_markerSize = QtWidgets.QLabel(self.parentOptions)
        self.label_markerSize.setObjectName("label_markerSize")
        self.label_markerSize.setText("Marker Size (10-30)")
        self.gridOptions.addWidget(self.label_markerSize, 40, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit Marker Size
        self.lineEdit_markerSize= QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_markerSize.setObjectName("label_markersize")
        self.lineEdit_markerSize.textChanged.connect(self.change_markerSize)
        self.gridOptions.addWidget(self.lineEdit_markerSize,40, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_markerSize.setText(str(6))
        self.change_markerSize()

        # label linewidth
        self.label_linewidth = QtWidgets.QLabel(self.parentOptions)
        self.label_linewidth.setObjectName("label_linewidth")
        self.label_linewidth.setText("Linewidth (1.0-12.0)")
        self.gridOptions.addWidget(self.label_linewidth, 42, 0, 1, 1,alignment=QtCore.Qt.AlignLeft)

        # line edit linewidth
        self.lineEdit_linewidth = QtWidgets.QLineEdit(self.parentOptions)
        self.lineEdit_linewidth.setObjectName("label_linewidth")
        self.lineEdit_linewidth.textChanged.connect(self.change_linewidth)
        self.gridOptions.addWidget(self.lineEdit_linewidth,42, 1, 1, 1,alignment=QtCore.Qt.AlignLeft)
        self.lineEdit_linewidth.setText(str(1.0))

        #_______________________________________________________________________


    #===========================================================================
    # Functions
    #===========================================================================

    def change_P1x(self):
        try:
            temp = self.lineEdit_P1x.text()
            if temp != "":
                new = int(temp)
                if new>=0 and new<self.N:
                    self.P1x = new
                    #self.update_pcolor()
                    self.update_draw()
        except Except as error:
            self.ui.update_outputText(str(error))

    def change_P1y(self):
        try:
            temp = self.lineEdit_P1y.text()
            if temp != "":
                new = int(temp)
                if new>=0 and new<self.N:
                    self.P1y = new
                    #self.update_pcolor()
                    self.update_draw()
        except Except as error:
            self.ui.update_outputText(str(error))

    def update_draw(self):
        self.canvas.draw()
        self.canvas.updateGeometry()


    #---------------------------------------------------------------------------
    # Magnitude
    #---------------------------------------------------------------------------
    def change_linewidth(self):
        try:
            self.axes.lines[0].set_linewidth(float(self.lineEdit_linewidth.text()))
            self.canvas.draw()
        except Exception as error:
            pass

    def change_legendText(self):
        try:
            self.axes.legend(labels=[str(self.lineEdit_legendText.text())])
            self.canvas.draw()
        except Exception as error:
            self.ui.update_outputText(error)

    def change_markerSize(self):
        try:
            self.axes.lines[0].set_markersize(int(self.lineEdit_markerSize.text()))
            self.canvas.draw()
        except Exception as error:
            pass

    def change_markers(self):
        try:
            if self.comboBox_markers.currentIndex()==0:
                self.axes.lines[0].set_marker(None)
                self.canvas.draw()
            else:
                self.axes.lines[0].set_marker(str(self.comboBox_markers.currentText()))
                self.canvas.draw()
        except Exception as error:
            self.ui.update_outputText(error)

    def change_legendLOC(self):
        try:
            new = self.lineEdit_legendLOC.text()
            if new != "":
                new = int(self.lineEdit_legendLOC.text())
                if new>=1 and new<=10:
                    self.axes.legend(loc=new)
                    self.canvas.draw()
        except Exception as error:
            self.ui.update_outputText(error)

    def change_legendFS(self):
        try:
            new = self.lineEdit_legendFS.text()
            if new != "":
                new = int(self.lineEdit_legendFS.text())
                self.axes.legend(fontsize=new)
                self.canvas.draw()
        except Exception as error:
            pass #self.ui.update_outputText(error)

    def change_dpi(self):
        try:
            new = int(self.lineEdit_dpi.text())
            if new>=100 and new<=500:
                self.dpi = new
                self.fig.set_dpi(new)
                self.update_draw()
        except:
            pass

    def change_fsize(self):
        try:
            self.fsize = int(self.lineEdit_fsize.text())
            self.change_title()
            self.change_labelx()
            self.change_labely()
            self.update_draw()
            ##print(self.fsize)

        except Exception as error:
            pass #self.ui.update_outputText(error)


    def change_grid(self):
        try:
            if self.checkBox_grid.checkState():
                self.axes.grid(True)
                self.canvas.draw()
            else:
                self.axes.grid(False)
                self.canvas.draw()
        except Exception as error:
            pass
            #self.ui.update_outputText(error)


    def change_legend(self):
        try:
            if self.checkBox_legend.checkState():
                self.axes.legend().set_visible(True)
                self.canvas.draw()
            else:
                self.axes.legend().set_visible(False)
                self.canvas.draw()

        except Exception as error:
            self.ui.update_outputText(error)


    def change_xlim(self):
        try:
            temp_txt = self.lineEdit_xlim.text()
            Ntxt     = len(temp_txt)
            numList = []
            if temp_txt[0]=="(" and temp_txt[-1]==")":
                actual=""
                for i in range(1,Ntxt-1):
                    if temp_txt[i] == ",":
                        numList.append(float(actual))
                        actual = ""
                    elif i==Ntxt-2:
                        actual+=temp_txt[i]
                        numList.append(float(actual))
                    else:
                        actual+=temp_txt[i]
            self.axes.set_xlim(numList[0],numList[1])
        except Exception as error:
            pass
            #self.ui.update_outputText(error)

    def change_ylim(self):
        try:
            temp_txt = self.lineEdit_ylim.text()
            Ntxt     = len(temp_txt)
            numList = []
            if temp_txt[0]=="(" and temp_txt[-1]==")":
                actual=""
                for i in range(1,Ntxt-1):
                    if temp_txt[i] == ",":
                        numList.append(float(actual))
                        actual = ""
                    elif i==Ntxt-2:
                        actual+=temp_txt[i]
                        numList.append(float(actual))
                    else:
                        actual+=temp_txt[i]
            self.axes.set_ylim(numList[0],numList[1])
            self.canvas.draw()
        except Exception as error:
            pass
            #self.ui.update_outputText(error)

    def change_title(self):
        try:
            self.axes.set_title(self.lineEdit_title.text(),fontsize = self.fsize)
            self.canvas.draw()
        except:
            pass

    def change_labelx(self):
        if self.lineEdit_xLabel.text()=="":
            self.axes.set_xlabel("")
        else:
            try:
                self.axes.set_xlabel(self.lineEdit_xLabel.text(),fontsize = self.fsize)
                self.canvas.draw()
            except Exception as error:

                self.ui.update_outputText(str(error))

    def change_labely(self):
        if self.lineEdit_yLabel.text()=="":
            self.axes.set_ylabel("")
        else:
            try:
                self.axes.set_ylabel(self.lineEdit_yLabel.text(),fontsize = self.fsize)
                self.canvas.draw()
            except:
                pass
Example #39
0
class matplotsink(wx.Panel):
    def __init__(self, parent, title, queue, gsz, zoom):
        wx.Panel.__init__(self, parent, wx.SIMPLE_BORDER)

        self.gsz = gsz
        self.parent = parent
        self.title = title
        self.q = queue
        self.zoom = zoom
        self.paused = False

        #        self.create_menu()
        #        self.create_status_bar()
        self.create_main_panel()

    def create_menu(self):
        self.menubar = wx.MenuBar()

        menu_file = wx.Menu()
        m_expt = menu_file.Append(-1, "&Save plot\tCtrl-S",
                                  "Save plot to file")
        self.Bind(wx.EVT_MENU, self.on_save_plot, m_expt)
        menu_file.AppendSeparator()
        m_exit = menu_file.Append(-1, "E&xit\tCtrl-X", "Exit")
        self.Bind(wx.EVT_MENU, self.on_exit, m_exit)
        self.menubar.Append(menu_file, "&File")
        self.SetMenuBar(self.menubar)

    def create_main_panel(self):
        self.panel = self

        self.init_plot()
        self.canvas = FigCanvas(self.panel, -1, self.fig)
        self.scroll_range = 400
        self.canvas.SetScrollbar(wx.HORIZONTAL, 0, 5, self.scroll_range)
        self.canvas.Bind(wx.EVT_SCROLLWIN, self.OnScrollEvt)

        self.pause_button = wx.Button(self.panel, -1, "Pause")
        self.Bind(wx.EVT_BUTTON, self.on_pause_button, self.pause_button)
        self.Bind(wx.EVT_UPDATE_UI, self.on_update_pause_button,
                  self.pause_button)

        self.cb_grid = wx.CheckBox(self.panel,
                                   -1,
                                   "Show Grid",
                                   style=wx.ALIGN_RIGHT)
        self.Bind(wx.EVT_CHECKBOX, self.on_cb_grid, self.cb_grid)
        self.cb_grid.SetValue(True)

        self.cb_xlab = wx.CheckBox(self.panel,
                                   -1,
                                   "Show X labels",
                                   style=wx.ALIGN_RIGHT)
        self.Bind(wx.EVT_CHECKBOX, self.on_cb_xlab, self.cb_xlab)
        self.cb_xlab.SetValue(True)

        self.hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        self.hbox1.Add(self.pause_button,
                       border=5,
                       flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
        self.hbox1.AddSpacer(20)
        self.hbox1.Add(self.cb_grid,
                       border=5,
                       flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
        self.hbox1.AddSpacer(10)
        self.hbox1.Add(self.cb_xlab,
                       border=5,
                       flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)

        self.vbox = wx.BoxSizer(wx.VERTICAL)
        self.vbox.Add(self.canvas, 1, flag=wx.LEFT | wx.TOP | wx.GROW)
        self.vbox.Add(self.hbox1, 0, flag=wx.ALIGN_LEFT | wx.TOP)

        self.panel.SetSizer(self.vbox)
        self.vbox.Fit(self)
        self.ani = animation.FuncAnimation(self.fig,
                                           self.draw_plot,
                                           interval=100)

    def OnScrollEvt(self, event):
        self.i_start = event.GetPosition()
        self.i_end = self.i_window + event.GetPosition()
        self.draw_plot(0)

    def create_status_bar(self):
        self.statusbar = self.CreateStatusBar()

    def draw_test(self, event):
        self.xar = np.arange(len(self.q.queue))
        self.yar = np.array(self.q.queue)
        self.axes.plot(self.xar, self.yar)

    def init_plot(self):
        self.dpi = 100
        self.fig = Figure((3.0, 3.0), dpi=self.dpi)
        self.fig.set_size_inches(7.0, 4.0)
        self.fig.set_dpi(self.dpi)

        self.axes = self.fig.add_subplot(111)
        self.axes.set_axis_bgcolor('black')
        self.axes.set_title(self.title, size=12)

        pylab.setp(self.axes.get_xticklabels(), fontsize=8)
        pylab.setp(self.axes.get_yticklabels(), fontsize=8)
        self.i_window = self.gsz
        self.i_start = 0
        self.i_end = self.i_start + self.i_window
        # plot the data as a line series, and save the reference
        # to the plotted line series
        #
        self.plot_data = self.axes.plot(
            [],
            linewidth=1,
            color=(1, 1, 0),
        )[0]

    def draw_plot(self, event):
        """ Redraws the plot
         """
        if len(list(self.q.queue)) > 1 and not self.paused:

            if self.zoom:
                xmax = len(list(
                    self.q.queue)) if len(list(self.q.queue)) > 50 else 50

                xmin = xmax - 50
                # for ymin and ymax, find the minimal and maximal values
                # in the data set and add a mininal margin.
                #
                # note that it's easy to change this scheme to the
                # minimal/maximal value in the current display, and not
                # the whole data set.
                #
                ymin = round(min(list(self.q.queue)), 0) - 1

                ymax = round(max(list(self.q.queue)), 0) + 1

                self.axes.set_xbound(lower=xmin, upper=xmax)
                self.axes.set_ybound(lower=ymin, upper=ymax)

                # anecdote: axes.grid assumes b=True if any other flag is
                # given even if b is set to False.
                # so just passing the flag into the first statement won't
                # work.
                #
                if self.cb_grid.IsChecked():
                    self.axes.grid(True, color='gray')
                else:
                    self.axes.grid(False)

                # Using setp here is convenient, because get_xticklabels
                # returns a list over which one needs to explicitly
                # iterate, and setp already handles this.
                #
                pylab.setp(self.axes.get_xticklabels(),
                           visible=self.cb_xlab.IsChecked())

                self.plot_data.set_xdata(np.arange(len(list(self.q.queue))))
                self.plot_data.set_ydata(np.array(list(self.q.queue)))
                self.canvas.draw()

            else:
                if self.cb_grid.IsChecked():
                    self.axes.grid(True, color='gray')
                else:
                    self.axes.grid(False)

        # Using setp here is convenient, because get_xticklabels
        # returns a list over which one needs to explicitly
        # iterate, and setp already handles this.

                pylab.setp(self.axes.get_xticklabels(),
                           visible=self.cb_xlab.IsChecked())

                self.plot_data.set_xdata(
                    np.arange(len(list(
                        self.q.queue)))[self.i_start:self.i_end])
                self.plot_data.set_ydata(
                    np.array(list(self.q.queue))[self.i_start:self.i_end])
                self.axes.set_xlim(
                    min(
                        np.arange(len(list(
                            self.q.queue)))[self.i_start:self.i_end]),
                    max(
                        np.arange(len(list(
                            self.q.queue)))[self.i_start:self.i_end]))
                #		 if self.zoom:
                self.axes.set_ylim(min(np.array(list(self.q.queue))),
                                   max(np.array(list(self.q.queue))))

                self.canvas.draw()

    def on_pause_button(self, event):
        self.paused = not self.paused

    def on_update_pause_button(self, event):
        label = "Resume" if self.paused else "Pause"
        self.pause_button.SetLabel(label)

    def on_cb_grid(self, event):
        self.draw_plot(0)

    def on_cb_xlab(self, event):
        self.draw_plot(0)

    def on_save_plot(self, event):
        file_choices = "PNG (*.png)|*.png"

        dlg = wx.FileDialog(self,
                            message="Save plot as...",
                            defaultDir=os.getcwd(),
                            defaultFile="plot.png",
                            wildcard=file_choices,
                            style=wx.SAVE)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.canvas.print_figure(path, dpi=self.dpi)
            self.flash_status_message("Saved to %s" % path)

    def on_redraw_timer(self, event):
        # if paused do not add data, but still redraw the plot
        # (to respond to scale modifications, grid change, etc.)
        #
        if not self.paused:
            self.data += self.datagen.next()
        self.draw_plot(0)

    def on_exit(self, event):
        self.Destroy()

    def flash_status_message(self, msg, flash_len_ms=1500):
        self.statusbar.SetStatusText(msg)
        self.timeroff = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.on_flash_status_off, self.timeroff)
        self.timeroff.Start(flash_len_ms, oneShot=True)

    def on_flash_status_off(self, event):
        self.statusbar.SetStatusText('')
Example #40
0
class PlotSettings(object):
    """
    The PlotSettings-class initializes the default values for the plot.

    The class can return those values to the main window and the plot-settings
    dialog. The plot-settings dialog will call the instance of this class to
    change the different settings. This class also stores the figure and can
    return different subplot-layouts. This class also stores the normal and
    inverse transformations of the stereonet, and will return the correct
    one for either the Schmidt- or Wulff-Net.
    """
    def __init__(self, testing):
        """
        Initalizes the default values, colors and the matplotlib-figure.

        Initializes and stores the default settings. Initializes the
        matplotlib-figure, a folder-icon for the group-layers of the layer-view.
        """
        self.folder_icon = Gtk.IconTheme.get_default().load_icon(
            "folder", 16, 0)
        self.props = OrderedDict(
            sorted({
                "draw_grid": True,
                "equal_area_projection": True,
                "minor_grid_spacing": 2,
                "major_grid_spacing": 10,
                "grid_cutoff_lat": 80,
                "show_north": True,
                "show_cross": True,
                "pixel_density": 75,
                "grid_linestyle": "--",
                "grid_color": "#787878",
                "grid_width": 0.4,
                "draw_legend": True,
                "canvas_color": "#bfbfbf",
                "highlight": False
            }.items()))
        self.night_mode = False
        self.fig = Figure(dpi=self.props["pixel_density"])
        if testing == False:
            try:
                self.g_settings = Gio.Settings.new("org.gtk.innstereo")
                self.get_defaults()
            except:
                pass

    def get_defaults(self):
        """
        Gets the defaults from the Gio.Settings.
        """
        self.props["draw_legend"] = self.g_settings.get_boolean("show-legend")
        self.props["draw_grid"] = self.g_settings.get_boolean("draw-grid")
        self.props["equal_area_projection"] = self.g_settings.get_boolean(
            "stereonet-projection")
        self.props["show_cross"] = self.g_settings.get_boolean("center-cross")
        self.night_mode = self.g_settings.get_boolean("night-mode")
        self.props["pixel_density"] = self.g_settings.get_value(
            "pixel-density").get_int32()
        self.props["highlight"] = self.g_settings.get_boolean("highlight-mode")

    def get_fig(self):
        """
        Returns the Matplotlib-Figure.

        Returns the figure that is stored by this class. The MainWindow class
        calls this function once during initialization to add the figure to
        the FigureCanvas.
        """
        return self.fig

    def get_inverse_transform(self):
        """
        Returns the inverse transform for the current stereonet projection.

        If the projection is equal are (True) the function returns the
        InvertedLambertTransform- or else the
        InvertedSterreographicTransform-class.
        """
        if self.props["equal_area_projection"] is True:
            return mplstereonet.stereonet_transforms.\
                        InvertedLambertTransform(0, 0,
                        self.props["pixel_density"])
        else:
            return mplstereonet.stereonet_transforms.\
                        InvertedStereographicTransform(0, 0,
                        self.props["pixel_density"])

    def get_transform(self):
        """
        Returns the normal transform for the current stereonet projection.

        If the projection is equal are (True) the function returns the
        LambertTransform- or else the SterreographicTransform-class.
        """
        if self.props["equal_area_projection"] is True:
            return mplstereonet.stereonet_transforms.\
                        LambertTransform(0, 0,
                        self.props["pixel_density"])
        else:
            return mplstereonet.stereonet_transforms.\
                        StereographicTransform(0, 0,
                        self.props["pixel_density"])

    def get_draw_grid_state(self):
        """
        Returns if the grid should be drawn for the stereonet.

        Returns a boolean. True mean that a grid should be drawn. False means
        that no grid should be drawn. This method is called by the MainWindow-
        redraw_plot-method.
        """
        return self.props["draw_grid"]

    def set_draw_grid_state(self, new_state):
        """
        Sets if the grid should be drawn for the stereonet.

        Expects a boolean. True mean that a grid should be drawn. False means
        that no grid should be drawn. This method is called by the
        LayerProperties-dialog when the setting is changed.
        """
        self.props["draw_grid"] = new_state

    def get_folder_icon(self):
        """
        Returns the folder icon used for the group-layer pixbuf.

        Always returns the "folder" icon from the Gtk.IconTheme. The folder
        will therefore match the desktop-theme set by the user. This method is
        called by the MainWindow "on_toolbutton_create_group_layer_clicked"-
        method.
        """
        return self.folder_icon

    def get_pixel_density(self):
        """
        Returns the pixel density the plot is using.

        The pixel density is an int and the default value is 75. This method
        is called by the LayerProperties-dialog so it can display the current
        value.
        """
        return self.props["pixel_density"]

    def set_pixel_density(self, new_pixel_density):
        """
        Sets a new pixel density for the plot.

        Expects an int. This method is called by the LayerProperties-dialog.
        The new value will be used when the plot redraws when the settings
        in the dialog are applied.
        """
        self.props["pixel_density"] = new_pixel_density

    def get_projection(self):
        """
        Returns the projection currently used by the stereonet.

        Returns one of two strings that MPLStereonet uses to distinguish
        between the equal-area and equal-angle projection. This method is only
        called from this class when the view is switched.
        """
        if self.props["equal_area_projection"] is True:
            return "equal_area_stereonet"
        else:
            return "equal_angle_stereonet"

    def get_projection_state(self):
        """
        Returns the projection state for the stereonet.

        Returns a boolean. True means that the stereonet should be drawn
        with equal-area. False mean equal-angle. This method is called by the
        StereonetProperties-dialog to load the current setting.
        """
        return self.props["equal_area_projection"]

    def set_projection_state(self, new_state):
        """
        Sets a new projection state.

        Expects a boolean. True means that the projection will be equal-area,
        False means equal-angle. This method is called by the
        StereonetProperties-dialog when a new setting for the projection is
        applied.
        """
        self.props["equal_area_projection"] = new_state

    def get_grid_linestyle(self):
        """
        Returns the linestyle of the grid.

        The linestyle is returned as a string. Default is "--" (dashed). This
        method is called by the MainWindow "redraw_plot"-method.
        """
        return self.props["grid_linestyle"]

    def get_grid_color(self):
        """
        Returns the color of the grid.

        Returns the color as a hex-triplet. The default is "#787878". This
        method is called by the MainWindow "redraw_plot"-method.
        """
        return self.props["grid_color"]

    def get_grid_width(self):
        """
        Returns the width of the grid lines.

        The width of the grid lines is returned as a float or int. The default
        is "0.4". This method is called by the MainWindow "redraw_plot"-method.
        """
        return self.props["grid_width"]

    def get_draw_legend(self):
        """
        Returns if the legend should be drawn as a boolean.

        The returned value is either True if a legend should be drawn, or False
        if no legend should be drawn. This method is called by the MainWindow
        "redraw_plot"-method and the StereonetProperties-dialog.
        """
        return self.props["draw_legend"]

    def set_draw_legend(self, new_state):
        """
        Sets a new state for whether the legend should be drawn.

        Expects a boolean. True means that the legend should be drawn. False
        means that no legend should be drawn. This method is called by the
        StereonetProperties-dialog when a new setting is applied.
        """
        self.props["draw_legend"] = new_state

    def get_canvas_rgba(self):
        """
        Returns the canvas color as a Gdk.RGBA.

        This method is called by the StereonetProperties-dialog to apply the
        current canvas color to the ColorButton.
        """
        rgba = Gdk.RGBA()
        rgba.parse(self.props["canvas_color"])
        return rgba.to_color()

    def set_canvas_color(self, new_color):
        """
        Sets a new canvas color.

        Expects a hex-triplet string (e.g. "#bfbfbf"). This method is called
        by the StereonetProperties-dialog when a new color is applied to the
        canvas.
        """
        self.props["canvas_color"] = new_color

    def get_stereonet(self):
        """
        Resets the figure and returns the stereonet axis.

        When the view in the main window is changed to only stereoent. The
        figure is reset. Then the current settings are applied and one subplot
        for the stereonet is created. This method is called when the
        MainWindow "__init__"-method and the "redraw_plot"-method. 
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.props["canvas_color"])
        self.fig.set_dpi(self.props["pixel_density"])
        gridspec = GridSpec(2, 3)
        sp_stereo = gridspec.new_subplotspec((0, 0), rowspan=2, colspan=2)
        sp_cbar = gridspec.new_subplotspec((1, 2), rowspan=1, colspan=1)
        ax_stereo = self.fig.add_subplot(sp_stereo,
                                         projection=self.get_projection())
        ax_cbar = self.fig.add_subplot(sp_cbar)
        ax_cbar.axis("off")
        ax_cbar.set_aspect(8)
        return ax_stereo, ax_cbar

    def get_stereo_rose(self):
        """
        Resets the figure and returns a stereonet and rose diagram axis.

        When the view in the main window is changed to stereonet and rose
        diagram, the figure is reset. The current settings are applied and
        two subplots for the stereonet and rose diagram are created. The
        axis of the stereonet and rose diagram are returned. This method is
        called by the MainWindow "redraw_plot"-method.
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.props["canvas_color"])
        self.fig.set_dpi(self.props["pixel_density"])
        gridspec = GridSpec(2, 5)
        sp_stereo = gridspec.new_subplotspec((0, 0), rowspan=2, colspan=2)
        sp_cbar = gridspec.new_subplotspec((1, 2), rowspan=1, colspan=1)
        sp_rose = gridspec.new_subplotspec((0, 3), rowspan=2, colspan=2)
        ax_stereo = self.fig.add_subplot(sp_stereo,
                                         projection=self.get_projection())
        ax_rose = self.fig.add_subplot(sp_rose, projection="northpolar")

        ax_cbar = self.fig.add_subplot(sp_cbar)
        ax_cbar.axis("off")
        ax_cbar.set_aspect(8)
        return ax_stereo, ax_rose, ax_cbar

    def get_stereo_two_rose(self):
        """
        Resets the figure and returns a stereonet two rose diagrams axis.

        When the view in the main window is changed to this setting, this
        function is called and sets up a plot with a stereonet and two
        rose diagram axis. One axis is for azimuth, the other one for
        dip.
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.props["canvas_color"])
        self.fig.set_dpi(self.props["pixel_density"])
        gridspec = GridSpec(2, 4)
        sp_stereo = gridspec.new_subplotspec((0, 0), rowspan=2, colspan=2)
        sp_cbar = gridspec.new_subplotspec((1, 2), rowspan=1, colspan=1)
        sp_rose = gridspec.new_subplotspec((0, 3), rowspan=1, colspan=1)
        sp_drose = gridspec.new_subplotspec((1, 3), rowspan=1, colspan=1)
        ax_stereo = self.fig.add_subplot(sp_stereo,
                                         projection=self.get_projection())
        ax_rose = self.fig.add_subplot(sp_rose, projection="northpolar")
        ax_drose = self.fig.add_subplot(sp_drose, projection="dippolar")
        ax_cbar = self.fig.add_subplot(sp_cbar)
        ax_cbar.axis("off")
        ax_cbar.set_aspect(8)
        return ax_stereo, ax_rose, ax_drose, ax_cbar

    def get_rose_diagram(self):
        """
        Resets the figure and returns the rose diagram axis.

        When the view in the main window is changed to rose-diagram-only the
        figure is reset. The current settings are applied and one subplot
        for the rose diagram is created. The axis of the rose-diagram is
        returned. This method is called by the MainWindow "redraw_plot"-method.
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.props["canvas_color"])
        self.fig.set_dpi(self.props["pixel_density"])
        gridspec = GridSpec(1, 1)
        sp_rose = gridspec.new_subplotspec((0, 0))
        ax_rose = self.fig.add_subplot(sp_rose, projection="northpolar")
        return ax_rose

    def get_pt_view(self):
        """
        Resets the canvas and returns the 3 axis of the paleostress view.

        When the view in the main window is changed to paleostress the figure
        is reset. The current settings are applied and 3 subplots are created.
        The 3 axis of the subplots are returned. This method is called by the
        MainWindow "redraw_plot"-method when the view has been changed.
        """
        self.fig.clf()
        self.fig.patch.set_facecolor(self.props["canvas_color"])
        self.fig.set_dpi(self.props["pixel_density"])
        gridspec = GridSpec(2, 5)
        sp_stereo = gridspec.new_subplotspec((0, 0), colspan=3, rowspan=2)
        sp_fluc = gridspec.new_subplotspec((0, 3), colspan=2)
        sp_mohr = gridspec.new_subplotspec((1, 3), colspan=2)
        ax_stereo = self.fig.add_subplot(sp_stereo,
                                         projection=self.get_projection())
        ax_fluc = self.fig.add_subplot(sp_fluc, aspect="equal")
        ax_mohr = self.fig.add_subplot(sp_mohr, aspect="equal")
        return ax_stereo, ax_fluc, ax_mohr

    def get_show_north(self):
        """
        Returns if the stereonet should show the North symbol or degrees

        Returns True if the North symbol should be drawn (the default value),
        or False in which case numbers will be drawn for different degrees.
        """
        return self.props["show_north"]

    def set_show_north(self, new_state):
        """
        Sets a new state for whether the North symbol should be drawn.

        Expects a boolean. True means the North symbol will be drawn. False
        means that the stereonet will show different degrees along the outside.
        """
        self.props["show_north"] = new_state

    def get_show_cross(self):
        """
        Returns if the stereonet should draw a cross at the center.

        Returns True if the cross should be drawn (the default value) or False
        if the cross should not be drawn.
        """
        return self.props["show_cross"]

    def set_show_cross(self, new_state):
        """
        Sets a new state for whether the center cross should be drawn.

        Expects a boolean. True means the center cross will be drawn. False
        means it will not be drawn.
        """
        self.props["show_cross"] = new_state

    def get_properties(self):
        """
        Returns the current plot properties in a dictionary.

        The plot properties are stored in a dictionary. For loading and saving
        the dict is requested by the main window.
        """
        return self.props

    def set_properties(self, new_props):
        """
        Sets the properties to those passed in a dictionary.

        Loading a file will also set the plot properties to the saved state.
        The properties are appllied to this plot.
        """
        for key in new_props:
            self.props[key] = new_props[key]

    def get_highlight(self):
        """
        Gets the state of selection highlighting.

        Default is False.
        """
        return self.props["highlight"]

    def set_highlight(self, new_state):
        """
        Sets a new state for highlighting.

        Expects a boolean.
        """
        self.props["highlight"] = new_state

    def get_night_mode(self):
        """
        Gets the state of the night mode.

        Default is False, which is usually a lighter interface color.
        """
        return self.night_mode

    def set_night_mode(self, new_state):
        """
        Sets a new state for the night mode.

        Expects a boolean.
        """
        self.night_mode = new_state
Example #41
0
class Graph(object):
    """
    Class for matplotlib graphs, i.e. for popups, krw graphs

    - Calculates correct size

    - Horizontal axis = dates

    - Vertical axis = user defined

    - Outputs httpresponse for png
    """

    def __init__(self,
                 start_date, end_date,
                 width=None, height=None,
                 today=datetime.datetime.now(),
                 restrict_to_month=None,
                 tz=None):
        self.start_date = start_date
        self.end_date = end_date
        self.today = today
        self.restrict_to_month = restrict_to_month
        self.tz = tz

        self.figure = Figure()
        if width is None or not width:
            width = 380.0
        if height is None or not height:
            height = 240.0
        self.width = float(width)
        self.height = float(height)
        self.figure.set_size_inches((_inches_from_pixels(self.width),
                                     _inches_from_pixels(self.height)))
        self.figure.set_dpi(SCREEN_DPI)
        # Figure color
        self.figure.set_facecolor('white')
        # Axes and legend location: full width is "1".
        self.legend_width = 0.08
        # ^^^ No legend by default, but we *do* allow a little space to the
        # right of the graph to prevent the rightmost label from being cut off
        # (at least, in a reasonable percentage of the cases).
        self.left_label_width = LEFT_LABEL_WIDTH / self.width
        self.bottom_axis_location = BOTTOM_LINE_HEIGHT / self.height
        self.x_label_height = 0.08
        self.legend_on_bottom_height = 0.0
        self.axes = self.figure.add_subplot(111)
        self.axes.grid(True)

        # We track whether y_lim has been set manually
        self._y_min_set_manually = False
        self._y_max_set_manually = False

        # Fixup_axes in init, so axes can be customised (for example set_ylim).
        self.fixup_axes()

        #deze kan je zelf zetten
        self.ax2 = None

    def set_ylim(self, y_min, y_max, min_manual=False, max_manual=False):
        logger.debug('set_ylim y_min = %f y_max = %f' % (y_min, y_max))
        self.axes.set_ylim(y_min, y_max)
        self._y_min_set_manually = min_manual
        self._y_max_set_manually = max_manual

    def add_today(self):
        # Show line for today.
        self.axes.axvline(self.today, color='orange', lw=1, ls='--')

    def set_ylim_margin(self, top=0.1, bottom=0.0):
        """Adjust y-margin of axes.

        The standard margin is sometimes zero. This method sets the margin
        based on already present data in the visible part of the plot, so
        call it after plotting and before http_png().

        Note that it is assumed here that the y-axis is not reversed.

        From matplotlib 1.0 on there is a set_ymargin method
        like this already.
        """

        lines = self.axes.lines
        arrays = [numpy.array(l.get_data()) for l in lines]

        # axhline and axvline give trouble - remove short lines from list
        big_arrays = [a for a in arrays if a.size > 4]
        if len(big_arrays) > 0:
            data = numpy.concatenate(big_arrays, axis=1)
            if len(data[0]) > 0:
                # Datatimes from database may have timezone information.
                # In that case, start_date and end_date cannot be naive.
                # Assume all datetimes do have the same timezone, so we
                # can do the comparison.
                start_date_tz =\
                    self.start_date.replace(tzinfo=data[0][0].tzinfo)
                end_date_tz =\
                    self.end_date.replace(tzinfo=data[0][0].tzinfo)
            index_in_daterange = ((data[0] < end_date_tz) &
                                  (data[0] > start_date_tz))

            # Calculate correct y_min and y_max, but use old if they have
            # already been set manually
            if index_in_daterange.any():
                data_low = numpy.min(data[1, index_in_daterange])
                data_high = numpy.max(data[1, index_in_daterange])
                data_span = data_high - data_low

                view_low = data_low - data_span * bottom
                view_high = data_high + data_span * top

                # Don't zoom in too much if values are essentially the same
                # and differ only in noise. Values shown at the Y-axis should
                # only have 2 decimals.
                view_low = math.floor(view_low * 40) / 40
                view_high = math.ceil(view_high * 40) / 40
                while (view_high - view_low) < 0.03:
                    # Difference is only 0.025 (or 0!), differences of
                    # smaller than 0.01 show up at the y-axis.
                    view_low -= 1.0 / 80
                    view_high += 1.0 / 80

                if self._y_min_set_manually:
                    view_low, _ = self.axes.get_ylim()
                if self._y_max_set_manually:
                    _, view_high = self.axes.get_ylim()

                self.axes.set_ylim(view_low, view_high)
        return None

    def suptitle(self, title):
        self.figure.suptitle(title,
                             x=self.left_label_width,
                             horizontalalignment='left')

    def set_xlabel(self, xlabel):
        self.axes.set_xlabel(xlabel)
        self.x_label_height = BOTTOM_LINE_HEIGHT / self.height

    def fixup_axes(self, second=False):
        """Fix up the axes by limiting the amount of items."""

        axes_to_change = self.axes
        if second:
            if self.ax2 is None:
                return
            else:
                axes_to_change = self.ax2

        if not self.restrict_to_month:
            major_locator = LessTicksAutoDateLocator()
            axes_to_change.xaxis.set_major_locator(major_locator)

            major_formatter = MultilineAutoDateFormatter(
                major_locator, axes_to_change, tz=self.tz)
            axes_to_change.xaxis.set_major_formatter(major_formatter)

        available_height = (self.height -
                            BOTTOM_LINE_HEIGHT -
                            self.x_label_height -
                            self.legend_on_bottom_height)
        approximate_lines = int(available_height / (FONT_SIZE * 2.5))
        logger.info("#lines: %s", approximate_lines)
        max_number_of_ticks = approximate_lines
        if max_number_of_ticks < 2:
            max_number_of_ticks = 2
        locator = MaxNLocator(nbins=max_number_of_ticks - 1)
        if not second:
            axes_to_change.yaxis.set_major_locator(locator)
            # ^^^ [Arjan:] Turns out default amount of ticks wasn't that bad.
            # [Reinout:] I keep hearing complaints so I've re-enabled it.
            axes_to_change.yaxis.set_major_formatter(
                ScalarFormatter(useOffset=False))
        self.axes.set_ylabel(self.axes.get_ylabel(), size='x-large')

    def legend_space(self):
        """Reserve space for legend (on the right side). even when
        there is no legend displayed
        """
        self.legend_width = LEGEND_WIDTH / self.width

    def legend(self,
               handles=None,
               labels=None,
               ncol=1,
               force_legend_below=False):
        """
        Displays legend. Default is right side, but if the width is
        too small, it will display under the graph.

        Handles is list of matplotlib objects (e.g. matplotlib.lines.Line2D)

        Labels is list of strings
        """
        # experimental update: do not reserve space for legend by
        # default, just place over graph. use legend_space to manually
        # add space

        if handles is None and labels is None:
            handles, labels = self.axes.get_legend_handles_labels()
        if handles and labels:
            # Determine 'small' or 'large'
            # if self.width < 500 or force_legend_below:
            if force_legend_below:
                # TODO: Maybe remove this feature? Needs tweaking. The
                # legend is still on top of the graph, while the graph
                # reserves room for the legend below.
                legend_loc = 4  # lower right
                # approximation of legend height
                self.legend_on_bottom_height = min(
                    (len(labels) / ncol + 2) * BOTTOM_LINE_HEIGHT /
                    self.height,
                    0.5)
            else:
                legend_loc = 1  # Upper right'

            # For width 464 (empty space 150px assumed), we have:
            # <= 40 = medium
            # > 40 = small
            # > 50 = x-small
            # > 65 = xx-small
            # Fixes #3095
            font_len = max([len(label) for label in labels])
            font_size = 'medium'  # 'medium'
            if font_len > 40 * ((self.width - 150) / 314.0):
                font_size = 'small'
            if font_len > 50 * ((self.width - 150) / 314.0):
                font_size = 'x-small'
            if font_len > 65 * ((self.width - 150) / 314.0):
                font_size = 'xx-small'
            prop = {'size': font_size}

            return self.axes.legend(
                handles,
                labels,
                bbox_to_anchor=(1 - self.legend_width,
                                0,  # self.bottom_axis_location
                                self.legend_width,
                                # 1 = Upper right of above bbox. Use 0 for
                                # 'best'
                                1),
                prop=prop,
                loc=legend_loc,
                ncol=ncol,
                fancybox=True,
                shadow=True,)
            #legend.set_size('medium')
            # TODO: get rid of the border around the legend.
            # to get rid of the border: graph.axes.legend_.draw_frame(False)

    def init_second_axes(self):
        """Init second axes """
        self.ax2 = self.axes.twinx()
        self.fixup_axes(second=True)

    def http_png(self):
        """Output plot to png. Also calculates size of plot and put 'now'
        line."""

        axes_left = self.left_label_width
        axes_bottom = (self.bottom_axis_location + self.x_label_height +
                       self.legend_on_bottom_height)
        axes_width = 1 - self.legend_width - self.left_label_width
        axes_height = (1 - 2 * self.bottom_axis_location -
                       self.x_label_height - self.legend_on_bottom_height)

        self.axes.set_position((axes_left, axes_bottom,
                                axes_width, axes_height))

        if self.ax2 is not None:
            self.ax2.set_position((axes_left, axes_bottom,
                                   axes_width, axes_height))

        # Set date range
        # Somehow, the range cannot be set in __init__
        if not self.restrict_to_month:
            self.axes.set_xlim(date2num((self.start_date, self.end_date)))
            try:
                self.set_ylim_margin(top=0.1, bottom=0.0)
            except:
                pass

        # Because of the use of setlocale to nl_NL, dutch monthnames can no
        # Longer be top-aligned.
        if locale.getlocale(locale.LC_TIME) == ('nl_NL', 'UTF8'):
            for l in self.axes.get_xticklabels():
                l.set_verticalalignment('baseline')
                l.set_position((0, -0.05))

        canvas = FigureCanvas(self.figure)
        response = HttpResponse(content_type='image/png')
        canvas.print_png(response)
        return response

    def render(self):
        '''
        more general alias for http_png(), to support FlotGraph
        should return a valid HttpResponse
        '''
        return self.http_png()
Example #42
0
class OldGraph(object):
    """
    Class for matplotlib graphs, i.e. for popups, krw graphs

    - calculates correct size
    - horizontal axis = dates
    - vertical axis = user defined
    - outputs httpresponse for png
    """

    def __init__(self,
                 start_date, end_date,
                 width=None, height=None,
                 today=datetime.datetime.now(),
                 restrict_to_month=None):
        self.restrict_to_month = restrict_to_month
        self.start_date = start_date
        self.end_date = end_date
        self.today = today

        self.figure = Figure()
        if width is None or not width:
            width = 380.0
        if height is None or not height:
            height = 250.0
        self.width = float(width)
        self.height = float(height)
        self.figure.set_size_inches((_inches_from_pixels(self.width),
                                     _inches_from_pixels(self.height)))
        self.figure.set_dpi(SCREEN_DPI)
        # Figure color
        self.figure.set_facecolor('white')
        # Axes and legend location: full width is "1".
        self.legend_width = 0.08
        # ^^^ No legend by default, but we *do* allow a little space to the
        # right of the graph to prevent the rightmost label from being cut off
        # (at least, in a reasonable percentage of the cases).
        self.left_label_width = LEFT_LABEL_WIDTH / self.width
        self.bottom_axis_location = BOTTOM_LINE_HEIGHT / self.height
        self.x_label_height = 0.08
        self.legend_on_bottom_height = 0.0
        self.axes = self.figure.add_subplot(111)
        self.axes.grid(True)

        # Fixup_axes in init, so axes can be customised (for example set_ylim).
        self.fixup_axes()

        #deze kan je zelf zetten
        self.ax2 = None

    def add_today(self):
        # Show line for today.
        self.axes.axvline(self.today, color='orange', lw=1, ls='--')

    def set_ylim_margin(self, top=0.1, bottom=0.0):
        """Adjust y-margin of axes.

        The standard margin is sometimes zero. This method sets the margin
        based on already present data in the visible part of the plot, so
        call it after plotting and before http_png().

        Note that it is assumed here that the y-axis is not reversed.

        From matplotlib 1.0 on there is a set_ymargin method
        like this already."""

        lines = self.axes.lines
        arrays = [numpy.array(l.get_data()) for l in lines]

        # axhline and axvline give trouble - remove short lines from list
        big_arrays = [a for a in arrays if a.size > 4]
        if len(big_arrays) > 0:
            data = numpy.concatenate(big_arrays, axis=1)
            if len(data[0]) > 0:
                # Datatimes from database may have timezone information.
                # In that case, start_date and end_date cannot be naive.
                # Assume all datetimes do have the same timezone, so we
                # can do the comparison.
                start_date_tz =\
                    self.start_date.replace(tzinfo=data[0][0].tzinfo)
                end_date_tz =\
                    self.end_date.replace(tzinfo=data[0][0].tzinfo)
            index_in_daterange = ((data[0] < end_date_tz) &
                                  (data[0] > start_date_tz))
            if index_in_daterange.any():
                data_low = numpy.min(data[1, index_in_daterange])
                data_high = numpy.max(data[1, index_in_daterange])
                data_span = data_high - data_low
                view_low = data_low - data_span * bottom
                view_high = data_high + data_span * top
                self.axes.set_ylim(view_low, view_high)
        return None

    def suptitle(self, title):
        self.figure.suptitle(title,
                             x=self.left_label_width,
                             horizontalalignment='left')

    def set_xlabel(self, xlabel):
        self.axes.set_xlabel(xlabel)
        self.x_label_height = BOTTOM_LINE_HEIGHT / self.height

    def fixup_axes(self, second=False):
        """Fix up the axes by limiting the amount of items."""

        axes_to_change = self.axes
        if second:
            if self.ax2 is None:
                return
            else:
                axes_to_change = self.ax2

#        available_width = self.width - LEFT_LABEL_WIDTH - LEGEND_WIDTH
#        approximate_characters = int(available_width / (FONT_SIZE / 2))
#        max_number_of_ticks = approximate_characters // 20
#        if max_number_of_ticks < 2:
#            max_number_of_ticks = 2
        if not self.restrict_to_month:
            major_locator = LessTicksAutoDateLocator()
            axes_to_change.xaxis.set_major_locator(major_locator)

            major_formatter = MultilineAutoDateFormatter(
                major_locator, axes_to_change)
            axes_to_change.xaxis.set_major_formatter(major_formatter)

        available_height = (self.height -
                            BOTTOM_LINE_HEIGHT -
                            self.x_label_height -
                            self.legend_on_bottom_height)
        approximate_lines = int(available_height / (FONT_SIZE * 1.5))
        max_number_of_ticks = approximate_lines
        if max_number_of_ticks < 2:
            max_number_of_ticks = 2
        locator = MaxNLocator(nbins=max_number_of_ticks - 1)
        if not second:
            axes_to_change.yaxis.set_major_locator(locator)
            axes_to_change.yaxis.set_major_formatter(
                ScalarFormatter(useOffset=False))

    def legend_space(self):
        """reserve space for legend (on the right side). even when
        there is no legend displayed"""
        self.legend_width = LEGEND_WIDTH / self.width

    def legend(self, handles=None, labels=None, ncol=1):
        """
        Displays legend. Default is right side, but if the width is
        too small, it will display under the graph.

        handles is list of matplotlib objects (e.g. matplotlib.lines.Line2D)
        labels is list of strings
        """
        # experimental update: do not reserve space for legend by
        # default, just place over graph. use legend_space to manually
        # add space

        if handles is None and labels is None:
            handles, labels = self.axes.get_legend_handles_labels()
        if handles and labels:
            # Determine 'small' or 'large'
            if self.width < 500:
                legend_loc = 4  # lower right
                # approximation of legend height
                self.legend_on_bottom_height = min(
                    (len(labels) / ncol + 2) * BOTTOM_LINE_HEIGHT /
                    self.height,
                    0.5)
            else:
                legend_loc = 1  # Upper right'

            return self.figure.legend(
                handles,
                labels,
                bbox_to_anchor=(1 - self.legend_width,
                                0,  # self.bottom_axis_location
                                self.legend_width,
                                # 1 = Upper right of above bbox. Use 0 for
                                # 'best'
                                1),
                loc=legend_loc,
                ncol=ncol,
                fancybox=True,
                shadow=True,)
         #legend.set_size('medium')
         # TODO: get rid of the border around the legend.

    def init_second_axes(self):
        """ init second axes """
        self.ax2 = self.axes.twinx()
        self.fixup_axes(second=True)

    def http_png(self):
        """Output plot to png. Also calculates size of plot and put 'now'
        line."""

        axes_left = self.left_label_width
        axes_bottom = (self.bottom_axis_location + self.x_label_height +
                       self.legend_on_bottom_height)
        axes_width = 1 - self.legend_width - self.left_label_width
        axes_height = (1 - 2 * self.bottom_axis_location -
                       self.x_label_height - self.legend_on_bottom_height)

        self.axes.set_position((axes_left, axes_bottom,
                                axes_width, axes_height))

        if self.ax2 is not None:
            self.ax2.set_position((axes_left, axes_bottom,
                                axes_width, axes_height))

        # Set date range
        # Somehow, the range cannot be set in __init__
        if not self.restrict_to_month:
            self.axes.set_xlim(date2num((self.start_date, self.end_date)))
            try:
                self.set_ylim_margin(top=0.1, bottom=0.0)
            except:
                pass

        canvas = FigureCanvas(self.figure)
        response = HttpResponse(content_type='image/png')
        canvas.print_png(response)
        return response
Example #43
0
    def calculateObstacleMap(self,
                             resolution=0.1,
                             level=0,
                             zlim=(0.15, 1.50),
                             xlim=None,
                             ylim=None,
                             roomIds=None,
                             layoutOnly=False):

        figSize = (10, 10)
        fig = Figure(figsize=figSize, dpi=100, frameon=False)
        canvas = FigureCanvas(fig)
        ax = fig.add_subplot(111, aspect='equal')
        fig.subplots_adjust(left=0,
                            bottom=0,
                            right=1,
                            top=1,
                            wspace=0,
                            hspace=0)
        ax.axis('off')
        ax.set_aspect('equal')

        floorZ = self._getFloorReferenceZ(level)
        zlim = np.array(zlim) + floorZ

        if roomIds is not None:
            layoutModels = []
            objModels = []
            for roomId in roomIds:
                layoutModels.extend([
                    model for model in self.scene.scene.findAllMatches(
                        '**/level-%d/room-%s/layouts/object-*/+ModelNode' %
                        (level, roomId))
                ])
                objModels.extend([
                    model for model in self.scene.scene.findAllMatches(
                        '**/level-%d/room-%s/objects/object-*/+ModelNode' %
                        (level, roomId))
                ])
        else:
            layoutModels = [
                model for model in self.scene.scene.findAllMatches(
                    '**/level-%d/**/layouts/object-*/+ModelNode' % level)
            ]
            objModels = [
                model for model in self.scene.scene.findAllMatches(
                    '**/level-%d/**/objects/object-*/+ModelNode' % level)
            ]

        # Loop for all walls in the scene:
        for model in layoutModels:
            modelId = model.getNetTag('model-id')

            if not modelId.endswith('w'):
                continue

            addModelTriangles(ax, model, zlim=zlim)

        # Loop for all doors in the scene:
        for model in objModels:

            modelId = model.getNetTag('model-id')
            if self._isDoor(modelId):

                if modelId in self.openedStandardDoorModelIds:
                    # Shift the model a little more to the wall
                    transform = TransformState.makePos(
                        LVector3f(0.0, -0.10, 0.0))
                    # Reduce width by 25% not to mess with close corner walls
                    transform = transform.compose(
                        TransformState.makeScale(LVector3f(0.75, 1.0, 1.0)))
                elif modelId in self.openedThinDoorModelIds:
                    # Rescale the model to be able to cover the entire depth of walls
                    # Reduce width by 25% not to mess with close corner walls
                    transform = TransformState.makeScale(
                        LVector3f(0.75, 4.0, 1.0))
                elif modelId in self.openedGarageDoorModelIds:
                    # Shift the model a little more to the wall
                    transform = TransformState.makePos(
                        LVector3f(0.0, 0.10, 0.0))
                    # Reduce width by 10% not to mess with close corner walls
                    transform = transform.compose(
                        TransformState.makeScale(LVector3f(0.90, 1.0, 1.0)))
                else:
                    raise Exception('Unsupported model id: %s' % (modelId))

                # TODO: would be more efficient if it needed not copying the
                # model
                parentNp = NodePath('tmp-objnode')
                parentNp.setTransform(model.getParent().getNetTransform())
                midNp = parentNp.attachNewNode('tmp-transform')
                midNp.setTransform(transform)
                model = model.copyTo(midNp)
                approxModel = getApproximationForModel(model, mode='box')
                addModelTriangles(ax, approxModel, invert=True, zlim=zlim)
                approxModel.removeNode()
                midNp.removeNode()
                parentNp.removeNode()

        # Loop for all objects in the scene:
        if not layoutOnly:
            for model in objModels:

                modelId = model.getNetTag('model-id')
                if self._isDoor(modelId):
                    continue

                approxModel = getApproximationForModel(model, mode='box')
                addModelTriangles(ax, approxModel, zlim=zlim)

        if xlim is not None and ylim is not None:
            ax.set_xlim(xlim)
            ax.set_ylim(ylim)
        else:
            ax.autoscale(True)
            set_axes_equal(ax)

        xlim, ylim = ax.get_xlim(), ax.get_ylim()
        xrange = xlim[1] - xlim[0]
        yrange = ylim[1] - ylim[0]
        assert np.allclose(xrange, yrange, atol=1e-6)
        dpi = (xrange / resolution) / figSize[0]
        fig.set_dpi(dpi)

        obstacleMap = canvas2image(canvas)
        plt.close(fig)

        # RGB to binary
        obstacleMap = np.round(np.mean(obstacleMap[:, :], axis=-1))

        # NOTE: inverse image so that obstacle areas are shown in white
        obstacleMap = 1.0 - obstacleMap

        return obstacleMap, xlim, ylim
Example #44
0
class AbstractMatplotlibRenderer(_RendererBackend, ABC):
    """Matplotlib renderer which can use any backend (agg, mplcairo).
    To pick a backend, subclass and set _canvas_type at the class level.
    """

    _canvas_type: Type["FigureCanvasBase"] = abstract_classvar

    @staticmethod
    @abstractmethod
    def _canvas_to_bytes(canvas: "FigureCanvasBase") -> ByteBuffer:
        pass

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        dict.__setitem__(matplotlib.rcParams, "lines.antialiased",
                         self.cfg.antialiasing)

        self._setup_axes(self.wave_nchans)

        self._artists: List["Artist"] = []

    _fig: "Figure"

    # _axes2d[wave][chan] = Axes
    # Primary, used to draw oscilloscope lines and gridlines.
    _axes2d: List[List["Axes"]]  # set by set_layout()

    # _axes_mono[wave] = Axes
    # Secondary, used for titles and debug plots.
    _axes_mono: List["Axes"]

    def _setup_axes(self, wave_nchans: List[int]) -> None:
        """
        Creates a flat array of Matplotlib Axes, with the new layout.
        Sets up each Axes with correct region limits.
        """

        self.layout = RendererLayout(self.lcfg, wave_nchans)
        self.layout_mono = RendererLayout(self.lcfg, [1] * self.nplots)

        if hasattr(self, "_fig"):
            raise Exception(
                "I don't currently expect to call _setup_axes() twice")
            # plt.close(self.fig)

        cfg = self.cfg

        self._fig = Figure()
        self._canvas_type(self._fig)

        px_inch = PX_INCH / cfg.res_divisor
        self._fig.set_dpi(px_inch)
        """
        Requirements:
        - px_inch /= res_divisor (to scale visual elements correctly)
        - int(set_size_inches * px_inch) == self.w,h
            - matplotlib uses int instead of round. Who knows why.
        - round(set_size_inches * px_inch) == self.w,h
            - just in case matplotlib changes its mind

        Solution:
        - (set_size_inches * px_inch) == self.w,h + 0.25
        - set_size_inches == (self.w,h + 0.25) / px_inch
        """
        offset = 0.25
        self._fig.set_size_inches((self.w + offset) / px_inch,
                                  (self.h + offset) / px_inch)

        real_dims = self._fig.canvas.get_width_height()
        assert (self.w, self.h) == real_dims, [(self.w, self.h), real_dims]

        # Setup background
        self._fig.set_facecolor(cfg.bg_color)

        # Create Axes (using self.lcfg, wave_nchans)
        # _axes2d[wave][chan] = Axes
        self._axes2d = self.layout.arrange(self._axes_factory)
        """
        Adding an axes using the same arguments as a previous axes
        currently reuses the earlier instance.
        In a future version, a new instance will always be created and returned.
        Meanwhile, this warning can be suppressed, and the future behavior ensured,
        by passing a unique label to each axes instance.

        ax=fig.add_axes(label=) is unused, even if you call ax.legend().
        """
        # _axes_mono[wave] = Axes
        self._axes_mono = []
        # Returns 2D list of [self.nplots][1]Axes.
        axes_mono_2d = self.layout_mono.arrange(self._axes_factory,
                                                label="mono")
        for axes_list in axes_mono_2d:
            (axes, ) = axes_list  # type: Axes

            # List of colors at
            # https://matplotlib.org/gallery/color/colormap_reference.html
            # Discussion at https://github.com/matplotlib/matplotlib/issues/10840
            cmap: ListedColormap = get_cmap("Accent")
            colors = cmap.colors
            axes.set_prop_cycle(color=colors)

            self._axes_mono.append(axes)

        # Setup axes
        for idx, N in enumerate(self.wave_nsamps):
            wave_axes = self._axes2d[idx]

            viewport_stride = self.render_strides[idx] * cfg.viewport_width
            ylim = cfg.viewport_height

            def scale_axes(ax: "Axes"):
                xlim = calc_limits(N, viewport_stride)
                ax.set_xlim(*xlim)
                ax.set_ylim(-ylim, ylim)

            scale_axes(self._axes_mono[idx])
            for ax in unique_by_id(wave_axes):
                scale_axes(ax)

                # Setup midlines (depends on max_x and wave_data)
                midline_color = cfg.midline_color
                midline_width = cfg.grid_line_width

                # Not quite sure if midlines or gridlines draw on top
                kw = dict(color=midline_color, linewidth=midline_width)
                if cfg.v_midline:
                    ax.axvline(x=calc_center(viewport_stride), **kw)
                if cfg.h_midline:
                    ax.axhline(y=0, **kw)

        self._save_background()

    transparent = "#00000000"

    # satisfies RegionFactory
    def _axes_factory(self, r: RegionSpec, label: str = "") -> "Axes":
        cfg = self.cfg

        width = 1 / r.ncol
        left = r.col / r.ncol
        assert 0 <= left < 1

        height = 1 / r.nrow
        bottom = (r.nrow - r.row - 1) / r.nrow
        assert 0 <= bottom < 1

        # Disabling xticks/yticks is unnecessary, since we hide Axises.
        ax = self._fig.add_axes([left, bottom, width, height],
                                xticks=[],
                                yticks=[],
                                label=label)

        grid_color = cfg.grid_color
        if grid_color:
            # Initialize borders
            # Hide Axises
            # (drawing them is very slow, and we disable ticks+labels anyway)
            ax.get_xaxis().set_visible(False)
            ax.get_yaxis().set_visible(False)

            # Background color
            # ax.patch.set_fill(False) sets _fill=False,
            # then calls _set_facecolor(...) "alpha = self._alpha if self._fill else 0".
            # It is no faster than below.
            ax.set_facecolor(self.transparent)

            # Set border colors
            for spine in ax.spines.values():  # type: Spine
                spine.set_linewidth(cfg.grid_line_width)
                spine.set_color(grid_color)

            def hide(key: str):
                ax.spines[key].set_visible(False)

            # Hide all axes except bottom-right.
            hide("top")
            hide("left")

            # If bottom of screen, hide bottom. If right of screen, hide right.
            if r.screen_edges & Edges.Bottom:
                hide("bottom")
            if r.screen_edges & Edges.Right:
                hide("right")

            # Dim stereo gridlines
            if cfg.stereo_grid_opacity > 0:
                dim_color = matplotlib.colors.to_rgba_array(grid_color)[0]
                dim_color[-1] = cfg.stereo_grid_opacity

                def dim(key: str):
                    ax.spines[key].set_color(dim_color)

            else:
                dim = hide

            # If not bottom of wave, dim bottom. If not right of wave, dim right.
            if not r.wave_edges & Edges.Bottom:
                dim("bottom")
            if not r.wave_edges & Edges.Right:
                dim("right")

        else:
            ax.set_axis_off()

        return ax

    # Public API
    def add_lines_stereo(self, dummy_datas: List[np.ndarray],
                         strides: List[int]) -> UpdateLines:
        cfg = self.cfg

        # Plot lines over background
        line_width = cfg.line_width

        # Foreach wave, plot dummy data.
        lines2d = []
        for wave_idx, wave_data in enumerate(dummy_datas):
            wave_zeros = np.zeros_like(wave_data)

            wave_axes = self._axes2d[wave_idx]
            wave_lines = []

            xs = calc_xs(len(wave_zeros), strides[wave_idx])

            # Foreach chan
            for chan_idx, chan_zeros in enumerate(wave_zeros.T):
                ax = wave_axes[chan_idx]
                line_color = self._line_params[wave_idx].color
                chan_line: Line2D = ax.plot(xs,
                                            chan_zeros,
                                            color=line_color,
                                            linewidth=line_width)[0]
                wave_lines.append(chan_line)

            lines2d.append(wave_lines)
            self._artists.extend(wave_lines)

        return lambda datas: self._update_lines_stereo(lines2d, datas)

    @staticmethod
    def _update_lines_stereo(lines2d: "List[List[Line2D]]",
                             datas: List[np.ndarray]) -> None:
        """
        Preconditions:
        - lines2d[wave][chan] = Line2D
        - datas[wave] = ndarray, [samp][chan] = FLOAT
        """
        nplots = len(lines2d)
        ndata = len(datas)
        if nplots != ndata:
            raise ValueError(
                f"incorrect data to plot: {nplots} plots but {ndata} dummy_datas"
            )

        # Draw waveform data
        # Foreach wave
        for wave_idx, wave_data in enumerate(datas):
            wave_lines = lines2d[wave_idx]

            # Foreach chan
            for chan_idx, chan_data in enumerate(wave_data.T):
                chan_line = wave_lines[chan_idx]
                chan_line.set_ydata(chan_data)

    def _add_xy_line_mono(self, wave_idx: int, xs: Sequence[float],
                          ys: Sequence[float], stride: int) -> CustomLine:
        cfg = self.cfg

        # Plot lines over background
        line_width = cfg.line_width

        ax = self._axes_mono[wave_idx]
        mono_line: Line2D = ax.plot(xs, ys, linewidth=line_width)[0]

        self._artists.append(mono_line)

        # noinspection PyTypeChecker
        return CustomLine(stride, xs, mono_line.set_xdata, mono_line.set_ydata)

    # Channel labels
    def add_labels(self, labels: List[str]) -> List["Text"]:
        """
        Updates background, adds text.
        Do NOT call after calling self.add_lines().
        """
        nlabel = len(labels)
        if nlabel != self.nplots:
            raise ValueError(
                f"incorrect labels: {self.nplots} plots but {nlabel} labels")

        cfg = self.cfg
        color = cfg.get_label_color

        size_pt = cfg.label_font.size
        distance_px = cfg.label_padding_ratio * size_pt

        @attr.dataclass
        class AxisPosition:
            pos_axes: float
            offset_px: float
            align: str

        xpos = cfg.label_position.x.match(
            left=AxisPosition(0, distance_px, "left"),
            right=AxisPosition(1, -distance_px, "right"),
        )
        ypos = cfg.label_position.y.match(
            bottom=AxisPosition(0, distance_px, "bottom"),
            top=AxisPosition(1, -distance_px, "top"),
        )

        pos_axes = (xpos.pos_axes, ypos.pos_axes)
        offset_pt = (xpos.offset_px, ypos.offset_px)

        out: List["Text"] = []
        for label_text, ax in zip(labels, self._axes_mono):
            # https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.annotate.html
            # Annotation subclasses Text.
            text: "Annotation" = ax.annotate(
                label_text,
                # Positioning
                xy=pos_axes,
                xycoords="axes fraction",
                xytext=offset_pt,
                textcoords="offset points",
                horizontalalignment=xpos.align,
                verticalalignment=ypos.align,
                # Cosmetics
                color=color,
                fontsize=px_from_points(size_pt),
                fontfamily=cfg.label_font.family,
                fontweight=("bold" if cfg.label_font.bold else "normal"),
                fontstyle=("italic" if cfg.label_font.italic else "normal"),
            )
            out.append(text)

        self._save_background()
        return out

    # Output frames
    def get_frame(self) -> ByteBuffer:
        """Returns bytes with shape (h, w, self.bytes_per_pixel).
        The actual return value's shape may be flat.
        """
        self._redraw_over_background()

        canvas = self._fig.canvas

        # Agg is the default noninteractive backend except on OSX.
        # https://matplotlib.org/faq/usage_faq.html
        if not isinstance(canvas, self._canvas_type):
            raise RuntimeError(
                f"oh shit, cannot read data from {obj_name(canvas)} != {self._canvas_type.__name__}"
            )

        buffer_rgb = self._canvas_to_bytes(canvas)
        assert len(buffer_rgb) == self.w * self.h * self.bytes_per_pixel

        return buffer_rgb

    # Pre-rendered background
    bg_cache: Any  # "matplotlib.backends._backend_agg.BufferRegion"

    def _save_background(self) -> None:
        """ Draw static background. """
        # https://stackoverflow.com/a/8956211
        # https://matplotlib.org/api/animation_api.html#funcanimation
        fig = self._fig

        fig.canvas.draw()
        self.bg_cache = fig.canvas.copy_from_bbox(fig.bbox)

    def _redraw_over_background(self) -> None:
        """ Redraw animated elements of the image. """

        # Both FigureCanvasAgg and FigureCanvasCairo, but not FigureCanvasBase,
        # support restore_region().
        canvas: FigureCanvasAgg = self._fig.canvas
        canvas.restore_region(self.bg_cache)

        for artist in self._artists:
            artist.axes.draw_artist(artist)
Example #45
0
class PlotController(DialogMixin):
    """
        A base class for matplotlib-canvas controllers that, sets up the 
        widgets and has image exporting functionality.
    """

    file_filters = ("Portable Network Graphics (PNG)", "*.png"), \
                   ("Scalable Vector Graphics (SVG)", "*.svg"), \
                   ("Portable Document Format (PDF)", "*.pdf")

    _canvas = None
    @property
    def canvas(self):
        if not self._canvas:
            self.setup_figure()
            self.setup_canvas()
            self.setup_content()
        return self._canvas

    # ------------------------------------------------------------
    #      Initialisation and other internals
    # ------------------------------------------------------------
    def __init__(self):
        self._proxies = dict()
        self.setup_figure()
        self.setup_canvas()
        self.setup_content()

    def setup_figure(self):
        style = gtk.Style()
        self.figure = Figure(dpi=72, edgecolor=str(style.bg[2]), facecolor=str(style.bg[0]))
        self.figure.subplots_adjust(hspace=0.0, wspace=0.0)

    def setup_canvas(self):
        self._canvas = FigureCanvasGTK(self.figure)

    def setup_content(self):
        raise NotImplementedError

    # ------------------------------------------------------------
    #      Update subroutines
    # ------------------------------------------------------------
    def draw(self):
        try:
            self.figure.canvas.draw()
            self.fix_after_drawing()
        except ParseFatalException:
            logger.exception("Caught unhandled exception when drawing")

    def fix_after_drawing(self):
        pass # nothing to fix

    # ------------------------------------------------------------
    #      Graph exporting
    # ------------------------------------------------------------
    def save(self, parent=None, suggest_name="graph", size="auto", num_specimens=1, offset=0.75):
        """
            Displays a save dialog to export an image from the current plot.
        """
        # Parse arguments:
        width, height = 0, 0
        if size == "auto":
            descr, width, height, dpi = settings.OUTPUT_PRESETS[0]
        else:
            width, height, dpi = map(float, size.replace("@", "x").split("x"))

        # Load gui:
        builder = gtk.Builder()
        builder.add_from_file(resource_filename("pyxrd.specimen", "glade/save_graph_size.glade")) # FIXME move this to this namespace!!
        size_expander = builder.get_object("size_expander")
        cmb_presets = builder.get_object("cmb_presets")

        # Setup combo with presets:
        cmb_store = gtk.ListStore(str, int, int, float)
        for row in settings.OUTPUT_PRESETS:
            cmb_store.append(row)
        cmb_presets.clear()
        cmb_presets.set_model(cmb_store)
        cell = gtk.CellRendererText()
        cmb_presets.pack_start(cell, True)
        cmb_presets.add_attribute(cell, 'text', 0)
        def on_cmb_changed(cmb, *args):
            itr = cmb_presets.get_active_iter()
            w, h, d = cmb_store.get(itr, 1, 2, 3)
            entry_w.set_text(str(w))
            entry_h.set_text(str(h))
            entry_dpi.set_text(str(d))
        cmb_presets.connect('changed', on_cmb_changed)

        # Setup input boxes:
        entry_w = builder.get_object("entry_width")
        entry_h = builder.get_object("entry_height")
        entry_dpi = builder.get_object("entry_dpi")
        entry_w.set_text(str(width))
        entry_h.set_text(str(height))
        entry_dpi.set_text(str(dpi))

        # What to do when the user wants to save this:
        def on_accept(dialog):
            # Get the selected file type and name:
            cur_fltr = dialog.get_filter()
            filename = dialog.get_filename()
            # Add the correct extension if not present yet:
            for fltr in self.file_filters:
                if cur_fltr.get_name() == fltr[0]:
                    if filename[len(filename) - 4:] != fltr[1][1:]:
                        filename = "%s%s" % (filename, fltr[1][1:])
                    break
            # Get the width, height & dpi
            width = float(entry_w.get_text())
            height = float(entry_h.get_text())
            dpi = float(entry_dpi.get_text())
            i_width, i_height = width / dpi, height / dpi
            # Save it all right!
            self.save_figure(filename, dpi, i_width, i_height)

        # Ask the user where, how and if he wants to save:
        self.run_save_dialog("Save Graph", on_accept, None, parent=parent, suggest_name=suggest_name, extra_widget=size_expander)

    def save_figure(self, filename, dpi, i_width, i_height):
        """
            Save the current plot
            
            Arguments:
             filename: the filename to save to (either .png, .pdf or .svg)
             dpi: Dots-Per-Inch resolution
             i_width: the width in inch
             i_height: the height in inch
        """
        # Get original settings:
        original_dpi = self.figure.get_dpi()
        original_width, original_height = self.figure.get_size_inches()
        # Set everything according to the user selection:
        self.figure.set_dpi(dpi)
        self.figure.set_size_inches((i_width, i_height))
        self.figure.canvas.draw() # replot
        bbox_inches = matplotlib.transforms.Bbox.from_bounds(0, 0, i_width, i_height)
        # Save the figure:
        self.figure.savefig(filename, dpi=dpi, bbox_inches=bbox_inches)
        # Put everything back the way it was:
        self.figure.set_dpi(original_dpi)
        self.figure.set_size_inches((original_width, original_height))
        self.figure.canvas.draw() # replot
Example #46
0
class PlotWidget(custom_result.ResultWidget):
    __gsignals__ = {
        'button-press-event': 'override',
        'button-release-event': 'override',
        'expose-event': 'override',
        'size-allocate': 'override',
        'unrealize': 'override'
    }

    def __init__(self, result):
        custom_result.ResultWidget.__init__(self)

        figsize=(DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_HEIGHT)

        self.figure = Figure(facecolor='white', figsize=figsize)
        self.canvas = _PlotResultCanvas(self.figure)

        self.axes = self.figure.add_subplot(111)

        self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE)

        self.cached_contents = None

        self.sidebar_width = -1

    def do_expose_event(self, event):
        cr = self.window.cairo_create()

        if not self.cached_contents:
            self.cached_contents = cr.get_target().create_similar(cairo.CONTENT_COLOR,
                                                                  self.allocation.width, self.allocation.height)

            renderer = RendererCairo(self.figure.dpi)
            renderer.set_width_height(self.allocation.width, self.allocation.height)
            renderer.set_ctx_from_surface(self.cached_contents)

            self.figure.draw(renderer)

        # event.region is not bound: http://bugzilla.gnome.org/show_bug.cgi?id=487158
#        gdk_context = gtk.gdk.CairoContext(renderer.ctx)
#        gdk_context.region(event.region)
#        gdk_context.clip()

        cr.set_source_surface(self.cached_contents, 0, 0)
        cr.paint()

    def do_size_allocate(self, allocation):
        if allocation.width != self.allocation.width or allocation.height != self.allocation.height:
            self.cached_contents = None

        gtk.DrawingArea.do_size_allocate(self, allocation)

    def do_unrealize(self):
        gtk.DrawingArea.do_unrealize(self)

        self.cached_contents = None

    def do_button_press_event(self, event):
        if event.button == 3:
            custom_result.show_menu(self, event, save_callback=self.__save)
            return True
        else:
            return True
    
    def do_button_release_event(self, event):
        return True

    def do_realize(self):
        gtk.DrawingArea.do_realize(self)
        cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)
        self.window.set_cursor(cursor)
    
    def do_size_request(self, requisition):
        try:
            # matplotlib < 0.98
            requisition.width = self.figure.bbox.width()
            requisition.height = self.figure.bbox.height()
        except TypeError:
            # matplotlib >= 0.98
            requisition.width = self.figure.bbox.width
            requisition.height = self.figure.bbox.height

    def recompute_figure_size(self):
        width = (self.sidebar_width / self.figure.dpi)
        height = width / DEFAULT_ASPECT_RATIO

        self.figure.set_figwidth(width)
        self.figure.set_figheight(height)

        self.queue_resize()

    def sync_dpi(self, dpi):
        self.figure.set_dpi(dpi)
        if self.sidebar_width >= 0:
            self.recompute_figure_size()

    def set_sidebar_width(self, width):
        if self.sidebar_width == width:
            return

        self.sidebar_width = width
        if self.sidebar_width >= 0:
            self.recompute_figure_size()

    def sync_style(self, style):
        self.cached_contents = None

        matplotlib.rcParams['font.size'] = self.parent.style.font_desc.get_size() / pango.SCALE

    def __save(self, filename):
        # The save/restore here was added to matplotlib's after 0.90. We duplicate
        # it for compatibility with older versions. (The code would need modification
        # for 0.98 and newer, which is the reason for the particular version in the
        # check)

        version = [int(x) for x in matplotlib.__version__.split('.')]
        need_save = version[:2] < [0, 98]
        if need_save:
            orig_dpi = self.figure.dpi.get()
            orig_facecolor = self.figure.get_facecolor()
            orig_edgecolor = self.figure.get_edgecolor()

        try:
            self.canvas.print_figure(filename)
        finally:
            if need_save:
                self.figure.dpi.set(orig_dpi)
                self.figure.set_facecolor(orig_facecolor)
                self.figure.set_edgecolor(orig_edgecolor)
                self.figure.set_canvas(self.canvas)
Example #47
0
class Diagram():

    zoom_factor = 1.2

    def __init__(self):

        self.figure = Figure()
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setMinimumWidth(200)
        self.canvas.setMinimumHeight(200)
        self.previous_dpi = self.figure.get_dpi()
        # Add axes that fill the figure (while maintaining aspect ratio)
        # https://stackoverflow.com/a/6377406/
        self.axes = self.figure.add_axes([0, 0, 1, 1])

        # Make it possible to focus on the canvas by clicking on it.
        # This allows the canvas to capture keypresses.
        # https://stackoverflow.com/questions/22043549/
        # http://doc.qt.io/qt-5/qt.html#FocusPolicy-enum
        self.canvas.setFocusPolicy(Qt.ClickFocus)

        self.canvas.setCursor(Qt.OpenHandCursor)
        self.drag_position = None

        self.rectangle_select_interaction = None
        self.save_rectangle = None
        self.rect_rubberband = QRubberBand(QRubberBand.Rectangle, self.canvas)

        self.canvas.mpl_connect('button_press_event', self.button_press_event)
        self.canvas.mpl_connect('button_release_event',
                                self.button_release_event)
        self.canvas.mpl_connect('motion_notify_event',
                                self.motion_notify_event)
        self.canvas.mpl_connect('key_press_event', self.key_press_event)
        self.canvas.mpl_connect('scroll_event', self.scroll_event)
        self.canvas.mpl_connect('resize_event', self.resize_event)

    def refresh(self):

        if not self.status.course_code:
            return

        old_axes_xlim = self.axes.get_xlim()
        old_axes_ylim = self.axes.get_ylim()

        self.axes.clear()
        self.draw_checkpoints()
        self.setup_figure()
        self.status.update_save_dimensions()

        # If the course is the same as the last refresh, we'd like to keep the
        # user's current pan and zoom positions.
        # draw_checkpoints() calls plot() which seems to unavoidably change
        # the limits, so we must revert the limits to before that call.
        if not self.status.course_code_changed:
            self.axes.set_xlim(old_axes_xlim)
            self.axes.set_ylim(old_axes_ylim)

        self.canvas.draw()

        self.deactivate_rectangle_select()

    def canvas_width(self):
        return self.canvas.get_width_height()[0]

    def canvas_height(self):
        return self.canvas.get_width_height()[1]

    def convert_coords_canvas_to_game(self, x, y):
        xlim = self.axes.get_xlim()
        ylim = self.axes.get_ylim()
        canvas_width, canvas_height = self.canvas.get_width_height()
        return (xlim[0] + (xlim[1] - xlim[0]) * (x / canvas_width),
                ylim[0] + (ylim[1] - ylim[0]) * (y / canvas_height))

    def button_press_event(self, event):
        # Mouse button press
        self.rectangle_select_button_press_event(event)

        if not self.rectangle_select_interaction:
            # Start pan
            #print(f'Button press: {event.x}, {event.y}, {event.button}')
            self.drag_position = (event.x, event.y)
            self.canvas.setCursor(Qt.ClosedHandCursor)

    def button_release_event(self, event):
        # Mouse button release
        self.rectangle_select_button_release_event(event)

        # End pan
        #print(f'Button release: {event.x}, {event.y}, {event.button}')
        self.drag_position = None
        self.canvas.setCursor(Qt.OpenHandCursor)

    def motion_notify_event(self, event):
        # Mouse motion
        self.rectangle_select_motion_notify_event(event)

        # If mouse button pressed, pan the figure
        #print(f'Motion: {event.x}, {event.y}')
        if self.drag_position:
            self.pan(event.x - self.drag_position[0],
                     event.y - self.drag_position[1])
            self.drag_position = (event.x, event.y)

        # Update coordinates display
        coords = self.convert_coords_canvas_to_game(event.x, event.y)
        # Instead of "-z = 490.73", display "z = -490.73"
        if self.status.axis_1.startswith('-'):
            coord_1_str = f'{self.status.axis_1[1:]} = {-coords[0]:.3f}'
        else:
            coord_1_str = f'{self.status.axis_1} = {coords[0]:.3f}'
        if self.status.axis_2.startswith('-'):
            coord_2_str = f'{self.status.axis_2[1:]} = {-coords[1]:.3f}'
        else:
            coord_2_str = f'{self.status.axis_2} = {coords[1]:.3f}'

        self.status.update_diagram_coords_text(f'{coord_1_str}, {coord_2_str}')

    def scroll_event(self, event):
        # Mousewheel scrolling
        #print(f'Scroll: {event.x}, {event.y}, {event.step}')
        if event.step > 0:
            # Scroll up -> zoom in on the current mouse position
            self.zoom_in(event.x, event.y)
        else:
            # Scroll down -> zoom out from the current mouse position
            self.zoom_out(event.x, event.y)

    def key_press_event(self, event):
        #print(f'Key press: {event.key}')
        if event.key == 'up':
            # Up arrow -> zoom in on the diagram center
            canvas_width, canvas_height = self.canvas.get_width_height()
            self.zoom_in(canvas_width / 2, canvas_height / 2)
        elif event.key == 'down':
            # Down arrow -> zoom out from the diagram center
            canvas_width, canvas_height = self.canvas.get_width_height()
            self.zoom_out(canvas_width / 2, canvas_height / 2)

    def resize_event(self, event):
        # Canvas is resized
        # Note: This does not get called if the canvas size changes due to
        # a diagram DPI update. It only gets called when a window resize
        # triggers a canvas resize.
        #print(f'Resize: {event.width}, {event.height}')

        # Fix aspect ratio of the diagram.
        axes_hmin, axes_hmax = self.axes.get_xlim()
        axes_vmin, axes_vmax = self.axes.get_ylim()
        hrange = axes_hmax - axes_hmin
        vrange = axes_vmax - axes_vmin

        if hrange / vrange >= event.width / event.height:
            # Add extra vertical range to maintain aspect ratio
            target_vrange = hrange * (event.height / event.width)
            extra_vspace_one_side = (target_vrange - vrange) / 2
            axes_vmin = axes_vmin - extra_vspace_one_side
            axes_vmax = axes_vmax + extra_vspace_one_side
        else:
            # Add extra horizontal range to maintain aspect ratio
            target_hrange = vrange * (event.width / event.height)
            extra_hspace_one_side = (target_hrange - hrange) / 2
            axes_hmin = axes_hmin - extra_hspace_one_side
            axes_hmax = axes_hmax + extra_hspace_one_side

        # Apply the new axes limits to fix the aspect ratio
        self.axes.set_xlim(axes_hmin, axes_hmax)
        self.axes.set_ylim(axes_vmin, axes_vmax)

        self.status.update_save_dimensions()

        # Rectangle can get wonky after a canvas resize, so just erase it
        self.deactivate_rectangle_select()

    def pan(self, change_x, change_y):
        canvas_width, canvas_height = self.canvas.get_width_height()

        xlim = self.axes.get_xlim()
        x_coord_ratio_game_to_canvas = (xlim[1] - xlim[0]) / canvas_width
        self.axes.set_xlim(xlim[0] - change_x * x_coord_ratio_game_to_canvas,
                           xlim[1] - change_x * x_coord_ratio_game_to_canvas)

        ylim = self.axes.get_ylim()
        y_coord_ratio_game_to_canvas = (ylim[1] - ylim[0]) / canvas_height
        self.axes.set_ylim(ylim[0] - change_y * y_coord_ratio_game_to_canvas,
                           ylim[1] - change_y * y_coord_ratio_game_to_canvas)

        self.canvas.draw()

        # print(f"Pan: {change_x}, {change_y}")
        # print(f"xlim: {self.axes.get_xlim()}")
        # print(f"ylim: {self.axes.get_ylim()}")

    def zoom(self, x, y, direction_is_inward):
        """Zoom in/out, centered on the current mouse position"""
        game_coords = self.convert_coords_canvas_to_game(x, y)

        if direction_is_inward:
            # Zoom in
            space_stretch_factor = 1 / self.zoom_factor
        else:
            # Zoom out
            space_stretch_factor = self.zoom_factor

        xlim = self.axes.get_xlim()
        self.axes.set_xlim(
            game_coords[0] - (game_coords[0] - xlim[0]) * space_stretch_factor,
            game_coords[0] - (game_coords[0] - xlim[1]) * space_stretch_factor)

        ylim = self.axes.get_ylim()
        self.axes.set_ylim(
            game_coords[1] - (game_coords[1] - ylim[0]) * space_stretch_factor,
            game_coords[1] - (game_coords[1] - ylim[1]) * space_stretch_factor)

        self.canvas.draw()

    def zoom_in(self, x, y):
        self.zoom(x, y, True)

    def zoom_out(self, x, y):
        self.zoom(x, y, False)

    def activate_rectangle_select(self):
        self.rect_rubberband.setGeometry(0, 0, 0, 0)
        self.rect_rubberband.show()
        self.canvas.setCursor(Qt.CrossCursor)
        self.rectangle_select_interaction = 'ready'

        self.save_rectangle = None
        self.status.update_save_dimensions()

    def deactivate_rectangle_select(self):
        self.rect_rubberband.hide()
        self.canvas.setCursor(Qt.OpenHandCursor)
        self.rectangle_select_interaction = None

        self.save_rectangle = None
        self.status.update_save_dimensions()

    def rectangle_select_button_press_event(self, event):
        # Mouse button press
        if self.rectangle_select_interaction == 'ready':
            # Start drawing rectangle.
            # Rectangle dimensions have opposite direction y from
            # event/canvas dimensions
            self.rectangle_select_origin_x = event.x
            self.rectangle_select_origin_y = event.y
            self.rectangle_select_interaction = 'drawing'
        else:
            self.deactivate_rectangle_select()

    def rectangle_select_motion_notify_event(self, event):
        # Mouse motion
        if self.rectangle_select_interaction == 'drawing':
            # Change the rectangle shape according to the mouse position.
            canvas_width, canvas_height = self.canvas.get_width_height()

            # If the mouse is outside of the canvas boundary, snap the
            # rectangle to the boundary
            event_x_bounded = event.x
            event_x_bounded = max(event_x_bounded, 0)
            event_x_bounded = min(event_x_bounded, canvas_width)
            event_y_bounded = event.y
            event_y_bounded = max(event_y_bounded, 0)
            event_y_bounded = min(event_y_bounded, canvas_height)

            # 1. Rect rubberband dimensions have opposite direction y from
            # event/canvas dimensions, so need to do canvas height minus
            # event y
            # 2. setGeometry() only works when the sizes are positive, so need
            # to start with the lower coordinates and ensure positive sizes
            self.rect_rubberband.setGeometry(
                min(self.rectangle_select_origin_x, event_x_bounded),
                min(canvas_height - self.rectangle_select_origin_y,
                    canvas_height - event_y_bounded),
                abs(self.rectangle_select_origin_x - event_x_bounded),
                abs(self.rectangle_select_origin_y - event_y_bounded))

    def rectangle_select_button_release_event(self, event):
        # Mouse button release
        if self.rectangle_select_interaction == 'drawing':
            # Finish the rectangle.
            self.rectangle_select_interaction = None

            # If the mouse is outside of the canvas boundary, snap the
            # rectangle to the boundary
            canvas_width, canvas_height = self.canvas.get_width_height()
            event_x_bounded = event.x
            event_x_bounded = max(event_x_bounded, 0)
            event_x_bounded = min(event_x_bounded, canvas_width)
            event_y_bounded = event.y
            event_y_bounded = max(event_y_bounded, 0)
            event_y_bounded = min(event_y_bounded, canvas_height)

            self.save_rectangle = ((self.rectangle_select_origin_x,
                                    self.rectangle_select_origin_y),
                                   (event_x_bounded, event_y_bounded))
            self.status.update_save_dimensions()
            #print(self.save_rectangle)

    def draw_checkpoints(self):

        # Prepare to plot checkpoints/paths on the chosen axes. The first will
        # appear as the horizontal axis, and the second will appear as the
        # vertical axis on the figure.
        haxis = get_checkpoint_position_function(self.status.axis_1)
        vaxis = get_checkpoint_position_function(self.status.axis_2)
        haxis_point = get_point_position_function(self.status.axis_1)
        vaxis_point = get_point_position_function(self.status.axis_2)

        # Track the farthest values on either axis so we can compute the
        # display boundaries.
        self.data_hmin = math.inf
        self.data_hmax = -math.inf
        self.data_vmin = math.inf
        self.data_vmax = -math.inf

        # Draw the checkpoints.
        for c in self.status.checkpoints:

            if c['checkpoint'] in self.status.hidden_checkpoints:
                continue

            track_width = c['track_width']
            half_track_width = track_width / 2

            # Draw markers on the checkpoint's center, and on both edges
            # of the track directly lateral from the checkpoint.
            # http://stackoverflow.com/a/8409110
            haxis_coords = [
                haxis(-half_track_width, c),
                haxis(0, c),
                haxis(half_track_width, c)
            ]
            vaxis_coords = [
                vaxis(-half_track_width, c),
                vaxis(0, c),
                vaxis(half_track_width, c)
            ]

            self.axes.plot(haxis_coords,
                           vaxis_coords,
                           color=c['color'],
                           marker='o')

            base_3d_length = half_track_width
            base_plane_length = math.sqrt(
                (haxis_coords[1] - haxis_coords[0])**2 +
                (vaxis_coords[1] - vaxis_coords[0])**2)

            if c['checkpoint'] in self.status.extended_checkpoints:
                # Draw an extended line for the checkpoint,
                # with equal line length on both sides.
                # The line length is defined in the diagram's coord plane.
                extended_plane_length = self.status.extend_length
                if base_plane_length > 0:
                    extended_3d_length = (extended_plane_length *
                                          (base_3d_length / base_plane_length))
                else:
                    # In this case the line is perpendicular to the
                    # diagram's plane.
                    extended_3d_length = 0

                extend_haxis_coords = [
                    haxis(-extended_3d_length, c),
                    haxis(extended_3d_length, c)
                ]
                extend_vaxis_coords = [
                    vaxis(-extended_3d_length, c),
                    vaxis(extended_3d_length, c)
                ]
                self.axes.plot(extend_haxis_coords, extend_vaxis_coords,
                               c['color'])

            # Label the checkpoint with its checkpoint number.
            # Position the label a certain distance away from one end
            # of the (non-extended) checkpoint line.
            # Negative distances put the number on the other side.
            # Again, make sure to define distance in the diagram's coord plane.
            if c['checkpoint'] not in self.status.hidden_numbers:
                if self.status.number_distance > 0:
                    label_distance = (self.status.number_distance +
                                      half_track_width)
                    side_track_is_on = 'left'
                else:
                    label_distance = (self.status.number_distance -
                                      half_track_width)
                    side_track_is_on = 'right'

                if base_plane_length > 0 or base_plane_length < 0:
                    label_3d_distance = (label_distance *
                                         (base_3d_length / base_plane_length))
                else:
                    label_3d_distance = 0
                label_coords = (haxis(label_3d_distance,
                                      c), vaxis(label_3d_distance, c))
                self.axes.text(
                    label_coords[0],
                    label_coords[1],
                    # Ensure the checkpoint number on the plot
                    # shows no decimal places
                    int(c['checkpoint']),
                    fontdict=dict(
                        # Number color should match the line color
                        color=c['color'],
                        # Font size
                        size=self.status.number_size,
                        # Base the position on the side of the text, not the
                        # center. This way, 1 digit and 3 digit numbers
                        # are the same distance from the side of the track.
                        # And it generally reduces instances where the text is
                        # struck-through by extended checkpoint lines.
                        horizontalalignment=side_track_is_on,
                        # Put the bottom of the text at this position.
                        # This generally reduces instances where the text is
                        # struck-through by extended checkpoint lines.
                        verticalalignment='bottom',
                    ),
                )

                # Update coordinate boundaries to ensure they contain the
                # checkpoint numbers.
                self.data_hmin = min([self.data_hmin, label_coords[0]])
                self.data_hmax = max([self.data_hmax, label_coords[0]])
                self.data_vmin = min([self.data_vmin, label_coords[1]])
                self.data_vmax = max([self.data_vmax, label_coords[1]])

            # Update coordinate boundaries to ensure they contain the
            # (non-extended) checkpoint lines.
            self.data_hmin = min([self.data_hmin] + haxis_coords)
            self.data_hmax = max([self.data_hmax] + haxis_coords)
            self.data_vmin = min([self.data_vmin] + vaxis_coords)
            self.data_vmax = max([self.data_vmax] + vaxis_coords)

        # Plot the path, if any.
        if self.status.data_path_points:
            haxis_coords = [
                haxis_point(p) for p in self.status.data_path_points
            ]
            vaxis_coords = [
                vaxis_point(p) for p in self.status.data_path_points
            ]
            # Plot in black.
            color = rgb2hex(hsv_to_rgb([0, 0, 0.0]))
            self.axes.plot(haxis_coords, vaxis_coords, color)

        # Plot crossing data, if any.
        if self.status.crossing_data:
            for c in self.status.crossing_data:
                if c['success'] == "Y":
                    # Success = black
                    color = rgb2hex(hsv_to_rgb([0, 0, 0.0]))
                else:
                    # Failure = gray
                    color = rgb2hex(hsv_to_rgb([0, 0, 0.6]))

                # Add line segments.
                p1 = dict(x=c['x1'], y=c['y1'], z=c['z1'])
                p2 = dict(x=c['x2'], y=c['y2'], z=c['z2'])
                haxis_coords = [haxis_point(p1), haxis_point(p2)]
                vaxis_coords = [vaxis_point(p1), vaxis_point(p2)]
                self.axes.plot(haxis_coords, vaxis_coords, color)

                # Add dot markers.
                self.axes.plot(haxis_coords, vaxis_coords, color, marker='o')

    def setup_figure(self):
        # Set the desired DPI.
        self.figure.set_dpi(self.status.dpi)

        # Fix the figure size in case of a new DPI.
        # If the DPI decreased then the figure inches need to increase,
        # and vice versa.
        # If this is not done, then updating the DPI will make the figure not
        # fit in the canvas. (It only fixes itself upon a window resize.)
        if self.previous_dpi != self.status.dpi:
            x_inches, y_inches = self.figure.get_size_inches()
            self.figure.set_size_inches(
                x_inches * (self.previous_dpi / self.status.dpi),
                y_inches * (self.previous_dpi / self.status.dpi))
        self.previous_dpi = self.status.dpi

        # Figure out what the axes limits should be to contain all the
        # checkpoints.
        margin_factor = 0.1
        axes_hmin = (self.data_hmin -
                     (self.data_hmax - self.data_hmin) * margin_factor)
        axes_hmax = (self.data_hmax +
                     (self.data_hmax - self.data_hmin) * margin_factor)
        axes_vmin = (self.data_vmin -
                     (self.data_vmax - self.data_vmin) * margin_factor)
        axes_vmax = (self.data_vmax +
                     (self.data_vmax - self.data_vmin) * margin_factor)
        hrange = axes_hmax - axes_hmin
        vrange = axes_vmax - axes_vmin

        # Expand one dimension as needed to fill the canvas while maintaining
        # aspect ratio.
        canvas_width, canvas_height = self.canvas.get_width_height()
        if hrange / vrange >= canvas_width / canvas_height:
            # Add extra vertical range to maintain aspect ratio
            target_vrange = hrange * (canvas_height / canvas_width)
            extra_vspace_one_side = (target_vrange - vrange) / 2
            axes_vmin = axes_vmin - extra_vspace_one_side
            axes_vmax = axes_vmax + extra_vspace_one_side
        else:
            # Add extra horizontal range to maintain aspect ratio
            target_hrange = vrange * (canvas_width / canvas_height)
            extra_hspace_one_side = (target_hrange - hrange) / 2
            axes_hmin = axes_hmin - extra_hspace_one_side
            axes_hmax = axes_hmax + extra_hspace_one_side

        # Apply the axes limits.
        self.axes.set_xlim(axes_hmin, axes_hmax)
        self.axes.set_ylim(axes_vmin, axes_vmax)

        # Debug info
        # print(f"canvas size: {canvas_width}, {canvas_height}")
        # print(f"figure size: {self.figure.get_size_inches()}")
        # print(
        #     f"data ranges: {self.data_hmin:.3f}~{self.data_hmax:.3f}"
        #     f" {self.data_vmin:.3f}~{self.data_vmax:.3f}")
        # print(f"axes range sizes: {hrange}, {vrange}")
        # print(f"xlim: {self.axes.get_xlim()}")
        # print(f"ylim: {self.axes.get_ylim()}")

    def compute_save_dimensions(self):
        x_inches, y_inches = self.figure.get_size_inches()
        if self.save_rectangle:
            canvas_width, canvas_height = self.canvas.get_width_height()
            save_rectangle_width = (abs(self.save_rectangle[0][0] -
                                        self.save_rectangle[1][0]))
            save_rectangle_height = (abs(self.save_rectangle[0][1] -
                                         self.save_rectangle[1][1]))
            x_inches = x_inches * (save_rectangle_width / canvas_width)
            y_inches = y_inches * (save_rectangle_height / canvas_height)
        save_dpi = self.status.save_dpi
        # Matplotlib seems to round down the resolution to a whole pixel
        # when saving, so use int() instead of int(round()).
        return (int(x_inches * save_dpi), int(y_inches * save_dpi))

    def save(self, filepath):
        if self.save_rectangle:
            # We've specified a specific region of the diagram to save.
            dpi = self.status.dpi
            # save_rectangle is in canvas pixels; need to convert to inches
            bbox_inches = Bbox([
                (min(self.save_rectangle[0][0], self.save_rectangle[1][0]) /
                 dpi,
                 min(self.save_rectangle[0][1], self.save_rectangle[1][1]) /
                 dpi),
                (max(self.save_rectangle[0][0], self.save_rectangle[1][0]) /
                 dpi,
                 max(self.save_rectangle[0][1], self.save_rectangle[1][1]) /
                 dpi),
            ])
        else:
            # Save the whole diagram.
            bbox_inches = None

        self.figure.savefig(
            filepath,
            # Force PNG format; JPEG is not supported by our MPL backend
            format='png',
            # DPI to use for saving.
            # This solely affects level of detail/resolution of the resulting
            # image file. Font size, line thickness, etc. should be the same
            # as seen in the figure canvas.
            dpi=self.status.save_dpi,
            bbox_inches=bbox_inches,
        )
Example #48
0
class MainPlotController(object):
    """
        A controller for the main plot canvas.
        Sets up the widgets and has image exporting functionality.
    """

    file_filters = ("Portable Network Graphics (PNG)", "*.png"), \
                   ("Scalable Vector Graphics (SVG)", "*.svg"), \
                   ("Portable Document Format (PDF)", "*.pdf")

    _canvas = None

    @property
    def canvas(self):
        if not self._canvas:
            self.setup_figure()
            self.setup_canvas()
            self.setup_content()
        return self._canvas

    # ------------------------------------------------------------
    #      View integration getters
    # ------------------------------------------------------------
    def get_toolbar_widget(self, window):
        return NavigationToolbar(self.canvas, window)

    def get_canvas_widget(self):
        return self.canvas

    # ------------------------------------------------------------
    #      Initialization and other internals
    # ------------------------------------------------------------
    def __init__(self, status_callback, marker_callback, *args, **kwargs):
        self.setup_layout_cache()
        self.setup_figure()
        self.setup_canvas()
        self.setup_content(status_callback, marker_callback)

    def setup_layout_cache(self):
        self.position_setup = PositionSetup()
        self.labels = list()
        self.marker_lbls = list()
        self._proxies = dict()
        self.scale = 1.0
        self.stats = False
        self._last_pos = None

    def setup_figure(self):
        self.figure = Figure(dpi=72, facecolor="#FFFFFF", linewidth=0)
        self.figure.subplots_adjust(hspace=0.0, wspace=0.0)

    def setup_canvas(self):
        self._canvas = FigureCanvasGTK(self.figure)

    def setup_content(self, status_callback, marker_callback):
        # Create subplot and add it to the figure:
        self.plot = Subplot(self.figure, 211, facecolor=(1.0, 1.0, 1.0, 0.0))
        self.plot.set_autoscale_on(False)
        self.figure.add_axes(self.plot)

        # Connect events:
        self.canvas.mpl_connect('draw_event', self.fix_after_drawing)
        self.canvas.mpl_connect('resize_event', self.fix_after_drawing)

        self.mtc = MotionTracker(self, status_callback)
        self.cc = ClickCatcher(self, marker_callback)

        #self.update()

    # ------------------------------------------------------------
    #      Update methods
    # ------------------------------------------------------------
    def draw(self):
        self._last_pos = self.fix_before_drawing()
        self.figure.canvas.draw()

    def fix_after_drawing(self, *args):
        _new_pos = self.fix_before_drawing()

        if _new_pos != self._last_pos:
            self._last_pos = _new_pos
            self._redraw_later()

        return False

    def _redraw_later(self):
        self.timer = self.figure.canvas.new_timer(interval=10)
        self.timer.single_shot = True
        self.timer.add_callback(lambda: self.figure.canvas.draw_idle())
        self.timer.start()

    def fix_before_drawing(self, *args):
        """
            Fixes alignment issues due to longer labels or smaller windows
            Is executed after an initial draw event, since we can then retrieve
            the actual label dimensions and shift/resize the plot accordingly.
        """
        renderer = get_renderer(self.figure)
        if not renderer or not self._canvas.get_realized():
            return False

        # Fix left side for wide specimen labels:
        if len(self.labels) > 0:
            bbox = self._get_joint_bbox(self.labels, renderer)
            if bbox is not None:
                self.position_setup.left = self.position_setup.default_left + bbox.width
        # Fix top for high marker labels:
        if len(self.marker_lbls) > 0:
            bbox = self._get_joint_bbox(
                [label for label, flag, _ in self.marker_lbls if flag],
                renderer)
            if bbox is not None:
                self.position_setup.top = self.position_setup.default_top - bbox.height
        # Fix bottom for x-axis label:
        bottom_label = self.plot.axis["bottom"].label
        if bottom_label is not None:
            bbox = self._get_joint_bbox([bottom_label], renderer)
            if bbox is not None:
                self.position_setup.bottom = self.position_setup.default_bottom + (
                    bbox.ymax - bbox.ymin) * 2.0  # somehow we need this?

        # Calculate new plot position & set it:
        plot_pos = self.position_setup.position
        self.plot.set_position(plot_pos)

        # Adjust specimen label position
        for label in self.labels:
            label.set_x(plot_pos[0] - 0.025)

        # Adjust marker label position
        for label, flag, y_offset in self.marker_lbls:
            if flag:
                newy = plot_pos[1] + plot_pos[3] + y_offset - 0.025
                label.set_y(newy)

        _new_pos = self.position_setup.to_string()
        return _new_pos

    def update(self, clear=False, project=None, specimens=None):
        """
            Updates the entire plot with the given information.
        """
        if clear: self.plot.cla()

        if project and specimens:
            self.labels, self.marker_lbls = plot_specimens(
                self.plot, self.position_setup, self.cc, project, specimens)
            # get mixtures for the selected specimens:
            plot_mixtures(self.plot, project, [
                mixture for mixture in project.mixtures
                if any(specimen in mixture.specimens for specimen in specimens)
            ])

        update_axes(self.plot, self.position_setup, project, specimens)

        self.draw()

    # ------------------------------------------------------------
    #      Plot position and size calculations
    # ------------------------------------------------------------
    def _get_joint_bbox(self, container, renderer):
        bboxes = []
        try:
            for text in container:
                bbox = text.get_window_extent(renderer=renderer)
                # the figure transform goes from relative coords->pixels and we
                # want the inverse of that
                bboxi = bbox.inverse_transformed(self.figure.transFigure)
                bboxes.append(bboxi)
        except (RuntimeError, ValueError):
            logger.exception(
                "Caught unhandled exception when joining boundig boxes")
            return None  # don't continue
        # this is the bbox that bounds all the bboxes, again in relative
        # figure coords
        if len(bboxes) > 0:
            bbox = transforms.Bbox.union(bboxes)
            return bbox
        else:
            return None

    # ------------------------------------------------------------
    #      Graph exporting
    # ------------------------------------------------------------
    def save(self,
             parent=None,
             current_name="graph",
             size="auto",
             num_specimens=1,
             offset=0.75):
        """
            Displays a save dialog to export an image from the current plot.
        """
        # Parse arguments:
        width, height = 0, 0
        if size == "auto":
            descr, width, height, dpi = settings.OUTPUT_PRESETS[0]
        else:
            width, height, dpi = list(
                map(float,
                    size.replace("@", "x").split("x")))

        # Load gui:
        builder = Gtk.Builder()
        builder.add_from_file(
            resource_filename("pyxrd.specimen", "glade/save_graph_size.glade")
        )  # FIXME move this to this namespace!!
        size_expander = builder.get_object("size_expander")
        cmb_presets = builder.get_object("cmb_presets")

        # Setup combo with presets:
        cmb_store = Gtk.ListStore(str, int, int, float)
        for row in settings.OUTPUT_PRESETS:
            cmb_store.append(row)
        cmb_presets.clear()
        cmb_presets.set_model(cmb_store)
        cell = Gtk.CellRendererText()
        cmb_presets.pack_start(cell, True)
        cmb_presets.add_attribute(cell, 'text', 0)

        def on_cmb_changed(cmb, *args):
            itr = cmb.get_active_iter()
            w, h, d = cmb_store.get(itr, 1, 2, 3)
            entry_w.set_text(str(w))
            entry_h.set_text(str(h))
            entry_dpi.set_text(str(d))

        cmb_presets.connect('changed', on_cmb_changed)

        # Setup input boxes:
        entry_w = builder.get_object("entry_width")
        entry_h = builder.get_object("entry_height")
        entry_dpi = builder.get_object("entry_dpi")
        entry_w.set_text(str(width))
        entry_h.set_text(str(height))
        entry_dpi.set_text(str(dpi))

        # What to do when the user wants to save this:
        def on_accept(dialog):
            # Get the width, height & dpi
            width = float(entry_w.get_text())
            height = float(entry_h.get_text())
            dpi = float(entry_dpi.get_text())
            i_width, i_height = width / dpi, height / dpi
            # Save it all right!
            self.save_figure(dialog.filename, dpi, i_width, i_height)

        # Ask the user where, how and if he wants to save:
        DialogFactory.get_save_dialog(
            "Save Graph",
            parent=parent,
            filters=self.file_filters,
            current_name=current_name,
            extra_widget=size_expander).run(on_accept)

    def save_figure(self, filename, dpi, i_width, i_height):
        """
            Save the current plot
            
            Arguments:
             filename: the filename to save to (either .png, .pdf or .svg)
             dpi: Dots-Per-Inch resolution
             i_width: the width in inch
             i_height: the height in inch
        """
        # Get original settings:
        original_dpi = self.figure.get_dpi()
        original_width, original_height = self.figure.get_size_inches()
        # Set everything according to the user selection:
        self.figure.set_dpi(dpi)
        self.figure.set_size_inches((i_width, i_height))
        self.figure.canvas.draw()  # replot
        bbox_inches = matplotlib.transforms.Bbox.from_bounds(
            0, 0, i_width, i_height)
        # Save the figure:
        self.figure.savefig(filename, dpi=dpi, bbox_inches=bbox_inches)
        # Put everything back the way it was:
        self.figure.set_dpi(original_dpi)
        self.figure.set_size_inches((original_width, original_height))
        self.figure.canvas.draw()  # replot

    pass  # end of class
Example #49
0
def activity(ui, repo, **opts):
    # The doc string below will show up in 'hg activity --help'
    """
    Create a file called activity.png displaying the activity of the current
    repository

    By default, the activity is computed using the number of commits. There
    is an option to consider instead the number of lines modified in the
    changesets (--uselines).

    Most options are self explanatory.
    The map file format used to specify aliases is fairly simple:
    <alias name>; <actual name>
    This file is only used when --split=authors is used.

    The name listed after the option --exclude are those found in the
    mercurial repository. That is, before the map file is applied.
    """
    # do it
    try:
        options = check_options(repo, opts)
        ui.write('There are %d changesets\n' % options.length)

        # do something with this data:
        if options.mode=='display':
            try:
                import matplotlib.pyplot as plt
            except:
                raise UiException('you need matplotlib in your python path in order to use the hg activity extension.')
            from draw import draw_graph

            # harvest data
            dates_tab = collect_data(repo.changelog, options)
            if len(dates_tab)<1 or not options.length:
                raise UiException('no data available with those options.')

            fig = plt.figure() 
            draw_graph(fig, options, dates_tab)
            plt.show()
        elif options.mode=='file':
            try:
                from matplotlib.figure import Figure
                from matplotlib.backends.backend_agg import FigureCanvasAgg
            except:
                raise UiException('you need matplotlib in your python path in order to use the hg activity extension.')
            from draw import draw_graph

            # harvest data
            dates_tab = collect_data(repo.changelog, options)
            if len(dates_tab)<1 or not options.length:
                raise UiException('no data available with those options.')

            fig = Figure()
            canvas = FigureCanvasAgg(fig)
            draw_graph(fig, options, dates_tab)
            fig.set_dpi(100)
            fig.set_size_inches(options.width/100.0,options.height/100.0)
            canvas.print_figure(options.filename)
            ui.status('Created the file \'%s\'\n' % options.filename)
        elif options.mode=='gui':
            from mode_qt import displayQtGui
            displayQtGui(repo, options)
        else:
            raise UiException('unknown mode %s', options.mode)
            
    except UiException, error:
        from sys import exit
        ui.warn("Hg activity, checking options: %s\n" % error.message)
        exit(1)