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

Commit44fcb87

Browse files
authored
Merge pull request#8253 from ngoldbaum/simplify-figsize-adjust
Handle floating point round-off error when converting to pixels for h264 animations
2 parents50bb88a +5d4f5de commit44fcb87

File tree

2 files changed

+71
-12
lines changed

2 files changed

+71
-12
lines changed

‎lib/matplotlib/animation.py

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
importsix
2424
fromsix.movesimportxrange,zip
2525

26+
importnumpyasnp
2627
importos
2728
importplatform
2829
importsys
@@ -62,9 +63,38 @@
6263

6364

6465
defadjusted_figsize(w,h,dpi,n):
66+
'''Compute figure size so that pixels are a multiple of n
67+
68+
Parameters
69+
----------
70+
w, h : float
71+
Size in inches
72+
73+
dpi : float
74+
The dpi
75+
76+
n : int
77+
The target multiple
78+
79+
Returns
80+
-------
81+
wnew, hnew : float
82+
The new figure size in inches.
83+
'''
84+
85+
# this maybe simplified if / when we adopt consistent rounding for
86+
# pixel size across the whole library
87+
defcorrect_roundoff(x,dpi,n):
88+
ifint(x*dpi)%n!=0:
89+
ifint(np.nextafter(x,np.inf)*dpi)%n==0:
90+
x=np.nextafter(x,np.inf)
91+
elifint(np.nextafter(x,-np.inf)*dpi)%n==0:
92+
x=np.nextafter(x,-np.inf)
93+
returnx
94+
6595
wnew=int(w*dpi/n)*n/dpi
6696
hnew=int(h*dpi/n)*n/dpi
67-
returnwnew,hnew
97+
return(correct_roundoff(wnew,dpi,n),correct_roundoff(hnew,dpi,n))
6898

6999

70100
# A registry for available MovieWriter classes
@@ -278,8 +308,11 @@ def _adjust_frame_size(self):
278308
verbose.report('figure size (inches) has been adjusted '
279309
'from %s x %s to %s x %s'% (wo,ho,w,h),
280310
level='helpful')
311+
else:
312+
w,h=self.fig.get_size_inches()
281313
verbose.report('frame size in pixels is %s x %s'%self.frame_size,
282314
level='debug')
315+
returnw,h
283316

284317
defsetup(self,fig,outfile,dpi=None):
285318
'''
@@ -301,7 +334,7 @@ def setup(self, fig, outfile, dpi=None):
301334
ifdpiisNone:
302335
dpi=self.fig.dpi
303336
self.dpi=dpi
304-
self._adjust_frame_size()
337+
self._w,self._h=self._adjust_frame_size()
305338

306339
# Run here so that grab_frame() can write the data to a pipe. This
307340
# eliminates the need for temp files.
@@ -337,6 +370,10 @@ def grab_frame(self, **savefig_kwargs):
337370
verbose.report('MovieWriter.grab_frame: Grabbing frame.',
338371
level='debug')
339372
try:
373+
# re-adjust the figure size in case it has been changed by the
374+
# user. We must ensure that every frame is the same size or
375+
# the movie will not save correctly.
376+
self.fig.set_size_inches(self._w,self._h)
340377
# Tell the figure to save its data to the sink, using the
341378
# frame format and dpi.
342379
self.fig.savefig(self._frame_sink(),format=self.frame_format,
@@ -386,16 +423,21 @@ def isAvailable(cls):
386423
ifnotbin_path:
387424
returnFalse
388425
try:
389-
p=subprocess.Popen(bin_path,
390-
shell=False,
391-
stdout=subprocess.PIPE,
392-
stderr=subprocess.PIPE,
393-
creationflags=subprocess_creation_flags)
394-
p.communicate()
395-
returnTrue
426+
p=subprocess.Popen(
427+
bin_path,
428+
shell=False,
429+
stdout=subprocess.PIPE,
430+
stderr=subprocess.PIPE,
431+
creationflags=subprocess_creation_flags)
432+
returncls._handle_subprocess(p)
396433
exceptOSError:
397434
returnFalse
398435

436+
@classmethod
437+
def_handle_subprocess(cls,process):
438+
process.communicate()
439+
returnTrue
440+
399441

400442
classFileMovieWriter(MovieWriter):
401443
'''`MovieWriter` for writing to individual files and stitching at the end.
@@ -570,10 +612,18 @@ def output_args(self):
570612

571613
returnargs+ ['-y',self.outfile]
572614

615+
@classmethod
616+
def_handle_subprocess(cls,process):
617+
_,err=process.communicate()
618+
# Ubuntu 12.04 ships a broken ffmpeg binary which we shouldn't use
619+
if'Libav'inerr.decode():
620+
returnFalse
621+
returnTrue
622+
573623

574624
# Combine FFMpeg options with pipe-based writing
575625
@writers.register('ffmpeg')
576-
classFFMpegWriter(MovieWriter,FFMpegBase):
626+
classFFMpegWriter(FFMpegBase,MovieWriter):
577627
'''Pipe-based ffmpeg writer.
578628
579629
Frames are streamed directly to ffmpeg via a pipe and written in a single
@@ -594,7 +644,7 @@ def _args(self):
594644

595645
# Combine FFMpeg options with temp file-based writing
596646
@writers.register('ffmpeg_file')
597-
classFFMpegFileWriter(FileMovieWriter,FFMpegBase):
647+
classFFMpegFileWriter(FFMpegBase,FileMovieWriter):
598648
'''File-based ffmpeg writer.
599649
600650
Frames are written to temporary files on disk and then stitched

‎lib/matplotlib/tests/test_animation.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ def test_save_animation_smoketest(tmpdir, writer, extension):
145145
ax.set_xlim(0,10)
146146
ax.set_ylim(-1,1)
147147

148+
dpi=None
149+
codec=None
150+
ifwriter=='ffmpeg':
151+
# Issue #8253
152+
fig.set_size_inches((10.85,9.21))
153+
dpi=100.
154+
codec='h264'
155+
148156
definit():
149157
line.set_data([], [])
150158
returnline,
@@ -160,7 +168,8 @@ def animate(i):
160168
withtmpdir.as_cwd():
161169
anim=animation.FuncAnimation(fig,animate,init_func=init,frames=5)
162170
try:
163-
anim.save('movie.'+extension,fps=30,writer=writer,bitrate=500)
171+
anim.save('movie.'+extension,fps=30,writer=writer,bitrate=500,
172+
dpi=dpi,codec=codec)
164173
exceptUnicodeDecodeError:
165174
pytest.xfail("There can be errors in the numpy import stack, "
166175
"see issues #1891 and #2679")

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp