{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Animations In VCS \n", "\n", "This Notebook demonstrates how to create animations in VCS\n", "\n", "Animations are rendered via FFMPEG\n", "\n", "The CDAT software was developed by LLNL. This tutorial was written by Charles Doutriaux. This work was performed under the auspices of the U.S. Department of Energy by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344.\n", "\n", "[Download the Jupyter notebook](Animations.ipynb)" ] }, { "cell_type": "markdown", "metadata": { "toc": true }, "source": [ "

Table of Contents

\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Preparing The Notebook\n", "[Back to top](#top)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We need some sample data" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import requests\n", "r = requests.get(\"https://uvcdat.llnl.gov/cdat/sample_data/clt.nc\",stream=True)\n", "with open(\"clt.nc\",\"wb\") as f:\n", " for chunk in r.iter_content(chunk_size=1024):\n", " if chunk: # filter local_filename keep-alive new chunks\n", " f.write(chunk)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Example 1: Simple 2D data animation\n", "\n", "In this example we will show a simple 2D animation\n", "\n", "[Back to top](#top)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Prepare data\n", "\n", "[Back to Top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import cdms2\n", "f=cdms2.open(\"clt.nc\")\n", "clt = f(\"clt\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create Frames\n", "[Back to top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# make directory for pngs if not present\n", "import os\n", "if not os.path.exists(\"pngs\"):\n", " os.makedirs(\"pngs\")\n", " \n", "import vcs\n", "x=vcs.init(bg=True)\n", "\n", "for i in range(clt.shape[0]):\n", " x.clear()\n", " x.plot(clt[i])\n", " x.png(\"pngs/2d_%s.png\" % str(i).zfill(6))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create Animation\n", "[Back to top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import glob\n", "name = \"2d_animation.mp4\"\n", "\n", "# Create animation into file\n", "x.ffmpeg(name,sorted(glob.glob(\"pngs/2d*png\")))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Example 2: 1D data moving behind a 1D target data\n", "\n", "In this example we will show a fix 1D *target* dataset and a moving red dataset in the back\n", "\n", "[Back to top](#top)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Let's prepare some data\n", "[Back to Top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import cdutil\n", "import numpy\n", "# Open data file\n", "f=cdms2.open(\"clt.nc\")\n", "\n", "# reads in data\n", "s=f(\"clt\")\n", "\n", "# Computes time serie\n", "ts=cdutil.averager(s,axis=\"xy\")\n", "\n", "# remove the mean\n", "mean = ts.mean()\n", "ts -= mean\n", "\n", "# create some random data with some extra points to fake the move\n", "Nextra = 120\n", "ts2 = numpy.random.rand(len(ts)+Nextra)*4.-2.\n", "\n", "# When plotting we will get data for 2 extra years than our target grid\n", "# Prepare the \"faxe time\" axis\n", "fake_time_axis = cdms2.createAxis(numpy.arange(-12,132))\n", "fake_time_axis.designateTime()\n", "fake_time_axis.id = \"time\"\n", "fake_time_axis.units=\"months since 1979\"\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Prepare graphic methods and templates\n", "[Back to top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a \"blank\" template\n", "blank = vcs.createtemplate()\n", "blank.blank()\n", "blank.data.priority=1 # turn only data area\n", "\n", "# Create the \"black\" 1D line\n", "black = vcs.create1d()\n", "black.linecolor =\"black\"\n", "black.markercolor = [0,0,0,0]\n", "black.linewidth = 4\n", "black.datawc_y1= -3\n", "black.datawc_y2 = 3\n", "black.datawc_x1 = -12\n", "black.datawc_x2 = 132\n", "\n", "# And from it let's create the \"red\" moving one\n", "red = vcs.create1d(source=black.name)\n", "red.linecolor=\"red\"\n", "red.linewidth=2\n", "red.linetype = \"dot\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create each frame/png\n", "[Back to top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x=vcs.init(bg=True)\n", "for i in range(Nextra-24):\n", " # Get some subset of data\n", " tsub = cdms2.MV2.array(ts2[i:i+len(ts)+24]) # Two years worth of extra data\n", " # Aplly fake axis to make it look like it moves\n", " tsub.setAxis(0,fake_time_axis)\n", " # clear and plot\n", " x.clear()\n", " x.plot(ts,black)\n", " x.plot(tsub,red,blank)\n", " # save data to a png file\n", " x.png(\"pngs/1d_%s.png\" % str(i).zfill(6))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create animation\n", "[Back to top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "name = \"1d_animation.mp4\"\n", "\n", "# Create animation into file\n", "x.ffmpeg(name,sorted(glob.glob(\"pngs/1d*png\")))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Slowing Down\n", "[Back to top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import glob\n", "name = \"1d_animation_slow.mp4\"\n", "\n", "# Create animation into file\n", "x.ffmpeg(name,sorted(glob.glob(\"pngs/1d*png\")),rate=2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Speeding up the animation\n", "[Back to top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import glob\n", "name = \"1d_animation_fast.mp4\"\n", "\n", "# Create animation into file\n", "x.ffmpeg(name,sorted(glob.glob(\"pngs/1d*png\")),rate=200)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Example 3: Rotating Globe\n", "\n", "In this example we will display a rotating earth\n", "[Back to top](#top)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Preparing the data\n", "[Back to top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f=cdms2.open(\"clt.nc\")\n", "clt=f(\"clt\",time=slice(0,1),longitude=(0,361),squeeze=1) # Read the time slice and squeeze it out" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Preparing the vcs objects\n", "[Back to top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# create new canvas\n", "x = vcs.init(bg=True)\n", "\n", "# Create projection\n", "polar = vcs.createprojection(\"rotate\")\n", "polar.type = \"orthographic\"\n", "polar.centerlongitude=0.\n", "polar.centerlatitude=45.\n", "\n", "# Create isofill method\n", "iso = vcs.createisofill()\n", "iso.levels = [a for a in range(0,110,10)]\n", "iso.fillareacolors = vcs.getcolors(iso.levels)\n", "\n", "iso.projection = polar" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Preparing the images\n", "[Back to top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for centerLongitude in range(0,366,5):\n", " polar.centerlongitude = centerLongitude\n", " x.clear()\n", " x.plot(clt,iso)\n", " x.png(\"pngs/rotate_%s.png\" % str(centerLongitude).zfill(6))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating the animation\n", "[Back to top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "name = \"rot_animation.mp4\"\n", "\n", "# Create animation into file\n", "print(\"files used\",glob.glob(\"pngs/rotate_*png\"))\n", "x.ffmpeg(name,sorted(glob.glob(\"pngs/rotate_*png\")), rate=15)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Controlling \n", "[Back to Top](#top)\n", "\n", "But it is rotating **THE WRONG WAY!!!*** \n", "\n", "Why?\n", "\n", "FFMPEG uses the images passed by the list in the order passed.\n", "\n", "Look above the order is with **growing** centerLongitude\n", "\n", "Let's fix this by passing the image sequence in **reversed** order" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "name = \"rot_animation_correct_order.mp4\"\n", "\n", "# Create animation into file\n", "x.ffmpeg(name,sorted(glob.glob(\"pngs/rotate_*png\"))[::-1], rate=15)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Animating Globe and Data\n", "[Back to Top](#top)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create pngs\n", "clt = f(\"clt\",longitude=(0,361))\n", "for i,centerLongitude in enumerate(range(0,361,4)):\n", " polar.centerlongitude = centerLongitude\n", " x.clear()\n", " x.plot(clt[i],iso)\n", " x.png(\"pngs/all_%s.png\" % str(centerLongitude).zfill(6))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "name = \"rot_animation_all.mp4\"\n", "\n", "# Create animation into file\n", "x.ffmpeg(name,sorted(glob.glob(\"pngs/all_*png\"))[::-1], rate=10)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": true, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }