Skip to content

Instantly share code, notes, and snippets.

@kashyapchhatbar
Created September 16, 2016 14:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kashyapchhatbar/2ac630443098fe3cd243cb6d3e6ebe01 to your computer and use it in GitHub Desktop.
Save kashyapchhatbar/2ac630443098fe3cd243cb6d3e6ebe01 to your computer and use it in GitHub Desktop.
An attempt to recreate global temperature plot from Earth Observatory, NASA in Python
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting global temparature rise (again) in Python\n",
"\n",
"Earth Observatory recently showcased the visualization of warmest August in 136 years [here](http://earthobservatory.nasa.gov/blogs/earthmatters/2016/09/12/heres-how-the-warmest-august-in-136-years-looks-in-chart-form/)\n",
"\n",
"This is an attempt to replicate the animation showcasing the warmest August that we have had yet. Also, I have shamelessly ripped off [@BioMickWatson](https://twitter.com/BioMickWatson) from his [blog post](http://www.opiniomics.org/how-to-produce-an-animated-gif-of-rise-in-global-temperature-in-r/) so as to minimize URL hunting. This is very similar but implemented in Python as compared to R.\n",
"\n",
"Here's the [gif](http://imgur.com/a/JOclo)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"#Import all the good stuff\n",
"import pandas as pd\n",
"import seaborn as sns\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.animation as animation\n",
"\n",
"#Use seaborn to set matplotlib theme\n",
"sns.set_context(\"paper\", font_scale=2)\n",
"sns.set_style(\"ticks\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"#Download data\n",
"data = pd.read_csv(\"http://data.giss.nasa.gov/gistemp/tabledata_v3/GLB.Ts.csv\", \n",
" skiprows=1, usecols=range(0, 13), index_col=0)\n",
"\n",
"#Get months' list\n",
"months = list(data.columns)\n",
"\n",
"#Replace months' names to int for plotting purposes\n",
"data.columns = list(range(1,13))\n",
"\n",
"#Replace data from Sep '2016 \n",
"data.replace(\"***\", 0, inplace=True)\n",
"\n",
"#Remove rows with any NaNs if found\n",
"data.dropna(inplace=True)\n",
"\n",
"#Convert values to float\n",
"data = data.copy().astype(float)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"#Anomalies recommended to add to the values\n",
"anomalies = pd.read_csv(\"http://data.giss.nasa.gov/gistemp/faq/merra2_seas_anom.txt\", \n",
" skiprows=3, sep=r\"\\s+\", usecols=[0,2], index_col=0)\n",
"anomalies = list(anomalies.seas_anom.values)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>1</th>\n",
" <th>2</th>\n",
" <th>3</th>\n",
" <th>4</th>\n",
" <th>5</th>\n",
" <th>6</th>\n",
" <th>7</th>\n",
" <th>8</th>\n",
" <th>9</th>\n",
" <th>10</th>\n",
" <th>11</th>\n",
" <th>12</th>\n",
" </tr>\n",
" <tr>\n",
" <th>Year</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>1880</th>\n",
" <td>-0.84</td>\n",
" <td>-0.42</td>\n",
" <td>-0.50</td>\n",
" <td>-0.68</td>\n",
" <td>-0.38</td>\n",
" <td>-0.51</td>\n",
" <td>-0.50</td>\n",
" <td>0.05</td>\n",
" <td>-0.52</td>\n",
" <td>-0.70</td>\n",
" <td>-0.54</td>\n",
" <td>-0.56</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1881</th>\n",
" <td>-0.80</td>\n",
" <td>-0.65</td>\n",
" <td>-0.39</td>\n",
" <td>-0.29</td>\n",
" <td>-0.06</td>\n",
" <td>-1.15</td>\n",
" <td>-0.56</td>\n",
" <td>-0.28</td>\n",
" <td>-0.38</td>\n",
" <td>-0.52</td>\n",
" <td>-0.60</td>\n",
" <td>-0.18</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1882</th>\n",
" <td>0.08</td>\n",
" <td>-0.15</td>\n",
" <td>-0.11</td>\n",
" <td>-0.60</td>\n",
" <td>-0.40</td>\n",
" <td>-1.05</td>\n",
" <td>-0.73</td>\n",
" <td>-0.14</td>\n",
" <td>-0.11</td>\n",
" <td>-0.35</td>\n",
" <td>-0.42</td>\n",
" <td>-0.70</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1883</th>\n",
" <td>-0.70</td>\n",
" <td>-0.97</td>\n",
" <td>-0.48</td>\n",
" <td>-0.33</td>\n",
" <td>-0.37</td>\n",
" <td>0.42</td>\n",
" <td>-0.04</td>\n",
" <td>-0.18</td>\n",
" <td>-0.49</td>\n",
" <td>-0.60</td>\n",
" <td>-0.72</td>\n",
" <td>-0.41</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1884</th>\n",
" <td>-0.62</td>\n",
" <td>-0.37</td>\n",
" <td>-0.41</td>\n",
" <td>-0.96</td>\n",
" <td>-1.22</td>\n",
" <td>-0.84</td>\n",
" <td>-0.87</td>\n",
" <td>0.13</td>\n",
" <td>-0.39</td>\n",
" <td>-0.81</td>\n",
" <td>-0.85</td>\n",
" <td>-1.01</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" 1 2 3 4 5 6 7 8 9 10 11 12\n",
"Year \n",
"1880 -0.84 -0.42 -0.50 -0.68 -0.38 -0.51 -0.50 0.05 -0.52 -0.70 -0.54 -0.56\n",
"1881 -0.80 -0.65 -0.39 -0.29 -0.06 -1.15 -0.56 -0.28 -0.38 -0.52 -0.60 -0.18\n",
"1882 0.08 -0.15 -0.11 -0.60 -0.40 -1.05 -0.73 -0.14 -0.11 -0.35 -0.42 -0.70\n",
"1883 -0.70 -0.97 -0.48 -0.33 -0.37 0.42 -0.04 -0.18 -0.49 -0.60 -0.72 -0.41\n",
"1884 -0.62 -0.37 -0.41 -0.96 -1.22 -0.84 -0.87 0.13 -0.39 -0.81 -0.85 -1.01"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#This is how the data looks\n",
"data.head()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"#Initialize the figure\n",
"fig = plt.figure(figsize=(10, 6))\n",
"ax = plt.axes(xlim=(.5, 12.5), ylim=(-3, 3.5))\n",
"\n",
"#Generate the list of colors\n",
"colors = sns.color_palette(\"PuRd\", len(data))\n",
"\n",
"#Create line objects which are the less pronounced\n",
"lines = []\n",
"for i in range(len(data)):\n",
" lobj = ax.plot([], [], lw=.75, marker=\"o\", ms=2, color=colors[i], alpha=0.25)[0]\n",
" lines.append(lobj)\n",
"\n",
"#Main line object which will be pronounced\n",
"mainline = ax.plot([], [], lw=3, marker=\"o\", ms=8, color=colors[0])[0]\n",
"\n",
"#X-axis data\n",
"x = list(range(1, 13))\n",
"\n",
"#Text representing the year (initially blank)\n",
"text = ax.text(6.75, 0.5, '', fontsize=24)\n",
"\n",
"#Figure aesthetics, labels, titles etc.\n",
"ax.set_xticks(range(1, 13))\n",
"ax.set_xticklabels(months)\n",
"ax.set_title(\"Temperature Anomaly (\" r\"$\\mathrm{^\\circ}$\" \"C)\\n\"\n",
" \"(Difference from 1980-2015 annual mean)\")\n",
"ax.yaxis.grid(lw=1, linestyle=':', color='grey')\n",
"sns.despine()\n",
"\n",
"#Animate function\n",
"def animate(i):\n",
" if i[1] == 2016:\n",
" mainline.set_data(x[:8], i[2]) \n",
" mainline.set_color(colors[-1])\n",
" text.set_text(\"2016\") \n",
" else:\n",
" mainline.set_data(x, i[2])\n",
" mainline.set_color(colors[i[0]])\n",
" for lnum, line in enumerate(lines): \n",
" if lnum == i[0]:\n",
" line.set_data(x, i[2])\n",
" text.set_text(str(i[1]))\n",
" return tuple(lines) + (text,) + (mainline,)\n",
"\n",
"# Init only required for blitting to give a clean slate.\n",
"def init():\n",
" for line in lines:\n",
" line.set_data([],[])\n",
" return lines\n",
"\n",
"#Convert dataframe to a list for easy iteration\n",
"rows = []\n",
"for ii, (i, j) in enumerate(data.iterrows()):\n",
" row = [l for k,l in j.items()]\n",
" for m, n in enumerate(row): \n",
" row[m] += anomalies[m] \n",
" if i == 2016:\n",
" #Don't know how to pause in matplotlib.animation so just shamelessly iterating the same thing\n",
" #over and over to let it stay\n",
" for jjj in range(100):\n",
" rows.append([ii, i, row[:8]])\n",
" else:\n",
" rows.append([ii, i, row])\n",
"\n",
"#The main animation function\n",
"ani = animation.FuncAnimation(fig, animate, rows, init_func=init, interval=100, repeat=False, blit=True)\n",
"\n",
"#Need this if you want to save a mp4\n",
"Writer = animation.writers['ffmpeg']\n",
"writer = Writer(fps=10, metadata=dict(artist='Kashyap Chhatbar'), bitrate=1800)\n",
"\n",
"#Always good to have if you are making changes to labels and stuff\n",
"plt.tight_layout()\n",
"\n",
"#Uncomment below to save a gif\n",
"#ani.save('global_temperature.gif', writer='imagemagick', fps=10, dpi=100)\n",
"\n",
"#Uncomment below to save a mp4 (recommended!!)\n",
"#ani.save('global_temperature.mp4', writer=writer, dpi=300)\n",
"\n",
"#Uncomment below to view it locally\n",
"#plt.show()"
]
}
],
"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.5.2"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment