{ "metadata": { "name": "", "signature": "sha256:ce776f6f756468340b871321dc49e2e27376713ae180fa5e9e05d2ca2054e65b" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Map Your Google Location History in 3D" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By Sukhbinder and inspired from [this](http://nbviewer.ipython.org/github/chrisalbon/code_py/blob/master/matplotlib_map_your_google_data.ipynb)" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Step 1: Download your Google Location History" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Google makes this process very easy. Go here to [download your location history data](https://www.google.com/settings/takeout) and unzip it." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "\n", "Step 2: Run this script" ] }, { "cell_type": "code", "collapsed": false, "input": [ "fname=r\"/Users/Sukhbinder/Downloads/Takeout/Location History/LocationHistory.json\"" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "# Import pandas\n", "import pandas as pd\n", "import numpy as np\n", "\n", "# Import matplotlib and Basemap\n", "import matplotlib.pyplot as plt\n", "#from mpl_toolkits.basemap import Basemap\n", "\n", "# Set iPython to display visualization inline\n", "%matplotlib inline" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 11 }, { "cell_type": "markdown", "metadata": {}, "source": [ "##Read in the location history json\n", "\n", "Simply change the string to point to where you unzipped your location history json file\n", "\n", " " ] }, { "cell_type": "code", "collapsed": false, "input": [ "raw = pd.read_json(fname) #pd.io.json.read_json(fname)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 12 }, { "cell_type": "markdown", "metadata": {}, "source": [ "##Let's take a look at some of the data\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "raw.tail(5)" ], "language": "python", "metadata": {}, "outputs": [ { "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", "
locationssomePointsTruncated
86241 {u'latitudeE7': 129896780, u'accuracy': 100, u... True
86242 {u'latitudeE7': 129896780, u'accuracy': 100, u... True
86243 {u'latitudeE7': 129896780, u'accuracy': 100, u... True
86244 {u'latitudeE7': 129896780, u'accuracy': 100, u... True
86245 {u'latitudeE7': 129947642, u'accuracy': 798, u... True
\n", "

5 rows \u00d7 2 columns

\n", "
" ], "metadata": {}, "output_type": "pyout", "prompt_number": 13, "text": [ " locations somePointsTruncated\n", "86241 {u'latitudeE7': 129896780, u'accuracy': 100, u... True\n", "86242 {u'latitudeE7': 129896780, u'accuracy': 100, u... True\n", "86243 {u'latitudeE7': 129896780, u'accuracy': 100, u... True\n", "86244 {u'latitudeE7': 129896780, u'accuracy': 100, u... True\n", "86245 {u'latitudeE7': 129947642, u'accuracy': 798, u... True\n", "\n", "[5 rows x 2 columns]" ] } ], "prompt_number": 13 }, { "cell_type": "markdown", "metadata": {}, "source": [ "##Expand the locations object into it's own dataframe\n", " " ] }, { "cell_type": "code", "collapsed": false, "input": [ "df = raw['locations'].apply(pd.Series)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ "##Take a peak at the data again\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "df.tail(5)" ], "language": "python", "metadata": {}, "outputs": [ { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
accuracyactivitysaltitudeheadinglatitudeE7longitudeE7timestampMsvelocity
86241 100 NaNNaNNaN 129896780 776881100 1304096571529NaN
86242 100 NaNNaNNaN 129896780 776881100 1304096556086NaN
86243 100 NaNNaNNaN 129896780 776881100 1304096541775NaN
86244 100 NaNNaNNaN 129896780 776881100 1304096526596NaN
86245 798 NaNNaNNaN 129947642 776835705 1297274751020NaN
\n", "

5 rows \u00d7 8 columns

\n", "
" ], "metadata": {}, "output_type": "pyout", "prompt_number": 15, "text": [ " accuracy activitys altitude heading latitudeE7 longitudeE7 \\\n", "86241 100 NaN NaN NaN 129896780 776881100 \n", "86242 100 NaN NaN NaN 129896780 776881100 \n", "86243 100 NaN NaN NaN 129896780 776881100 \n", "86244 100 NaN NaN NaN 129896780 776881100 \n", "86245 798 NaN NaN NaN 129947642 776835705 \n", "\n", " timestampMs velocity \n", "86241 1304096571529 NaN \n", "86242 1304096556086 NaN \n", "86243 1304096541775 NaN \n", "86244 1304096526596 NaN \n", "86245 1297274751020 NaN \n", "\n", "[5 rows x 8 columns]" ] } ], "prompt_number": 15 }, { "cell_type": "markdown", "metadata": {}, "source": [ "##Wrangle the data and look at the data" ] }, { "cell_type": "code", "collapsed": false, "input": [ "df['latitude'] = df['latitudeE7'] * 0.0000001\n", "\n", "# Create a list from the longitude column, multiplied by -E7\n", "df['longitude'] = df['longitudeE7'] * 0.0000001" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 16 }, { "cell_type": "code", "collapsed": false, "input": [ "df.tail(5)" ], "language": "python", "metadata": {}, "outputs": [ { "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", " \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", "
accuracyactivitysaltitudeheadinglatitudeE7longitudeE7timestampMsvelocitylatitudelongitude
86241 100 NaNNaNNaN 129896780 776881100 1304096571529NaN 12.989678 77.688110
86242 100 NaNNaNNaN 129896780 776881100 1304096556086NaN 12.989678 77.688110
86243 100 NaNNaNNaN 129896780 776881100 1304096541775NaN 12.989678 77.688110
86244 100 NaNNaNNaN 129896780 776881100 1304096526596NaN 12.989678 77.688110
86245 798 NaNNaNNaN 129947642 776835705 1297274751020NaN 12.994764 77.683571
\n", "

5 rows \u00d7 10 columns

\n", "
" ], "metadata": {}, "output_type": "pyout", "prompt_number": 17, "text": [ " accuracy activitys altitude heading latitudeE7 longitudeE7 \\\n", "86241 100 NaN NaN NaN 129896780 776881100 \n", "86242 100 NaN NaN NaN 129896780 776881100 \n", "86243 100 NaN NaN NaN 129896780 776881100 \n", "86244 100 NaN NaN NaN 129896780 776881100 \n", "86245 798 NaN NaN NaN 129947642 776835705 \n", "\n", " timestampMs velocity latitude longitude \n", "86241 1304096571529 NaN 12.989678 77.688110 \n", "86242 1304096556086 NaN 12.989678 77.688110 \n", "86243 1304096541775 NaN 12.989678 77.688110 \n", "86244 1304096526596 NaN 12.989678 77.688110 \n", "86245 1297274751020 NaN 12.994764 77.683571 \n", "\n", "[5 rows x 10 columns]" ] } ], "prompt_number": 17 }, { "cell_type": "code", "collapsed": false, "input": [ "df.head(5)" ], "language": "python", "metadata": {}, "outputs": [ { "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", " \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", "
accuracyactivitysaltitudeheadinglatitudeE7longitudeE7timestampMsvelocitylatitudelongitude
0 165 NaN 901-1 129919563 777150227 1404655403815-1 12.991956 77.715023
1 165 NaN 900-1 129919981 777145832 1404634564910-1 12.991998 77.714583
2 165 NaN 900-1 129919532 777150546 1404630560819-1 12.991953 77.715055
3 165 NaN 900-1 129920234 777143167 1404626864671-1 12.992023 77.714317
4 1414 NaN 900-1 129954840 776779268 1404626799099-1 12.995484 77.677927
\n", "

5 rows \u00d7 10 columns

\n", "
" ], "metadata": {}, "output_type": "pyout", "prompt_number": 18, "text": [ " accuracy activitys altitude heading latitudeE7 longitudeE7 \\\n", "0 165 NaN 901 -1 129919563 777150227 \n", "1 165 NaN 900 -1 129919981 777145832 \n", "2 165 NaN 900 -1 129919532 777150546 \n", "3 165 NaN 900 -1 129920234 777143167 \n", "4 1414 NaN 900 -1 129954840 776779268 \n", "\n", " timestampMs velocity latitude longitude \n", "0 1404655403815 -1 12.991956 77.715023 \n", "1 1404634564910 -1 12.991998 77.714583 \n", "2 1404630560819 -1 12.991953 77.715055 \n", "3 1404626864671 -1 12.992023 77.714317 \n", "4 1404626799099 -1 12.995484 77.677927 \n", "\n", "[5 rows x 10 columns]" ] } ], "prompt_number": 18 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Get x,y,z coordinated for the sphere using the latitude and longitude\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "lat=df['longitude'].values*np.pi/180.0 \n", "long=df['latitude'].values*np.pi/180.0\n", "x = np.cos(long)*np.cos(lat)\n", "y = np.cos(long)*np.sin(lat)\n", "z = np.sin(long)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 19 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Map the data using vtk\n", "\n", "#####Create two actors one of the earth and other of the 3D location points" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import vtk\n", " \n", "class VtkPointCloud:\n", " def __init__(self, zMin=-10.0, zMax=10.0, maxNumPoints=1e6):\n", " self.maxNumPoints = maxNumPoints\n", " self.vtkPolyData = vtk.vtkPolyData()\n", " self.clearPoints()\n", " mapper = vtk.vtkPolyDataMapper()\n", " mapper.SetInput(self.vtkPolyData)\n", " mapper.SetScalarRange(zMin, zMax)\n", " mapper.SetScalarVisibility(1)\n", " self.vtkActor = vtk.vtkActor()\n", " self.vtkActor.SetMapper(mapper)\n", " self.vtkActor.GetProperty().SetPointSize(4)\n", " self.vtkActor.GetProperty().SetColor(1,0,0)\n", " \n", " def addPoint(self, point):\n", " if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:\n", " pointId = self.vtkPoints.InsertNextPoint(point[:])\n", " self.vtkDepth.InsertNextValue(point[2])\n", " self.vtkCells.InsertNextCell(1)\n", " self.vtkCells.InsertCellPoint(pointId)\n", " self.vtkCells.Modified()\n", " self.vtkPoints.Modified()\n", " self.vtkDepth.Modified()\n", " \n", " def clearPoints(self):\n", " self.vtkPoints = vtk.vtkPoints()\n", " self.vtkCells = vtk.vtkCellArray()\n", " self.vtkDepth = vtk.vtkDoubleArray()\n", " self.vtkDepth.SetName('DepthArray')\n", " self.vtkPolyData.SetPoints(self.vtkPoints)\n", " self.vtkPolyData.SetVerts(self.vtkCells)\n", " self.vtkPolyData.GetPointData().SetScalars(self.vtkDepth)\n", " self.vtkPolyData.GetPointData().SetActiveScalars('DepthArray')\n", " \n", "\n", "cldpnts= VtkPointCloud()\n", "for i in range(len(x)):\n", " cldpnts.addPoint([x[i],y[i],z[i]])\n", " \n", " \n", " \n", "ren = vtk.vtkRenderer()\n", "renWin = vtk.vtkRenderWindow()\n", "renWin.AddRenderer(ren)\n", "WIDTH=640\n", "HEIGHT=480\n", "renWin.SetSize(WIDTH,HEIGHT)\n", " \n", "# create a renderwindowinteractor\n", "iren = vtk.vtkRenderWindowInteractor()\n", "iren.SetRenderWindow(renWin)\n", "ren.SetBackground(0.48, 0.48, 0.48)\n", " \n", "# create source\n", "source = vtk.vtkEarthSource()\n", "source.SetOnRatio = 2\n", " \n", " \n", "# mapper for original earth\n", "coneMapper1 = vtk.vtkPolyDataMapper()\n", "if vtk.VTK_MAJOR_VERSION <= 5:\n", " coneMapper1.SetInput(source.GetOutput())\n", "else:\n", " coneMapper1.SetInputConnection(source.GetOutputPort())\n", " \n", " \n", "# actor for earth\n", "actor1 = vtk.vtkActor()\n", "actor1.SetMapper(coneMapper1)\n", "actor1.GetProperty().SetColor(0, 0, 0) # (R,G,B)\n", "actor1.GetProperty().SetSpecular = 0.45\n", "actor1.GetProperty().SetSpecularPower = 5\n", "actor1.SetBackfaceCulling = True\n", " \n", "# add points actor on the earth\n", "# assign actor to the renderer\n", "ren.AddActor(cldpnts.vtkActor)\n", "ren.AddActor(actor1)\n", " \n", "# enable user interface interactor\n", "iren.Initialize()\n", "renWin.Render()\n", "iren.Start()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 20 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### For continuty, Map the data using basemap" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Create a figure of size (i.e. pretty big)\n", "fig = plt.figure(figsize=(20,10))\n", "\n", "# Create a map, using the Gall\u2013Peters projection, \n", "map = Basemap(projection='gall', \n", " # with low resolution,\n", " resolution = 'l', \n", " # And threshold 100000\n", " area_thresh = 100000.0,\n", " # Centered at 0,0 (i.e null island)\n", " lat_0=0, lon_0=0)\n", "\n", "# Draw the coastlines on the map\n", "map.drawcoastlines()\n", "\n", "# Draw country borders on the map\n", "map.drawcountries()\n", "\n", "# Fill the land with grey\n", "map.fillcontinents(color = '#888888')\n", "\n", "# Draw the map boundaries\n", "map.drawmapboundary(fill_color='#f4f4f4')\n", "\n", "# Define our longitude and latitude points\n", "x,y = map(df['longitude'].values, df['latitude'].values)\n", "\n", "# Plot them using round markers of size 6\n", "map.plot(x, y, 'ro', markersize=6)\n", " \n", "# Show the map\n", "plt.show()" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'Basemap' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;31m# Create a map, using the Gall\u2013Peters projection,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m map = Basemap(projection='gall', \n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0;31m# with low resolution,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mresolution\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'l'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mNameError\u001b[0m: name 'Basemap' is not defined" ] }, { "metadata": {}, "output_type": "display_data", "text": [ "" ] } ], "prompt_number": 11 } ], "metadata": {} } ] }