Embedding multiple real-time graphs in one Python Tkinter GUI
Question:
I am new with Tkinter. I am trying to plot two real-time animated graphs in a window, but two realtime data overlaps onto the same graph after a while. I want them to be displayed on separate graphs. I put a gif to show my output.
I want to plot the other data to left graph. Is there any way to fix this? If I can make it I will try to plot three graphs instead of two. Can you help me with my code below?
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
import tkinter as Tk
from matplotlib.figure import Figure
import random
from itertools import count
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
from pandas import DataFrame
plt.style.use('fivethirtyeight')
# values for first graph
x_vals = []
y_vals = []
# values for second graph
x_vals2 = []
y_vals2 = []
index = count()
index2 = count()
def animate(i):
x_vals.append(next(index))
y_vals.append(random.randint(0, 5))
plt.cla() # clear the current axes
plt.plot(x_vals, y_vals)
def animate2(j):
x_vals2.append(next(index2))
y_vals2.append(random.randint(0, 5))
plt.cla() # clear the current axes
plt.plot(x_vals2, y_vals2)
# GUI
root = Tk.Tk()
label = Tk.Label(root, text="Realtime Animated Graphs").grid(column=0, row=0)
# graph 1
canvas = FigureCanvasTkAgg(plt.gcf(), master=root)
canvas.get_tk_widget().grid(column=0, row=1)
ani = FuncAnimation(plt.gcf(), animate, interval=1000, blit=False)
# graph 2
canvas2 = FigureCanvasTkAgg(plt.gcf(), master=root)
canvas2.get_tk_widget().grid(column=1, row=1)
ax2 = plt.gcf().add_subplot(111)
line2, = ax2.plot(x_vals2, y_vals2)
ani2 = FuncAnimation(plt.gcf(), animate2, interval=1000, blit=False)
Tk.mainloop()
Answers:
If You don’t specifically need canvas1 and 2, You can create two subplots for one figure / canvas.
Then You will get 2 axes: ax1
and ax2
.
You can use just one FuncAnimation
with same x
.
If You need separate animations for ax1
and ax2
, You can do that as well and just update either ax1
or ax2
in respective animation.
Here is code snippet:
import random
import tkinter as Tk
from itertools import count
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
plt.style.use('fivethirtyeight')
# values for first graph
x_vals = []
y_vals = []
# values for second graph
y_vals2 = []
index = count()
index2 = count()
def animate(i):
# Generate values
x_vals.append(next(index))
y_vals.append(random.randint(0, 5))
y_vals2.append(random.randint(0, 5))
# Get all axes of figure
ax1, ax2 = plt.gcf().get_axes()
# Clear current data
ax1.cla()
ax2.cla()
# Plot new data
ax1.plot(x_vals, y_vals)
ax2.plot(x_vals, y_vals2)
# GUI
root = Tk.Tk()
label = Tk.Label(root, text="Realtime Animated Graphs").grid(column=0, row=0)
# graph 1
canvas = FigureCanvasTkAgg(plt.gcf(), master=root)
canvas.get_tk_widget().grid(column=0, row=1)
# Create two subplots in row 1 and column 1, 2
plt.gcf().subplots(1, 2)
ani = FuncAnimation(plt.gcf(), animate, interval=1000, blit=False)
Tk.mainloop()
This is the output:
I am new with Tkinter. I am trying to plot two real-time animated graphs in a window, but two realtime data overlaps onto the same graph after a while. I want them to be displayed on separate graphs. I put a gif to show my output.
I want to plot the other data to left graph. Is there any way to fix this? If I can make it I will try to plot three graphs instead of two. Can you help me with my code below?
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
import tkinter as Tk
from matplotlib.figure import Figure
import random
from itertools import count
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
from pandas import DataFrame
plt.style.use('fivethirtyeight')
# values for first graph
x_vals = []
y_vals = []
# values for second graph
x_vals2 = []
y_vals2 = []
index = count()
index2 = count()
def animate(i):
x_vals.append(next(index))
y_vals.append(random.randint(0, 5))
plt.cla() # clear the current axes
plt.plot(x_vals, y_vals)
def animate2(j):
x_vals2.append(next(index2))
y_vals2.append(random.randint(0, 5))
plt.cla() # clear the current axes
plt.plot(x_vals2, y_vals2)
# GUI
root = Tk.Tk()
label = Tk.Label(root, text="Realtime Animated Graphs").grid(column=0, row=0)
# graph 1
canvas = FigureCanvasTkAgg(plt.gcf(), master=root)
canvas.get_tk_widget().grid(column=0, row=1)
ani = FuncAnimation(plt.gcf(), animate, interval=1000, blit=False)
# graph 2
canvas2 = FigureCanvasTkAgg(plt.gcf(), master=root)
canvas2.get_tk_widget().grid(column=1, row=1)
ax2 = plt.gcf().add_subplot(111)
line2, = ax2.plot(x_vals2, y_vals2)
ani2 = FuncAnimation(plt.gcf(), animate2, interval=1000, blit=False)
Tk.mainloop()
If You don’t specifically need canvas1 and 2, You can create two subplots for one figure / canvas.
Then You will get 2 axes: ax1
and ax2
.
You can use just one FuncAnimation
with same x
.
If You need separate animations for ax1
and ax2
, You can do that as well and just update either ax1
or ax2
in respective animation.
Here is code snippet:
import random
import tkinter as Tk
from itertools import count
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
plt.style.use('fivethirtyeight')
# values for first graph
x_vals = []
y_vals = []
# values for second graph
y_vals2 = []
index = count()
index2 = count()
def animate(i):
# Generate values
x_vals.append(next(index))
y_vals.append(random.randint(0, 5))
y_vals2.append(random.randint(0, 5))
# Get all axes of figure
ax1, ax2 = plt.gcf().get_axes()
# Clear current data
ax1.cla()
ax2.cla()
# Plot new data
ax1.plot(x_vals, y_vals)
ax2.plot(x_vals, y_vals2)
# GUI
root = Tk.Tk()
label = Tk.Label(root, text="Realtime Animated Graphs").grid(column=0, row=0)
# graph 1
canvas = FigureCanvasTkAgg(plt.gcf(), master=root)
canvas.get_tk_widget().grid(column=0, row=1)
# Create two subplots in row 1 and column 1, 2
plt.gcf().subplots(1, 2)
ani = FuncAnimation(plt.gcf(), animate, interval=1000, blit=False)
Tk.mainloop()
This is the output: