2

Faced with the fact that MatPlotlib when using self.frame.canvas.draw() I got only 12 FPS on a simple chart. I found a good article about acceleration speed MatPlotlib: https://bastibe.de/2013-05-30-speeding-up-matplotlib.html But part of the examples is working code, but the example with the fastest code (500 FPS) is not working. Attempts to read the documentation MatPlotlib have not yet led to success in understanding where the error is in the code: «AttributeError: draw_artist can only be used after an initial draw which caches the renderer». Where is the error in the code?

import matplotlib.pyplot as plt
import numpy as np
import time

fig, ax = plt.subplots()
line, = ax.plot(np.random.randn(100))
plt.show(block=False)

tstart = time.time()
num_plots = 0
while time.time()-tstart < 5:
    line.set_ydata(np.random.randn(100))
    ax.draw_artist(ax.patch)
    ax.draw_artist(line)
    fig.canvas.update()
    fig.canvas.flush_events()
    num_plots += 1
print(num_plots/5)
14
  • Try plt.draw() immediately after plt.show() Commented Jan 12, 2020 at 8:39
  • I also tried this variant, but the error remains the same. Commented Jan 12, 2020 at 8:46
  • Which line gives the error? Also by the way block=False is deprecated, you should use the approach in this answer instead Commented Jan 12, 2020 at 8:53
  • If delete «block=False» - the chart is drawn once and stops. After closing the chart, the code is executed further, where everything rests on the same error. I looked at the answer on the link: pauses do not help either. Commented Jan 12, 2020 at 9:17
  • 1
    Everything is ok) The main thing is that there is a solution to the problem. Commented Jan 12, 2020 at 16:35

1 Answer 1

2

If using the Qt5Agg backend, you can indeed just do what the error suggest, namely draw the canvas once before starting the loop.

import time
import numpy as np
import matplotlib
matplotlib.use("Qt5Agg")
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
line, = ax.plot(np.random.randn(100))

fig.canvas.draw()
plt.show(block=False)


tstart = time.time()
num_plots = 0
while time.time()-tstart < 5:
    line.set_ydata(np.random.randn(100))
    ax.draw_artist(ax.patch)
    ax.draw_artist(line)
    fig.canvas.update()
    fig.canvas.flush_events()
    num_plots += 1
print(num_plots/5)

However, I would actually use blit instead of PyQt's update, such that it would work with any backend,

import time
import numpy as np
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
line, = ax.plot(np.random.randn(100))

fig.canvas.draw()
plt.show(block=False)


tstart = time.time()
num_plots = 0
while time.time()-tstart < 5:
    line.set_ydata(np.random.randn(100))
    ax.draw_artist(ax.patch)
    ax.draw_artist(line)
    fig.canvas.blit(ax.bbox)
    fig.canvas.flush_events()
    num_plots += 1
print(num_plots/5)
Sign up to request clarification or add additional context in comments.

Super! Thanks to your help, a bug has been fixed and graphics rendering has been accelerated by almost 10 times. According to your recommendation: the use of “blit” is faster than “Qt5Agg” by 1.3..1.4 times.

Your Answer

Draft saved
Draft discarded

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.