Last active
September 22, 2021 23:02
-
-
Save jdmaturen/1e0e3c7fa69e1ccb6c21257c260ac676 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"# Animated charts\n", | |
"\n", | |
"Often times its important to be able to see a multidimensional data over time\n", | |
"or another linear dimension. We can help our brains out by making a video!\n", | |
"\n", | |
"To do this we'll use a pretty contrived example to:\n", | |
"1. Use matplotlib to output individual frames\n", | |
"2. Combine the frames with ffmpeg" | |
], | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 17, | |
"source": [ | |
"# Ensure we have an output directory\n", | |
"! [ ! -d \"output\" ] && mkdir output" | |
], | |
"outputs": [], | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 18, | |
"source": [ | |
"import matplotlib.pyplot as plt\n", | |
"import numpy as np\n", | |
"\n", | |
"\n", | |
"def write_img(frame: int):\n", | |
" fig, axis = plt.subplots(1, 1, figsize=(4, 4))\n", | |
" plt.suptitle(f\"Frame {frame:04d}\")\n", | |
" x = np.linspace(0, 2 * np.pi, 100)\n", | |
" y = np.sin(frame / np.pi + x)\n", | |
" axis.plot(x, y)\n", | |
" plt.savefig(f\"output/{frame:04d}.png\", dpi=400)\n", | |
" fig.clf()\n", | |
" plt.close()\n", | |
"\n", | |
"\n", | |
"for i in range(100):\n", | |
" write_img(i)\n" | |
], | |
"outputs": [], | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 20, | |
"source": [ | |
"!ffmpeg -y -r 60 -f image2 -s 1600x1600 -i output/%04d.png -crf 25 -pix_fmt yuv420p output/animated-chart.mp4" | |
], | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"ffmpeg version 4.4 Copyright (c) 2000-2021 the FFmpeg developers\n", | |
" built with Apple clang version 12.0.5 (clang-1205.0.22.9)\n", | |
" configuration: --prefix=/usr/local/Cellar/ffmpeg/4.4_2 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-avresample --enable-videotoolbox\n", | |
" libavutil 56. 70.100 / 56. 70.100\n", | |
" libavcodec 58.134.100 / 58.134.100\n", | |
" libavformat 58. 76.100 / 58. 76.100\n", | |
" libavdevice 58. 13.100 / 58. 13.100\n", | |
" libavfilter 7.110.100 / 7.110.100\n", | |
" libavresample 4. 0. 0 / 4. 0. 0\n", | |
" libswscale 5. 9.100 / 5. 9.100\n", | |
" libswresample 3. 9.100 / 3. 9.100\n", | |
" libpostproc 55. 9.100 / 55. 9.100\n", | |
"Input #0, image2, from 'output/%04d.png':\n", | |
" Duration: 00:00:01.67, start: 0.000000, bitrate: N/A\n", | |
" Stream #0:0: Video: png, rgba(pc), 1600x1600 [SAR 15748:15748 DAR 1:1], 60 fps, 60 tbr, 60 tbn, 60 tbc\n", | |
"Stream mapping:\n", | |
" Stream #0:0 -> #0:0 (png (native) -> h264 (libx264))\n", | |
"Press [q] to stop, [?] for help\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0musing SAR=1/1\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0musing cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mprofile High, level 5.1, 4:2:0, 8-bit\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0m264 - core 163 r3060 5db6aa6 - H.264/MPEG-4 AVC codec - Copyleft 2003-2021 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=18 lookahead_threads=3 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=25.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00\n", | |
"Output #0, mp4, to 'output/animated-chart.mp4':\n", | |
" Metadata:\n", | |
" encoder : Lavf58.76.100\n", | |
" Stream #0:0: Video: h264 (avc1 / 0x31637661), yuv420p(tv, progressive), 1600x1600 [SAR 1:1 DAR 1:1], q=2-31, 60 fps, 15360 tbn\n", | |
" Metadata:\n", | |
" encoder : Lavc58.134.100 libx264\n", | |
" Side data:\n", | |
" cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A\n", | |
"frame= 100 fps= 56 q=-1.0 Lsize= 295kB time=00:00:01.61 bitrate=1494.9kbits/s speed=0.899x \n", | |
"video:294kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.426828%\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mframe I:1 Avg QP:26.32 size: 18243\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mframe P:99 Avg QP:36.29 size: 2847\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mmb I I16..4: 33.0% 61.9% 5.1%\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mmb P I16..4: 0.2% 2.5% 0.9% P16..4: 2.3% 0.3% 0.1% 0.0% 0.0% skip:93.8%\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0m8x8 transform intra:68.0% inter:15.9%\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mcoded y,uvDC,uvAC intra: 15.2% 23.8% 23.6% inter: 0.1% 0.2% 0.0%\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mi16 v,h,dc,p: 56% 41% 3% 0%\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mi8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 14% 2% 78% 1% 0% 1% 0% 4% 0%\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mi4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 11% 5% 40% 12% 1% 4% 1% 25% 1%\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mi8c dc,h,v,p: 87% 2% 7% 4%\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mWeighted P-Frames: Y:0.0% UV:0.0%\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mref P L0: 64.2% 2.7% 29.5% 3.5%\n", | |
"\u001b[1;36m[libx264 @ 0x7fb3d280d400] \u001b[0mkb/s:1440.64\n" | |
] | |
} | |
], | |
"metadata": {} | |
} | |
], | |
"metadata": { | |
"orig_nbformat": 4, | |
"language_info": { | |
"name": "python", | |
"version": "3.9.5", | |
"mimetype": "text/x-python", | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"pygments_lexer": "ipython3", | |
"nbconvert_exporter": "python", | |
"file_extension": ".py" | |
}, | |
"kernelspec": { | |
"name": "python3", | |
"display_name": "Python 3.9.5 64-bit ('gauntlet-dev-KpC29WPo-py3.9': poetry)" | |
}, | |
"interpreter": { | |
"hash": "efab027e9e3fb4f9baa78cd5d4b10a127c6a1f0828167436cb2ce385c61b8e5c" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
output video:
animated-chart.mp4
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ffmpeg can be installed on osx with homebrew.