Skip to content

Instantly share code, notes, and snippets.

@simeonf
Last active August 29, 2015 14:26
Show Gist options
  • Save simeonf/052aee61c1e1481e6311 to your computer and use it in GitHub Desktop.
Save simeonf/052aee61c1e1481e6311 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Sample map of Countries with vincent\n",
"\n",
"This is actually pretty straightforward - once you figure out the naming issues to makes vincent look at your data.\n",
"\n",
"First we need to import `vincent`, `pandas`, and `json` + call the `vincent.initialize_notebook()` to load the javascript needed to render our map in the browser."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"\n",
" <script>\n",
" \n",
" function vct_load_lib(url, callback){\n",
" if(typeof d3 !== 'undefined' &&\n",
" url === 'http://d3js.org/d3.v3.min.js'){\n",
" callback()\n",
" }\n",
" var s = document.createElement('script');\n",
" s.src = url;\n",
" s.async = true;\n",
" s.onreadystatechange = s.onload = callback;\n",
" s.onerror = function(){\n",
" console.warn(\"failed to load library \" + url);\n",
" };\n",
" document.getElementsByTagName(\"head\")[0].appendChild(s);\n",
" };\n",
" var vincent_event = new CustomEvent(\n",
" \"vincent_libs_loaded\",\n",
" {bubbles: true, cancelable: true}\n",
" );\n",
" \n",
" function load_all_libs(){\n",
" console.log('Loading Vincent libs...')\n",
" vct_load_lib('http://d3js.org/d3.v3.min.js', function(){\n",
" vct_load_lib('http://d3js.org/d3.geo.projection.v0.min.js', function(){\n",
" vct_load_lib('http://wrobstory.github.io/d3-cloud/d3.layout.cloud.js', function(){\n",
" vct_load_lib('http://wrobstory.github.io/vega/vega.v1.3.3.js', function(){\n",
" window.dispatchEvent(vincent_event);\n",
" });\n",
" });\n",
" });\n",
" });\n",
" };\n",
" if(typeof define === \"function\" && define.amd){\n",
" if (window['d3'] === undefined ||\n",
" window['topojson'] === undefined){\n",
" require.config(\n",
" {paths: {\n",
" d3: 'http://d3js.org/d3.v3.min',\n",
" topojson: 'http://d3js.org/topojson.v1.min'\n",
" }\n",
" }\n",
" );\n",
" require([\"d3\"], function(d3){\n",
" console.log('Loading Vincent from require.js...')\n",
" window.d3 = d3;\n",
" require([\"topojson\"], function(topojson){\n",
" window.topojson = topojson;\n",
" load_all_libs();\n",
" });\n",
" });\n",
" } else {\n",
" load_all_libs();\n",
" };\n",
" }else{\n",
" console.log('Require.js not found, loading manually...')\n",
" load_all_libs();\n",
" };\n",
"\n",
" </script>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import json\n",
"\n",
"import vincent\n",
"import pandas as pd\n",
"\n",
"vincent.initialize_notebook()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now imagine we have some data reflecting the level of interest in a product in various countries. We'll represent that here as `list` of `dict`."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"countries = [{\"id\": 'USA', \"Interest\": 55}, \n",
" {\"id\": 'MEX', \"Interest\": 20},\n",
" {'id': 'CAN', 'Interest': 19}\n",
" ]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To do data binding with vincent we need that data to be in a `pandas.Dataframe`"
]
},
{
"cell_type": "code",
"execution_count": 3,
"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>Interest</th>\n",
" <th>id</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>55</td>\n",
" <td>USA</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>20</td>\n",
" <td>MEX</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>19</td>\n",
" <td>CAN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Interest id\n",
"0 55 USA\n",
"1 20 MEX\n",
"2 19 CAN"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data_df = pd.DataFrame(countries)\n",
"data_df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can build a geometry layer for the map. Several explanation:\n",
"\n",
"- `geo_data` is a list of data sources. The `name` field in each data source is the primary key. (We'll call our data source *countries*)\n",
"- The url must be an http-accessible url where topo-json data can be loaded. Just drop the files from https://github.com/wrobstory/vincent_map_data in the same directory as your notebook and Jupyter will serve them up. Because we rendering country data we're loading the `world-countries.topo.json` file. (Note: I'm direct-linking to github so I can put up a public gist. Don't do this otherwise!)\n",
"- Last - the feature is a topo.json feature name. Fortunately it's a key in the json file and for countries we use `world-countries`"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"geo_data = [{'name': 'countries',\n",
" 'url': 'https://raw.githubusercontent.com/wrobstory/vincent_map_data/master/world-countries.topo.json',\n",
" 'feature': 'world-countries'}]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And finally we can draw the map. \n",
"\n",
"The `Map` constructor needs data (that's our `Dataframe`), `geo_data` (our list of map geometry layers).\n",
"\n",
"It also takes some parameters to figure out how to relate the data to the geometry data. \n",
"\n",
"- `data_bind` tells it what column to use as a range in our data and we point it to the `Interest` column of our dataframe.\n",
"- `data_key` tells it what column in our dataframe to use to relate to the geometry data.\n",
"- `map_key` is a composite key: `key` part of the dict tells what geometry layer to look in (we only have one but you have to specify) and the `value` part of the dict tells you what field in the geometries object to look at in order to join a piece of data to a particular object in this geometry.\n",
"\n",
"If you open up the `world-countries.topo.json` you'd find the country objects look like:\n",
"\n",
" \"objects\": {\n",
" \"world-countries\": {\n",
" \"Geometries\": [\n",
" {\n",
" ... geo fields first, then some identifying info ...\n",
" \"id\": \"AFG\",\n",
" \"properties\": {\n",
" \"name\": \"Afghanistan\"\n",
" },\n",
" },\n",
"\n",
"We can bind to the `id` but if we had names we could specify `properties.name` as the field to join against."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div id=\"vis70283322ba144e1c8364df1cdd1e8dba\"></div>\n",
"<script>\n",
" ( function() {\n",
" var _do_plot = function() {\n",
" if (typeof vg === 'undefined') {\n",
" window.addEventListener('vincent_libs_loaded', _do_plot)\n",
" return;\n",
" }\n",
" vg.parse.spec({\"axes\": [], \"data\": [{\"name\": \"table\", \"values\": [{\"x\": \"USA\", \"y\": 55}, {\"x\": \"MEX\", \"y\": 20}, {\"x\": \"CAN\", \"y\": 19}]}, {\"format\": {\"feature\": \"world-countries\", \"type\": \"topojson\"}, \"name\": \"countries\", \"transform\": [{\"as\": \"value\", \"default\": \"noval\", \"key\": \"data.id\", \"type\": \"zip\", \"with\": \"table\", \"withKey\": \"data.x\"}, {\"test\": \"d.path!='noval' && d.value!='noval'\", \"type\": \"filter\"}, {\"projection\": \"winkel3\", \"scale\": 500, \"translate\": [480, 250], \"type\": \"geopath\", \"value\": \"data\"}], \"url\": \"https://raw.githubusercontent.com/wrobstory/vincent_map_data/master/world-countries.topo.json\"}], \"height\": 500, \"legends\": [], \"marks\": [{\"from\": {\"data\": \"countries\"}, \"properties\": {\"enter\": {\"path\": {\"field\": \"path\"}, \"stroke\": {\"value\": \"#000000\"}, \"strokeOpacity\": {\"value\": 0.2}}, \"update\": {\"fill\": {\"field\": \"value.data.y\", \"scale\": \"color\"}}}, \"type\": \"path\"}], \"padding\": \"auto\", \"scales\": [{\"domain\": [19, 51.49999999999999], \"name\": \"color\", \"range\": [\"#f7fcf0\", \"#e0f3db\", \"#ccebc5\", \"#a8ddb5\", \"#7bccc4\", \"#4eb3d3\", \"#2b8cbe\", \"#0868ac\", \"#084081\"], \"type\": \"quantize\"}], \"width\": 960}, function(chart) {\n",
" chart({el: \"#vis70283322ba144e1c8364df1cdd1e8dba\"}).update();\n",
" });\n",
" };\n",
" _do_plot();\n",
" })();\n",
"</script>\n",
"<style>.vega canvas {width: 100%;}</style>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"vis = vincent.Map(data=data_df, \n",
" geo_data=geo_data,\n",
" data_bind='Interest', \n",
" data_key='id',\n",
" map_key={'countries': 'id'},\n",
" scale=500,\n",
" )\n",
"vis.marks[0].properties.enter.stroke_opacity = vincent.ValueRef(value=0.2)\n",
"vis.display()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"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.10"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment