In [1]:
import holoviews as hv
import geoviews as gv
import param, paramnb, parambokeh
import pandas as pd
import dask.dataframe as dd
import datashader as ds

from colorcet import cm
from bokeh.models import WMTSTileSource
from holoviews.operation.datashader import datashade
from holoviews.operation import decimate
from holoviews.streams import RangeXY, PlotSize


D:\tools\dev\python\Anaconda3-4.2.0\lib\site-packages\seaborn\apionly.py:6: UserWarning: As seaborn no longer sets a default style on import, the seaborn.apionly module is deprecated. It will be removed in a future version.
  warnings.warn(msg, UserWarning)
D:\tools\dev\python\Anaconda3-4.2.0\lib\site-packages\odo\backends\pandas.py:94: FutureWarning: pandas.tslib is deprecated and will be removed in a future version.
You can access NaTType as type(pandas.NaT)
  @convert.register((pd.Timestamp, pd.Timedelta), (pd.tslib.NaTType, type(None)))

In [2]:
hv.extension('bokeh')



In [3]:
%%time
df = dd.read_parquet('../data/crimes-2017.snappy.parq/').persist()
print(len(df))


146711
Wall time: 2.71 s

In [4]:
df.head()


Out[4]:
Date Block PrimaryType Description LocationDescription Arrest Domestic Latitude Longitude
0 2017-07-22 04:39:00 082XX S EMERALD AVE HOMICIDE FIRST DEGREE MURDER STREET False False NaN NaN
1 2017-07-25 22:32:00 078XX S CARPENTER ST HOMICIDE FIRST DEGREE MURDER STREET False False 41.751545 -87.650128
2 2017-07-25 06:25:00 003XX N LOREL AVE HOMICIDE FIRST DEGREE MURDER ALLEY False False 41.886330 -87.758956
3 2017-02-15 11:20:00 003XX S CANAL ST HOMICIDE FIRST DEGREE MURDER STREET True False NaN NaN
4 2017-07-14 09:00:00 014XX W 112TH PL BURGLARY FORCIBLE ENTRY VACANT LOT/LAND False False NaN NaN

In [5]:
# drop records with NaN coordinates
df = df.dropna(how='any', subset=['Latitude', 'Longitude']) 
df.head()


Out[5]:
Date Block PrimaryType Description LocationDescription Arrest Domestic Latitude Longitude
1 2017-07-25 22:32:00 078XX S CARPENTER ST HOMICIDE FIRST DEGREE MURDER STREET False False 41.751545 -87.650128
2 2017-07-25 06:25:00 003XX N LOREL AVE HOMICIDE FIRST DEGREE MURDER ALLEY False False 41.886330 -87.758956
59 2017-07-25 11:15:00 070XX S YALE AVE MOTOR VEHICLE THEFT AUTOMOBILE STREET False False 41.766408 -87.631027
60 2017-07-25 00:01:00 081XX S CARPENTER ST THEFT $500 AND UNDER STREET False False 41.746417 -87.649988
61 2017-07-25 22:31:00 027XX N LINCOLN AVE CRIMINAL DAMAGE TO VEHICLE PARKING LOT/GARAGE(NON.RESID.) False False 41.931287 -87.656934

In [6]:
# plot coordinates
points = hv.Points(df, kdims=['Longitude', 'Latitude'], vdims=['PrimaryType'], label='Map')
decimate(points) # limit to 1K points max


Out[6]:

In [7]:
# create map tiles
tiles = gv.WMTS(WMTSTileSource(url='https://server.arcgisonline.com/ArcGIS/rest/services/'
                                   'World_Imagery/MapServer/tile/{Z}/{Y}/{X}.jpg'))

In [8]:
options = dict(width=400,height=400,xaxis=None,yaxis=None,bgcolor='black',show_grid=False)

In [ ]:
#TODO
gv_dataset = gv.Dataset(df, kdims=['Longitude', 'Latitude'], vdims=['PrimaryType'])
tiles * datashade(gv_dataset, 
                  x_sampling=10, y_sampling=10, 
                  cmap=cm['fire'], 
                  element_type=gv.Image, aggregator=ds.count_cat('PrimaryType')).opts(plot=options)

In [ ]:
crime_points = datashade(points, 
                         x_sampling=1, y_sampling=1, 
                         cmap=cm['fire'], element_type=gv.Image).opts(plot=options)
crime_points

In [ ]: