简体   繁体   中英

My matplotlib bar-chart duplicates every time a function is run, how can I refresh my bar-chart?

My bar chart that I created by looking around the internet here and the bar chart seems to stack the same result on top of a previous plot from a function that is run instead of changing values while taking data from a database.

The code below utilizes classes and consists of a page I created in tkinter alongside the use of SQLite3 and a function:

class ViewTrackData(tkinter.Frame):
def __init__(self, parent, controller):
    tkinter.Frame.__init__(self, parent)
    # label1 = tkinter.Label(self, text="This is the page where track data will be shown.")
    # label1.grid(row=50, column=70, sticky="nsew")

    self.athleteData = ""
    self.athlete = ""
    self.position = 1
    self.times = {}
    self.roundFigUp = ""
    self.roundFigDown = ""
    self.x = []
    self.y = []
    self.text = ""


    self.trackName = tkinter.Spinbox(self, values=trackTables, width=50, justify="center", font=entry_font,
                                     foreground="#000000", background="#FFFFFF")
    self.trackName.place(relx=0.15, rely=0.1)

    self.eventYear = tkinter.Entry(self, width=50, justify="center", font=entry_font, foreground="#000000",
                                   background="#FFFFFF")
    self.eventYear.insert(0, "The year which the event took place.")
    self.eventYear.place(relx=0.15, rely=0.41)

    self.yearGroup = tkinter.Spinbox(self, from_=7, to=11, width=50, justify="center", font=entry_font,
                                     foreground="#000000", background="#FFFFFF")
    self.yearGroup.place(relx=0.15, rely=0.70)

    self.filterButton = tkinter.Button(self, text="filter", bg="#383A39", fg="#AB97BD", width=15, height=3,
                                       command=self.show_graph)
    self.filterButton.place(relx=0.24, rely=0.82)

    self.infoLabel = tkinter.Label(self, height=25, width=40, wraplength=300, anchor="center", relief="groove", font=font_use)
    self.infoLabel.place(relx=0.52, rely=0.1)

def show_graph(self):
    self.infoLabel.configure(text="")
    c.execute("SELECT * FROM " + self.trackName.get() + " WHERE Year_Of_Event = ? AND Athlete_Year_Group = ? "
                                                        "ORDER BY ATHLETE_TIME ASC", (self.eventYear.get(), self.yearGroup.get()))
    self.athleteData = c.fetchall()
    if self.athleteData is None:
        self.infoLabel.configure(text="There are no records in this year for this year group.")
    else:
        for self.item in self.athleteData:
            self.athlete = self.item
            self.times.update({self.athlete[1] : self.position}) # adds data about the name of the athlete as the key and the position which a athlete placed as a value.
            self.position += 1 # increments the position value
            self.x.append(self.times[self.athlete[1]]) # adds the position in which an athlete placed as an argument to the x axis
            self.truncatedTime = str(self.athlete[3]).replace((self.athlete[3])[5:],"") # turns the value for the seconds an athlete has run under into a string and slices off " seconds"
            print(self.truncatedTime)
            if int((self.truncatedTime)[3]) >= 5: # if statement which rounds up or down depending on the first value after the decimal point.
                self.roundFigUp = math.ceil(float(self.truncatedTime))
                self.y.append(int(self.roundFigUp))
            else:
                self.roundFigDown = math.floor(float(self.truncatedTime))
                self.y.append(int(self.roundFigDown))
            self.text += ("representing number " + str(self.times[self.athlete[1]]) + " is " + str(self.athlete[1])
                          + ", ")
            self.infoLabel.configure(text=self.text)
            print(self.athlete)

    plt.bar(self.x, self.y, label="Athlete time bars", color="green")

    plt.xlabel("Athlete Positions")
    plt.ylabel("Athlete Time")
    plt.title("Bar chart, representing times of athletes.")
    plt.legend()
    plt.show()

I have tried to search for an answer but I can't seem to be able implement everything I see into my program.

I apologize beforehand if this question seems noob-ish to you.

There is also one last thing i would like to request.

Could you explain to me how I should go about using plt.xticks? In order to change the labels from numbers to the actual names of the athletes. Which is denoted from self.athlete[1].

Every time show_graph is called more data is appended to self.x and self.y :

self.x.append(self.times[self.athlete[1]]) 
...
if int((self.truncatedTime)[3]) >= 5: 
    self.roundFigUp = math.ceil(float(self.truncatedTime))
    self.y.append(int(self.roundFigUp))
else:
    self.roundFigDown = math.floor(float(self.truncatedTime))
    self.y.append(int(self.roundFigDown))

The fix is to re-initialize self.x and self.y at the beginning of show_graph :

def show_graph(self):
    self.x = []
    self.y = []
    ...

The initialization of self.x and self.y that happens within the __init__ method only happens once, when the ViewTrackData Frame was instantiated.


PS. You may also be interested in seeing this example which shows how to embed a matplotlib figure inside a Tk app. One advantage of doing it this way is that showing the graph will not freeze the rest of the app's graphical user interface (eg menus and buttons).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM