{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "**Table of Contents**\n", "\n", "
\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Demo based on these:\n", "\n", "- https://plot.ly/python/graph-data-from-mysql-database-in-python/\n", "- http://moderndata.plot.ly/graph-data-from-mysql-database-in-python/\n", "- http://moderndata.plot.ly/widgets-in-ipython-notebook-and-plotly/\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# First download the world database\n", "http://dev.mysql.com/doc/index-other.html" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "--2016-09-22 13:08:55-- http://downloads.mysql.com/docs/world.sql.gz\n", "Resolving downloads.mysql.com (downloads.mysql.com)... 137.254.60.14\n", "Connecting to downloads.mysql.com (downloads.mysql.com)|137.254.60.14|:80... connected.\n", "HTTP request sent, awaiting response... 200 OK\n", "Length: 92094 (90K) [application/x-gzip]\n", "Saving to: ‘world.sql.gz’\n", "\n", " 0K .......... .......... .......... .......... .......... 55% 205K 0s\n", " 50K .......... .......... .......... ......... 100% 490K=0.3s\n", "\n", "2016-09-22 13:08:56 (277 KB/s) - ‘world.sql.gz’ saved [92094/92094]\n", "\n" ] } ], "source": [ "%%sh\n", "wget http://downloads.mysql.com/docs/world.sql.gz" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 takanori takanori 90K Sep 22 12:27 world.sql.gz\n" ] } ], "source": [ "%%sh\n", "# aboute 90KB\n", "ls -lh world*" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ "%%sh\n", "# unzip\n", "gunzip world.sql.gz" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 takanori takanori 389K Sep 22 12:27 world.sql\r\n" ] } ], "source": [ "# now we have world.sql file\n", "ls -lh world*" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-- MySQL dump 10.13 Distrib 5.1.51, for pc-linux-gnu (i686)\n", "--\n", "-- Host: 127.0.0.1 Database: world\n", "-- ------------------------------------------------------\n", "-- Server version 5.1.51-debug-log\n", "\n", "/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;\n", "/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;\n", "/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;\n", "/*!40101 SET NAMES latin1 */;\n", "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n", "/*!40103 SET TIME_ZONE='+00:00' */;\n", "/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n", "/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n", "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n", "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n", "\n", "DROP SCHEMA IF EXISTS world;\n", "CREATE SCHEMA world;\n", "USE world;\n", "SET AUTOCOMMIT=0;\n", "\n", "--\n", "-- Table structure for table `city`\n", "--\n", "\n", "DROP TABLE IF EXISTS `city`;\n", "/*!40101 SET @saved_cs_client = @@character_set_client */;\n", "/*!40101 SET character_set_client = utf8 */;\n", "CREATE TABLE `city` (\n" ] } ], "source": [ "%%sh\n", "head -30 world.sql" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Install database in mysql\n", "https://dev.mysql.com/doc/world-setup/en/world-setup-installation.html\n", "\n", "```sql\n", "$ mysql -u root -p\n", "mysql> source world.sql;\n", "mysql> show databases;\n", "+--------------------+\n", "| Database |\n", "+--------------------+\n", "| information_schema |\n", "| TUTORIALS |\n", "| mysql |\n", "| performance_schema |\n", "| tutorial |\n", "| world |\n", "+--------------------+\n", "6 rows in set (0.01 sec)\n", "```" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "show databases;\n", "system ls\n", "\\#\n", "source world.sql;\n" ] } ], "source": [ "%%sh\n", "# sourced the sql file to create database\n", "\n", "tail -4 ~/.mysql_history" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## For this demo, create user with all privileges to this `world` database" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```bash\n", "mysql> CREATE USER 'tak'@'localhost' IDENTIFIED BY 'nori';\n", "Query OK, 0 rows affected (0.16 sec)\n", "\n", "mysql> USE world;\n", "Reading table information for completion of table and column names\n", "You can turn off this feature to get a quicker startup with -A\n", "\n", "Database changed\n", "mysql> GRANT ALL ON world.* TO 'tak'@'localhost';\n", "Query OK, 0 rows affected (0.02 sec)\n", "```\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Alright, we are in business. Let's analyze this database!" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import MySQLdb\n", "import pandas as pd\n", "import plotly.plotly as py\n", "from plotly.graph_objs import *" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# use credential i create above to connect to the world-database\n", "conn = MySQLdb.connect(host=\"localhost\", user=\"tak\", passwd=\"nori\", db=\"world\")\n", "cursor = conn.cursor()" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(('city',), ('country',), ('countrylanguage',))" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# show names of the table in the database\n", "cursor.execute('show tables')\n", "cursor.fetchall()" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(('Code', 'char(3)', 'NO', 'PRI', '', ''),\n", " ('Name', 'char(52)', 'NO', '', '', ''),\n", " ('Continent',\n", " \"enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America')\",\n", " 'NO',\n", " '',\n", " 'Asia',\n", " ''),\n", " ('Region', 'char(26)', 'NO', '', '', ''),\n", " ('SurfaceArea', 'float(10,2)', 'NO', '', '0.00', ''),\n", " ('IndepYear', 'smallint(6)', 'YES', '', None, ''),\n", " ('Population', 'int(11)', 'NO', '', '0', ''),\n", " ('LifeExpectancy', 'float(3,1)', 'YES', '', None, ''),\n", " ('GNP', 'float(10,2)', 'YES', '', None, ''),\n", " ('GNPOld', 'float(10,2)', 'YES', '', None, ''),\n", " ('LocalName', 'char(45)', 'NO', '', '', ''),\n", " ('GovernmentForm', 'char(45)', 'NO', '', '', ''),\n", " ('HeadOfState', 'char(60)', 'YES', '', None, ''),\n", " ('Capital', 'int(11)', 'YES', '', None, ''),\n", " ('Code2', 'char(2)', 'NO', '', '', ''))" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ugly format, but print schema for the country table\n", "cursor.execute('describe country')\n", "cursor.fetchall()" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "collapsed": false }, "outputs": [ { "ename": "ProgrammingError", "evalue": "(1146, \"Table 'world.Country' doesn't exist\")", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mProgrammingError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mcursor\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexecute\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'select Name, Continent, Population, LifeExpectancy, GNP from Country'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;32m/home/takanori/.local/lib/python2.7/site-packages/MySQLdb/cursors.pyc\u001b[0m in \u001b[0;36mexecute\u001b[1;34m(self, query, args)\u001b[0m\n\u001b[0;32m 203\u001b[0m \u001b[1;32mdel\u001b[0m \u001b[0mtb\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 204\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmessages\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mexc\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 205\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0merrorhandler\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mexc\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 206\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_executed\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mquery\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 207\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_defer_warnings\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_warning_check\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m/home/takanori/.local/lib/python2.7/site-packages/MySQLdb/connections.pyc\u001b[0m in \u001b[0;36mdefaulterrorhandler\u001b[1;34m(***failed resolving arguments***)\u001b[0m\n\u001b[0;32m 34\u001b[0m \u001b[1;32mdel\u001b[0m \u001b[0mcursor\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 35\u001b[0m \u001b[1;32mdel\u001b[0m \u001b[0mconnection\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 36\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0merrorclass\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0merrorvalue\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 37\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 38\u001b[0m \u001b[0mre_numeric_part\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mre\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcompile\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34mr\"^(\\d+)\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mProgrammingError\u001b[0m: (1146, \"Table 'world.Country' doesn't exist\")" ] } ], "source": [ "cursor.execute('select Name, Continent, Population, LifeExpectancy, GNP from Country')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**HMMM, mysqldb appears to be case-sensitive in python**\n", "- so extra attention is required, i suppose" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(('city',), ('country',), ('countrylanguage',))" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# above threw an exception cuz *Country* needed to be in lower case...\n", "# see below\n", "cursor.execute('show tables')\n", "cursor.fetchall()" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "239L" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# this should work\n", "cursor.execute('select Name, Continent, Population, LifeExpectancy, GNP from country')" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "collapsed": true }, "outputs": [], "source": [ "rows = cursor.fetchall()" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "239" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(rows)" ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "\"(('Aruba', 'North America', 103000L, 78.4, 828.0), ('Afghanistan', 'Asia', 22720000L, 45.9, 5976.0), ('Angola', 'Africa', 12878000L, 38.3, 6648.0), ('Anguilla', 'North America', 8000L, 76.1, 63.2), ('Albania', 'Europe', 3401200L, 71.6, 3205.0), ('Andorra', 'Europe', 78000L, 83.5, 1630.0), ('Netherla\"" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "str(rows)[0:300]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## create pandas DataFrame" ] }, { "cell_type": "code", "execution_count": 56, "metadata": { "collapsed": false }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/takanori/anaconda2/lib/python2.7/site-packages/ipykernel/__main__.py:3: FutureWarning:\n", "\n", "sort(columns=....) is deprecated, use sort_values(by=.....)\n", "\n" ] } ], "source": [ "df = pd.DataFrame( [[ij for ij in i] for i in rows] )\n", "df.rename(columns={0: 'Name', 1: 'Continent', 2: 'Population', 3: 'LifeExpectancy', 4:'GNP'}, inplace=True);\n", "df = df.sort(['LifeExpectancy'], ascending=[1]);" ] }, { "cell_type": "code", "execution_count": 57, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
NameContinentPopulationLifeExpectancyGNP
237ZambiaAfrica916900037.23377.0
143MozambiqueAfrica1968000037.52891.0
148MalawiAfrica1092500037.61687.0
238ZimbabweAfrica1166900037.85951.0
2AngolaAfrica1287800038.36648.0
\n", "
" ], "text/plain": [ " Name Continent Population LifeExpectancy GNP\n", "237 Zambia Africa 9169000 37.2 3377.0\n", "143 Mozambique Africa 19680000 37.5 2891.0\n", "148 Malawi Africa 10925000 37.6 1687.0\n", "238 Zimbabwe Africa 11669000 37.8 5951.0\n", "2 Angola Africa 12878000 38.3 6648.0" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## A bit of data cleansing\n", "- above, some country names cause serialization errors in early versions of Plotly's Python client. \n", "- The code block below takes care of this." ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "collapsed": false }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/takanori/anaconda2/lib/python2.7/site-packages/ipykernel/__main__.py:4: SettingWithCopyWarning:\n", "\n", "\n", "A value is trying to be set on a copy of a slice from a DataFrame\n", "\n", "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", "\n", "/home/takanori/anaconda2/lib/python2.7/site-packages/ipykernel/__main__.py:6: SettingWithCopyWarning:\n", "\n", "\n", "A value is trying to be set on a copy of a slice from a DataFrame\n", "\n", "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n", "\n" ] } ], "source": [ "country_names = df['Name']\n", "for i in range(len(country_names)):\n", " try:\n", " country_names[i] = str(country_names[i]).decode('utf-8')\n", " except:\n", " country_names[i] = 'Country name decode error'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Plot interactive scatterplots!" ] }, { "cell_type": "code", "execution_count": 60, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "trace1 = Scatter(\n", " x=df['GNP'],\n", " y=df['LifeExpectancy'],\n", " text=country_names,\n", " mode='markers'\n", ")\n", "layout = Layout(\n", " title='Life expectancy vs GNP from MySQL world database',\n", " xaxis=XAxis( type='log', title='GNP' ),\n", " yaxis=YAxis( title='Life expectancy' ),\n", ")\n", "data = Data([trace1])\n", "fig = Figure(data=data, layout=layout)\n", "py.iplot(fig, filename='plotly-demo/world GNP vs life expectancy')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## prettify the above :)" ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# (!) Set 'size' values to be proportional to rendered area,\n", "# instead of diameter. This makes the range of bubble sizes smaller\n", "sizemode='area' \n", "\n", "# (!) Set a reference for 'size' values (i.e. a population-to-pixel scaling).\n", "# Here the max bubble area will be on the order of 100 pixels\n", "sizeref=df['Population'].max()/1e2**2\n", "\n", "colors = {\n", " 'Asia':\"rgb(255,65,54)\", \n", " 'Europe':\"rgb(133,20,75)\",\n", " 'Africa':\"rgb(0,116,217)\",\n", " 'North America':\"rgb(255,133,27)\",\n", " 'South America':\"rgb(23,190,207)\",\n", " 'Antarctica':\"rgb(61,153,112)\",\n", " 'Oceania':\"rgb(255,220,0)\",\n", "}\n", "\n", "# Define a hover-text generating function (returns a list of strings)\n", "def make_text(X):\n", " return 'Country: %s\\\n", "
Life Expectancy: %s years\\\n", "
Population: %s million'\\\n", " % (X['Name'], X['LifeExpectancy'], X['Population']/1e6) \n", "\n", "# Define a trace-generating function (returns a Scatter object)\n", "def make_trace(X, continent, sizes, color): \n", " return Scatter(\n", " x=X['GNP'], # GDP on the x-xaxis\n", " y=X['LifeExpectancy'], # life Exp on th y-axis\n", " name=continent, # label continent names on hover\n", " mode='markers', # (!) point markers only on this plot\n", " text=X.apply(make_text, axis=1).tolist(),\n", " marker= Marker(\n", " color=color, # marker color\n", " size=sizes, # (!) marker sizes (sizes is a list)\n", " sizeref=sizeref, # link sizeref\n", " sizemode=sizemode, # link sizemode\n", " opacity=0.6, # (!) partly transparent markers\n", " line= Line(width=3,color=\"white\") # marker borders\n", " )\n", " )\n", "\n", "# Initialize data object \n", "data = Data()\n", "\n", "# Group data frame by continent sub-dataframe (named X), \n", "# make one trace object per continent and append to data object\n", "for continent, X in df.groupby('Continent'):\n", " \n", " sizes = X['Population'] # get population array \n", " color = colors[continent] # get bubble color\n", " \n", " data.append(\n", " make_trace(X, continent, sizes, color) # append trace to data object\n", " ) \n", "\n", " # Set plot and axis titles\n", "title = \"Life expectancy vs GNP from MySQL world database (bubble chart)\"\n", "x_title = \"Gross National Product\"\n", "y_title = \"Life Expectancy [in years]\"\n", "\n", "# Define a dictionary of axis style options\n", "axis_style = dict( \n", " type='log',\n", " zeroline=False, # remove thick zero line\n", " gridcolor='#FFFFFF', # white grid lines\n", " ticks='outside', # draw ticks outside axes \n", " ticklen=8, # tick length\n", " tickwidth=1.5 # and width\n", ")\n", "\n", "# Make layout object\n", "layout = Layout(\n", " title=title, # set plot title\n", " plot_bgcolor='#EFECEA', # set plot color to grey\n", " hovermode=\"closest\",\n", " xaxis=XAxis(\n", " axis_style, # add axis style dictionary\n", " title=x_title, # x-axis title\n", " range=[2.0,7.2], # log of min and max x limits\n", " ),\n", " yaxis=YAxis(\n", " axis_style, # add axis style dictionary\n", " title=y_title, # y-axis title\n", " )\n", ")\n", "\n", "# Make Figure object\n", "fig = Figure(data=data, layout=layout)\n", "\n", "# (@) Send to Plotly and show in notebook\n", "py.iplot(fig, filename='plotly-demo/s3_life-gdp')" ] } ], "metadata": { "kernelspec": { "display_name": "Python [Root]", "language": "python", "name": "Python [Root]" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.12" } }, "nbformat": 4, "nbformat_minor": 0 }