I am trying to create a process monitor with python using matplotlib to produce the graphs, I had it all working when testing a single graph, however I am noticing some strange behaviour when I add a second graph.
The main issue is that I cannot remove the margin on the left, this is a live updating graph moving from right to left so the margin is only after 10 seconds. I have tried to use tight_layout()
and manually setting the margin.
the second issue arises when trying to set the amount of ticks on the y axis, using locator_params(axis="y", nbins=8)
on a single graph works perfectly however when I add the second graph it only applies to the second graph.
I have created a cut down demo to show the problems:
My Code:
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
import psutil
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("Graph Test")
self.geometry("800x300")
self.figure = Figure(figsize=(8, 3), dpi=100)
self.cpu_graph = self.figure.add_subplot(121)
self.set_graph_style(self.cpu_graph)
self.memory_graph = self.figure.add_subplot(122)
self.set_graph_style(self.memory_graph)
canvas = FigureCanvasTkAgg(self.figure, self)
canvas.get_tk_widget().grid(row=0, column=0)
self.frame_length = 10
self.x_list = []
for i in range(self.frame_length):
self.x_list.append(i)
self.cpu_y_list = [-1] * self.frame_length
self.memory_y_list = [-1] * self.frame_length
self.anim = animation.FuncAnimation(self.figure, self.animate, interval=1000)
def animate(self, i):
lower_limit = i
upper_limit = i self.frame_length
self.x_list.append(i self.frame_length)
self.cpu_y_list.append(psutil.cpu_percent())
self.memory_y_list.append(psutil.virtual_memory().percent)
if len(self.cpu_y_list) > self.frame_length:
self.x_list.pop(0)
self.cpu_y_list.pop(0)
self.memory_y_list.pop(0)
self.cpu_graph.clear()
self.cpu_graph.plot(self.x_list, self.cpu_y_list, "#117dbb")
self.cpu_graph.set_title("CPU")
self.cpu_graph.set_xlim(lower_limit, upper_limit)
self.cpu_graph.fill_between(self.x_list, self.cpu_y_list, color="#f1f6fa")
self.set_graph_style(self.cpu_graph)
self.memory_graph.clear()
self.memory_graph.plot(self.x_list, self.memory_y_list, "#117dbb")
self.memory_graph.set_title("Memory")
self.memory_graph.set_xlim(lower_limit, upper_limit)
self.memory_graph.fill_between(self.x_list, self.memory_y_list, color="#f1f6fa")
self.set_graph_style(self.memory_graph)
def set_graph_style(self, graph):
graph.grid()
graph.set_yticklabels([])
graph.set_xticklabels([])
graph.set_ylim(0, 100)
# This works on a single graph but only applies to 2nd graph when there is 2 graphs
graph.locator_params(axis="y", nbins=8)
graph.spines["bottom"].set_color("#117dbb")
graph.spines["left"].set_color("#117dbb")
graph.spines["top"].set_visible(False)
graph.spines["right"].set_visible(False)
# tight_layout() produces error:
# AttributeError: 'AxesSubplot' object has no attribute 'tight_layout'. Did you mean: '_in_layout'?
# graph.tight_layout()
# Try adjusting margin instead
# This only applies to second graph
graph.margins(x=0)
self.figure.tight_layout()
if __name__ == "__main__":
app = App()
app.mainloop()
Here is a picture showing the results, the red rectangle highlights the margin problem:
Any advice on either of these issues?
EDIT:
I have done some more debugging and realised that the margin is not the issue, I am using i
as the iterator within the animate()
method and then using this to set the axis limits, however i
is not incrementing until the 3rd iteration of the loop which in turn sets the wrong limits:
i: 0
Low: 0
Up: 5
x_list: [1, 2, 3, 4, 5]
cpu_y_list: [-1, -1, -1, -1, 32.4]
memory_y_list: [-1, -1, -1, -1, 25.3]
i: 0
Low: 0
Up: 5
x_list: [2, 3, 4, 5, 5]
cpu_y_list: [-1, -1, -1, 32.4, 4.9]
memory_y_list: [-1, -1, -1, 25.3, 25.3]
i: 1
Low: 1
Up: 6
x_list: [3, 4, 5, 5, 6]
cpu_y_list: [-1, -1, 32.4, 4.9, 6.5]
memory_y_list: [-1, -1, 25.3, 25.3, 25.3]
Does anybody know why i
is not incrementing?
I have also realised that locator_params(axis="y", nbins=8)
can only reduce the amount of ticks, not increase them so I either need to find a method that will increase ticks or multiply the figures for display purposes.
CodePudding user response:
For the margin, modify this :
lower_limit = i
by this :
lower_limit = i 1
For the i iterator, you can add a self.first_animate = True
in your init method and add
if self.first_animate:
self.first_animate = False
return
at the beginning of your animate method.
This code (https://pastebin.com/8GwAZRme) works well on my computer.