Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4249e18

Browse files
authored
Merge pull request#10187 from tacaswell/doc_blitting_tutorial
DOC: add a blitting tutorial
2 parentsf8e4012 +bb9afe7 commit4249e18

File tree

3 files changed

+226
-1
lines changed

3 files changed

+226
-1
lines changed

‎doc/api/animation_api.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ performance), to be non-blocking, not repeatedly start/stop the GUI
5555
event loop, handle repeats, multiple animated axes, and easily save
5656
the animation to a movie file.
5757

58-
'Blitting' is a `old technique
58+
'Blitting' is a `standard technique
5959
<https://en.wikipedia.org/wiki/Bit_blit>`__ in computer graphics. The
6060
general gist is to take an existing bit map (in our case a mostly
6161
rasterized figure) and then 'blit' one more artist on top. Thus, by

‎lib/matplotlib/backend_bases.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,7 @@ class FigureCanvasBase:
16711671

16721672
@cbook._classproperty
16731673
defsupports_blit(cls):
1674+
"""If this Canvas sub-class supports blitting."""
16741675
return (hasattr(cls,"copy_from_bbox")
16751676
andhasattr(cls,"restore_region"))
16761677

‎tutorials/advanced/blitting.py

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
"""
2+
=================
3+
Blitting tutorial
4+
=================
5+
6+
'Blitting' is a `standard technique
7+
<https://en.wikipedia.org/wiki/Bit_blit>`__ in raster graphics that,
8+
in the context of Matplotlib, can be used to (drastically) improve
9+
performance of interactive figures. For example, the
10+
:mod:`~.animation` and :mod:`~.widgets` modules use blitting
11+
internally. Here, we demonstrate how to implement your own blitting, outside
12+
of these classes.
13+
14+
The source of the performance gains is simply not re-doing work we do
15+
not have to. If the limits of an Axes have not changed, then there is
16+
no need to re-draw all of the ticks and tick-labels (particularly
17+
because text is one of the more expensive things to render).
18+
19+
The procedure to save our work is roughly:
20+
21+
- draw the figure, but exclude any artists marked as 'animated'
22+
- save a copy of the RBGA buffer
23+
24+
In the future, to update the 'animated' artists we
25+
26+
- restore our copy of the RGBA buffer
27+
- redraw only the animated artists
28+
- show the resulting image on the screen
29+
30+
thus saving us from having to re-draw everything which is _not_
31+
animated. One consequence of this procedure is that your animated
32+
artists are always drawn at a higher z-order than the static artists.
33+
34+
Not all backends support blitting. You can check if a given canvas does via
35+
the `.FigureCanvasBase.supports_blit` property.
36+
37+
.. warning::
38+
39+
This code does not work with the OSX backend (but does work with other
40+
GUI backends on mac).
41+
42+
Minimal example
43+
---------------
44+
45+
We can use the `.FigureCanvasAgg` methods
46+
`~.FigureCanvasAgg.copy_from_bbox` and
47+
`~.FigureCanvasAgg.restore_region` in conjunction with setting
48+
``animated=True`` on our artist to implement a minimal example that
49+
uses blitting to accelerate rendering
50+
51+
"""
52+
53+
importmatplotlib.pyplotasplt
54+
importnumpyasnp
55+
56+
x=np.linspace(0,2*np.pi,100)
57+
58+
fig,ax=plt.subplots()
59+
60+
# animated=True tells matplotlib to only draw the artist when we
61+
# explicitly request it
62+
(ln,)=ax.plot(x,np.sin(x),animated=True)
63+
64+
# make sure the window is raised, but the script keeps going
65+
plt.show(block=False)
66+
67+
# stop to admire our empty window axes and ensure it is rendered at
68+
# least once.
69+
#
70+
# We need to fully draw the figure at its final size on the screen
71+
# before we continue on so that :
72+
# a) we have the correctly sized and drawn background to grab
73+
# b) we have a cached renderer so that ``ax.draw_artist`` works
74+
# so we spin the event loop to let the backend process any pending operations
75+
plt.pause(0.1)
76+
77+
# get copy of entire figure (everything inside fig.bbox) sans animated artist
78+
bg=fig.canvas.copy_from_bbox(fig.bbox)
79+
# draw the animated artist, this uses a cached renderer
80+
ax.draw_artist(ln)
81+
# show the result to the screen, this pushes the updated RGBA buffer from the
82+
# renderer to the GUI framework so you can see it
83+
fig.canvas.blit(fig.bbox)
84+
85+
forjinrange(100):
86+
# reset the background back in the canvas state, screen unchanged
87+
fig.canvas.restore_region(bg)
88+
# update the artist, neither the canvas state nor the screen have changed
89+
ln.set_ydata(np.sin(x+ (j/100)*np.pi))
90+
# re-render the artist, updating the canvas state, but not the screen
91+
ax.draw_artist(ln)
92+
# copy the image to the GUI state, but screen might not changed yet
93+
fig.canvas.blit(fig.bbox)
94+
# flush any pending GUI events, re-painting the screen if needed
95+
fig.canvas.flush_events()
96+
# you can put a pause in if you want to slow things down
97+
# plt.pause(.1)
98+
99+
###############################################################################
100+
# This example works and shows a simple animation, however because we
101+
# are only grabbing the background once, if the size of the figure in
102+
# pixels changes (due to either the size or dpi of the figure
103+
# changing) , the background will be invalid and result in incorrect
104+
# (but sometimes cool looking!) images. There is also a global
105+
# variable and a fair amount of boiler plate which suggests we should
106+
# wrap this in a class.
107+
#
108+
# Class-based example
109+
# -------------------
110+
#
111+
# We can use a class to encapsulate the boilerplate logic and state of
112+
# restoring the background, drawing the artists, and then blitting the
113+
# result to the screen. Additionally, we can use the ``'draw_event'``
114+
# callback to capture a new background whenever a full re-draw
115+
# happens to handle resizes correctly.
116+
117+
118+
classBlitManager:
119+
def__init__(self,canvas,animated_artists=()):
120+
"""
121+
Parameters
122+
----------
123+
canvas : FigureCanvasAgg
124+
The canvas to work with, this only works for sub-classes of the Agg
125+
canvas which have the `~FigureCanvasAgg.copy_from_bbox` and
126+
`~FigureCanvasAgg.restore_region` methods.
127+
128+
animated_artists : Iterable[Artist]
129+
List of the artists to manage
130+
"""
131+
self.canvas=canvas
132+
self._bg=None
133+
self._artists= []
134+
135+
forainanimated_artists:
136+
self.add_artist(a)
137+
# grab the background on every draw
138+
self.cid=canvas.mpl_connect("draw_event",self.on_draw)
139+
140+
defon_draw(self,event):
141+
"""Callback to register with 'draw_event'."""
142+
cv=self.canvas
143+
ifeventisnotNone:
144+
ifevent.canvas!=cv:
145+
raiseRuntimeError
146+
self._bg=cv.copy_from_bbox(cv.figure.bbox)
147+
self._draw_animated()
148+
149+
defadd_artist(self,art):
150+
"""
151+
Add an artist to be managed.
152+
153+
Parameters
154+
----------
155+
art : Artist
156+
157+
The artist to be added. Will be set to 'animated' (just
158+
to be safe). *art* must be in the figure associated with
159+
the canvas this class is managing.
160+
161+
"""
162+
ifart.figure!=self.canvas.figure:
163+
raiseRuntimeError
164+
art.set_animated(True)
165+
self._artists.append(art)
166+
167+
def_draw_animated(self):
168+
"""Draw all of the animated artists."""
169+
fig=self.canvas.figure
170+
forainself._artists:
171+
fig.draw_artist(a)
172+
173+
defupdate(self):
174+
"""Update the screen with animated artists."""
175+
cv=self.canvas
176+
fig=cv.figure
177+
# paranoia in case we missed the draw event,
178+
ifself._bgisNone:
179+
self.on_draw(None)
180+
else:
181+
# restore the background
182+
cv.restore_region(self._bg)
183+
# draw all of the animated artists
184+
self._draw_animated()
185+
# update the GUI state
186+
cv.blit(fig.bbox)
187+
# let the GUI event loop process anything it has to do
188+
cv.flush_events()
189+
190+
191+
###############################################################################
192+
# Here is how we would use our class. This is a slightly more complicated
193+
# example than the first case as we add a text frame counter as well.
194+
195+
# make a new figure
196+
fig,ax=plt.subplots()
197+
# add a line
198+
(ln,)=ax.plot(x,np.sin(x),animated=True)
199+
# add a frame number
200+
fr_number=ax.annotate(
201+
"0",
202+
(0,1),
203+
xycoords="axes fraction",
204+
xytext=(10,-10),
205+
textcoords="offset points",
206+
ha="left",
207+
va="top",
208+
animated=True,
209+
)
210+
bm=BlitManager(fig.canvas, [ln,fr_number])
211+
# make sure our window is on the screen and drawn
212+
plt.show(block=False)
213+
plt.pause(.1)
214+
215+
forjinrange(100):
216+
# update the artists
217+
ln.set_ydata(np.sin(x+ (j/100)*np.pi))
218+
fr_number.set_text("frame: {j}".format(j=j))
219+
# tell the blitting manager to do it's thing
220+
bm.update()
221+
222+
###############################################################################
223+
# This class does not depend on `.pyplot` and is suitable to embed
224+
# into larger GUI application.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp