Skip to content

Commit 7a90819

Browse files
committed
blitting works with the class but not with plt
1 parent 8cbd81d commit 7a90819

File tree

3 files changed

+127
-3
lines changed

3 files changed

+127
-3
lines changed

pygame_matplotlib/backend_pygame.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ def set_bounding_rect(self, rect: pygame.Rect):
5656
# Redraw the figure
5757
self.canvas.draw()
5858

59+
#def draw(self, *args, **kwargs):
60+
# print(*args, **kwargs)
61+
# return super().draw(self, *args, **kwargs)
62+
5963

6064
class RendererPygame(RendererBase):
6165
"""The renderer handles drawing/rendering operations.
@@ -71,7 +75,7 @@ def __init__(self, dpi):
7175

7276
def rect_from_bbox(self, bbox: Bbox) -> pygame.Rect:
7377
"""Convert a matplotlib bbox to the equivalent pygame Rect."""
74-
print(bbox.get_points())
78+
raise NotImplementedError()
7579

7680
def draw_path(self, gc, path, transform, rgbFace=None):
7781

@@ -354,10 +358,12 @@ def draw(self):
354358
self.figure.draw(self.renderer)
355359

356360
def blit(self, bbox=None):
361+
# self._png_is_old = True
357362
self.renderer = self.get_renderer(cleared=False)
358363
self.renderer.surface = self.figure
359364
self.figure.draw(self.renderer)
360365

366+
361367
def get_renderer(self, cleared=False) -> RendererPygame:
362368
fig = self.figure
363369
reuse_renderer = (
@@ -388,6 +394,17 @@ def flush_events(self):
388394
pygame.quit()
389395
show_fig = False
390396

397+
def start_event_loop(self, interval: float):
398+
FPS = 60
399+
FramePerSec = pygame.time.Clock()
400+
time_elapsed = 0
401+
while time_elapsed < interval:
402+
events = pygame.event.get()
403+
time_elapsed += FramePerSec.tick(FPS) / 1000. # Convert ms
404+
for event in events:
405+
if event.type == pygame.QUIT:
406+
pygame.quit()
407+
391408

392409
class FigureManagerPygame(FigureManagerBase):
393410
"""

test_blitting.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,21 @@
3434
ax.draw_artist(ln)
3535
# show the result to the screen, this pushes the updated RGBA buffer from the
3636
# renderer to the GUI framework so you can see it
37-
fig.canvas.blit(fig.bbox)
3837

3938
for j in range(1000):
4039
# reset the background back in the canvas state, screen unchanged
4140
fig.canvas.restore_region(bg)
4241
# update the artist, neither the canvas state nor the screen have changed
4342
ln.set_ydata(np.sin(x + (j / 100) * np.pi))
4443
# re-render the artist, updating the canvas state, but not the screen
44+
print(ax.get_renderer_cache())
45+
print('Draw starts')
4546
ax.draw_artist(ln)
47+
print('Draw ends')
4648
# copy the image to the GUI state, but screen might not be changed yet
4749
fig.canvas.blit(fig.bbox)
50+
print(fig._cachedRenderer)
4851
# flush any pending GUI events, re-painting the screen if needed
4952
fig.canvas.flush_events()
5053
# you can put a pause in if you want to slow things down
51-
# plt.pause(.1)
54+
plt.pause(1)

test_blitting_class.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import matplotlib.pyplot as plt
2+
import numpy as np
3+
import matplotlib
4+
matplotlib.use('module://pygame_matplotlib.backend_pygame')
5+
6+
class BlitManager:
7+
def __init__(self, canvas, animated_artists=()):
8+
"""
9+
Parameters
10+
----------
11+
canvas : FigureCanvasAgg
12+
The canvas to work with, this only works for sub-classes of the Agg
13+
canvas which have the `~FigureCanvasAgg.copy_from_bbox` and
14+
`~FigureCanvasAgg.restore_region` methods.
15+
16+
animated_artists : Iterable[Artist]
17+
List of the artists to manage
18+
"""
19+
self.canvas = canvas
20+
self._bg = None
21+
self._artists = []
22+
23+
for a in animated_artists:
24+
self.add_artist(a)
25+
# grab the background on every draw
26+
self.cid = canvas.mpl_connect("draw_event", self.on_draw)
27+
28+
def on_draw(self, event):
29+
"""Callback to register with 'draw_event'."""
30+
cv = self.canvas
31+
if event is not None:
32+
if event.canvas != cv:
33+
raise RuntimeError
34+
self._bg = cv.copy_from_bbox(cv.figure.bbox)
35+
self._draw_animated()
36+
37+
def add_artist(self, art):
38+
"""
39+
Add an artist to be managed.
40+
41+
Parameters
42+
----------
43+
art : Artist
44+
45+
The artist to be added. Will be set to 'animated' (just
46+
to be safe). *art* must be in the figure associated with
47+
the canvas this class is managing.
48+
49+
"""
50+
if art.figure != self.canvas.figure:
51+
raise RuntimeError
52+
art.set_animated(True)
53+
self._artists.append(art)
54+
55+
def _draw_animated(self):
56+
"""Draw all of the animated artists."""
57+
fig = self.canvas.figure
58+
for a in self._artists:
59+
fig.draw_artist(a)
60+
61+
def update(self):
62+
"""Update the screen with animated artists."""
63+
cv = self.canvas
64+
fig = cv.figure
65+
# paranoia in case we missed the draw event,
66+
if self._bg is None:
67+
self.on_draw(None)
68+
else:
69+
# restore the background
70+
cv.restore_region(self._bg)
71+
# draw all of the animated artists
72+
self._draw_animated()
73+
# update the GUI state
74+
cv.blit(fig.bbox)
75+
# let the GUI event loop process anything it has to do
76+
cv.flush_events()
77+
78+
x = np.linspace(0, 2 * np.pi, 100)
79+
# make a new figure
80+
fig, ax = plt.subplots()
81+
# add a line
82+
(ln,) = ax.plot(x, np.sin(x), animated=True)
83+
# add a frame number
84+
fr_number = ax.annotate(
85+
"0",
86+
(0, 1),
87+
xycoords="axes fraction",
88+
xytext=(10, -10),
89+
textcoords="offset points",
90+
ha="left",
91+
va="top",
92+
animated=True,
93+
)
94+
bm = BlitManager(fig.canvas, [ln, fr_number])
95+
# make sure our window is on the screen and drawn
96+
plt.show(block=False)
97+
plt.pause(.1)
98+
99+
for j in range(1000):
100+
# update the artists
101+
ln.set_ydata(np.sin(x + (j / 100) * np.pi))
102+
fr_number.set_text("frame: {j}".format(j=j))
103+
# tell the blitting manager to do its thing
104+
bm.update()

0 commit comments

Comments
 (0)