Home > Back-end >  Python matplotlib: How do I remove the left margin
Python matplotlib: How do I remove the left margin

Time:09-11

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: enter image description here

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.

  • Related