class Barplot:
    def __init__(
        self,
        series: Series,
        *,
        style: str = "whitegrid",
        palette: str = "pastel",
    ) -> None:
        self.__axes = Figure(tight_layout=True).add_subplot()

        seaborn.set_theme(style=style, palette=palette)
        seaborn.barplot(x=series.index, y=series, ax=self.__axes)
        seaborn.despine(ax=self.__axes)

    def get_xticklabels(self) -> List[str]:
        return [
            xticklabel.get_text()
            for xticklabel in self.__axes.get_xticklabels()
        ]

    def get_xlabel(self) -> str:
        return self.__axes.get_xlabel()

    def get_ylabel(self) -> str:
        return self.__axes.get_ylabel()

    def get_annotations(self) -> List[str]:
        return [
            child.get_text() for child in self.__axes.get_children()
            if isinstance(child, Annotation)
        ]

    def set_xticklabels(self, labels: List[str]) -> Barplot:
        xticklabels = self.__axes.get_xticklabels()

        for xticklabel in xticklabels:
            old_text = xticklabel.get_text()

            idx = int(old_text)
            new_text = labels[idx]

            xticklabel.set_text(new_text)

        self.__axes.set_xticklabels(xticklabels)
        return self

    def set_xlabel(self, label: str) -> Barplot:
        self.__axes.set_xlabel(label)
        return self

    def set_ylabel(self, label: str) -> Barplot:
        self.__axes.set_ylabel(label)
        return self

    def set_annotations(
        self,
        *,
        ha: str = "center",
        va: str = "bottom",
    ) -> Barplot:
        for patch in self.__axes.patches:
            x = patch.get_x()
            y = patch.get_y()

            height = patch.get_height()
            width = patch.get_width()

            if round(height, 2) != 0:
                self.__axes.annotate(
                    text=f"{height:.0f}"
                    if height.is_integer() else f"{height:.2f}",
                    xy=(x + width / 2, y + height * 1.025),
                    ha=ha,
                    va=va,
                )

        return self

    def save(self, file_name: str) -> None:
        figure = self.__axes.get_figure()
        figure.savefig(file_name + ".png")
Exemple #2
0
class BasicGrapher(grapher.BasicGrapher):
    """Documentation string for Basic Grapher

    A simple graphing widget
    By Randy P. and Bart O."""
    def __init__(self, parent=None, **kw):
        self.ax = Figure(figsize=(4.3, 3.0)).gca()
        self.ax2d = self.ax
        self.ax3d = None
        if kw.get("hide"):
            self.canvas = FigureCanvasAgg(self.ax.get_figure())
        else:
            self.canvas = FigureCanvasTkAggRedraw(self, parent)
            tk_widget = self.canvas.get_tk_widget()
            self.quit = tk_widget.quit
            self.bind = tk_widget.bind
            self.unbind = tk_widget.unbind
            self.winfo_rootx = tk_widget.winfo_rootx
            self.winfo_rooty = tk_widget.winfo_rooty
        self.ax.set_autoscale_on(0)
        self.postscript = self.canvas.print_figure
        self.savefig = self.ax.get_figure().savefig

        self.redrawlabels = 0

        callback = self.__optionCallback
        grapher.BasicGrapher.__init__(self, parent, callback, **kw)
        optionDefaults = {}
        optionDefaults["xticks"] = (None, callback)
        optionDefaults["yticks"] = (None, callback)
        optionDefaults["zticks"] = (None, callback)
        optionDefaults["background"] = ("white", callback)
        optionAliases = {}
        optionAliases["bg"] = "background"

        self.addOptions(**optionDefaults)
        self.addAliases(**optionAliases)

        for key in [
                "grid", "decorations", "xlabel", "ylabel", "zlabel",
                "xlabel_fontsize", "ylabel_fontsize", "zlabel_fontsize",
                "minx", "maxx", "miny", "maxy", "minz", "maxz", "width",
                "height", "left_margin", "right_margin", "top_margin",
                "bottom_margin"
        ]:
            self.__optionCallback(key, self.cget(key), [])
        matplotlib.rcParams["axes.edgecolor"] = self.cget("foreground")

    def pack(self, **kw):
        self.canvas.get_tk_widget().pack(kw)

    def update(self):
        if isinstance(self.canvas, FigureCanvasTkAggRedraw):
            self.canvas.get_tk_widget().update()
            FigureCanvasTkAgg.draw(self.canvas)
        else:
            self.canvas.draw()

    def __optionCallback(self, key, value, options):
        if key in [
                "minx", "maxx", "miny", "maxy", "minz", "maxz", "realwidth",
                "realheight", "azimuth", "elevation", "left_margin",
                "right_margin", "top_margin", "bottom_margin"
        ]:
            self.redrawlabels = 1
            if key[:3] in ["min", "max"]:
                minc = self.cget("min" + key[3])
                maxc = self.cget("max" + key[3])
                if minc < maxc:
                    func = None
                    if self.ax is self.ax3d:
                        func = getattr(self.ax, "set_" + key[3] + "lim3d")
                        self._cur_lims = (Axes.get_xlim(self.ax),
                                          Axes.get_ylim(self.ax))
                    elif key[3] != 'z':
                        func = getattr(self.ax, "set_" + key[3] + "lim")
                    if func is not None:
                        func(minc, maxc)
                        tickskey = key[3] + "ticks"
                        ticksval = self.cget(tickskey)
                        if ticksval is not None:
                            self.__optionCallback(tickskey, ticksval, options)
            elif key == "realwidth":
                lm = float(self.cget("left_margin"))
                rm = float(self.cget("right_margin"))
                self.ax.get_figure().subplots_adjust(left=lm / value,
                                                     right=1 - rm / value)
            elif key == "realheight":
                tm = float(self.cget("top_margin"))
                bm = float(self.cget("bottom_margin"))
                top = 1 - tm / value
                bottom = bm / value
                if top > bottom:
                    self.ax.get_figure().subplots_adjust(top=top,
                                                         bottom=bottom)
            elif key == "left_margin":
                fig = self.ax.get_figure()
                width = fig.get_figwidth() * fig.get_dpi()
                fig.subplots_adjust(left=value / width)
            elif key == "right_margin":
                fig = self.ax.get_figure()
                width = fig.get_figwidth() * fig.get_dpi()
                fig.subplots_adjust(right=1 - value / width)
            elif key == "top_margin":
                fig = self.ax.get_figure()
                height = fig.get_figheight() * fig.get_dpi()
                fig.subplots_adjust(top=1 - value / height)
            elif key == "bottom_margin":
                fig = self.ax.get_figure()
                height = fig.get_figheight() * fig.get_dpi()
                fig.subplots_adjust(bottom=value / height)
            elif self.ax is self.ax3d:
                elev = self.cget("elevation")
                azim = self.cget("azimuth")
                if elev is not None or azim is not None:
                    self.ax.view_init(elev, azim)
        elif key == "grid":
            if value in ["yes", True]:
                self.ax.grid(color=self.cget("foreground"))
            else:
                self.ax.grid(False)
        elif key in ["width", "height"]:
            if isinstance(self.canvas, FigureCanvasTkAggRedraw):
                self.canvas.get_tk_widget()[key] = value
            else:
                fig = self.ax.get_figure()
                if key == "width":
                    fig.set_figwidth(float(value) / fig.get_dpi())
                    self._configNoDraw(realwidth=value)
                else:
                    fig.set_figheight(float(value) / fig.get_dpi())
                    self._configNoDraw(realheight=value)
        elif key == "top_title":
            fontsize = self.cget("top_title_fontsize")
            if fontsize is None:
                self.ax.set_title(value)
            else:
                self.ax.set_title(value, fontsize=fontsize)
        elif key == "top_title_fontsize":
            title = self.cget("top_title")
            if title is not None:
                self.ax.set_title(title, fontsize=value)
        elif key in ["background", "bg"]:
            if hasattr(self.ax, 'set_facecolor'):
                # matplotlib >= 2.0
                self.ax.set_facecolor(value)
            else:
                self.ax.set_axis_bgcolor(value)
        elif key in ["foreground", "fg"]:
            matplotlib.rcParams["axes.edgecolor"] = self.cget("foreground")
            self.redrawlabels = 1
            if self.cget("grid") in ["yes", True]:
                self.ax.grid(color=value)
        elif key == "color_list":
            color_list = value.split()
            i = 0
            for d in self.data:
                if d["newsect"] is None or d["newsect"]:
                    i = i + 1
                if d["color"] is None:
                    color = i
                else:
                    color = d["color"]
                d["mpline"].set_color(color_list[color % len(color_list)])
        elif key == "decorations":
            if value:
                self.ax.set_axis_on()
            else:
                self.ax.set_axis_off()
        elif key == "use_symbols":
            self.plotsymbols()
        elif key == "use_labels":
            self.plotlabels()
        elif key in ["xlabel", "ylabel", "zlabel"]:
            if value is None:
                value = ""
            fontsize = self.cget(key + "_fontsize")
            if hasattr(self.ax, "set_" + key):
                func = getattr(self.ax, "set_" + key)
                if fontsize is None:
                    func(value)
                else:
                    func(value, fontsize=fontsize)
        elif key in ["xlabel_fontsize", "ylabel_fontsize", "zlabel_fontsize"]:
            label = self.cget(key[:6])
            if hasattr(self.ax, "set_" + key[:6]):
                func = getattr(self.ax, "set_" + key[:6])
                if value is None:
                    func(label)
                else:
                    func(label, fontsize=value)
        elif key in ["xticks", "yticks", "zticks"]:
            if value is None:
                if self.ax is self.ax3d:
                    axis = getattr(self.ax, "w_" + key[0] + "axis")
                    axis.set_major_locator(AutoLocator())
                elif key == "xticks":
                    self.ax.set_xscale('linear')
                else:
                    self.ax.set_yscale('linear')
            else:
                min = self.cget("min" + key[0])
                max = self.cget("max" + key[0])
                ticks = [
                    min + ((max - min) * i) / float(value - 1)
                    for i in range(value)
                ]
                if self.ax is self.ax3d:
                    axis = getattr(self.ax, "w_" + key[0] + "axis")
                    axis.set_major_locator(FixedLocator(ticks))
                elif key == "xticks":
                    self.ax.set_xticks(ticks)
                elif key == "yticks":
                    self.ax.set_yticks(ticks)

    def _delAllData(self):
        for d in self.data:
            if "mpline" in d:
                self.ax.lines.remove(d["mpline"])
        self.data = []

        # set type for next data
        try:
            zcolumn = self.cget(self.cget("type") + "_z")
        except Tkinter.TclError:  #in regression test
            return
        oldax = self.ax
        if zcolumn is None or Axes3D is None:
            if zcolumn is not None:
                self._configNoDraw({self.cget("type") + "_z": None})
                print("\nmatplotlib 0.98.x does not support 3D plots.")
                print("Plotting only the first two coordinates.")
            if self.ax is self.ax3d:
                # restore zoom mode
                new_zoom_mode = self.zoom_mode
                self.ax = self.ax2d
        else:
            if self.ax3d is None:
                self.ax3d = Axes3D(self.ax.get_figure())
                try:
                    self.ax3d.set_autoscale_on(0)
                except TypeError:  #Matplotlib 1.1 bug
                    self.ax2d.set_autoscale_on(0)
                    self.ax3d.set_autoscalez_on(0)
            if self.ax is self.ax2d:
                # remember zoom mode and disable zoom
                if isinstance(self.canvas, FigureCanvasTkAggRedraw):
                    self.zoom_mode = self.toolbar.mode
                    new_zoom_mode = ''
                self.ax = self.ax3d
        if self.ax is not oldax:
            if (isinstance(self.canvas, FigureCanvasTkAggRedraw)
                    and new_zoom_mode != self.toolbar.mode):
                if "rect" in new_zoom_mode:
                    self.toolbar.zoom()
                elif "pan" in new_zoom_mode:
                    self.toolbar.pan()
                elif "rect" in self.toolbar.mode:
                    self.toolbar.zoom()
                elif "pan" in self.toolbar.mode:
                    self.toolbar.pan()
            #copy settings from 3d to 2d or vice versa
            for key in ("grid", "decorations", "xlabel", "ylabel", "zlabel",
                        "xticks", "yticks", "zticks", "minx", "maxx", "miny",
                        "maxy", "minz", "maxz", "azimuth", "elevation",
                        "top_title", "background"):
                self.__optionCallback(key, self.cget(key), [])

    def _delData(self, index):
        if "mpline" in data[index]:
            self.ax.lines.remove(data[index]["mpline"])
        del self.data[index]

    def clear(self):
        if len(self.ax.get_figure().axes) > 0:
            self.ax.get_figure().delaxes(self.ax.get_figure().axes[0])

    def draw(self):
        if self.redrawlabels:
            self.plotlabels()
        if len(self.ax.get_figure().axes) == 0:
            self.ax.get_figure().add_axes(self.ax)
        if isinstance(self.canvas, FigureCanvasTkAggRedraw):
            FigureCanvasTkAgg.draw(self.canvas)
        else:
            self.canvas.draw()

    def plot(self):
        color_list = self.cget("color_list").split()

        # data
        line_width = self.cget("line_width")
        dashes = list(map(float, self.cget("dashes")))
        i = -1
        for d in self.data:
            if d["newsect"] is None or d["newsect"]:
                i = i + 1
            curve = "curve:%d" % (i, )
            if self.ax is self.ax2d:
                v = [d["x"], d["y"]]
            else:
                v = [d["x"], d["y"], d["z"]]
            if d["color"] is None:
                color = i
            else:
                color = d["color"]
            kw = {'color': color_list[color % len(color_list)]}
            if len(v[0]) == 1:
                # If we only have one point we draw a small circle or a pixel
                if self.cget("type") == "solution":
                    marker = 'o'
                else:
                    marker = ','
                v.append(marker)
                #tags=("data_point:%d"%(0,),curve,"data")
            else:
                stable = d["stable"]
                #tags=(curve,"data")
                kw['lw'] = line_width
                if stable is not None and not stable:
                    kw.update({'ls': '--', 'dashes': dashes})
            if self.ax is self.ax2d:
                self.ax.plot(*v, **kw)
            else:
                self.ax.plot3D(*v, **kw)
            d["mpline"] = self.ax.lines[-1]
        if len(self.ax.get_figure().axes) == 0:
            self.ax.get_figure().add_axes(self.ax)

    def __setitem__(self, key, value):
        self.configure(**{key: value})

    def __getitem__(self, key):
        return self.cget(key)
Exemple #3
0
class GuiClass(object):
    def __init__(self):

        self.root = tk.Tk()
        self.root.wm_title("MatPlotDemo.py")

        # buttonFrame       
        self.buttonFrame = ttk.Frame(self.root,borderwidth=5, relief="sunken")
        self.buttonFrame.grid(column = 0, row = 0, sticky = 'N')
        Button1 = ttk.Button(self.buttonFrame,text="clearFigure()",command=lambda: self.clearFigure())
        Button1.grid(column = 0, row = 0)
        Button2 = ttk.Button(self.buttonFrame,text="figureAndAxes()",command=lambda: self.figureAndAxes())
        Button2.grid(column = 0, row = 1)
        Button3 = ttk.Button(self.buttonFrame,text="patchesAndLines()",command=lambda: self.patchesAndLines())
        Button3.grid(column = 0, row = 2)
        Button4 = ttk.Button(self.buttonFrame,text="drawSomeLInes()",command=lambda arg = 1: self.drawSomeLines())
        Button4.grid(column = 0, row = 3)
        
        Button5 = ttk.Button(self.buttonFrame,text="drawSinePlot",command=lambda: self.drawSinePlot())
        Button5.grid(column = 0, row = 4)
        Button6 = ttk.Button(self.buttonFrame,text="curveFitLinear()",command=lambda: self.curveFitLinear())
        Button6.grid(column = 0, row = 5)        
        Button7 = ttk.Button(self.buttonFrame,text="curveFitExp(0)",command=lambda arg = 0: self.curveFitExp(arg))
        Button7.grid(column = 0, row = 6)
        Button8 = ttk.Button(self.buttonFrame,text="curveFitExp(1)",command=lambda arg = 1: self.curveFitExp(arg))
        Button8.grid(column = 0, row = 7)
        Button9 = ttk.Button(self.buttonFrame,text="drawDoublePlot()",command=lambda arg = 0: self.drawDoublePlot(arg))
        Button9.grid(column = 0, row = 8)
        Button10 = ttk.Button(self.buttonFrame,text="twinxCurves",command=lambda arg = 0: self.twinxCurves())
        Button10.grid(column = 0, row = 9)
        Button11 = ttk.Button(self.buttonFrame,text="Report",command=lambda arg = 0: self.report())
        Button11.grid(column = 0, row = 10)
        Button12 = ttk.Button(self.buttonFrame,text="PlayGround",command=lambda arg = 0: self.playGround())
        Button12.grid(column = 0, row = 11)
        
        self.radioButtonFrame = ttk.Frame(self.root,borderwidth=5, relief="sunken")
        self.radioButtonFrame.grid(column = 0, row = 1, sticky = 'N')

        # add button for drawSomeLInes()
        
        self.showOn_tkCanvas = BooleanVar(value = True)
        """
        pyplotButton = Checkbutton(self.radioButtonFrame, text = "Show on Canvas", variable = self.showOn_tkCanvas, onvalue = True, offvalue = False)
        pyplotButton.grid(row = 1, column = 0)
        """
        
        canvasButton = Radiobutton(self.radioButtonFrame, text = "tk Canvas", variable = self.showOn_tkCanvas, value = 1).grid(row = 0, column = 0, sticky = W)
        pyplotButton = Radiobutton(self.radioButtonFrame, text = "pyplot ", variable = self.showOn_tkCanvas, value = 0).grid(row = 0, column = 1, sticky = W)
        
        # Create a ttk Frame to hold the MatplotLib Figure
        self.canvasFrame = ttk.Frame(self.root,borderwidth=5, relief="sunken")
        self.canvasFrame.grid(column = 1, row = 0)
        #self.canvasFrame.grid(column = 1, row = 0, rowspan = 5)

        # Create a matplotLib Figure - a matplotlib container for plots (axes) and patches 
        self.matPlotFigure = Figure(figsize=(6,6), dpi=80, constrained_layout = False) # Creates a 480 x 480 pixel figure.
        self.matPlotFigure.set_facecolor("white")        

        # Create the matplotlib canvas that the TkAgg backend renders on.
        # And this is the thing that gets redrawn after things are changed.
        self.matPlotCanvas = FigureCanvasTkAgg(self.matPlotFigure, master=self.canvasFrame)
        self.matPlotCanvas.get_tk_widget().grid(row=1,column=0)
      
        # Date Time Frame 
        self.dateTimeFrame = ttk.Frame(self.root,borderwidth=5, relief="sunken")
        self.dateTimeFrame.grid(column = 0, row = 1, columnspan = 2)
        self.timeStringVar = tk.StringVar()
        timeLabel = ttk.Label(self.dateTimeFrame, textvariable = self.timeStringVar)
        timeLabel.grid(column = 0, row = 0)

    def clearFigure(self):
        print("clearFigure")
        self.matPlotFigure.clf()
        self.matPlotCanvas.draw()

    def figureAndAxes(self):       
        if (self.showOn_tkCanvas.get()):
            fig = self.matPlotFigure    # Previously defined Figure containing matPlotCanvas
            fig.clf()
        else:
            fig = plt.figure(figsize=(6,6), dpi=80, constrained_layout = False)  # Newly instantaited pyplot figure
                       
        print(fig) # - outputs:  "Figure(400x400)"
        print(fig.axes)     #  returns : []
        
        # Figure stuff       
        fig.patch.set_facecolor("azure") # or "none"
        fig.patch.set_linewidth(5.0)     # 0.5 would be very thin
        fig.patch.set_edgecolor("black") # or "none"
        fig.suptitle("Figure Title", fontsize = 16, x = 0.2, y = 0.94)

        # Axes stuff
        ax1 = fig.add_subplot(111)  
        print("ax1", ax1)
        ax1.set_title("aGraph Title \n Second Row", pad = 25.0)
        ax1.set_position([0.2, 0.2, 0.6, 0.6])
        ax1.patch.set_facecolor("green")  # or "none"
        ax1.patch.set_alpha(0.2)          # Here we make it 80% transparent to tone down the green.

        # X Axis        
        ax1.set_xlim(0,100)
        ax1.xaxis.set_major_locator(MaxNLocator(5))       # Four major intervals
        ax1.xaxis.set_minor_locator(AutoMinorLocator(4))  # 5 ticks per interval

        ax1.set_xlabel('X axis label: fontsize = 14', fontsize = 14, color = 'blue')
        ax1.xaxis.labelpad = 25          # Move label up or down

        # Y Axis
        ax1.set_ylim(0, 5)
        ax1.yaxis.set_major_locator(MultipleLocator(1.0))  # Pick interval
        ax1.yaxis.set_minor_locator(AutoMinorLocator(5))  # 5 ticks per interval
        ax1.set_ylabel('Y axis label: fontsize = 14', fontsize = 14)
        ax1.yaxis.labelpad = 25          # Move label left or right

        ax1.spines['top'].set_color('blue')
        ax1.spines['top'].set_position(('axes', 1.02))    # Offset the axis 0.02 to left of zero
        ax1.spines['bottom'].set_color('blue')
        ax1.spines['bottom'].set_position(('axes', -0.02))  # Offset X axis down 0.02 
        ax1.spines['left'].set_color('blue')
        ax1.spines['left'].set_position(('axes', -0.02))    # Offset the axis 0.02 to left of zero
        ax1.spines['right'].set_color('blue')
        ax1.spines['right'].set_position(('axes', 1.02))    # Offset to the right

        ax1.set_aspect(15.0)        # This pegs the aspect ratio and guarantees that
                                    # the tk and pyplot are the same ratio
        print('Aspect Ratio:', ax1.get_aspect())  

        if (self.showOn_tkCanvas.get()):
            self.matPlotCanvas.draw()
        else:
            plt.show()

    def patchesAndLines(self):       
        if (self.showOn_tkCanvas.get()):
            fig = self.matPlotFigure    # Previously defined Figure containing matPlotCanvas
            fig.clf()
        else:
            fig = plt.figure(figsize=(6,6), dpi=80, constrained_layout = False)  # Newly instantaited pyplot figure
                       
        print(fig) # - outputs:  "Figure(400x400)"
        print(fig.axes)     #  returns : []

        def myArrow(x,y,l, aTransform, aColor = 'k'):
            """
            Creates a horizontal Arrow that points at [x,y] with length = l
            A positive l will point to the right
            A negative l will point to the left

            Annoyingly, the patches.Arrow starts at [x,y] and points away.
            """
            p = patches.Arrow(x+l, y, -l, 0.0, width = 0.05, clip_on = False, color = aColor, \
            transform = aTransform)
            # The tail of the arrow is at X1, Y1,
            # (X1,Y1, head offset from X1, head offset from Y1, width...)
            #p = patches.Arrow(0.5, 0.6, 0.0, -0.1, width = 0.05, clip_on = False, color = 'r')
            return p
 
        # Figure stuff       
        fig.patch.set_facecolor("azure") # or "none"
        fig.patch.set_linewidth(5.0)     # 0.5 would be very thin
        fig.patch.set_edgecolor("black") # or "none"

        # Axes stuff
        ax1 = fig.add_subplot(111)  
        ax1.set_position([0.2, 0.2, 0.6, 0.6])
        ax1.patch.set_facecolor("green")  # or "none"
        ax1.patch.set_alpha(0.2)          # Here we make it 80% transparent to tone down the green.

        # X Axis        
        # Y Axis

        for position in ax1.spines:         #'top', 'bottom', 'left', right'
            ax1.spines[position].set_color('blue')

        ax1.set_aspect(1.0)        # This pegs the aspect ratio and guarantees that
                                    # the tk and pyplot are the same ratio
        print('Aspect Ratio:', ax1.get_aspect())  

        l1 = lines.Line2D([0, 1], [0, 1], transform = fig.transFigure, figure = fig)
        l2 = lines.Line2D([0, 1], [1, 0], transform = fig.transFigure, figure = fig)

        # Pathches are 2D shapes that are rendered onto the Figure or Axes.

        circ1 = patches.Circle((0.0, 0.8), 0.1, color='r', alpha=0.3, transform = ax1.transAxes, \
                              clip_on = True)
        circ2 = patches.Circle((0.0, 0.2), 0.1, color='b', alpha=0.3, transform = ax1.transAxes, \
                              clip_on = False)
        rect = patches.Rectangle((0.8,0.7), 0.2, 0.2, color='cyan', alpha=0.4, transform = fig.transFigure, \
                                 clip_on = False)

        ax1.lines.extend([l1,l2])
        ax1.add_patch(circ1)
        ax1.add_patch(circ2)
        ax1.add_patch(rect)    

        ax1.text(0.5, 0.7, '[0.5,0.7] align right', ha = 'right', transform=ax1.transAxes)
        ax1.text(0.5, 0.5, '[0.5,0.5] centered', ha = 'center', va = 'center', transform=ax1.transAxes)
        ax1.text(0.5, 0.3, '[0.5,0.3] align left', ha = 'left', transform=ax1.transAxes)
        ax1.text(0.5, 0.1, '[0.5,0.1] vertical', ha = 'center', rotation= 'vertical', transform=ax1.transAxes)
        ax1.text(0.5, 1.1, '[0.5,1.1]', ha = 'center', transform=ax1.transAxes, \
                 fontsize=20, color='red')
        # ha = horizontalalignment, va = verticalalignment, 'center', 'right' or 'left'

        arrow1 = myArrow(0.0,0.5, 0.1, ax1.transData, aColor = 'r')
        arrow2 = myArrow(0.0,0.5, -0.1, ax1.transAxes)
        ax1.add_patch(arrow1)
        ax1.add_patch(arrow2)

        if (self.showOn_tkCanvas.get()):
            self.matPlotCanvas.draw()
        else:
            plt.show()


    def drawSomeLines(self):
        """
        Line2D args:        https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html
        Marker styles: https://matplotlib.org/api/markers_api.html#module-matplotlib.markers

        """     
        if (self.showOn_tkCanvas.get()):
            fig = self.matPlotFigure    # Previously defined Figure containing matPlotCanvas
            fig.clf()
        else:
            fig = plt.figure(figsize=(6,6), dpi=80, constrained_layout = True)  # Newly instantaited pyplot figure
  
        ax1 = fig.add_subplot(111)   # Create a new subplot
        ax1.set_title('Another Graph \n Second line')
        ax1.set_xlabel('X axis label: fontsize = 12', fontsize = 12)      
        ax1.set_ylabel('Y axis label: fontsize = 10', fontsize = 10)       
        ax1.set_xscale("linear")
        ax1.set_yscale("linear")
        ax1.set_xlim(0, 22)  
        ax1.set_ylim(0, 22)

        x = [2,6,10,14,18]
        y1 = [16,18,18,18,16] 
        line1 = Line2D(x,y1, color = 'red', ls = 'solid', marker = 'o')       # circle
        ax1.add_line(line1)

        x = [2,6,10,14,18]
        y2 = [14,16,16,16,14]
        line2 = Line2D(x,y2, color = 'blue', ls = "dashed", marker = 's')      # square
        ax1.add_line(line2)

        x = [2,6,10,14,18]
        y3 = [12,14,14,14,12]
        line3 = Line2D(x,y3, color = 'green', ls = 'dotted', marker = 'D', markersize = 3.5)      # diamond
        ax1.add_line(line3)

        ax1.legend(handles=(line1, line2, line3), labels=('label1', 'label2', 'label3'),loc='upper right')

        if (self.showOn_tkCanvas.get()):
            self.matPlotCanvas.draw()
        else:
            plt.show()
            
    def drawSinePlot(self):
        """
        Simple example of drawing a graph using Line2D
        """
        if (self.showOn_tkCanvas.get()):
            fig = self.matPlotFigure    # Previously defined Figure containing matPlotCanvas
            fig.clf()
        else:
            fig = plt.figure(figsize=(6,6), dpi=80, constrained_layout = True)  # Newly instantaited pyplot figure
 
        ax1 = fig.add_subplot(111)   # Create a new subplot
        ax1.set_position([0.2, 0.2, 0.6, 0.6])
        ax1.set_xlim(0,1)
        ax1.set_ylim(-1, 1)
        ax1.set_title('First line of title\n Second line')
        ax1.set_xlabel('X axis label: fontsize = 14', fontsize = 14)
        ax1.xaxis.labelpad = 25 
        ax1.set_ylabel('Y axis label: fontsize = 14', fontsize = 14)
        ax1.yaxis.labelpad = 25 

        x = np.arange(0.0,1.0,0.01)   # Using numpy, generate an array of x values from 0 to 1 in 0.01 intervals
        y = np.sin(3*np.pi*x)         # Generate a corresponding array of y using the numpy sine function        
        aLine   = Line2D(x,y, color = 'black')  
        ax1.add_line(aLine)

        if (self.showOn_tkCanvas.get()):
            self.matPlotCanvas.draw()
        else:
            plt.show()

    def curveFitLinear(self):
        """
        curve_fit() example.
        Might be a little easier to understand using y = ax + b as function

        This genenerate a noisy dataset using parameters. It then submits this dataset
        to curve_fit() which returns its best guess at a and b.

        The scatter plot is generated with the best fit line (plus and minus some measure of varaince).
              
        """
        def fitFunc(x,a,b):
            y = (a * x) + b
            return y

        if (self.showOn_tkCanvas.get()):
            fig = self.matPlotFigure    # Previously defined Figure containing matPlotCanvas
            fig.clf()
        else:
            fig = plt.figure(figsize=(6,6), dpi=80, constrained_layout = True)  # Newly instantaited pyplot figure
 
        ax1 = fig.add_subplot(111)   # Create a new subplot

        # Generate a dataset using known parameters (temp) and add some noise (noisyDataset)               
        x = np.arange(0,10,0.1)         # Using numpy, generate an array of x from 0 to 10 in interavsl of 0.1    
        y = fitFunc(x, 2.5, 10)         # Generate a corresponding array of y values using fitFunc()
        noisyDataset = y + 5*np.random.normal(size=len(y))
 
        fitParams, fitCovariances = curve_fit(fitFunc, x, noisyDataset)
        print (fitParams)
        print (fitCovariances)
        
        ax1.set_ylabel('Y Label', fontsize = 16)
        ax1.set_xlabel('X Label', fontsize = 16)
        ax1.set_xlim(0,10)

        sigma = [fitCovariances[0,0], \
                 fitCovariances[1,1]]
        ax1.plot(x, fitFunc(x, fitParams[0], fitParams[1]),\
                 x, fitFunc(x, fitParams[0] + sigma[0], fitParams[1] - sigma[1]),\
                 x, fitFunc(x, fitParams[0] - sigma[0], fitParams[1] + sigma[1]))
        ax1.scatter(x, noisyDataset) 
                
        if (self.showOn_tkCanvas.get()):
            self.matPlotCanvas.draw()
        else:
            plt.show()

    def curveFitExp(self,arg):
        """
        Example using  curve_fit to solve for three parameters in an exponential function.
        The equation is given in fitFunc()
        - curve_fit uses fitFunc() and arrays of x and y data: 
        - curve_fit() returns fitParams and fitCovariances
        - fitParams is an array corresponding to a,b anc c in the fitFunc().
        - fitCovariances reflect the varainaces around those parameters.
        - aGraph plots the best fit curve plus/minus the varaince.

        arg == 1 - plots using log scales
        arg == 0 - plots using linear scales

        ToDo: It might be easier to understand if the lines are plotted with Line2D
              Plot the fitline in blue and the 
         
        """

        def fitFunc(x, a, b, c):
            y = a * np.exp(-b*x) + c
            return y

        if (self.showOn_tkCanvas.get()):
            fig = self.matPlotFigure    # Previously defined Figure containing matPlotCanvas
            fig.clf()
        else:
            fig = plt.figure(figsize=(6,6), dpi=80, constrained_layout = True)  # Newly instantaited pyplot figure
 
        ax1 = fig.add_subplot(111)   # Create a new subplot

        # Generate a dataset using known parameters (temp) and add some noise (noisyDataset)
        x = np.linspace(0.1,4,50)             # Generate an array with 50 points, starting at 0.1 and ending at 4
        temp = fitFunc(x, 2.5, 1.3, 0.5)      # Generate a corresponding array of y using fitFunc
        noisyDataset = temp + 0.5 * np.random.normal(size=len(temp))   # Add some noise to the dataset

        # Try curve fitting - 
        fitParams, fitCovariances = curve_fit(fitFunc, x, noisyDataset)
        #print (fitParams)
        #print (fitCovariances)

        ax1.set_ylabel('Y Axis Label', fontsize = 16)
        ax1.set_xlabel('X Axis Label', fontsize = 16)

        if (arg == 0):
            ax1.set_xscale("log")
            ax1.set_yscale("log")
            ax1.set_xlim(0.03, 10)        
            ax1.set_ylim(0.1, 10)
        else:
            ax1.set_xscale("linear")
            ax1.set_yscale("linear")
            ax1.set_xlim(0, 4)        
            ax1.set_ylim(0, 4)
            
                  # .0001 to 10
        sigma = [fitCovariances[0,0], \
                 fitCovariances[1,1], \
                 fitCovariances[2,2] \
                 ]
        ax1.plot(x, fitFunc(x, fitParams[0], fitParams[1], fitParams[2]),\
                 x, fitFunc(x, fitParams[0] + sigma[0], fitParams[1] - sigma[1], fitParams[2] + sigma[2]),\
                 x, fitFunc(x, fitParams[0] - sigma[0], fitParams[1] + sigma[1], fitParams[2] - sigma[2]))

        ax1.scatter(x, noisyDataset)
        
        if (self.showOn_tkCanvas.get()):
            self.matPlotCanvas.draw()
        else:
            plt.show()

    def drawDoublePlot(self,arg):

        """
        For positioning graphs see:
        https://matplotlib.org/tutorials/intermediate/gridspec.html?highlight=gridspec

        Use GridSpec to define how the figures fit into the space.
        Here we define a 3x3 space. The top figure uses a 2x3 space
        and the bottom uses a 1x3 space. 

        uses numpy two dimensional indexing for a 3x3 array
        >>> x = np.arange(10)
        >>> x
        array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
        >>> x[0:2]
        array([0, 1])
        >>> x[0:3]
        array([0, 1, 2])
        """
        from matplotlib import gridspec

        if (self.showOn_tkCanvas.get()):
            fig = self.matPlotFigure    # Previously defined Figure containing matPlotCanvas
            fig.clf()
        else:
            fig = plt.figure(figsize=(6,6), dpi=80, constrained_layout = False)  # Newly instantaited pyplot figure
 
        gs = gridspec.GridSpec(nrows = 3, ncols= 3, figure = fig)


        ax1 = fig.add_subplot(gs[0:2,0:3]) # Create a new subplot 2 rows, 3 columns
        
        # The program is expecting to fill 3 rows and 3 columns.
        # [0:2,0:3] tells it that this subplot will use two rows (from 0 up to, but not including, 2)
        # and 3 columns (from 0 up to, but not including,  3)
               
        #aCumRecGraph.set_title('Another Graph \n Second line')
        ax1.set_xlabel('X axis label: fontsize = 12', fontsize = 12)      
        ax1.set_ylabel('Y axis label: fontsize = 10', fontsize = 10)       
        ax1.set_xscale("linear")
        ax1.set_yscale("linear")
        ax1.set_xlim(0, 21)  
        ax1.set_ylim(0, 21)
        x = [0,2,3,4,20]
        y = [4,4.1,4.7,2.0,2.5]
        aLine = Line2D(x,y, color = 'black', ls = 'solid', drawstyle = 'steps')
        ax1.add_line(aLine)

        bins = 20
        ax2 = fig.add_subplot(gs[2,0:3])       # row [2] and col [0,1,2]
        ax2.set_xlim(0, bins+1)  
        ax2.set_ylim(0, 6)
        
        barHeights = [0.5,1.0,1.5,2.0,2.5, 3.0,3.5,4.0,4.5,5.0, \
                     5.0,4.5,4.0,3.5,3.0, 2.5,2.0,1.5,1.0,0.5]


        index = np.arange(bins)       
        bar_width = 0.35
        ax2.bar(index,barHeights,bar_width)

        if (self.showOn_tkCanvas.get()):
            self.matPlotCanvas.draw()
        else:
            plt.show()


    def twinxCurves(self):
        """
        Example of a graph with two axes.
        The main graph is a loglog line and a scatter plot
        """

        x =  [2.53, 4.49, 8.0, 14.23, 25.32, 42.55, 80.0, 142.86, 258.06, 444.44, 800.0, 1428.57]
        y1 = [0.864, 0.690, 0.486, 0.286, 0.134, 0.048, 0.012, 0.003, 0.00069, 0.000262, 0.000171, 0.0001607]
        y2 = [1.58, 0.69, 1.13, 1.75, 1.50, 0.98, 0.804, 0.891, 0.325, 0.064, 0.09, 0.01]
        y3 = [4, 3, 9, 25, 38, 44, 64, 127, 100, 50, 20, 20]

        if (self.showOn_tkCanvas.get()):
            fig = self.matPlotFigure    # Previously defined Figure containing matPlotCanvas
            fig.clf()
        else:
            fig = plt.figure(figsize=(6,6), dpi=80, constrained_layout = True)  # Newly instantaited pyplot figure

        ax1 = fig.add_subplot(111)
        ax1.set_title('Demand Curve\n Second line of title')
        ax1.set_xlabel('X axis label: fontsize = 16', fontsize = 16)      
        ax1.set_ylabel('Y axis label: fontsize = 14', fontsize = 14)
        ax1.set_xscale("log")
        ax1.set_yscale("log")
        ax1.set_xlim(1e0, 1e4)                   # 1 to 10,000
        ax1.set_ylim(1e-4, 1e1)                  # .0001 to 10
        ax1.loglog(x, y1, color ='red')          # Draw a loglog line 
        ax1.scatter(x, y2)                       # and a scatter plot
        ax2 = ax1.twinx()                        # create a 2nd axes that shares the same x-axis
        ax2.set_ylabel('Responses', fontsize = 16)
        ax2.set_ylim(0,250)                      # Y axis from 0 to 250
        ax2.plot(x,y3, color = 'black')
        #    OR
        #responseLine = Line2D(x,y3, color = 'black')
        #secondAxisPlot.add_line(responseLine)

        if (self.showOn_tkCanvas.get()):
            self.matPlotCanvas.draw()
        else:
            plt.show()
        
    def report(self):
        print("Report:")
        axes = self.matPlotFigure.gca()
        print("Current Axes", axes)
        figure = self.matPlotFigure.get_figure()
        print("Current Figure", figure)
        #print("graph1:", self.graph1)
        #print("line1:", self.line1)
        print("Axes:", self.matPlotFigure.axes)
        print("DPI:", self.matPlotFigure.get_dpi())
        print("size in inches:", self.matPlotFigure.get_size_inches())

    def playGround(self):
        """
        Template to generate graph for discussion with Jones Lab
        
        """


        
        Qzero = 10.0  # arbitrary
        k = 2.0       # arbitrary - Highest to lowest is 10, so k should be 1. But 2 looks better. 

        def demandFunction(x,alpha):
            """
            Demand function described by Hursh
            y = np.e**(np.log10(Qzero)+k*(np.exp(-alpha*Qzero*x)-1))            
            """
            y = 10**(np.log10(Qzero)+k*(np.exp(-alpha*Qzero*x)-1))                       
            return y

        from matplotlib import gridspec
        gs = gridspec.GridSpec(nrows = 4, ncols= 3)

        if (self.showOn_tkCanvas.get()):
            fig = self.matPlotFigure    # Previously defined Figure containing matPlotCanvas
            fig.clf()
        else:
            fig = plt.figure(figsize=(6,6), dpi=80, constrained_layout = False)  # Newly instantaited pyplot figure

        # Data
        responseList = [9.9, 19, 37, 72, 140, 200, 150, 50, 10, 10, 10, 10]       
        consumptionList = [0,0,0,0,0,0,0,0,0,0,0,0]

        # Each times is half of the previous
        TH_PumpTimes = [8.0,4.0,2.0,1.0,0.5,0.25,0.125,0.0625,0.0312,0.0156,0.0078,0.0039]

        dosePerResponse = []

        priceList = []
        for i in range(12):
            binDose = TH_PumpTimes[i] * 5.0 * 0.025  # pumptime(mSec) * mg/ml * ml/sec)
            dosePerResponse.append(round(binDose,5))           
            price = round(1/binDose,2)
            priceList.append(price)

        print("Doses =",dosePerResponse)
        print("Prices =",priceList)
        
        for i in range(12):
            consumptionList[i] = round(responseList[i] * dosePerResponse[i],4)

        print("Consumption =",consumptionList)
 
        ax1 = fig.add_subplot(gs[0:2,0:3])   # Create a new subplot, 2 rows and 3 columns 
        ax1.set_ylabel('Intake (mg per 2h session)', fontsize = 16)
        ax1.set_xlabel('Price (responses/mg)', fontsize = 16)
        ax1.set_xscale("log")
        ax1.set_yscale("linear")
        ax1.set_xlim(0.75, 1000)        
        ax1.set_ylim(0.0, 12)

        # Fit the curve. i.e.
 
        param_bounds=([0.0001],[0.02])
        fitParams, fitCovariances = curve_fit(demandFunction, priceList, consumptionList, bounds=param_bounds)
        alpha = fitParams[0]
        alphaString = "alpha (curve fit) = {0:7.5f}".format(alpha)
        print(alphaString)

        fitLine = []      
        for x in priceList:
            y = demandFunction(x,alpha)
            fitLine.append(y)

        ax1.scatter(priceList, consumptionList)
        ax1.plot(priceList,fitLine, color='red')


        ax2 = fig.add_subplot(gs[3,0:3])       # fourth row and col [0,1,2]

        ax2.set_xscale("log")
        ax2.set_xlim(1.5, 0.001)
        ax2.set_xlabel('Dose (mg/injection)', fontsize = 16)
        ax2.set_yscale("linear")
        ax2.set_ylim(0,300) 
        ax2.set_ylabel('Responses', fontsize = 16)
        #line1 = Line2D(priceList,responseList, color = 'red', ls = 'solid', marker = 'o')       # circle
        #ax2.add_line(line1)
        ax2.plot(dosePerResponse,responseList, marker = 'o', color = 'black')

        # Draw ellipse
        from matplotlib.patches import Ellipse
        mean = [0.25 , 0.80]
        width = 0.55
        height = 0.3
        myEllipse = Ellipse(xy=mean, width=width, color = 'blue', height=height, fill = False, transform = ax1.transAxes)
        ax1.add_patch(myEllipse)
        
        if (self.showOn_tkCanvas.get()):
            self.matPlotCanvas.draw()
        else:
            plt.show()

    def periodic_check(self):
        # http://docs.python.org/dev/library/datetime.html#strftime-strptime-behavior
        time = datetime.now()
        self.timeStringVar.set(time.strftime("%B %d -- %H:%M:%S"))        
        self.root.after(100, self.periodic_check)

    def go(self):
        self.root.after(100, self.periodic_check)
        self.root.mainloop()