pythonlinuxmatplotlibplotdynamic

Dynamic update of plot in Matplotlib generating strange lines


I'm trying use dynamically add rectangles to a plot using Matplotlib but some weird lines are showing up in the plot.

enter image description here

My grid is a class with init and an update function to add new rectangle shapes to the plot

class GridDisplay:
    def __init__(self):
        # initialize and configure the plot

    def UpdatePlotWithIndicesCoords(self, layerID, newData):
        # update the plot with a new rectangle

The definition of the functions are shown in the code snippet below

def UpdatePlotWithIndicesCoords(self, layerID, newData):
        
        x0 = newData[0]
        x1 = newData[2]
        y0 = round(newData[1], 6)
        y1 = round(newData[3], 6)
        
        height = round(y1 - y0, 6)
        width = round(x1 - x0, 6)
    
        y = y0

        x = x0
        
        self.rectangles.append((x, y, width, height))
        
        self.graph.remove()

        rectangle = plt.Rectangle((x, y), width, height, edgecolor='yellow', facecolor=layerID, lw=1)

        self.ax.add_patch(rectangle)

        self.graph = self.ax.plot(self.rectangles)[0]
def __init__(self):
        
        ySize = 15
        xSize = 25
        xStart = -6
        yStart = -6
        xEnd = 5
        yEnd = 5

        self.fig, self.ax = plt.subplots(figsize=(xSize, ySize))
        
        # Set axis limits
        self.ax.set_ylim( yStart, yEnd)
        self.ax.set_xlim(xStart, xEnd)
        
        # Change major ticks to show every 0.5
        self.ax.xaxis.set_major_locator(MultipleLocator(0.5))
        self.ax.yaxis.set_major_locator(MultipleLocator(0.5))
        
        # Change minor ticks to show every 0.1
        self.ax.xaxis.set_minor_locator(AutoMinorLocator(0.1))
        self.ax.yaxis.set_minor_locator(AutoMinorLocator(0.5))
        
        # Turn grid on for both major and minor ticks and style minor slightly
        # differently.
        self.ax.grid(which='major', color='#CCCCCC', linestyle='--')
        self.ax.grid(which='minor', color='#CCCCCC', linestyle=':')
        
        
        # Set labels and title
    
        self.ax.set_xlabel('h')
    
        self.ax.set_ylabel('v')
    
        self.ax.set_title('S-Cell Routing grid')
    
        # Set grid
    
        self.ax.grid(True)
        
        self.rectangles = []
        
        self.graph = self.ax.plot(self.rectangles)[0]

The UpdatePlotWithIndicesCoords function is called from another package which simply specifies the bound coordinates of the rectangle (x0, y0, x1, y1) as shown in the snippet below

self.gridDisplay.UpdatePlotWithIndicesCoords(layerID, (startX, startY, endX, endY))

The layerID parameter is used to specify the colour of the rectangle and is not so important to the problem

The image shown is generated from the code below which demonstrates the problem.

import bin.ui.display as GridDisplay


gridDisplay = GridDisplay()

startX = -5
startY = -5

for i in range(1, 6):
    
    layer = str('Metal') + str(i)
    
    newData = (startX + round(i*0.2, 6), startY + round(i*0.5, 6), startX + round(i*0.6, 6), startY + round(i*0.7, 6))
    
    
    gridDisplay.UpdatePlotWithBoundboxCoords(layer, newData)

I'm not sure what I'm doing wrong but I can't seem to figure out why the random lines are plotted.

I've looked up the documentation and posts on dynamically ploting shapes with Matplotlib but none on the solutions seem to work.

By the way, I also enabled the interactive mode for Matplotlib plt.ion() Thanks and kind regards.

Update What worked for me was to change the graph assignment in the last line of code in the UpdatePlotWithIndicesCoords function from self.graph = self.ax.plot(self.rectangles)[0] to self.graph = self.ax.add_patch(rectangle)


Solution

  • As explained by @JohanC, the >=4 lines appear because Axes.plot(*args, ...) is treating the rectangles (which is a list of 4-tuple elements) as a list of sequences to be plotted. You can visualize it with this minimal reproducible code :

    import matplotlib.pyplot as plt
    
    rectangles = [
        (-4.8, -4.5, 0.4, 0.2),
        (-4.6, -4.0, 0.8, 0.4),
        (-4.4, -3.5, 1.2, 0.6),
        (-4.2, -3.0, 1.6, 0.8),
        (-4.0, -2.5, 2.0, 1.0),
    ]
    
    plt.plot(rectangles) # gives exactly 4 lines like OP
    

    The solution is to remove the line below and/or assign the graph to the add_patch call :

    self.ax.add_patch(rectangle)
    
    self.graph = self.ax.plot(self.rectangles)[0]

    Output (GridDisplayProject> python .\main.py, including a restart) :

    enter image description here