Как очистить график mathplotlib в tkinter? - PullRequest
0 голосов
/ 28 апреля 2020

Я пытаюсь очистить (весь) график mathplotlib в tkinker. Смысл, я пытаюсь построить график А. Нажмите кнопку очистки. После нажатия кнопки очистки моя цель - очистить график A от холста. Если бы я нажал на график графика кнопки B, то появилось бы содержание графика B. В настоящее время я вижу AttributeError: 'GetInterfaceValues' object has no attribute 'canvas', когда пытаюсь очистить график (нажав кнопку очистки графика). Может кто-нибудь направить меня в правильном направлении?

В основном вот мой код: файл plotting.py

    import matplotlib
    import pandas as pd
    matplotlib.use("TkAgg")
    import matplotlib.pyplot as plt
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

    fig, ax = plt.subplots()


    def plotGraph(self):
        df = pd.DataFrame({'Years': ['2016-12-31', '2017-12-31', '2018-12-31', '2019-12-31'],
                           'Value': [-495982.0, -405549.0, -351541.0, -283790.0]})

        yLabelText = "Value"
        ax.set_xlabel('Years')
        ax.set_ylabel(yLabelText)

        fig = plt.figure(figsize=(12, 10), dpi=80)
        ax1 = fig.add_subplot(111)
        ax1.set_title('Keg values')
        ax1.set_xlabel('Years')
        ax1.set_ylabel(yLabelText)

        datas = df.plot(ax=ax1, color ='orange')
        ax.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
        fig.tight_layout()
        canvas = FigureCanvasTkAgg(fig, self)
        canvas.draw()
        canvas.get_tk_widget().pack(side="bottom", fill="both", expand=True)


    def plotCashGraph(self):
        df = pd.DataFrame({'Quarter': ['2018-03-31', '2018-06-30', '2018-10-31', '2020-01-01'],
                           'Value': [-9000.0, 105549.0, -51541.0, 2790.0]})


        yLabelText = "Value"
        ax.set_xlabel('Quarter')
        ax.set_ylabel(yLabelText)

        fig = plt.figure(figsize=(12, 10), dpi=80)
        ax1 = fig.add_subplot(111)
        ax1.set_title('Cash')
        ax1.set_xlabel('Quarter')
        ax1.set_ylabel(yLabelText)

        datas = df.plot(ax=ax1, color ='green')
        ax.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
        fig.tight_layout()
        canvas = FigureCanvasTkAgg(fig, self)
        canvas.draw()
        canvas.get_tk_widget().pack(side="bottom", fill="both", expand=True)


    def clearPlotPage(self):
            self.canvas.destroy()
            self.canvas = None

и файл интерфейса:

    try:
        import Tkinter as tk
    except:
        import tkinter as tk

    import plotting as pyt


    class GetInterfaceValues():
        def __init__(self):
            self.root = tk.Tk()
            self.totalValue = tk.StringVar()

            self.root.geometry('900x500')

            self.plotGraphButton = tk.Button(self.root, text='plot the kegs values', command=self.plotKeg)
            self.plotCashValue = tk.Button(self.root, text='plot cash value', command=self.plotCash)

            self.clearButton = tk.Button(self.root,text='Clear Chart',command=self.clear)

            self.plotGraphButton.pack()
            self.plotCashValue.pack()
            self.clearButton.pack()

            self.root.mainloop()



        def plotKeg(self):
            pyt.plotGraph(self.root)

        def plotCash(self):
            pyt.plotCashGraph(self.root)


        def clear(self):
            pyt.clearPlotPage(self)




    app = GetInterfaceValues()

1 Ответ

1 голос
/ 28 апреля 2020

Пара вещей:

  1. Странно, что ваши функции принимают self в качестве аргумента, когда вы не используете class. Я полагаю, вы изначально скопировали код с OOP подхода.
  2. Вам не нужно удалять canvas и создавать его заново. Вы можете просто повторно использовать его.
  3. То же самое относится к fig - вам просто нужно очистить его и перерисовать.

Начиная с вашего plotting.py Я предлагаю вам создать class и создать методы класса вместо этого:

import matplotlib
import pandas as pd

matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure #as said before, use Figure instead of pyplot

class PlotGraph:
    def __init__(self):
        self.canvas = None
        self.fig = Figure(figsize=(12, 10), dpi=80)

    def plotGraph(self, container):
        df = pd.DataFrame({'Years': ['2016-12-31', '2017-12-31', '2018-12-31', '2019-12-31'],
                           'Value': [-495982.0, -405549.0, -351541.0, -283790.0]})
        ax = self.fig.add_subplot(111)
        ax.set_title('Keg values')
        ax.set_xlabel('Years')
        ax.set_ylabel("Value")
        ax.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
        df.plot(ax=ax, color='orange')
        if not self.canvas:
            self.canvas = FigureCanvasTkAgg(self.fig, container)
            self.canvas.get_tk_widget().pack(side="bottom", fill="both", expand=True)
        self.canvas.draw_idle()

    def plotCashGraph(self, container):
        df = pd.DataFrame({'Quarter': ['2018-03-31', '2018-06-30', '2018-10-31', '2020-01-01'],
                           'Value': [-9000.0, 105549.0, -51541.0, 2790.0]})
        ax = self.fig.add_subplot(111)
        ax.set_xlabel('Quarter')
        ax.set_ylabel("Value")
        ax.get_yaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ',')))
        df.plot(ax=ax, color='green')
        if not self.canvas:
            self.canvas = FigureCanvasTkAgg(self.fig, container)
            self.canvas.get_tk_widget().pack(side="bottom", fill="both", expand=True)
        self.canvas.draw_idle()

    def clearPlotPage(self):
        self.fig.clear() #clear your figure
        self.canvas.draw_idle() #redraw your canvas so it becomes empty

С заданным бэкэндом вам просто нужно немного изменить файл интерфейса:

try:
    import Tkinter as tk
except:
    import tkinter as tk

import plotting as pyt

class GetInterfaceValues():
    def __init__(self):
        self.root = tk.Tk()
        self.totalValue = tk.StringVar()

        self.root.geometry('900x500')

        self.plotGraphButton = tk.Button(self.root, text='plot the kegs values', command=self.plotKeg)
        self.plotCashValue = tk.Button(self.root, text='plot cash value', command=self.plotCash)

        self.clearButton = tk.Button(self.root, text='Clear Chart', command=self.clear)

        self.plotGraphButton.pack()
        self.plotCashValue.pack()
        self.clearButton.pack()

        self.root.mainloop()

    def plotKeg(self):
        plot.plotGraph(self.root)

    def plotCash(self):
        plot.plotCashGraph(self.root)

    def clear(self):
        plot.clearPlotPage()

plot = pyt.PlotGraph() #initiate a class instance
app = GetInterfaceValues()
...