Plotly's Python API User Guide

Section 5: Heatmaps, Contours and 2D Histograms

Welcome to Plotly's Python API User Guide.

Links to the other sections are on the User Guide's homepage
The Github repository is available here

Quickstart (make a simple heatmap of 6 pts):

>>> import plotly.plotly as py
>>> from plotly.graph_objs import *
>>> # auto sign-in with credentials or use py.sign_in()
>>> trace1 = Heatmap(
        z=[[1, 2, 3], [4, 5, 6]]
    )
>>> data = Data([trace1])
>>> py.plot(data)


Check which version is installed on your machine and please upgrade if needed.

In [1]:
# (*) Import plotly package
import plotly

# Check plolty version (if not latest, please upgrade)
plotly.__version__
Out[1]:
'1.6.6'

See the User Guide's homepage for more info on installation and upgrading.


In this section, we analyze bike counter data taken from the open data website of the city of Montreal using heatmaps, contour maps and 2D histograms. Along side learning about the Heatmap, Contour, Histogram2d and Histogram2dContour, we explore:

We first import a few modules and sign in to Plotly using our credentials file:

In [2]:
# (*) To communicate with Plotly's server, sign in with credentials file
import plotly.plotly as py  

# (*) Useful Python/Plotly tools
import plotly.tools as tls   

# (*) Graph objects to piece together plots
from plotly.graph_objs import *

import numpy as np  # (*) numpy for math functions and arrays

If you are not familiar with credentials files, refer to the User Guide's homepage.

The data is stored in a file named mtl-bike-2013.csv. For readers looking to run this notebook, the data file is in this section's Github folder. Here is the original download link from the open data site of the city of Montreal.

As in section 3 on Bubble Charts, we use the pandas module in this section to help us manipulate the data. You can download the module using pip. Simply run:

$ pip install pandas

For more info on this module, we recommand Hernán Rojas' Pandas tutorial.

As a small heads up, this section features quite a bit of computations. That said, computations and plot styling commands are separated into different code cells; readers only looking for Plotly styling ideas are invited to skip the computation code cells.

So, first read the data and copy it into a dataframe object:

In [3]:
# (*) Pandas for data manipulation
import pandas as pd 

# Read csv file and define dataframe object (df for dataframe)
df_all = pd.read_csv('mtl-bike-2013.csv')

df_all.head()  # show dataframe header
Out[3]:
Date Unnamed: 1 Berri1 CSC Mais1 Mais2 Parc PierDup Rachel1 Totem_Laurier
0 01/01/2013 00:00 0 0 1 0 6 0 1 0
1 02/01/2013 00:00 69 0 13 0 18 0 2 0
2 03/01/2013 00:00 69 2 21 6 22 1 0 0
3 04/01/2013 00:00 80 0 22 4 16 0 125 0
4 05/01/2013 00:00 52 4 19 3 12 0 97 0

5 rows × 10 columns

Unfortunately, this is not the cleanest looking data file in the world.

The first column contains the dates, then we have an unnamed column and the 8 following columns represent the bike counters sites around town. The values below are the total number of cyclists that passed by the counters each day.

The sites' names are not written in full in the column header. So, with the help of the project's web page, make a list of sites' full names:

In [4]:
# Sites' full names
sites = [
    'Berri/<br>de Maisonneuve', 'Côte-Ste-Catherine<br>(parc Beaubien)',
    'de Maisonneuve/<br>Berri', 'de Maisonneuve/<br>Peel', 'du Parc/<br>Duluth',
    'Pierre-Dupuy<br>(Habitat 67)', 'Rachel/<br>Marquette', 'Laurier<br>(métro)'
]

Where we used the <br> HTML tags to break line inside some of the sites' names for better-looking tick labels.

Moreover, the data set does not include every day of the year 2013:

In [5]:
df_all.tail()  # show dataframe tail
Out[5]:
Date Unnamed: 1 Berri1 CSC Mais1 Mais2 Parc PierDup Rachel1 Totem_Laurier
256 14/09/2013 00:00 2488 1494 1706 2911 979 1075 3277 2456
257 15/09/2013 00:00 2243 1749 1417 2933 1804 1459 3623 2527
258 16/09/2013 00:00 4206 2466 2799 5485 3272 855 4307 3012
259 17/09/2013 00:00 5506 3153 3563 6626 3882 1485 5332 3745
260 18/09/2013 00:00 1564 3330 1154 1803 4074 1759 1511 3921

5 rows × 10 columns

In [6]:
df_all.shape  # df_all does not contain 365 days
Out[6]:
(261, 10)

To have a more homogenous data set, trim the data frame to have 8 full months of data, from January 1st to August 31st:

In [7]:
# List of booleans corresponding to days in Jan to Aug
i_JanAug = ['/09/' not in date for date in df_all['Date']]

# Trim the few September days in df_all
df_JanAug = df_all[i_JanAug]

df_JanAug.tail() # show trimmed dataframe tail
Out[7]:
Date Unnamed: 1 Berri1 CSC Mais1 Mais2 Parc PierDup Rachel1 Totem_Laurier
238 27/08/2013 00:00 5566 2805 3662 6355 3373 2153 5888 3738
239 28/08/2013 00:00 5560 2759 3717 6323 3355 1881 5673 3886
240 29/08/2013 00:00 5806 2766 3902 6713 3466 1941 6044 3995
241 30/08/2013 00:00 4381 2209 3019 5409 2724 1632 5109 3106
242 31/08/2013 00:00 2682 1018 1701 3178 1385 1494 3593 2303

5 rows × 10 columns

In [8]:
df_JanAug.shape 

# rows: 243 days
# cols: 1 date column, 1 empty column and 8 sites
Out[8]:
(243, 10)

5.1 Heatmaps of cyclist traffic for each day, week, month

First, check the total number of cyclists that passed by all the counter sites from January 1st to August 31th.

To do so, we could plot the data as a time series where the x-axis represents all the dates in the sample and the y-axis the total number of cyclists that passed by all counter sites. But, here with a sample of 243 dates, this would make a pretty big or not-that-precise plot.

Instead, let's plot the data using a Plotly heatmap where the color scheme represents the total number of cyclists, the x-axis the month (January to August) and the y-axis the day of the month (1 to 31).

So, start by calling help on the heatmap graph object:

In [9]:
help(Heatmap)  # call help()!
Help on class Heatmap in module plotly.graph_objs.graph_objs:

class Heatmap(PlotlyTrace)
 |  A dictionary-like object for representing a heatmap trace in plotly.
 |  
 |  Example:
 |  
 |      >>> z = [[0, 1, 0, 1, 0], [1, 0, 1, 0, 1], [0, 1, 0, 1, 0]]
 |      >>> y = ['a', 'b', 'c']
 |      >>> x = [1, 2, 3, 4, 5]py.plot([Contour(z=z, x=x, y=y)])
 |  
 |  Online example:
 |  
 |      https://plot.ly/python/heatmaps/
 |  
 |  Quick method reference:
 |  
 |      Heatmap.update(changes)
 |      Heatmap.strip_style()
 |      Heatmap.get_data()
 |      Heatmap.to_graph_objs()
 |      Heatmap.validate()
 |      Heatmap.to_string()
 |      Heatmap.force_clean()
 |  
 |  Valid keys:
 |  
 |      z [required=True] (value=list of lists or 2d numpy array of numbers)
 |      (streamable):
 |          Sets the data that describes the heatmap mapping. Say the dimensions
 |          of the list of lists or 2d numpy array linked to 'z' has n rows and
 |          m columns then the resulting heatmap will show n partitions along
 |          the y-axis and m partitions along the x-axis. Therefore, the i-th
 |          row/ j-th column cell in the list of lists or 2d numpy array linked
 |          to 'z' is mapped to the i-th partition of the y-axis (starting from
 |          the bottom of the plot) and the j-th partition of the x-axis
 |          (starting from the left of the plot).
 |  
 |      x [required=False] (value=list or 1d numpy array of numbers, strings,
 |      datetimes) (streamable):
 |          Sets the horizontal coordinates referring to the columns of the list
 |          of lists or 2d numpy array linked to 'z'. If the 'z' is a list or 1d
 |          numpy array of strings, then the x-labels are spaced evenly. If the
 |          dimensions of the list of lists or 2d numpy array linked to 'z' are
 |          (n x m), the length of the 'x' array should equal m.
 |  
 |      y [required=False] (value=list or 1d numpy array of numbers, strings,
 |      datetimes) (streamable):
 |          Sets the vertical coordinates referring to the rows of the list of
 |          lists or 2d numpy array linked to 'z'. If strings, the y-labels are
 |          spaced evenly. If the dimensions of the list of lists or 2d numpy
 |          array linked to 'z' are (n x m), the length of the 'y' array should
 |          equal n.
 |  
 |      name [required=False] (value=a string):
 |          The label associated with this trace. This name will appear in the
 |          legend, on hover and in the column header in the online spreadsheet.
 |  
 |      zauto [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the default values of 'zmax' and 'zmax' can be
 |          overwritten.
 |  
 |      zmin [required=False] (value=number):
 |          Sets the minimum 'z' data value to be resolved by the color scale.
 |          Its default value is the minimum of the 'z' data values. This value
 |          will be used as the minimum in the color scale normalization. For
 |          more info see 'colorscale'.
 |  
 |      zmax [required=False] (value=number):
 |          Sets the maximum 'z' data value to be resolved by the color scale.
 |          Its default value is the maximum of the 'z' data values. This value
 |          will be used as the maximum in the color scale normalization. For
 |          more info see 'colorscale'.
 |  
 |      colorscale [required=False] (value=list or 1d numpy array of value-color
 |      pairs | 'Greys' | 'Greens' | 'Bluered' | 'Hot' | 'Picnic' | 'Portland' |
 |      'Jet' | 'RdBu' | 'Blackbody' | 'Earth' | 'Electric' | 'YIOrRd' |
 |      'YIGnBu'):
 |          Sets and/or defines the color scale for this trace. The string
 |          values are pre-defined color scales. For custom color scales, define
 |          a list or 1d numpy array of value-color pairs where, the first
 |          element of the pair corresponds to a normalized value of z from 0-1,
 |          i.e. (z-zmin)/ (zmax-zmin), and the second element of pair
 |          corresponds to a color. Use with 'zauto', 'zmin' and 'zmax to fine-
 |          tune the map from 'z' to rendered colors.
 |  
 |          Examples:
 |              'Greys' | [[0, 'rgb(0,0,0)'], [0.5, 'rgb(65, 182, 196)'], [1,
 |              'rgb(255,255,255)']]
 |  
 |      reversescale [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the color scale will be reversed.
 |  
 |      showscale [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the color scale associated with this mapping
 |          will be shown alongside the figure.
 |  
 |      colorbar [required=False] (value=ColorBar object | dictionary-like
 |      object):
 |          Links a dictionary-like object defining the parameters of the color
 |          bar associated with this trace (including its title, length and
 |          width).
 |  
 |          For more, run `help(plotly.graph_objs.ColorBar)`
 |  
 |      zsmooth [required=False] (value=False | 'best' | 'fast'):
 |          Choose between algorithms ('best' or 'fast') to smooth data linked
 |          to 'z'. The default value is False corresponding to no smoothing.
 |  
 |      opacity [required=False] (value=number: x in [0, 1]):
 |          Sets the opacity, or transparency, of the entire object, also known
 |          as the alpha channel of colors. If the object's color is given in
 |          terms of 'rgba' color model, 'opacity' is redundant.
 |  
 |      xaxis [required=False] (value='x1' | 'x2' | 'x3' | etc.):
 |          This key determines which x-axis the x-coordinates of this trace
 |          will reference in the figure.  Values 'x1' and 'x' reference to
 |          'xaxis' in 'layout', 'x2' references to 'xaxis2' in 'layout', and so
 |          on. Note that 'x1' will always refer to 'xaxis' or 'xaxis1' in
 |          'layout', they are the same.
 |  
 |      yaxis [required=False] (value='y1' | 'y2' | 'y3' | etc.):
 |          This key determines which y-axis the y-coordinates of this trace
 |          will reference in the figure.  Values 'y1' and 'y' reference to
 |          'yaxis' in 'layout', 'y2' references to 'yaxis2' in 'layout', and so
 |          on. Note that 'y1' will always refer to 'yaxis' or 'yaxis1' in
 |          'layout', they are the same.
 |  
 |      showlegend [required=False] (value=a boolean: True | False):
 |          Toggle whether or not this trace will be labeled in the legend.
 |  
 |      stream [required=False] (value=Stream object | dictionary-like object):
 |          Links a dictionary-like object that initializes this trace as a
 |          writable-stream, for use with the streaming API.
 |  
 |          For more, run `help(plotly.graph_objs.Stream)`
 |  
 |      visible [required=False] (value=a boolean: True | False):
 |          Toggles whether or not this object will be visible on the rendered
 |          figure.
 |  
 |      x0 [required=False] (value=number):
 |          The location of the first coordinate of the x-axis. Use with 'dx' an
 |          alternative to an 'x' list or 1d numpy array. Has no effect if 'x'
 |          is set.
 |  
 |      dx [required=False] (value=number):
 |          Spacing between x-axis coordinates. Use with 'x0' an alternative to
 |          an 'x' list or 1d numpy array. Has no effect if 'x' is set.
 |  
 |      y0 [required=False] (value=number):
 |          The location of the first coordinate of the y-axis. Use with 'dy' an
 |          alternative to an 'y' list or 1d numpy array. Has no effect if 'y'
 |          is set.
 |  
 |      dy [required=False] (value=number):
 |          Spacing between y-axis coordinates. Use with 'y0' an alternative to
 |          an 'y' list or 1d numpy array. Has no effect if 'y' is set.
 |  
 |      xtype [required=False] (value='array' | 'scaled'):
 |          If set to 'scaled' and 'x' is linked to a list or 1d numpy array,
 |          then the horizontal labels are scaled to a list or 1d numpy array of
 |          integers of unit step starting from 0.
 |  
 |      ytype [required=False] (value='array' | 'scaled'):
 |          If set to 'scaled' and 'y' is linked to a list or 1d numpy array,
 |          then the vertical labels are scaled to a list or 1d numpy array of
 |          integers of unit step starting from 0.
 |  
 |      type [required=False] (value='heatmap'):
 |          Plotly identifier for this data's trace type.
 |  
 |  Method resolution order:
 |      Heatmap
 |      PlotlyTrace
 |      PlotlyDict
 |      __builtin__.dict
 |      __builtin__.object
 |  
 |  Methods inherited from PlotlyTrace:
 |  
 |  __init__(self, *args, **kwargs)
 |  
 |  to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80)
 |      Returns a formatted string showing graph_obj constructors.
 |      
 |      Example:
 |      
 |          print(obj.to_string())
 |      
 |      Keyword arguments:
 |      level (default = 0) -- set number of indentations to start with
 |      indent (default = 4) -- set indentation amount
 |      eol (default = '\n') -- set end of line character(s)
 |      pretty (default = True) -- curtail long list output with a '...'
 |      max_chars (default = 80) -- set max characters per line
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from PlotlyDict:
 |  
 |  __setitem__(self, key, value)
 |  
 |  force_clean(self, caller=True)
 |      Attempts to convert to graph_objs and call force_clean() on values.
 |      
 |      Calling force_clean() on a PlotlyDict will ensure that the object is
 |      valid and may be sent to plotly. This process will also remove any
 |      entries that end up with a length == 0.
 |      
 |      Careful! This will delete any invalid entries *silently*.
 |  
 |  get_data(self)
 |      Returns the JSON for the plot with non-data elements stripped.
 |  
 |  get_ordered(self, caller=True)
 |  
 |  strip_style(self)
 |      Strip style from the current representation.
 |      
 |      All PlotlyDicts and PlotlyLists are guaranteed to survive the
 |      stripping process, though they made be left empty. This is allowable.
 |      
 |      Keys that will be stripped in this process are tagged with
 |      `'type': 'style'` in graph_objs_meta.json.
 |      
 |      This process first attempts to convert nested collections from dicts
 |      or lists to subclasses of PlotlyList/PlotlyDict. This process forces
 |      a validation, which may throw exceptions.
 |      
 |      Then, each of these objects call `strip_style` on themselves and so
 |      on, recursively until the entire structure has been validated and
 |      stripped.
 |  
 |  to_graph_objs(self, caller=True)
 |      Walk obj, convert dicts and lists to plotly graph objs.
 |      
 |      For each key in the object, if it corresponds to a special key that
 |      should be associated with a graph object, the ordinary dict or list
 |      will be reinitialized as a special PlotlyDict or PlotlyList of the
 |      appropriate `kind`.
 |  
 |  update(self, dict1=None, **dict2)
 |      Update current dict with dict1 and then dict2.
 |      
 |      This recursively updates the structure of the original dictionary-like
 |      object with the new entries in the second and third objects. This
 |      allows users to update with large, nested structures.
 |      
 |      Note, because the dict2 packs up all the keyword arguments, you can
 |      specify the changes as a list of keyword agruments.
 |      
 |      Examples:
 |      # update with dict
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      update_dict = dict(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj.update(update_dict)
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      # update with list of keyword arguments
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      obj.update(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      This 'fully' supports duck-typing in that the call signature is
 |      identical, however this differs slightly from the normal update
 |      method provided by Python's dictionaries.
 |  
 |  validate(self, caller=True)
 |      Recursively check the validity of the keys in a PlotlyDict.
 |      
 |      The valid keys constitute the entries in each object
 |      dictionary in graph_objs_meta.json
 |      
 |      The validation process first requires that all nested collections be
 |      converted to the appropriate subclass of PlotlyDict/PlotlyList. Then,
 |      each of these objects call `validate` and so on, recursively,
 |      until the entire object has been validated.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from PlotlyDict:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from __builtin__.dict:
 |  
 |  __cmp__(...)
 |      x.__cmp__(y) <==> cmp(x,y)
 |  
 |  __contains__(...)
 |      D.__contains__(k) -> True if D has a key k, else False
 |  
 |  __delitem__(...)
 |      x.__delitem__(y) <==> del x[y]
 |  
 |  __eq__(...)
 |      x.__eq__(y) <==> x==y
 |  
 |  __ge__(...)
 |      x.__ge__(y) <==> x>=y
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __getitem__(...)
 |      x.__getitem__(y) <==> x[y]
 |  
 |  __gt__(...)
 |      x.__gt__(y) <==> x>y
 |  
 |  __iter__(...)
 |      x.__iter__() <==> iter(x)
 |  
 |  __le__(...)
 |      x.__le__(y) <==> x<=y
 |  
 |  __len__(...)
 |      x.__len__() <==> len(x)
 |  
 |  __lt__(...)
 |      x.__lt__(y) <==> x<y
 |  
 |  __ne__(...)
 |      x.__ne__(y) <==> x!=y
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __sizeof__(...)
 |      D.__sizeof__() -> size of D in memory, in bytes
 |  
 |  clear(...)
 |      D.clear() -> None.  Remove all items from D.
 |  
 |  copy(...)
 |      D.copy() -> a shallow copy of D
 |  
 |  fromkeys(...)
 |      dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
 |      v defaults to None.
 |  
 |  get(...)
 |      D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
 |  
 |  has_key(...)
 |      D.has_key(k) -> True if D has a key k, else False
 |  
 |  items(...)
 |      D.items() -> list of D's (key, value) pairs, as 2-tuples
 |  
 |  iteritems(...)
 |      D.iteritems() -> an iterator over the (key, value) items of D
 |  
 |  iterkeys(...)
 |      D.iterkeys() -> an iterator over the keys of D
 |  
 |  itervalues(...)
 |      D.itervalues() -> an iterator over the values of D
 |  
 |  keys(...)
 |      D.keys() -> list of D's keys
 |  
 |  pop(...)
 |      D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
 |      If key is not found, d is returned if given, otherwise KeyError is raised
 |  
 |  popitem(...)
 |      D.popitem() -> (k, v), remove and return some (key, value) pair as a
 |      2-tuple; but raise KeyError if D is empty.
 |  
 |  setdefault(...)
 |      D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
 |  
 |  values(...)
 |      D.values() -> list of D's values
 |  
 |  viewitems(...)
 |      D.viewitems() -> a set-like object providing a view on D's items
 |  
 |  viewkeys(...)
 |      D.viewkeys() -> a set-like object providing a view on D's keys
 |  
 |  viewvalues(...)
 |      D.viewvalues() -> an object providing a view on D's values
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from __builtin__.dict:
 |  
 |  __hash__ = None
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T

Important (2d array dimensions):

2-dimension array sent to Plotly via the 'z' key are plotted on a grid with as many partitions on the y-axis as there are rows in the 2D array and with as many partitions on the x-axis as there are columns in the 2D array. This is the same convention as in matplotlib.

So, if Z is a 2D array, then element Z[i][j] (or Z[i,j] in a numpy array or matrix) is mapped to the ith partition of the y-axis starting from the bottom and the jth partition of the x-axis starting from the left.

Morevover, note that:

List of lists, numpy arrays and numpy matrices are valid values for the 'z' key in Heatmap, Contour, Histogram2d and Histogram2dContour. However, at the moment, values for 'x' and 'y' must both be flat lists, 1d numpy arrays or 1d numpy matrices (map makers, we apologize).

For better readability, as a convention in this section:

  • Variables starting with z (lower case) link to 1D numpy arrays or flat lists, whereas

  • Variables starting with Z (upper case) link to 2D numpy arrays or lists of lists.

So, let's start with summing the daily bike traffic count across all 8 sites in the January-to-August dataframe:

In [10]:
# Row sum of dataframe, get a numpy array
z_JanAug = np.array(df_JanAug.sum(axis=1).tolist())

# The dataframe .sum() method ignores non-number (e.g. the date strings)
# while computing the row (with axis=1) sum.

# The resulting array is 1d, 1 entry per date from Jan to Aug
z_JanAug.shape
Out[10]:
(243,)

Next, we need to convert the 1D array to a 2D array where the columns correspond to the months (January to August) and the rows to the days of the month (1 to 31).

The following code cell is a bit technical; hence, readers only interesting in heatmap plot styling ideas are invited to skip it.

In [11]:
import datetime  # (*) to manipulate date strings

# Define a convertion function 
def dates_to_dayXmonth(df_in, z_in):
    
    dates = df_in['Date'].tolist()  # make list of dates in dataframe

    # (1.1) List of months for all item in dates 
    months = np.array([datetime.datetime.strptime(date,'%d/%m/%Y').strftime('%B') 
                       for date in dates])
    
    # (1.2) Find indices of first day of the months
    _,ind_tmp = np.unique(months,return_index=True) # -> array([90,212,31,0, ...])
    the_months_ind = np.sort(ind_tmp).tolist()      # -> array([0,31,59,90, ...])
    
    # (1*) Use these indices to make list months' name
    the_months = months[the_months_ind]
    N_the_months = len(the_months)        # 8 months, in our case, from Jan to Aug
    
    # (2*) Make list of days of the month 
    N_the_days = 31
    the_days = np.arange(1, N_the_days+1)  # [1, ..., 31]
    
    # (3.1) Make tmp array filled with NaNs
    Z_tmp = np.empty((N_the_days, N_the_months))
    Z_tmp.fill(np.nan)
    
    # (3.2) Make list of indices to fill in Z_tmp month by month
    fill_i = the_months_ind + [len(months)]
    
    # (3.3) Loop through months
    for i in range(N_the_months):
        i0 = fill_i[i]    # get start
        i1 = fill_i[i+1]  #  and end index
        delta_i = i1-i0   # compute their difference (either 30,31 or 28)
        Z_tmp[0:delta_i,i] = z_in[i0:i1]  # fill in rows of 
        
    # (3*) Copy tmp array to output variable
    Z = Z_tmp
    
    return (the_months, the_days, Z)  # output coordinates for our plot
    
# Call function, get coordinates for our plot
the_months_JanAug, the_days, Z_dayXmonth_JanAug = dates_to_dayXmonth(df_JanAug,z_JanAug)

Ok. So, now we have a 1D array of x-axis labels, a 1D array of y-axis labels and a 2D array corresponding to our heatmap.

Before building the Plotly graph object, let's check the dimensions of our arrays:

In [12]:
# Dimensions of array to be used for our next plot
Z_dayXmonth_JanAug.shape, the_months_JanAug.shape, the_days.shape
Out[12]:
((31, 8), (8,), (31,))

The arrays are compatible, as the 2D array has as many rows as the array of y-axis labels and has as many columns as the array of x-axis labels.

Plotly's pre-defined color scales

Next, we select a colormap to be linked to the 'scl' key ('scl' for scale) in Heatmap. In the next subsection we define a custom colormap, but for now let's choose one from Plotly's selection of pre-defined colormaps. These are

and their associated names from left to right:

  1. 'Greys', black to light-grey
  2. 'YIGnBu', white to green to blue to dark-blue
  3. 'Greens', dark-green to light-green
  4. 'YIOrRd', red to orange to gold to tan to white
  5. 'Bluered', bright-blue to purple to bright-red
  6. 'RdBu', blue to red (dim, the default color scale)
  7. 'Picnic', blue to light-blue to white to pink to red
  8. currently only available from the GUI, a slight alternative to 'Jet'
  9. 'Portland', blue to green to yellow to orange to red (dim)
  10. 'Jet', blue to light-blue to green to yellow to orange to red (bright)
  11. 'Hot', tan to yellow to red to black
  12. 'Blackbody', black to red to yellow to white to light-blue
  13. 'Earth', blue to green to yellow to brown to tan to white
  14. 'Electric', black to purple to orange to yellow to tan to white

where the colors listed are mapped from low to high values.

Select 'YIGnBu' for our plot and make a heatmap object:

In [13]:
# Make heatmap object
trace1 = Heatmap(
    z=Z_dayXmonth_JanAug,  # link 2D array
    x=the_months_JanAug,   # link x-axis labels
    y=the_days,            # link y-axis labels
    colorscale='YIGnBu',   # (!) select pre-defined colormap
    reversescale=True      # (!) reverve color ordering
)

# Link it up in a data object
data = Data([trace1])

Experienced Plotly users should note:

Keys 'colorscale' and 'reversescale' now replace (and are equivalent to) the old keys 'scl' and 'reversescl' respectively. We made the change in an effort to have more descriptive key names.

That said, in version 1.2.3 and up, 'scl' and 'reversescl' are converted (and accompanied by a friendly warning) by the Plotly Python package before being sent to Plotly. So, statements like this one:

>>> trace1 = Heatmap(
        z=[[1,2,3], [3,4,5]],
        scl='YIGnBu',
        reversescl=True
    )

still passes validation.

Where we reversed the color ordering with reversescale=True so that, in this case, low values will be plotted in white and high values in dark-blue.

Next, make a layout object:

In [14]:
width = 650   # plot width 
height = 800  # plot height

title = "Fig 5.1a: Bike traffic daily totals \
across 8 Montreal sites in 2013"                # plot's title

layout = Layout(
    title=title,  # set plot's title
    font=Font(
        family="Droid Sans, sans-serif",
    ),
    xaxis=XAxis(
        title='Months in sample',  # x-axis title
        showgrid=False             # remove grid
    ),
    yaxis=YAxis(
        title='Days of the month', # y-axis title
        autorange='reversed',  # (!) reverse tick ordering
        showgrid=False,   # remove grid
        autotick=False,   # custom ticks
        dtick=1           # show 1 tick per day
    ),
    autosize=False,  # custom size
    height=height,   # plot's height in pixels 
    width=width      # plot's width in pixels
)           

In the above, we reverse the order of the y-axis with autorange='reversed' in YAxis so that day 1 appears on the top of the y-axis instead of at the bottom. Alternatively, we could have reversed the order of the y-label array and flipped the 2D array accordingly.

Next, let's add an annotation citing our data source:

In [15]:
# String citing the data source
url='http://donnees.ville.montreal.qc.ca/dataset/velos-comptage' 
text_source = "Source and info: <a href=\"{}\">\
Données ouvertes de la Ville de Montréal</a>".format(url)

# Annotation generating function, 
#  to be used in all plots in this section
def make_anno(x=1, y=1, text=text_source):
    return Annotation(
        text=text,          # annotation text
        showarrow=False,    # remove arrow 
        xref='paper',     # use paper coords
        yref='paper',     #  for both coordinates
        xanchor='right',  # x-coord line up with right end of text 
        yanchor='bottom', # y-coord line up with bottom end of text 
        x=x,              # position's x-coord
        y=y               #   and y-coord
    )
In [16]:
# Add an annotation citing the data source
layout.update(annotations=[make_anno()])

And now package the layout and data object into the figure object and send it to Plotly:

In [17]:
# Make a figure object
fig = Figure(data=data, layout=layout)

# (@) Send figure object to Plotly, show result in notebook
py.iplot(fig, filename='s5_cyclists-per-day', width=width, height=height) 

# adjust output cell with 'width' and 'height'
Out[17]:

Not bad.

These numbers may seem a little high, but note that a particular cyclist can pass by one or multiple counter sites several times during the same day.

Months will less than 31 days have blank cells showing as z=null on hover. They correspond to NaNs (Not-a-Number) values in the 2D array.

A few additional comments on Plotly heatmaps:

  • By default, the color scale and the colorbar extend from the 2D array's minimum value to its maximum value. This behavior can be modified, as we will see in subsection 5.2.

  • The heatmap data can be smoothed for using the 'zsmooth' which has three possible values 'fast', 'best' and False (the default value). Smoothing decreases the color gradient between partitions. See an examples in subsection 5.4.

  • The opacity of the color scale can be modified with the 'opacity' key in Heatmap. A value of 0 correspond to a fully transparent color scale and 1 (the default) a fully opaque.

Now, comparing bike traffic for some day of month (1,2,..,31) across all month may not be the most informative analysis. Why would June 9 and July 9 show the same patterns in bike traffic? That said, comparing day of week totals could be. We expect week day (Monday to Friday) to be higher than weekend totals. Now, let's see by how much.

For subsequent analysis, we will drop the lesser-trafficked months of January, February and March. The corresponding dataframe and ararys are named without suffixes from this point on. So, first we trim the January to August dataframe:

In [18]:
# List of booleans corresponding to days in Apr to Aug
i_AprAug = ['/01/' not in date 
                and '/02/' not in date 
                and '/03/' not in date
                    for date in df_JanAug['Date']]

# Trim the Jan, Feb and Mar days in df_JanAug
df = df_JanAug[i_AprAug]

df.head()  # dataframe now starts on April 1st
Out[18]:
Date Unnamed: 1 Berri1 CSC Mais1 Mais2 Parc PierDup Rachel1 Totem_Laurier
90 01/04/2013 00:00 371 245 276 608 343 66 2315 524
91 02/04/2013 00:00 1055 547 669 1316 840 105 2835 818
92 03/04/2013 00:00 1030 614 719 1470 869 119 3085 947
93 04/04/2013 00:00 1466 855 1027 2022 1243 261 2492 1147
94 05/04/2013 00:00 1098 543 723 1384 761 145 2553 995

5 rows × 10 columns

Perform the same operation as before to get the daily totals for all sites combined:

In [19]:
# Row sum of dataframe, get a numpy array
z = np.array(df.sum(axis=1).tolist())

# The dataframe .sum() method ignores non-number (e.g. the date strings)
# while computing the row (with axis=1) sum.

# The resulting array is 1d, 1 entry per date from Apr to Aug
z.shape
Out[19]:
(153,)

Now, we convert the daily total 1D array into a 2D array of mean traffic for each day of week for each month. Readers only interesting in heatmap plot styling ideas are invited to skip it.

In [20]:
# (*) Here again, we use the datetime module in this code cell

# Define another convertion function
def dates_to_wdayXmonth(df_in, z_in):
    
    dates = df_in['Date'].tolist()  # make list of dates in dataframe
    
    # (1.1) List of months for all item in dates
    months = np.array([datetime.datetime.strptime(i,'%d/%m/%Y').strftime('%B') 
                       for i in dates])
    
    # (1.2) Find indices of first day of the months
    _, ind_tmp = np.unique(months,return_index=True) # -> array([0,122,91,61,30])
    the_months_ind = np.sort(ind_tmp).tolist()       # -> array([0,30,61,91,122])
    
    # (1*) Use these indices to make list months' names
    the_months = months[the_months_ind]
    N_the_months = len(the_months)      # 5 months, in our case, from Apr to Aug
    
    # (2.1) List of week day names for all items in dates
    wdays = np.array([datetime.datetime.strptime(i,'%d/%m/%Y').strftime('%A') 
                       for i in dates])
    
    # (2*) Make list of week day names
    the_wdays = np.array(['Monday', 'Tuesday', 'Wednesday',
                          'Thursday', 'Friday',
                          'Saturday', 'Sunday'])
    N_the_wdays = len(the_wdays)  # 7 days in a week
    
    # (3.1) Init. tmp array 7 days-of-week by 5 months 
    Z_tmp = np.empty((N_the_wdays, N_the_months))
    
    i_month = 0  # init. month counter

    for the_month in the_months:  # loop through the months
    
        # (3.2) Find indices corresp. to the_month, trim wdays and z_in
        ind_month = np.where(months==the_month)
        wdays_month = wdays[ind_month]
        z_month = z_in[ind_month]
    
        i_wday = 0 # init/re-init week day counter
    
        for the_wday in the_wdays:   # loop through the week days
        
            # (3.3) Find indices corresp. to the week day, trim z_month, 
            #       fill in Z_tmp with mean value
            ind_month_wday = np.where(wdays_month==the_wday)    
            Z_tmp[i_wday, i_month] = np.mean(z_month[ind_month_wday])
            
            i_wday += 1  # inc. week day counter
            
        i_month += 1  # inc. month counter
    
    # (3*) Copy tmp array to output variable
    Z = Z_tmp

    return (the_months, the_wdays, Z)  # output coordinates for our next plot
    
# Call conversion function, get coordinates for our next plot
the_months, the_wdays, Z_dayXwday = dates_to_wdayXmonth(df,z)

A quick check on the dimensions:

In [21]:
# Dimensions of array to be used for our next plot
Z_dayXwday.shape, the_months.shape, the_wdays.shape
Out[21]:
((7, 5), (5,), (7,))

Next, make the y-axis labels plural (e.g. Mondays instead of Monday) and normalized the 2D array by its maximum value:

In [22]:
# Make y-axis labels plural 
the_wdays_pl = [the_wday + 's' for the_wday in the_wdays]

# Normalize 2D array by max value
Z_dayXwday_norm = Z_dayXwday / Z_dayXwday.max()

Tweak the colorbar using the colorbar graph object:

In [23]:
help(ColorBar)  # call help!
Help on class ColorBar in module plotly.graph_objs.graph_objs:

class ColorBar(PlotlyDict)
 |  A dictionary-like object object for representing a color bar in plotly.
 |  
 |  Parent key:
 |  
 |      colorbar
 |  
 |  Quick method reference:
 |  
 |      ColorBar.update(changes)
 |      ColorBar.strip_style()
 |      ColorBar.get_data()
 |      ColorBar.to_graph_objs()
 |      ColorBar.validate()
 |      ColorBar.to_string()
 |      ColorBar.force_clean()
 |  
 |  Valid keys:
 |  
 |      title [required=False] (value=a string):
 |          The title of the colorbar.
 |  
 |      titleside [required=False] (value='right' | 'top' | 'bottom'):
 |          Location of colorbar title with respect to the colorbar.
 |  
 |      titlefont [required=False] (value=Font object | dictionary-like object):
 |          Links a dictionary-like object describing the font settings of the
 |          colorbar title.
 |  
 |          For more, run `help(plotly.graph_objs.Font)`
 |  
 |      thickness [required=False] (value=number: x >= 0):
 |          Sets the thickness of the line surrounding the colorbar.
 |  
 |      thicknessmode [required=False] (value=string: 'pixels' | 'fraction' ):
 |          Sets thickness unit mode.
 |  
 |      len [required=False] (value=number: x >= 0):
 |          Sets the length of the colorbar.
 |  
 |      lenmode [required=False] (value=string: 'pixels' | 'fraction' ):
 |          Sets length unit mode.
 |  
 |      autotick [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the colorbar ticks parameters are picked
 |          automatically by Plotly. Once 'autotick' is set to False, the
 |          colorbar ticks parameters can be declared with 'ticks', 'tick0',
 |          'dtick0' and other tick-related key in this colorbar object.
 |  
 |      nticks [required=False] (value=number: x > 0):
 |          Sets the number of colorbar ticks. No need to set 'autoticks' to
 |          False for 'nticks' to apply.
 |  
 |      ticks [required=False] (value='' | 'inside' | 'outside'):
 |          Sets the format of the ticks on this colorbar. For hidden ticks,
 |          link 'ticks' to an empty string.
 |  
 |      showticklabels [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the colorbar ticks will feature tick labels.
 |  
 |      tick0 [required=False] (value=number):
 |          Sets the starting point of the ticks of this colorbar.
 |  
 |      dtick [required=False] (value=number):
 |          Sets the distance between ticks on this colorbar.
 |  
 |      ticklen [required=False] (value=number):
 |          Sets the length of the tick lines on this colorbar.
 |  
 |      tickwidth [required=False] (value=number: x > 0):
 |          Sets the width of the tick lines on this colorbar.
 |  
 |      tickcolor [required=False] (value=a string describing color):
 |          Sets the color of the tick lines on this colorbar.
 |  
 |          Examples:
 |              'green' | 'rgb(0, 255, 0)' | 'rgba(0, 255, 0, 0.3)' |
 |              'hsl(120,100%,50%)' | 'hsla(120,100%,50%,0.3)' | '#434F1D'
 |  
 |      tickangle [required=False] (value=number: x in [-90, 90]):
 |          Sets the angle in degrees of the ticks on this colorbar.
 |  
 |      tickfont [required=False] (value=Font object | dictionary-like object):
 |          Links a dictionary-like object defining the parameters of the ticks'
 |          font.
 |  
 |          For more, run `help(plotly.graph_objs.Font)`
 |  
 |      exponentformat [required=False] (value='none' | 'e' | 'E' | 'power' |
 |      'SI' | 'B'):
 |          Sets how exponents show up. Here's how the number 1000000000 (1
 |          billion) shows up in each. If set to 'none': 1,000,000,000. If set
 |          to 'e': 1e+9. If set to 'E': 1E+9. If set to 'power': 1x10^9 (where
 |          the 9 will appear super-scripted). If set to 'SI': 1G. If set to
 |          'B': 1B (useful when referring to currency).
 |  
 |      showexponent [required=False] (value='all' | 'first' | 'last' | 'none'):
 |          If set to 'all', ALL exponents will be shown appended to their
 |          significands. If set to 'first', the first tick's exponent will be
 |          appended to its significand, however no other exponents will appear
 |          --only the significands. If set to 'last', the last tick's exponent
 |          will be appended to its significand, however no other exponents will
 |          appear--only the significands. If set to 'none', no exponents will
 |          appear, only the significands.
 |  
 |      x [required=False] (value=number):
 |          Sets the 'x' position of this colorbar.
 |  
 |      y [required=False] (value=number):
 |          Sets the 'y' position of this colorbar.
 |  
 |      xanchor [required=False] (value='auto' | 'left' | 'center' | 'right'):
 |          Sets the horizontal position anchor of this colorbar. That is, bind
 |          the position set with the 'x' key to the 'left' or 'center' or
 |          'right' of this colorbar.
 |  
 |      yanchor [required=False] (value='auto' | 'bottom' | 'middle' | 'top'):
 |          Sets the vertical position anchor of this colorbar. That is, bind
 |          the position set with the 'y' key to the 'bottom' or 'middle' or
 |          'top' of this colorbar.
 |  
 |      bgcolor [required=False] (value=a string describing color):
 |          Sets the background (bg) color of this colorbar.
 |  
 |          Examples:
 |              'green' | 'rgb(0, 255, 0)' | 'rgba(0, 255, 0, 0.3)' |
 |              'hsl(120,100%,50%)' | 'hsla(120,100%,50%,0.3)' | '#434F1D'
 |  
 |      outlinecolor [required=False] (value=a string describing color):
 |          The color of the outline surrounding this colorbar.
 |  
 |          Examples:
 |              'green' | 'rgb(0, 255, 0)' | 'rgba(0, 255, 0, 0.3)' |
 |              'hsl(120,100%,50%)' | 'hsla(120,100%,50%,0.3)' | '#434F1D'
 |  
 |      outlinewidth [required=False] (value=number):
 |          Sets the width of the outline surrounding this colorbar.
 |  
 |      bordercolor [required=False] (value=a string describing color):
 |          Sets the color of the enclosing boarder of this colorbar.
 |  
 |          Examples:
 |              'green' | 'rgb(0, 255, 0)' | 'rgba(0, 255, 0, 0.3)' |
 |              'hsl(120,100%,50%)' | 'hsla(120,100%,50%,0.3)' | '#434F1D'
 |  
 |      borderwidth [required=False] (value=number: x >= 0):
 |          Sets the width of the boarder enclosing this colorbar
 |  
 |      xpad [required=False] (value=number: x in [0, 50]):
 |          Sets the amount of space (padding) between the colorbar and the
 |          enclosing boarder in the x-direction.
 |  
 |      ypad [required=False] (value=number: x in [0, 50]):
 |          Sets the amount of space (padding) between the colorbar and the
 |          enclosing boarder in the y-direction.
 |  
 |  Method resolution order:
 |      ColorBar
 |      PlotlyDict
 |      __builtin__.dict
 |      __builtin__.object
 |  
 |  Methods inherited from PlotlyDict:
 |  
 |  __init__(self, *args, **kwargs)
 |  
 |  __setitem__(self, key, value)
 |  
 |  force_clean(self, caller=True)
 |      Attempts to convert to graph_objs and call force_clean() on values.
 |      
 |      Calling force_clean() on a PlotlyDict will ensure that the object is
 |      valid and may be sent to plotly. This process will also remove any
 |      entries that end up with a length == 0.
 |      
 |      Careful! This will delete any invalid entries *silently*.
 |  
 |  get_data(self)
 |      Returns the JSON for the plot with non-data elements stripped.
 |  
 |  get_ordered(self, caller=True)
 |  
 |  strip_style(self)
 |      Strip style from the current representation.
 |      
 |      All PlotlyDicts and PlotlyLists are guaranteed to survive the
 |      stripping process, though they made be left empty. This is allowable.
 |      
 |      Keys that will be stripped in this process are tagged with
 |      `'type': 'style'` in graph_objs_meta.json.
 |      
 |      This process first attempts to convert nested collections from dicts
 |      or lists to subclasses of PlotlyList/PlotlyDict. This process forces
 |      a validation, which may throw exceptions.
 |      
 |      Then, each of these objects call `strip_style` on themselves and so
 |      on, recursively until the entire structure has been validated and
 |      stripped.
 |  
 |  to_graph_objs(self, caller=True)
 |      Walk obj, convert dicts and lists to plotly graph objs.
 |      
 |      For each key in the object, if it corresponds to a special key that
 |      should be associated with a graph object, the ordinary dict or list
 |      will be reinitialized as a special PlotlyDict or PlotlyList of the
 |      appropriate `kind`.
 |  
 |  to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80)
 |      Returns a formatted string showing graph_obj constructors.
 |      
 |      Example:
 |      
 |          print(obj.to_string())
 |      
 |      Keyword arguments:
 |      level (default = 0) -- set number of indentations to start with
 |      indent (default = 4) -- set indentation amount
 |      eol (default = '\n') -- set end of line character(s)
 |      pretty (default = True) -- curtail long list output with a '...'
 |      max_chars (default = 80) -- set max characters per line
 |  
 |  update(self, dict1=None, **dict2)
 |      Update current dict with dict1 and then dict2.
 |      
 |      This recursively updates the structure of the original dictionary-like
 |      object with the new entries in the second and third objects. This
 |      allows users to update with large, nested structures.
 |      
 |      Note, because the dict2 packs up all the keyword arguments, you can
 |      specify the changes as a list of keyword agruments.
 |      
 |      Examples:
 |      # update with dict
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      update_dict = dict(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj.update(update_dict)
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      # update with list of keyword arguments
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      obj.update(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      This 'fully' supports duck-typing in that the call signature is
 |      identical, however this differs slightly from the normal update
 |      method provided by Python's dictionaries.
 |  
 |  validate(self, caller=True)
 |      Recursively check the validity of the keys in a PlotlyDict.
 |      
 |      The valid keys constitute the entries in each object
 |      dictionary in graph_objs_meta.json
 |      
 |      The validation process first requires that all nested collections be
 |      converted to the appropriate subclass of PlotlyDict/PlotlyList. Then,
 |      each of these objects call `validate` and so on, recursively,
 |      until the entire object has been validated.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from PlotlyDict:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from __builtin__.dict:
 |  
 |  __cmp__(...)
 |      x.__cmp__(y) <==> cmp(x,y)
 |  
 |  __contains__(...)
 |      D.__contains__(k) -> True if D has a key k, else False
 |  
 |  __delitem__(...)
 |      x.__delitem__(y) <==> del x[y]
 |  
 |  __eq__(...)
 |      x.__eq__(y) <==> x==y
 |  
 |  __ge__(...)
 |      x.__ge__(y) <==> x>=y
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __getitem__(...)
 |      x.__getitem__(y) <==> x[y]
 |  
 |  __gt__(...)
 |      x.__gt__(y) <==> x>y
 |  
 |  __iter__(...)
 |      x.__iter__() <==> iter(x)
 |  
 |  __le__(...)
 |      x.__le__(y) <==> x<=y
 |  
 |  __len__(...)
 |      x.__len__() <==> len(x)
 |  
 |  __lt__(...)
 |      x.__lt__(y) <==> x<y
 |  
 |  __ne__(...)
 |      x.__ne__(y) <==> x!=y
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __sizeof__(...)
 |      D.__sizeof__() -> size of D in memory, in bytes
 |  
 |  clear(...)
 |      D.clear() -> None.  Remove all items from D.
 |  
 |  copy(...)
 |      D.copy() -> a shallow copy of D
 |  
 |  fromkeys(...)
 |      dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
 |      v defaults to None.
 |  
 |  get(...)
 |      D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
 |  
 |  has_key(...)
 |      D.has_key(k) -> True if D has a key k, else False
 |  
 |  items(...)
 |      D.items() -> list of D's (key, value) pairs, as 2-tuples
 |  
 |  iteritems(...)
 |      D.iteritems() -> an iterator over the (key, value) items of D
 |  
 |  iterkeys(...)
 |      D.iterkeys() -> an iterator over the keys of D
 |  
 |  itervalues(...)
 |      D.itervalues() -> an iterator over the values of D
 |  
 |  keys(...)
 |      D.keys() -> list of D's keys
 |  
 |  pop(...)
 |      D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
 |      If key is not found, d is returned if given, otherwise KeyError is raised
 |  
 |  popitem(...)
 |      D.popitem() -> (k, v), remove and return some (key, value) pair as a
 |      2-tuple; but raise KeyError if D is empty.
 |  
 |  setdefault(...)
 |      D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
 |  
 |  values(...)
 |      D.values() -> list of D's values
 |  
 |  viewitems(...)
 |      D.viewitems() -> a set-like object providing a view on D's items
 |  
 |  viewkeys(...)
 |      D.viewkeys() -> a set-like object providing a view on D's keys
 |  
 |  viewvalues(...)
 |      D.viewvalues() -> an object providing a view on D's values
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from __builtin__.dict:
 |  
 |  __hash__ = None
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T

In [24]:
cbar_title = "Mean bike traffic<br>per week day<br>\
norm. by max value<br>(so 1=max value)"    # colorbar title

# Make colorbar object
colorbar = ColorBar(
    title=cbar_title,    # set color bar title
    titleside='bottom',  # (!) title placed below the color bar
    thickness=25,        # color bar thickness in px
    autotick=False,      # custom colorbar ticks
    ticks='outside',     # tick outside colorbar
    dtick=0.1            # distance between ticks
)

Note that the colorbar object is meant to be linked to the 'colorbar' key in Heatmap or, more generally, in the trace object in question. Plotly colorbars are considered specifications of each plotted trace. In other words, Plotly allows users to add multiple colorbars to the same figure. So,

In [25]:
trace1 = Heatmap(
    z=Z_dayXwday_norm,  # 2D array for heatmap
    x=the_months,       # x-axis labels
    y=the_wdays_pl,     # y-axis labels 
    colorscale='Greys',   # (!) try another predefined colormap
    reversescale=True,    # (!) reverse its color ordering
    opacity=0.9,        # a slightly transparent color scale
    colorbar=colorbar,  # (!) link colormap object
)

# Make data object filled with the above heatmap object
data = Data([trace1])

Next, update the layout object (from the previous figure):

In [26]:
# Update the figure's height (in px)
layout.update(height=500)

# Update y-axis title and set tick angle
layout['yaxis'].update(
    title='Days of the weeks',
    tickangle=-20
)

# Update frame/axis margin to leave room for y-axis ticks 
layout.update(margin=Margin(l=100))

# Update title
title = "Fig 5.1b: Bike traffic across 8 Montreal sites in 2013"
layout.update(title=title)

Finally, make a new figure object and send it to Plotly:

In [27]:
# Make figure object
fig = Figure(data=data, layout=layout)

# Send figure object to Plotly's server, show result in notebook
py.iplot(fig, filename='s5_cyclists-per-wday')
Out[27]:

Thursdays in July were on average the busiest days in 2013. Weekends are less busy than weekday by roughly 30 to 40 percent, a pretty interesting result.

5.2 Correlation heatmap between sites

Our next plot will be a correlation heatmap between the 8 sites. The correlations coefficient of two datasets $X$ and $Y$ is computed as follows:

$$ \text{Corr}_{X,Y} = \frac{\sum_i^N (X_i - \bar{X})(Y_i-\bar{Y})} {\sqrt{\sum_i^N (X_i - \bar{X})}\sqrt{\sum_i^N (Y_i - \bar{Y})}} $$

Where $N$ is the sample size. $X_i$ and $Y_i$ are the sample values in each datasets.

Here, for us, we have not two by eight datasets and we would like to compute the correlation coefficient of each combination of dataset, making up a correlation matrix. The sample corresponds to the daily traffic totals at each sites.

So, first extract these values from the dataframe into a numpy 2D array:

In [28]:
# Get values of every row of columns 2 and up
Z_dayXsite = df.ix[:,2:].values

# 153 sample days (rows) at 8 sites (columns)
Z_dayXsite.shape
Out[28]:
(153, 8)

Next, compute the correlation matrix

In [29]:
# Compute correlation, rows (i.e. days of the year) are our sample space
Corr_site = np.corrcoef(Z_dayXsite,rowvar=0)

# 8 sites correlated with themselves
Corr_site.shape
Out[29]:
(8, 8)

The correlation matrix contains 64 entries, one for each permutation (i.e. ordered combinations) of bike counter sites.

In addition, let's first check the range of values of the correlation matrix:

In [30]:
Corr_site.min(), Corr_site.max()
Out[30]:
(0.47982343592869092, 1.0)

Next in a heatmap trace object, we overwrite the default minimum and maximum color scale values (with 'zmin' and 'zmax' respectively) to round up the color bar's range. So, consider,

In [31]:
trace1 = Heatmap(
    z=Corr_site,  # correlation as color contours 
    x=sites,      # sites on both
    y=sites,      #  axes
    zauto=False,  # (!) overwrite Plotly's default color levels
    zmin=0.4,     # (!) set value of min color level
    zmax=1,       # (!) set value of max color level
    colorscale='YIOrRd', # light yellow-orange-red colormap
    reversescale=True    # inverse colormap order
)

# Make data object
data = Data([trace1])       

Before plotting the correlation matrix, we will need to adjust the margin around the heatmap so that the long site names fit on the tick labels.

In [32]:
title = "Fig 5.2a: Bike traffic correlations \
between different sites in 2013"  # plot's title

# Make layout object
layout = Layout(
    title=title,  # set plot title
    autosize=False,       # turn off autosize 
    height=500,           # plot's height in pixels 
    width=600,            # plot's width in pixels
    margin=Margin(l=130), # adjust left margin
    annotations=Annotations([  # add annotaion citing the source
        make_anno()            #   using make_anno() defined in 5.1
    ])
)
In [33]:
# Make Figure object
fig = Figure(data=data, layout=layout)

# (@) Send to Plotly and show in notebook 
py.iplot(fig, filename='s5_correlations')
Out[33]:

Notice that Plotly automatically tilts the x-axis label to make them fit in the frame. Nice.

As the correlation coefficient of $X$ and $Y$ is the same as the correlation coefficient of $Y$ and $X$, we have a lot of useless information on the above plot. Let's remedy this situation with some inspiration from the Seaborn project and, more specificaly this plot. Thanks!

Seaborn styling in Plotly

To convert our previous plot to the Seaborn styling, we must:

  • Make a new array with values from correlation matrix but without duplicates,
  • Reverse the order of the y-axis,
  • Tilt the x-axis labels to the vertical,
  • Define a custom color scale.
In [34]:
# Convert data and labels array to match Seaborn
def make_seaborn(x_old, y_old,  z_old):
    x_sns = x_old[0:-1]      # remove last entry in x-corrd array
    y_sns = y_old[-1:0:-1]   # remove first entry, reverse order in y-coord array
    m,n = z_old.shape        # get dimension of original array
    tmp = np.empty((m,n))    # init. tmp array
    tmp.fill(np.nan)         #   with NaNs
    for i in range(m):             # loop through rows
        tmp[i,0:i] = z_old[i,0:i]  # add items below the diagonal
    tmp = np.flipud(tmp)     #  reverse order of all columns in tmp array
    z_sns = tmp  # copy tmp array to outpur variable
    return (x_sns,y_sns,z_sns)  # return new coodinates in tuple

# Call conversion function, get coordinates for our next plot
sites_x_sns,sites_y_sns,Corr_site_sns=make_seaborn(sites,sites,Corr_site)
In [35]:
# Check position of NaNs in new 2D array
np.isnan(Corr_site_sns)
Out[35]:
array([[False, False, False, False, False, False, False,  True],
       [False, False, False, False, False, False,  True,  True],
       [False, False, False, False, False,  True,  True,  True],
       [False, False, False, False,  True,  True,  True,  True],
       [False, False, False,  True,  True,  True,  True,  True],
       [False, False,  True,  True,  True,  True,  True,  True],
       [False,  True,  True,  True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True,  True,  True,  True]], dtype=bool)

Recall that Plotly maps the array's rows to y-axis and the array's columns to x-axis. So when plotted Corr_site_sns will have non-NaNs values on the lower diagonal as on the Seaborn plot.

Custom color scales in Plotly

Next, we build a custom color scale (or color map or color scheme).

A custom color scale in Plotly is a list of lists linked to the 'scl' key in Heatmap, Contour, Histogram2d or Histogram2dcontour where the nested lists have the normalized level (more info below) values as first item and the level colors as second item using whatever color model you prefer.

From this point on, Plotly takes over. The color scale is interpolated in-between the color levels, resulting in a continuous map from values in the 2D array to colors. So,

In [36]:
scl_sns = [
    [0,"#00008B"],   # color of minimun level (from 'zmin')
    [0.25,"#6A5ACD"], [0.5,"#FFE6F8"], [0.75, "#C71585"],  # in-between
    [1, "#8B0000"]   # color of maximum level (from 'zmax')
]

The 0 color level is the level of the value linked to the 'zmin' key in Heatmap. Correspondingly, the 1 color level is the level of the value linked to the 'zmax' key set in Heatmap.

By default, the value of 'zmin' is the 2D array's minimum value of the value of 'zmax' is its maxmium value. That said, they can be easily overwritten. Consider the following

In [37]:
trace1 = Heatmap(
    z=Corr_site_sns,  # 2D array
    x=sites_x_sns,    # x-labels 
    y=sites_y_sns,    # y-labels  
    zauto=False,  # (!) custom color levels
    zmin=0.3,     # (!) value of min color level
    zmax=1,       # (!) value of max color level
    colorscale=scl_sns,  # (!) custom color scales list of lists
)

# Make data object
data = Data([trace1])

Ok, now tilt the axes' labels and add two annotations:

In [38]:
# Define a dictionary of axis style options
axis_style = dict(
    autotick=False,   # custom ticks 
    showgrid=False,   # remove grid
    showline=False    # remove axes line
)

# Add style options on both axes, tilt the labels of x-axis
layout.update(xaxis=XAxis(
    axis_style,
    tickangle=90
))
layout.update(yaxis=YAxis(axis_style))

# Update bottom frame/axis margin 
layout['margin'].update(b=150)

# Add an annotation describing the sample
# (using make_anno() defined in subsection 5.1)

text_sample="Data used:<br>April 01, 2013<br>to<br>August 31, 2013"

layout['annotations'].append(make_anno(text=text_sample,x=0.8,y=0.6))


# Update title
title = "Fig 5.2b: Bike traffic correlations between different sites"
layout.update(title=title)

Finally, make a figure object and send it to Plotly:

In [39]:
# Make new figure object
fig = Figure(data=data, layout=layout)

# (@) Send figure object to Plotly
py.iplot(fig, filename='s5_correlations-seaborn')
Out[39]:

Much better. We now have room to spare for some annotations.

From the above plot, all the sites are well-correlated and five of them are almost perfectly correlation (correlation coefficients > 0.9). This means that we do not need to check the 8 sites to evaluate day-to-day traffic fluctuations. In other words, if traffic increases at one site, it is very likely that traffic increases at the 7 other sites.

5.3 Contours of traffic progression from most to least trafficked sites

Positive trends in bike traffic are expected to propage from the most trafficked counter site to the least trafficked counter site over time and vice versa. In our next plot, we attempt to assess this claim with a contour plot of daily bike traffic totals as a function of the date and counter site.

In [40]:
help(Contour)  # call help!
Help on class Contour in module plotly.graph_objs.graph_objs:

class Contour(PlotlyTrace)
 |  A dictionary-like object for representing a contour trace in plotly.
 |  
 |  Example:
 |  
 |      >>> z = [[0, 1, 0, 1, 0], [1, 0, 1, 0, 1], [0, 1, 0, 1, 0]]
 |      >>> y = ['a', 'b', 'c']
 |      >>> x = [1, 2, 3, 4, 5]py.plot([Contour(z=z, x=x, y=y)])
 |  
 |  Online example:
 |  
 |      https://plot.ly/python/contour-plots/
 |  
 |  Quick method reference:
 |  
 |      Contour.update(changes)
 |      Contour.strip_style()
 |      Contour.get_data()
 |      Contour.to_graph_objs()
 |      Contour.validate()
 |      Contour.to_string()
 |      Contour.force_clean()
 |  
 |  Valid keys:
 |  
 |      z [required=True] (value=list of lists or 2d numpy array of numbers)
 |      (streamable):
 |          Sets the data that describes the contour map mapping. Say the
 |          dimensions of the list of lists or 2d numpy array linked to 'z' has
 |          n rows and m columns then the resulting contour map will show n
 |          partitions along the y-axis and m partitions along the x-axis.
 |          Therefore, the i-th row/ j-th column cell in the list of lists or 2d
 |          numpy array linked to 'z' is mapped to the i-th partition of the
 |          y-axis (starting from the bottom of the plot) and the j-th partition
 |          of the x-axis (starting from the left of the plot).
 |  
 |      x [required=False] (value=list or 1d numpy array of numbers, strings,
 |      datetimes) (streamable):
 |          Sets the horizontal coordinates referring to the columns of the list
 |          of lists or 2d numpy array linked to 'z'. If the 'z' is a list or 1d
 |          numpy array of strings, then the x-labels are spaced evenly. If the
 |          dimensions of the list of lists or 2d numpy array linked to 'z' are
 |          (n x m), the length of the 'x' array should equal m.
 |  
 |      y [required=False] (value=list or 1d numpy array of numbers, strings,
 |      datetimes) (streamable):
 |          Sets the vertical coordinates referring to the rows of the list of
 |          lists or 2d numpy array linked to 'z'. If strings, the y-labels are
 |          spaced evenly. If the dimensions of the list of lists or 2d numpy
 |          array linked to 'z' are (n x m), the length of the 'y' array should
 |          equal n.
 |  
 |      name [required=False] (value=a string):
 |          The label associated with this trace. This name will appear in the
 |          legend, on hover and in the column header in the online spreadsheet.
 |  
 |      zauto [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the default values of 'zmax' and 'zmax' can be
 |          overwritten.
 |  
 |      zmin [required=False] (value=number):
 |          Sets the minimum 'z' data value to be resolved by the color scale.
 |          Its default value is the minimum of the 'z' data values. This value
 |          will be used as the minimum in the color scale normalization. For
 |          more info see 'colorscale'.
 |  
 |      zmax [required=False] (value=number):
 |          Sets the maximum 'z' data value to be resolved by the color scale.
 |          Its default value is the maximum of the 'z' data values. This value
 |          will be used as the maximum in the color scale normalization. For
 |          more info see 'colorscale'.
 |  
 |      autocontour [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the contour parameters are picked
 |          automatically by Plotly. If False, declare the contours parameters
 |          in 'contours'.
 |  
 |      ncontours [required=False] (value=number: x > 1):
 |          Specifies the number of contours lines in the contour plot. No need
 |          to set 'autocontour' to False for 'ncontours' to apply.
 |  
 |      contours [required=False] (value=Contours object | dictionary-like
 |      object):
 |          Links a dictionary-like object defining the parameters of the
 |          contours of this trace.
 |  
 |          For more, run `help(plotly.graph_objs.Contours)`
 |  
 |      line [required=False] (value=Line object | dictionary-like object)
 |      (streamable):
 |          Links a dictionary-like object containing line parameters for
 |          contour lines of this contour trace (including line width, dash,
 |          color and smoothing level). Has no an effect if 'showlines' is set
 |          to False in 'contours'.
 |  
 |          For more, run `help(plotly.graph_objs.Line)`
 |  
 |      colorscale [required=False] (value=list or 1d numpy array of value-color
 |      pairs | 'Greys' | 'Greens' | 'Bluered' | 'Hot' | 'Picnic' | 'Portland' |
 |      'Jet' | 'RdBu' | 'Blackbody' | 'Earth' | 'Electric' | 'YIOrRd' |
 |      'YIGnBu'):
 |          Sets and/or defines the color scale for this trace. The string
 |          values are pre-defined color scales. For custom color scales, define
 |          a list or 1d numpy array of value-color pairs where, the first
 |          element of the pair corresponds to a normalized value of z from 0-1,
 |          i.e. (z-zmin)/ (zmax-zmin), and the second element of pair
 |          corresponds to a color. Use with 'zauto', 'zmin' and 'zmax to fine-
 |          tune the map from 'z' to rendered colors.
 |  
 |          Examples:
 |              'Greys' | [[0, 'rgb(0,0,0)'], [0.5, 'rgb(65, 182, 196)'], [1,
 |              'rgb(255,255,255)']]
 |  
 |      reversescale [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the color scale will be reversed.
 |  
 |      showscale [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the color scale associated with this mapping
 |          will be shown alongside the figure.
 |  
 |      colorbar [required=False] (value=ColorBar object | dictionary-like
 |      object):
 |          Links a dictionary-like object defining the parameters of the color
 |          bar associated with this trace (including its title, length and
 |          width).
 |  
 |          For more, run `help(plotly.graph_objs.ColorBar)`
 |  
 |      opacity [required=False] (value=number: x in [0, 1]):
 |          Sets the opacity, or transparency, of the entire object, also known
 |          as the alpha channel of colors. If the object's color is given in
 |          terms of 'rgba' color model, 'opacity' is redundant.
 |  
 |      xaxis [required=False] (value='x1' | 'x2' | 'x3' | etc.):
 |          This key determines which x-axis the x-coordinates of this trace
 |          will reference in the figure.  Values 'x1' and 'x' reference to
 |          'xaxis' in 'layout', 'x2' references to 'xaxis2' in 'layout', and so
 |          on. Note that 'x1' will always refer to 'xaxis' or 'xaxis1' in
 |          'layout', they are the same.
 |  
 |      yaxis [required=False] (value='y1' | 'y2' | 'y3' | etc.):
 |          This key determines which y-axis the y-coordinates of this trace
 |          will reference in the figure.  Values 'y1' and 'y' reference to
 |          'yaxis' in 'layout', 'y2' references to 'yaxis2' in 'layout', and so
 |          on. Note that 'y1' will always refer to 'yaxis' or 'yaxis1' in
 |          'layout', they are the same.
 |  
 |      showlegend [required=False] (value=a boolean: True | False):
 |          Toggle whether or not this trace will be labeled in the legend.
 |  
 |      stream [required=False] (value=Stream object | dictionary-like object):
 |          Links a dictionary-like object that initializes this trace as a
 |          writable-stream, for use with the streaming API.
 |  
 |          For more, run `help(plotly.graph_objs.Stream)`
 |  
 |      visible [required=False] (value=a boolean: True | False):
 |          Toggles whether or not this object will be visible on the rendered
 |          figure.
 |  
 |      x0 [required=False] (value=number):
 |          The location of the first coordinate of the x-axis. Use with 'dx' an
 |          alternative to an 'x' list or 1d numpy array. Has no effect if 'x'
 |          is set.
 |  
 |      dx [required=False] (value=number):
 |          Spacing between x-axis coordinates. Use with 'x0' an alternative to
 |          an 'x' list or 1d numpy array. Has no effect if 'x' is set.
 |  
 |      y0 [required=False] (value=number):
 |          The location of the first coordinate of the y-axis. Use with 'dy' an
 |          alternative to an 'y' list or 1d numpy array. Has no effect if 'y'
 |          is set.
 |  
 |      dy [required=False] (value=number):
 |          Spacing between y-axis coordinates. Use with 'y0' an alternative to
 |          an 'y' list or 1d numpy array. Has no effect if 'y' is set.
 |  
 |      xtype [required=False] (value='array' | 'scaled'):
 |          If set to 'scaled' and 'x' is linked to a list or 1d numpy array,
 |          then the horizontal labels are scaled to a list or 1d numpy array of
 |          integers of unit step starting from 0.
 |  
 |      ytype [required=False] (value='array' | 'scaled'):
 |          If set to 'scaled' and 'y' is linked to a list or 1d numpy array,
 |          then the vertical labels are scaled to a list or 1d numpy array of
 |          integers of unit step starting from 0.
 |  
 |      type [required=False] (value='contour'):
 |          Plotly identifier for this data's trace type.
 |  
 |  Method resolution order:
 |      Contour
 |      PlotlyTrace
 |      PlotlyDict
 |      __builtin__.dict
 |      __builtin__.object
 |  
 |  Methods inherited from PlotlyTrace:
 |  
 |  __init__(self, *args, **kwargs)
 |  
 |  to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80)
 |      Returns a formatted string showing graph_obj constructors.
 |      
 |      Example:
 |      
 |          print(obj.to_string())
 |      
 |      Keyword arguments:
 |      level (default = 0) -- set number of indentations to start with
 |      indent (default = 4) -- set indentation amount
 |      eol (default = '\n') -- set end of line character(s)
 |      pretty (default = True) -- curtail long list output with a '...'
 |      max_chars (default = 80) -- set max characters per line
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from PlotlyDict:
 |  
 |  __setitem__(self, key, value)
 |  
 |  force_clean(self, caller=True)
 |      Attempts to convert to graph_objs and call force_clean() on values.
 |      
 |      Calling force_clean() on a PlotlyDict will ensure that the object is
 |      valid and may be sent to plotly. This process will also remove any
 |      entries that end up with a length == 0.
 |      
 |      Careful! This will delete any invalid entries *silently*.
 |  
 |  get_data(self)
 |      Returns the JSON for the plot with non-data elements stripped.
 |  
 |  get_ordered(self, caller=True)
 |  
 |  strip_style(self)
 |      Strip style from the current representation.
 |      
 |      All PlotlyDicts and PlotlyLists are guaranteed to survive the
 |      stripping process, though they made be left empty. This is allowable.
 |      
 |      Keys that will be stripped in this process are tagged with
 |      `'type': 'style'` in graph_objs_meta.json.
 |      
 |      This process first attempts to convert nested collections from dicts
 |      or lists to subclasses of PlotlyList/PlotlyDict. This process forces
 |      a validation, which may throw exceptions.
 |      
 |      Then, each of these objects call `strip_style` on themselves and so
 |      on, recursively until the entire structure has been validated and
 |      stripped.
 |  
 |  to_graph_objs(self, caller=True)
 |      Walk obj, convert dicts and lists to plotly graph objs.
 |      
 |      For each key in the object, if it corresponds to a special key that
 |      should be associated with a graph object, the ordinary dict or list
 |      will be reinitialized as a special PlotlyDict or PlotlyList of the
 |      appropriate `kind`.
 |  
 |  update(self, dict1=None, **dict2)
 |      Update current dict with dict1 and then dict2.
 |      
 |      This recursively updates the structure of the original dictionary-like
 |      object with the new entries in the second and third objects. This
 |      allows users to update with large, nested structures.
 |      
 |      Note, because the dict2 packs up all the keyword arguments, you can
 |      specify the changes as a list of keyword agruments.
 |      
 |      Examples:
 |      # update with dict
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      update_dict = dict(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj.update(update_dict)
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      # update with list of keyword arguments
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      obj.update(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      This 'fully' supports duck-typing in that the call signature is
 |      identical, however this differs slightly from the normal update
 |      method provided by Python's dictionaries.
 |  
 |  validate(self, caller=True)
 |      Recursively check the validity of the keys in a PlotlyDict.
 |      
 |      The valid keys constitute the entries in each object
 |      dictionary in graph_objs_meta.json
 |      
 |      The validation process first requires that all nested collections be
 |      converted to the appropriate subclass of PlotlyDict/PlotlyList. Then,
 |      each of these objects call `validate` and so on, recursively,
 |      until the entire object has been validated.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from PlotlyDict:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from __builtin__.dict:
 |  
 |  __cmp__(...)
 |      x.__cmp__(y) <==> cmp(x,y)
 |  
 |  __contains__(...)
 |      D.__contains__(k) -> True if D has a key k, else False
 |  
 |  __delitem__(...)
 |      x.__delitem__(y) <==> del x[y]
 |  
 |  __eq__(...)
 |      x.__eq__(y) <==> x==y
 |  
 |  __ge__(...)
 |      x.__ge__(y) <==> x>=y
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __getitem__(...)
 |      x.__getitem__(y) <==> x[y]
 |  
 |  __gt__(...)
 |      x.__gt__(y) <==> x>y
 |  
 |  __iter__(...)
 |      x.__iter__() <==> iter(x)
 |  
 |  __le__(...)
 |      x.__le__(y) <==> x<=y
 |  
 |  __len__(...)
 |      x.__len__() <==> len(x)
 |  
 |  __lt__(...)
 |      x.__lt__(y) <==> x<y
 |  
 |  __ne__(...)
 |      x.__ne__(y) <==> x!=y
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __sizeof__(...)
 |      D.__sizeof__() -> size of D in memory, in bytes
 |  
 |  clear(...)
 |      D.clear() -> None.  Remove all items from D.
 |  
 |  copy(...)
 |      D.copy() -> a shallow copy of D
 |  
 |  fromkeys(...)
 |      dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
 |      v defaults to None.
 |  
 |  get(...)
 |      D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
 |  
 |  has_key(...)
 |      D.has_key(k) -> True if D has a key k, else False
 |  
 |  items(...)
 |      D.items() -> list of D's (key, value) pairs, as 2-tuples
 |  
 |  iteritems(...)
 |      D.iteritems() -> an iterator over the (key, value) items of D
 |  
 |  iterkeys(...)
 |      D.iterkeys() -> an iterator over the keys of D
 |  
 |  itervalues(...)
 |      D.itervalues() -> an iterator over the values of D
 |  
 |  keys(...)
 |      D.keys() -> list of D's keys
 |  
 |  pop(...)
 |      D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
 |      If key is not found, d is returned if given, otherwise KeyError is raised
 |  
 |  popitem(...)
 |      D.popitem() -> (k, v), remove and return some (key, value) pair as a
 |      2-tuple; but raise KeyError if D is empty.
 |  
 |  setdefault(...)
 |      D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
 |  
 |  values(...)
 |      D.values() -> list of D's values
 |  
 |  viewitems(...)
 |      D.viewitems() -> a set-like object providing a view on D's items
 |  
 |  viewkeys(...)
 |      D.viewkeys() -> a set-like object providing a view on D's keys
 |  
 |  viewvalues(...)
 |      D.viewvalues() -> an object providing a view on D's values
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from __builtin__.dict:
 |  
 |  __hash__ = None
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T

To better visualize the traffic propagation, the counter sites will be placed on the x-axis in order, from the most trafficked to the least in the yearly total.

So, first, sum the traffic total of all dates from April 1 to August 31:

In [41]:
# Column sum of dataframe, keep columns correps. to sites, get a numpy array
z_site = np.array(df.sum(axis=0).tolist()[2:])

# The dataframe .sum() method ignores non-number (e.g. the date strings)
# while computing the column (with axis=0) sum.

# Show list of sites and total cyclist count
for tple in zip(sites,z_site):
    print tple
('Berri/<br>de Maisonneuve', '617472')
('C\xc3\xb4te-Ste-Catherine<br>(parc Beaubien)', '272218')
('de Maisonneuve/<br>Berri', '393995')
('de Maisonneuve/<br>Peel', '716427')
('du Parc/<br>Duluth', '367109')
('Pierre-Dupuy<br>(Habitat 67)', '273008')
('Rachel/<br>Marquette', '693354')
('Laurier<br>(m\xc3\xa9tro)', '414548')

Next, order the sites from most trafficked to least (the x-axis labels), swap the dataframe's columns accordingly and make a list of dates (the y-axis labels):

In [42]:
# (*) with the datetime module

def convert_in_order(df_in,sites,z_site):

    dates = df_in['Date'].tolist()  # make list of dates in dataframe
     
    # Get values of every row of columns 2 and up (as in subsection 5.2)
    Z_dayXsite = df.ix[:,2:].values
    
    # (1-) Get list of dates in words (e.g. Mon, Jan 1)
    dates_in_words = [datetime.datetime.strptime(i,'%d/%m/%Y').strftime('%a, %b %d') 
                      for i in dates]
    
    # (2.1-3.1) Get indices of sorted array in decreasing order
    ind_in_order = np.argsort(z_site)[::-1]

    # (2-) Shuffle sites list in order
    sites_in_order = [sites[i] for i in ind_in_order]
    
    # (3-) Shuffle columns (corresp. to the sites) of 2D array in order
    Z_dayXsite_in_order = Z_dayXsite[:,ind_in_order]

    # Output coordinates for our plot
    return (dates_in_words, sites_in_order, Z_dayXsite_in_order)  
    
# Get plot coordinates
dates_in_words,sites_in_order,Z_dayXsite_in_order=convert_in_order(df,sites,z_site)

Data for contours plot is input in the Contour object. The Contours object (N.B. plural) contains the style options for the contours, similar to what XBins and YBins are for Histogram.

Ultimately, the Contours is meant to be linked to the 'contours' key in Contour.

In [43]:
help(Contours)  # call help!
Help on class Contours in module plotly.graph_objs.graph_objs:

class Contours(PlotlyDict)
 |  A dictionary-like object containing specifications of the contours.
 |  
 |  Online example:
 |  
 |      https://plot.ly/python/contour-plots/
 |  
 |  Parent key:
 |  
 |      contours
 |  
 |  Quick method reference:
 |  
 |      Contours.update(changes)
 |      Contours.strip_style()
 |      Contours.get_data()
 |      Contours.to_graph_objs()
 |      Contours.validate()
 |      Contours.to_string()
 |      Contours.force_clean()
 |  
 |  Valid keys:
 |  
 |      showlines [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the contour lines appear on the plot.
 |  
 |      start [required=False] (value=number: x > 0):
 |          Sets the value of the first contour level.
 |  
 |      end [required=False] (value=number: x > 0):
 |          Sets the value of the last contour level.
 |  
 |      size [required=False] (value=number: x > 0) (streamable):
 |          Sets the size of each contour level.
 |  
 |      coloring [required=False] (value= 'fill' | 'heatmap' | 'lines' | 'none'
 |      ):
 |          Choose the coloring method for this contour trace. The default value
 |          is 'fill' where coloring is done evenly between each contour line.
 |          'heatmap' colors on a grid point-by-grid point basis. 'lines' colors
 |          only the contour lines, each with respect to the color scale. 'none'
 |          prints all contour lines with the same color; choose their color in
 |          a Line object at the trace level if desired.
 |  
 |  Method resolution order:
 |      Contours
 |      PlotlyDict
 |      __builtin__.dict
 |      __builtin__.object
 |  
 |  Methods inherited from PlotlyDict:
 |  
 |  __init__(self, *args, **kwargs)
 |  
 |  __setitem__(self, key, value)
 |  
 |  force_clean(self, caller=True)
 |      Attempts to convert to graph_objs and call force_clean() on values.
 |      
 |      Calling force_clean() on a PlotlyDict will ensure that the object is
 |      valid and may be sent to plotly. This process will also remove any
 |      entries that end up with a length == 0.
 |      
 |      Careful! This will delete any invalid entries *silently*.
 |  
 |  get_data(self)
 |      Returns the JSON for the plot with non-data elements stripped.
 |  
 |  get_ordered(self, caller=True)
 |  
 |  strip_style(self)
 |      Strip style from the current representation.
 |      
 |      All PlotlyDicts and PlotlyLists are guaranteed to survive the
 |      stripping process, though they made be left empty. This is allowable.
 |      
 |      Keys that will be stripped in this process are tagged with
 |      `'type': 'style'` in graph_objs_meta.json.
 |      
 |      This process first attempts to convert nested collections from dicts
 |      or lists to subclasses of PlotlyList/PlotlyDict. This process forces
 |      a validation, which may throw exceptions.
 |      
 |      Then, each of these objects call `strip_style` on themselves and so
 |      on, recursively until the entire structure has been validated and
 |      stripped.
 |  
 |  to_graph_objs(self, caller=True)
 |      Walk obj, convert dicts and lists to plotly graph objs.
 |      
 |      For each key in the object, if it corresponds to a special key that
 |      should be associated with a graph object, the ordinary dict or list
 |      will be reinitialized as a special PlotlyDict or PlotlyList of the
 |      appropriate `kind`.
 |  
 |  to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80)
 |      Returns a formatted string showing graph_obj constructors.
 |      
 |      Example:
 |      
 |          print(obj.to_string())
 |      
 |      Keyword arguments:
 |      level (default = 0) -- set number of indentations to start with
 |      indent (default = 4) -- set indentation amount
 |      eol (default = '\n') -- set end of line character(s)
 |      pretty (default = True) -- curtail long list output with a '...'
 |      max_chars (default = 80) -- set max characters per line
 |  
 |  update(self, dict1=None, **dict2)
 |      Update current dict with dict1 and then dict2.
 |      
 |      This recursively updates the structure of the original dictionary-like
 |      object with the new entries in the second and third objects. This
 |      allows users to update with large, nested structures.
 |      
 |      Note, because the dict2 packs up all the keyword arguments, you can
 |      specify the changes as a list of keyword agruments.
 |      
 |      Examples:
 |      # update with dict
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      update_dict = dict(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj.update(update_dict)
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      # update with list of keyword arguments
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      obj.update(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      This 'fully' supports duck-typing in that the call signature is
 |      identical, however this differs slightly from the normal update
 |      method provided by Python's dictionaries.
 |  
 |  validate(self, caller=True)
 |      Recursively check the validity of the keys in a PlotlyDict.
 |      
 |      The valid keys constitute the entries in each object
 |      dictionary in graph_objs_meta.json
 |      
 |      The validation process first requires that all nested collections be
 |      converted to the appropriate subclass of PlotlyDict/PlotlyList. Then,
 |      each of these objects call `validate` and so on, recursively,
 |      until the entire object has been validated.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from PlotlyDict:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from __builtin__.dict:
 |  
 |  __cmp__(...)
 |      x.__cmp__(y) <==> cmp(x,y)
 |  
 |  __contains__(...)
 |      D.__contains__(k) -> True if D has a key k, else False
 |  
 |  __delitem__(...)
 |      x.__delitem__(y) <==> del x[y]
 |  
 |  __eq__(...)
 |      x.__eq__(y) <==> x==y
 |  
 |  __ge__(...)
 |      x.__ge__(y) <==> x>=y
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __getitem__(...)
 |      x.__getitem__(y) <==> x[y]
 |  
 |  __gt__(...)
 |      x.__gt__(y) <==> x>y
 |  
 |  __iter__(...)
 |      x.__iter__() <==> iter(x)
 |  
 |  __le__(...)
 |      x.__le__(y) <==> x<=y
 |  
 |  __len__(...)
 |      x.__len__() <==> len(x)
 |  
 |  __lt__(...)
 |      x.__lt__(y) <==> x<y
 |  
 |  __ne__(...)
 |      x.__ne__(y) <==> x!=y
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __sizeof__(...)
 |      D.__sizeof__() -> size of D in memory, in bytes
 |  
 |  clear(...)
 |      D.clear() -> None.  Remove all items from D.
 |  
 |  copy(...)
 |      D.copy() -> a shallow copy of D
 |  
 |  fromkeys(...)
 |      dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
 |      v defaults to None.
 |  
 |  get(...)
 |      D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
 |  
 |  has_key(...)
 |      D.has_key(k) -> True if D has a key k, else False
 |  
 |  items(...)
 |      D.items() -> list of D's (key, value) pairs, as 2-tuples
 |  
 |  iteritems(...)
 |      D.iteritems() -> an iterator over the (key, value) items of D
 |  
 |  iterkeys(...)
 |      D.iterkeys() -> an iterator over the keys of D
 |  
 |  itervalues(...)
 |      D.itervalues() -> an iterator over the values of D
 |  
 |  keys(...)
 |      D.keys() -> list of D's keys
 |  
 |  pop(...)
 |      D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
 |      If key is not found, d is returned if given, otherwise KeyError is raised
 |  
 |  popitem(...)
 |      D.popitem() -> (k, v), remove and return some (key, value) pair as a
 |      2-tuple; but raise KeyError if D is empty.
 |  
 |  setdefault(...)
 |      D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
 |  
 |  values(...)
 |      D.values() -> list of D's values
 |  
 |  viewitems(...)
 |      D.viewitems() -> a set-like object providing a view on D's items
 |  
 |  viewkeys(...)
 |      D.viewkeys() -> a set-like object providing a view on D's keys
 |  
 |  viewvalues(...)
 |      D.viewvalues() -> an object providing a view on D's values
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from __builtin__.dict:
 |  
 |  __hash__ = None
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T

To enable custom contours (i.e. by setting 'start', 'end' and 'size' in Contours) set autocontour to False in Contour.

By default, Plotly contours are colored uniformly between contour lines, corresponding to 'coloring':'fill' in Contours. With the 'heatmap' value coloring is done on a grid point-by-grid point basis and with lines only the contour lines are colored with respect to the color scale. Finally, with 'coloring:'none' contour lines and the areas between them are not colored, use this value to make a contour plot with all contour lines of the same color.

To modify the appearance of the contour lines (e.g. their color), use the Line object:

In [44]:
help(Line)  # call help!

# notice 'smoothing'
Help on class Line in module plotly.graph_objs.graph_objs:

class Line(PlotlyDict)
 |  A dictionary-like object containing specifications of the line segments.
 |  
 |  Online examples:
 |  
 |      https://plot.ly/python/line-and-scatter/
 |      https://plot.ly/python/filled-area-plots/
 |      https://plot.ly/python/contour-plots/
 |  
 |  Parent key:
 |  
 |      line
 |  
 |  Quick method reference:
 |  
 |      Line.update(changes)
 |      Line.strip_style()
 |      Line.get_data()
 |      Line.to_graph_objs()
 |      Line.validate()
 |      Line.to_string()
 |      Line.force_clean()
 |  
 |  Valid keys:
 |  
 |      color [required=False] (value=a string describing color) (streamable):
 |          Sets the color of the line object. If linked within 'marker', sets
 |          the color of the marker's bordering line. If linked within,
 |          'contours', sets the color of the contour lines.
 |  
 |          Examples:
 |              'green' | 'rgb(0, 255, 0)' | 'rgba(0, 255, 0, 0.3)' |
 |              'hsl(120,100%,50%)' | 'hsla(120,100%,50%,0.3)' | '#434F1D'
 |  
 |      width [required=False] (value=number: x >= 0):
 |          Sets the width (in pixels) of the line segments in question.
 |  
 |      dash [required=False] (value='dash' | 'dashdot' | 'dot' | 'solid'):
 |          Sets the drawing style of the lines segments in this trace.
 |  
 |      opacity [required=False] (value=number: x in [0, 1]):
 |          Sets the opacity, or transparency, of the entire object, also known
 |          as the alpha channel of colors. If the object's color is given in
 |          terms of 'rgba' color model, 'opacity' is redundant.
 |  
 |      shape [required=False] (value='linear' | 'spline' | 'hv' | 'vh' | 'hvh'
 |      | 'vhv'):
 |          Choose the line shape between each coordinate pair in this trace.
 |          Applies only to scatter traces. The default value is 'linear'. If
 |          set to 'spline', then the lines are drawn using spline interpolation
 |          between the coordinate pairs. The remaining available values
 |          correspond to step-wise line shapes.
 |  
 |      smoothing [required=False] (value=number: x >= 0):
 |          Sets the amount of smoothing applied to the lines segments in this
 |          trace. Applies only to contour traces and scatter traces if 'shape'
 |          is set to 'spline'. The default value is 1. If 'smoothing' is set to
 |          0, then no smoothing is applied. Set 'smoothing' to a value less
 |          (greater) than 1 for a less (more) pronounced line smoothing.
 |  
 |      outliercolor [required=False] (value=a string describing color):
 |          For box plots only. Has an effect only if 'boxpoints' is set to
 |          'suspectedoutliers'. Sets the color of the bordering line of the
 |          outlier points.
 |  
 |          Examples:
 |              'green' | 'rgb(0, 255, 0)' | 'rgba(0, 255, 0, 0.3)' |
 |              'hsl(120,100%,50%)' | 'hsla(120,100%,50%,0.3)' | '#434F1D'
 |  
 |      outlierwidth [required=False] (value=a string describing color):
 |          For box plots only. Has an effect only if 'boxpoints' is set to
 |          'suspectedoutliers'. Sets the width in pixels of bordering line of
 |          the outlier points.
 |  
 |          Examples:
 |              'green' | 'rgb(0, 255, 0)' | 'rgba(0, 255, 0, 0.3)' |
 |              'hsl(120,100%,50%)' | 'hsla(120,100%,50%,0.3)' | '#434F1D'
 |  
 |  Method resolution order:
 |      Line
 |      PlotlyDict
 |      __builtin__.dict
 |      __builtin__.object
 |  
 |  Methods inherited from PlotlyDict:
 |  
 |  __init__(self, *args, **kwargs)
 |  
 |  __setitem__(self, key, value)
 |  
 |  force_clean(self, caller=True)
 |      Attempts to convert to graph_objs and call force_clean() on values.
 |      
 |      Calling force_clean() on a PlotlyDict will ensure that the object is
 |      valid and may be sent to plotly. This process will also remove any
 |      entries that end up with a length == 0.
 |      
 |      Careful! This will delete any invalid entries *silently*.
 |  
 |  get_data(self)
 |      Returns the JSON for the plot with non-data elements stripped.
 |  
 |  get_ordered(self, caller=True)
 |  
 |  strip_style(self)
 |      Strip style from the current representation.
 |      
 |      All PlotlyDicts and PlotlyLists are guaranteed to survive the
 |      stripping process, though they made be left empty. This is allowable.
 |      
 |      Keys that will be stripped in this process are tagged with
 |      `'type': 'style'` in graph_objs_meta.json.
 |      
 |      This process first attempts to convert nested collections from dicts
 |      or lists to subclasses of PlotlyList/PlotlyDict. This process forces
 |      a validation, which may throw exceptions.
 |      
 |      Then, each of these objects call `strip_style` on themselves and so
 |      on, recursively until the entire structure has been validated and
 |      stripped.
 |  
 |  to_graph_objs(self, caller=True)
 |      Walk obj, convert dicts and lists to plotly graph objs.
 |      
 |      For each key in the object, if it corresponds to a special key that
 |      should be associated with a graph object, the ordinary dict or list
 |      will be reinitialized as a special PlotlyDict or PlotlyList of the
 |      appropriate `kind`.
 |  
 |  to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80)
 |      Returns a formatted string showing graph_obj constructors.
 |      
 |      Example:
 |      
 |          print(obj.to_string())
 |      
 |      Keyword arguments:
 |      level (default = 0) -- set number of indentations to start with
 |      indent (default = 4) -- set indentation amount
 |      eol (default = '\n') -- set end of line character(s)
 |      pretty (default = True) -- curtail long list output with a '...'
 |      max_chars (default = 80) -- set max characters per line
 |  
 |  update(self, dict1=None, **dict2)
 |      Update current dict with dict1 and then dict2.
 |      
 |      This recursively updates the structure of the original dictionary-like
 |      object with the new entries in the second and third objects. This
 |      allows users to update with large, nested structures.
 |      
 |      Note, because the dict2 packs up all the keyword arguments, you can
 |      specify the changes as a list of keyword agruments.
 |      
 |      Examples:
 |      # update with dict
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      update_dict = dict(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj.update(update_dict)
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      # update with list of keyword arguments
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      obj.update(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      This 'fully' supports duck-typing in that the call signature is
 |      identical, however this differs slightly from the normal update
 |      method provided by Python's dictionaries.
 |  
 |  validate(self, caller=True)
 |      Recursively check the validity of the keys in a PlotlyDict.
 |      
 |      The valid keys constitute the entries in each object
 |      dictionary in graph_objs_meta.json
 |      
 |      The validation process first requires that all nested collections be
 |      converted to the appropriate subclass of PlotlyDict/PlotlyList. Then,
 |      each of these objects call `validate` and so on, recursively,
 |      until the entire object has been validated.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from PlotlyDict:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from __builtin__.dict:
 |  
 |  __cmp__(...)
 |      x.__cmp__(y) <==> cmp(x,y)
 |  
 |  __contains__(...)
 |      D.__contains__(k) -> True if D has a key k, else False
 |  
 |  __delitem__(...)
 |      x.__delitem__(y) <==> del x[y]
 |  
 |  __eq__(...)
 |      x.__eq__(y) <==> x==y
 |  
 |  __ge__(...)
 |      x.__ge__(y) <==> x>=y
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __getitem__(...)
 |      x.__getitem__(y) <==> x[y]
 |  
 |  __gt__(...)
 |      x.__gt__(y) <==> x>y
 |  
 |  __iter__(...)
 |      x.__iter__() <==> iter(x)
 |  
 |  __le__(...)
 |      x.__le__(y) <==> x<=y
 |  
 |  __len__(...)
 |      x.__len__() <==> len(x)
 |  
 |  __lt__(...)
 |      x.__lt__(y) <==> x<y
 |  
 |  __ne__(...)
 |      x.__ne__(y) <==> x!=y
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __sizeof__(...)
 |      D.__sizeof__() -> size of D in memory, in bytes
 |  
 |  clear(...)
 |      D.clear() -> None.  Remove all items from D.
 |  
 |  copy(...)
 |      D.copy() -> a shallow copy of D
 |  
 |  fromkeys(...)
 |      dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
 |      v defaults to None.
 |  
 |  get(...)
 |      D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
 |  
 |  has_key(...)
 |      D.has_key(k) -> True if D has a key k, else False
 |  
 |  items(...)
 |      D.items() -> list of D's (key, value) pairs, as 2-tuples
 |  
 |  iteritems(...)
 |      D.iteritems() -> an iterator over the (key, value) items of D
 |  
 |  iterkeys(...)
 |      D.iterkeys() -> an iterator over the keys of D
 |  
 |  itervalues(...)
 |      D.itervalues() -> an iterator over the values of D
 |  
 |  keys(...)
 |      D.keys() -> list of D's keys
 |  
 |  pop(...)
 |      D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
 |      If key is not found, d is returned if given, otherwise KeyError is raised
 |  
 |  popitem(...)
 |      D.popitem() -> (k, v), remove and return some (key, value) pair as a
 |      2-tuple; but raise KeyError if D is empty.
 |  
 |  setdefault(...)
 |      D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
 |  
 |  values(...)
 |      D.values() -> list of D's values
 |  
 |  viewitems(...)
 |      D.viewitems() -> a set-like object providing a view on D's items
 |  
 |  viewkeys(...)
 |      D.viewkeys() -> a set-like object providing a view on D's keys
 |  
 |  viewvalues(...)
 |      D.viewvalues() -> an object providing a view on D's values
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from __builtin__.dict:
 |  
 |  __hash__ = None
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T

Contour lines are smoothed by default, corresponding to 'smoothing': 1 in Line. Set 'smoothing' to a value larger than 1 to smooth the contours more and to a value between 0 and 1 to for less smoothing.

Now, fill in a contour object with our data:

In [45]:
cbar_title = "Daily cyclist count per site"

# Make a colorbar object
colorbar = ColorBar(
    title=cbar_title,    # set colorbar title
    titleside='right',   # put colorbar title at right of colorbar
    thickness=30,        # colorbar thickness in px
    len=0.8,             # colorbar length in plot fraction
    ticks='outside'      # tick outside colorbar
)

trace1 = Contour(
    z=Z_dayXsite_in_order,  # 2D array a f(sites,dates)
    x=sites_in_order,       # sites on the x-axis
    y=dates_in_words,       # dates on the y-axis
    colorscale='Greens',    # choose a color scale from the pre-defined
    reversescale=True,       #   and reverse its order
    line=Line(
        smoothing=1.5,    # (!) contour smmothing, default is 1
        color='#999999',  # light grey contour lines, default is black
        width=1           # default is 0.5 
    ),
    colorbar=colorbar    # link colorbar object
)

# Make a data object
data = Data([trace1])

On to the layout,

In [46]:
width = 650    # plot width in px
height = 1000  # plot height in px

title = "Fig 5.3: Montral bike traffic daily progression<br>\
from the most trafficked site to the least in 2013<br>"  # plot's title

x_title = 'Sites [from the most trafficked to the least in 2013]' 

layout = Layout(
    title=title,  # plot's title
    font=Font(
        family='Raleway, sans-serif',  # global font 
        color='#635F5D'
    ),
    xaxis=XAxis(title=x_title),  # x-axis title
    yaxis=YAxis(
        autorange='reversed', # (!) start y-axis at top
        autotick=False,       # custom tick
        dtick=7               # 1 tick per week
    ),
    margin=Margin(b=120),      # increase bottom margin
    annotations=Annotations([  # add annotation citing the data source
        make_anno()
    ]),
    autosize=False,  # custom size
    height=height,   # set plot's height      
    width=width      # set plot's width
) 

Get a Plotly plot:

In [47]:
# Make figure object
fig = Figure(data=data, layout=layout)
    
# (@) Send figure object and show result in notebook
py.iplot(fig, filename='s5_cyclist-time-progression', width=width, height=height) 

# adjust output frame size with 'width' and 'height'
Out[47]:

Traffic progressions are noticeable in April, but overall all counter sites got busier at the same time.

The above contour plot contains information about all counter totals between April and September for all 8 sites. Hovering over the contours reveals each daily cyclist count, which on a static figure would be impossible. This is just another example of how Plotly makes graphing come alive.

5.4 Joint daily traffic probability distribution for 2 sites

Our upcoming plot will evaluate the probability distribution of daily cyclist counts at two different sites simultaneously using 2-dimensional histograms. To make things insteresting we choose the two least correlated counter sites.

Roughly speaking, 2-dimensional histograms present the likelihood of two event happening of the same time. In our case, the two events are site 1 getting x cyclists in a day and site 2 getting y cyclists during the same day.

As for 1-dimensional histograms (more in section 4), Plotly does the computations for you. All you need to input are the two samples corresponding to the variables of interest (e.g. the daily cyclist count at each site).

In [48]:
help(Histogram2d)  # call help!
Help on class Histogram2d in module plotly.graph_objs.graph_objs:

class Histogram2d(PlotlyTrace)
 |  A dictionary-like object for representing a 2D histogram trace in plotly.
 |  
 |  Example:
 |  
 |      >>> import numpy as np
 |      >>> x = np.random.randn(500)
 |      >>> y = np.random.randn(500)+1
 |      >>> py.iplot([Histogram2d(x=x, y=y)])
 |  
 |  Online example:
 |  
 |      https://plot.ly/python/2D-Histograms/
 |  
 |  Quick method reference:
 |  
 |      Histogram2d.update(changes)
 |      Histogram2d.strip_style()
 |      Histogram2d.get_data()
 |      Histogram2d.to_graph_objs()
 |      Histogram2d.validate()
 |      Histogram2d.to_string()
 |      Histogram2d.force_clean()
 |  
 |  Valid keys:
 |  
 |      x [required=True] (value=list or 1d numpy array of numbers, strings,
 |      datetimes) (streamable):
 |          Sets the data sample to be binned on the x-axis and whose
 |          distribution (computed by Plotly) will correspond to the
 |          x-coordinates of this 2D histogram trace.
 |  
 |      y [required=True] (value=list or 1d numpy array of numbers, strings,
 |      datetimes) (streamable):
 |          Sets the data sample to be binned on the y-axis and whose
 |          distribution (computed by Plotly) will correspond to the
 |          y-coordinates of this 2D histogram trace.
 |  
 |      histnorm [required=False] (value='' | 'percent' | 'probability' |
 |      'density' | 'probability density'):
 |          Sets the type of normalization for this histogram trace. By default
 |          ('histnorm' set to '') the height of each bar displays the frequency
 |          of occurrence, i.e., the number of times this value was found in the
 |          corresponding bin. If set to 'percent', the height of each bar
 |          displays the percentage of total occurrences found within the
 |          corresponding bin. If set to 'probability', the height of each bar
 |          displays the probability that an event will fall into the
 |          corresponding bin. If set to 'density', the height of each bar is
 |          equal to the number of occurrences in a bin divided by the size of
 |          the bin interval such that summing the area of all bins will yield
 |          the total number of occurrences. If set to 'probability density',
 |          the height of each bar is equal to the number of probability that an
 |          event will fall into the corresponding bin divided by the size of
 |          the bin interval such that summing the area of all bins will yield
 |          1.
 |  
 |      histfunc [required=False] (value='count' | 'sum' | 'avg' | 'min' |
 |      'max'):
 |          Sets the binning function used for this histogram trace. The default
 |          value is 'count' where the histogram values are computed by counting
 |          the number of values lying inside each bin. With 'histfunc' set to
 |          'sum', 'avg', 'min' or 'max', the histogram values are computed
 |          using the sum, the average, the minimum or the 'maximum' of the
 |          values lying inside each bin respectively.
 |  
 |      name [required=False] (value=a string):
 |          The label associated with this trace. This name will appear in the
 |          legend, on hover and in the column header in the online spreadsheet.
 |  
 |      autobinx [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the x-axis bin parameters are picked
 |          automatically by Plotly. Once 'autobinx' is set to False, the x-axis
 |          bins parameters can be declared in 'xbins' object.
 |  
 |      nbinsx [required=False] (value=number: x > 0):
 |          Specifies the number of x-axis bins. No need to set 'autobinx' to
 |          False for 'nbinsx' to apply.
 |  
 |      xbins [required=False] (value=XBins object | dictionary-like object):
 |          Links a dictionary-like object defining the parameters of x-axis
 |          bins of this trace, for example, the bin width and the bins'
 |          starting and  ending value. Has an effect only if 'autobinx' is set
 |          to False.
 |  
 |          For more, run `help(plotly.graph_objs.XBins)`
 |  
 |      autobiny [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the y-axis bin parameters are picked
 |          automatically by Plotly. Once 'autobiny' is set to False, the y-axis
 |          bins parameters can be declared in 'ybins' object.
 |  
 |      nbinsy [required=False] (value=number: x > 0):
 |          Specifies the number of y-axis bins. No need to set 'autobiny' to
 |          False for 'nbinsy' to apply.
 |  
 |      ybins [required=False] (value=YBins object | dictionary-like object):
 |          Links a dictionary-like object defining the parameters of y-axis
 |          bins of this trace, for example, the bin width and the bins'
 |          starting and  ending value. Has an effect only if 'autobiny' is set
 |          to False.
 |  
 |          For more, run `help(plotly.graph_objs.YBins)`
 |  
 |      colorscale [required=False] (value=list or 1d numpy array of value-color
 |      pairs | 'Greys' | 'Greens' | 'Bluered' | 'Hot' | 'Picnic' | 'Portland' |
 |      'Jet' | 'RdBu' | 'Blackbody' | 'Earth' | 'Electric' | 'YIOrRd' |
 |      'YIGnBu'):
 |          Sets and/or defines the color scale for this trace. The string
 |          values are pre-defined color scales. For custom color scales, define
 |          a list or 1d numpy array of value-color pairs where, the first
 |          element of the pair corresponds to a normalized value of z from 0-1,
 |          i.e. (z-zmin)/ (zmax-zmin), and the second element of pair
 |          corresponds to a color. Use with 'zauto', 'zmin' and 'zmax to fine-
 |          tune the map from 'z' to rendered colors.
 |  
 |          Examples:
 |              'Greys' | [[0, 'rgb(0,0,0)'], [0.5, 'rgb(65, 182, 196)'], [1,
 |              'rgb(255,255,255)']]
 |  
 |      reversescale [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the color scale will be reversed.
 |  
 |      showscale [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the color scale associated with this mapping
 |          will be shown alongside the figure.
 |  
 |      colorbar [required=False] (value=ColorBar object | dictionary-like
 |      object):
 |          Links a dictionary-like object defining the parameters of the color
 |          bar associated with this trace (including its title, length and
 |          width).
 |  
 |          For more, run `help(plotly.graph_objs.ColorBar)`
 |  
 |      zauto [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the default values of 'zmax' and 'zmax' can be
 |          overwritten.
 |  
 |      zmin [required=False] (value=number):
 |          Sets the minimum 'z' data value to be resolved by the color scale.
 |          Its default value is the minimum of the 'z' data values. This value
 |          will be used as the minimum in the color scale normalization. For
 |          more info see 'colorscale'.
 |  
 |      zmax [required=False] (value=number):
 |          Sets the maximum 'z' data value to be resolved by the color scale.
 |          Its default value is the maximum of the 'z' data values. This value
 |          will be used as the maximum in the color scale normalization. For
 |          more info see 'colorscale'.
 |  
 |      zsmooth [required=False] (value=False | 'best' | 'fast'):
 |          Choose between algorithms ('best' or 'fast') to smooth data linked
 |          to 'z'. The default value is False corresponding to no smoothing.
 |  
 |      opacity [required=False] (value=number: x in [0, 1]):
 |          Sets the opacity, or transparency, of the entire object, also known
 |          as the alpha channel of colors. If the object's color is given in
 |          terms of 'rgba' color model, 'opacity' is redundant.
 |  
 |      xaxis [required=False] (value='x1' | 'x2' | 'x3' | etc.):
 |          This key determines which x-axis the x-coordinates of this trace
 |          will reference in the figure.  Values 'x1' and 'x' reference to
 |          'xaxis' in 'layout', 'x2' references to 'xaxis2' in 'layout', and so
 |          on. Note that 'x1' will always refer to 'xaxis' or 'xaxis1' in
 |          'layout', they are the same.
 |  
 |      yaxis [required=False] (value='y1' | 'y2' | 'y3' | etc.):
 |          This key determines which y-axis the y-coordinates of this trace
 |          will reference in the figure.  Values 'y1' and 'y' reference to
 |          'yaxis' in 'layout', 'y2' references to 'yaxis2' in 'layout', and so
 |          on. Note that 'y1' will always refer to 'yaxis' or 'yaxis1' in
 |          'layout', they are the same.
 |  
 |      showlegend [required=False] (value=a boolean: True | False):
 |          Toggle whether or not this trace will be labeled in the legend.
 |  
 |      stream [required=False] (value=Stream object | dictionary-like object):
 |          Links a dictionary-like object that initializes this trace as a
 |          writable-stream, for use with the streaming API.
 |  
 |          For more, run `help(plotly.graph_objs.Stream)`
 |  
 |      visible [required=False] (value=a boolean: True | False):
 |          Toggles whether or not this object will be visible on the rendered
 |          figure.
 |  
 |      xsrc [required=True] (value=a string equal to the unique identifier of a
 |      plotly grid column) (streamable):
 |          Sets the data sample to be binned on the x-axis and whose
 |          distribution (computed by Plotly) will correspond to the
 |          x-coordinates of this 2D histogram trace.
 |  
 |      ysrc [required=True] (value=a string equal to the unique identifier of a
 |      plotly grid column) (streamable):
 |          Sets the data sample to be binned on the y-axis and whose
 |          distribution (computed by Plotly) will correspond to the
 |          y-coordinates of this 2D histogram trace.
 |  
 |      type [required=False] (value='histogram2d'):
 |          Plotly identifier for this data's trace type.
 |  
 |  Method resolution order:
 |      Histogram2d
 |      PlotlyTrace
 |      PlotlyDict
 |      __builtin__.dict
 |      __builtin__.object
 |  
 |  Methods inherited from PlotlyTrace:
 |  
 |  __init__(self, *args, **kwargs)
 |  
 |  to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80)
 |      Returns a formatted string showing graph_obj constructors.
 |      
 |      Example:
 |      
 |          print(obj.to_string())
 |      
 |      Keyword arguments:
 |      level (default = 0) -- set number of indentations to start with
 |      indent (default = 4) -- set indentation amount
 |      eol (default = '\n') -- set end of line character(s)
 |      pretty (default = True) -- curtail long list output with a '...'
 |      max_chars (default = 80) -- set max characters per line
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from PlotlyDict:
 |  
 |  __setitem__(self, key, value)
 |  
 |  force_clean(self, caller=True)
 |      Attempts to convert to graph_objs and call force_clean() on values.
 |      
 |      Calling force_clean() on a PlotlyDict will ensure that the object is
 |      valid and may be sent to plotly. This process will also remove any
 |      entries that end up with a length == 0.
 |      
 |      Careful! This will delete any invalid entries *silently*.
 |  
 |  get_data(self)
 |      Returns the JSON for the plot with non-data elements stripped.
 |  
 |  get_ordered(self, caller=True)
 |  
 |  strip_style(self)
 |      Strip style from the current representation.
 |      
 |      All PlotlyDicts and PlotlyLists are guaranteed to survive the
 |      stripping process, though they made be left empty. This is allowable.
 |      
 |      Keys that will be stripped in this process are tagged with
 |      `'type': 'style'` in graph_objs_meta.json.
 |      
 |      This process first attempts to convert nested collections from dicts
 |      or lists to subclasses of PlotlyList/PlotlyDict. This process forces
 |      a validation, which may throw exceptions.
 |      
 |      Then, each of these objects call `strip_style` on themselves and so
 |      on, recursively until the entire structure has been validated and
 |      stripped.
 |  
 |  to_graph_objs(self, caller=True)
 |      Walk obj, convert dicts and lists to plotly graph objs.
 |      
 |      For each key in the object, if it corresponds to a special key that
 |      should be associated with a graph object, the ordinary dict or list
 |      will be reinitialized as a special PlotlyDict or PlotlyList of the
 |      appropriate `kind`.
 |  
 |  update(self, dict1=None, **dict2)
 |      Update current dict with dict1 and then dict2.
 |      
 |      This recursively updates the structure of the original dictionary-like
 |      object with the new entries in the second and third objects. This
 |      allows users to update with large, nested structures.
 |      
 |      Note, because the dict2 packs up all the keyword arguments, you can
 |      specify the changes as a list of keyword agruments.
 |      
 |      Examples:
 |      # update with dict
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      update_dict = dict(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj.update(update_dict)
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      # update with list of keyword arguments
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      obj.update(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      This 'fully' supports duck-typing in that the call signature is
 |      identical, however this differs slightly from the normal update
 |      method provided by Python's dictionaries.
 |  
 |  validate(self, caller=True)
 |      Recursively check the validity of the keys in a PlotlyDict.
 |      
 |      The valid keys constitute the entries in each object
 |      dictionary in graph_objs_meta.json
 |      
 |      The validation process first requires that all nested collections be
 |      converted to the appropriate subclass of PlotlyDict/PlotlyList. Then,
 |      each of these objects call `validate` and so on, recursively,
 |      until the entire object has been validated.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from PlotlyDict:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from __builtin__.dict:
 |  
 |  __cmp__(...)
 |      x.__cmp__(y) <==> cmp(x,y)
 |  
 |  __contains__(...)
 |      D.__contains__(k) -> True if D has a key k, else False
 |  
 |  __delitem__(...)
 |      x.__delitem__(y) <==> del x[y]
 |  
 |  __eq__(...)
 |      x.__eq__(y) <==> x==y
 |  
 |  __ge__(...)
 |      x.__ge__(y) <==> x>=y
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __getitem__(...)
 |      x.__getitem__(y) <==> x[y]
 |  
 |  __gt__(...)
 |      x.__gt__(y) <==> x>y
 |  
 |  __iter__(...)
 |      x.__iter__() <==> iter(x)
 |  
 |  __le__(...)
 |      x.__le__(y) <==> x<=y
 |  
 |  __len__(...)
 |      x.__len__() <==> len(x)
 |  
 |  __lt__(...)
 |      x.__lt__(y) <==> x<y
 |  
 |  __ne__(...)
 |      x.__ne__(y) <==> x!=y
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __sizeof__(...)
 |      D.__sizeof__() -> size of D in memory, in bytes
 |  
 |  clear(...)
 |      D.clear() -> None.  Remove all items from D.
 |  
 |  copy(...)
 |      D.copy() -> a shallow copy of D
 |  
 |  fromkeys(...)
 |      dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
 |      v defaults to None.
 |  
 |  get(...)
 |      D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
 |  
 |  has_key(...)
 |      D.has_key(k) -> True if D has a key k, else False
 |  
 |  items(...)
 |      D.items() -> list of D's (key, value) pairs, as 2-tuples
 |  
 |  iteritems(...)
 |      D.iteritems() -> an iterator over the (key, value) items of D
 |  
 |  iterkeys(...)
 |      D.iterkeys() -> an iterator over the keys of D
 |  
 |  itervalues(...)
 |      D.itervalues() -> an iterator over the values of D
 |  
 |  keys(...)
 |      D.keys() -> list of D's keys
 |  
 |  pop(...)
 |      D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
 |      If key is not found, d is returned if given, otherwise KeyError is raised
 |  
 |  popitem(...)
 |      D.popitem() -> (k, v), remove and return some (key, value) pair as a
 |      2-tuple; but raise KeyError if D is empty.
 |  
 |  setdefault(...)
 |      D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
 |  
 |  values(...)
 |      D.values() -> list of D's values
 |  
 |  viewitems(...)
 |      D.viewitems() -> a set-like object providing a view on D's items
 |  
 |  viewkeys(...)
 |      D.viewkeys() -> a set-like object providing a view on D's keys
 |  
 |  viewvalues(...)
 |      D.viewvalues() -> an object providing a view on D's values
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from __builtin__.dict:
 |  
 |  __hash__ = None
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T

The style keys in Histogram2d are the same as in Heatmap.

First, find the two least correlated sites using the correlation matrix Corr_site computed in subsection 5.2:

In [49]:
# Get 2D index (as a tuple) of the least correlated sites 
ind_least_corr = np.unravel_index(Corr_site.argmin(), Corr_site.shape)

# Get 1st site, remove <br> tag from string
site1 = sites[ind_least_corr[0]].replace('<br>', '')
z_day1 = Z_dayXsite[:, ind_least_corr[0]]

# And similarly for the 2nd site, remove <br> tag from string
site2 = sites[ind_least_corr[1]].replace('<br>', ' ')
z_day2 = Z_dayXsite[:, ind_least_corr[1]]
In [50]:
site1, site2  # show 2 least-correlated sites
Out[50]:
('du Parc/Duluth', 'Pierre-Dupuy (Habitat 67)')

Our plot will feature custom axes ranges and bin sizes.

So, let's get an idea of the range of each sample:

In [51]:
z_day1.max(), z_day2.max()
Out[51]:
(4103, 4841)

For presentation purposes, the axes' and bins' upper limits will be rounded up to 5000.

Moreover, we will smooth the counters using 'zsmooth key in Histogram2d and overlay scatter points of both two sites' daily cyclist counts, plotted against each other. Each scatter point will be label by the date using dates_in_words list defined in subsection 5.3.

In [52]:
# Select axis and bin range and bin size
xy_range = [0,5000]
bin_size = 500

# Define a dictionary of bins specification 
bins = dict(
    start=xy_range[0],
    end=xy_range[1], 
    size=bin_size
)

cbar_title='Number of occurences from Apr 1 to Aug 31'  # colorbar title

# Make histogram2d object, no histogram normalization (the default)
trace1 = Histogram2d(
    x=z_day1,  # sample to be binned on the x-axis
    y=z_day2,  # sample to be binned on of the y-axis
    xbins=XBins(bins),  # link custom bine specs
    ybins=YBins(bins),  # link custom bin specs
    zsmooth='best',     # (!) apply smoothing to contours
    colorscale='Portland',  # choose a pre-defined color scale
    colorbar=ColorBar(
        title=cbar_title,   # set colorbar title
        titleside='right',  # put title right of colorbar
        ticks='outside'     # put ticks outside colorbar
    )
)

# Make a scatter object
trace2 = Scatter(
    x=z_day1,  # x coordinates
    y=z_day2,  # y coordinates
    mode='markers',  # just marker pts
    name='',         # no hover name
    text=dates_in_words,  # text label corresp. to date
    marker=Marker(
        size=5,           # set marker size (px)
        color='#e0e0e0'   # set marker color
    )
)

# Package two traces in data object, 
# (!) plot scatter on top of 2d histogram
data = Data([trace1, trace2])

On to the latyout:

In [53]:
title = 'Fig 5.4a: Joint frequency distribution<br>\
of daily cyclist counts at two Montreal sites in 2013'  # plot's title

x_title = 'Daily cyclist count at {}'.format(site1)  # x and y axis titles
y_title = 'Daily cyclist count at {}'.format(site2)

# Make a layout object
layout = Layout(
    title=title,  # set plot's title
    font=Font(
        family='PT Sans Narrow, sans-serif',  # global font
        size=13
    ),
    xaxis=XAxis(
        title=x_title,   # set x-axis title
        range=xy_range,  # x-axis range
        zeroline=False   # remove x=0 line
    ),
    yaxis=YAxis(
        title=y_title,   # y-axis title
        range=xy_range,  # y-axis range (same as x-axis)
        zeroline=False   # remove y=0 line
    ),
    annotations=Annotations([  # add annotation citing the data source
        make_anno()
    ]),
    showlegend=False,  # remove legend
    autosize=False,    # custom size
    width=650,         # set figure width 
    height=520         #  and height
)

Finally, package data and layout object into a figure object and send it to Plotly:

In [54]:
# Make figure object
fig = Figure(data=data, layout=layout)

# Define filename in relation to the sites chosen
filename = 's5_hist2d-sites-{}-{}'.format(*ind_least_corr)

# (@) Send figure object to Plotly, show result in notebook
py.iplot(fig, filename=filename)
Out[54]:
In [55]:
# Make figure object
fig = Figure(data=data, layout=layout)

# Define filename in relation to the sites chosen
filename = 's5_hist2d-sites-{}-{}'.format(*ind_least_corr)

# (@) Send figure object to Plotly, show result in notebook
py.iplot(fig, filename=filename)
Out[55]:

Notice that there are a few hotspots of probability. By hovering over the scatter points, we notice that the Pierre-Dupuy site gets most of its traffic during weekends and holidays.

Next, we add two subplots to the above figure showing 1D histograms of daily cyclist counts for each of the two counter site (i.e. their marginal distibutions).

From our current figure object, we first adjust the domains of the axes in place and add one x-axis and one y-axis:

In [56]:
# Adjust the existing axes
layout['xaxis'].update(domain=[0, 0.7])  # decrease domain of x-axis1 (norm. coord.)
layout['yaxis'].update(
    domain=[0, 0.7],  # decrease domain of y-axis1
    showgrid=False    # remove vertical grid lines
)

# Set up new axes
layout.update(xaxis2=XAxis(
    domain=[0.75, 1], # domain of x-axis2
    zeroline=False,   # remove x=0 line
    showgrid=True     # show horizontal grid line
))
layout.update(yaxis2=YAxis(
    domain=[0.75, 1], # domain of y-axis2
    zeroline=False,   # remove y=0 line
    showgrid=True     # show vertical line
))

Next, make two histogram objects (N.B. the 1D version) and append to the current data object:

In [57]:
hist_color="rgb(242,211,56)"  # pick a color for the bars

# Make an Histogram object with vertical bins and no normalization
trace3 = Histogram(
    x=z_day1,    # x sample, bind bins to x-axis
    name='',     # no name on hover
    xbins=XBins(bins),  # use same bins as in the 2D histogram 
    marker=Marker(color=hist_color), # choose bin color
    xaxis='x1',  # bind x coords to xaxis1
    yaxis='y2'   # bind y coords to yaxis2
)

# Make an Histogram object with horizontal bins and no normalization
trace4 = Histogram(
    y=z_day2,    # y sample, bind bins to y-axis
    name='',     # no name on hover
    ybins=YBins(bins),  # use same bins as in the 2D histogram
    marker=Marker(color=hist_color), # choose bin color
    xaxis='x2',  # bind x coords to xaxis2
    yaxis='y1'   # bind y coords to yaxis2
)

# Extend data object with the two 1d histogram traces
data.extend([trace3, trace4])

Tweak the colorbar's appearance, update the figure's titls and call Plotly:

In [58]:
# Update colorbar position, length and thickness
data[0]['colorbar'].update(
    x=0.99,
    y=0.35,
    len=0.7,
    thickness=20
)
                              
# Update title
title = 'Fig 5.4b: Joint frequency distribution<br>\
of daily cyclist counts at two Montreal sites in 2013'

layout.update(title=title)
In [59]:
# Make figure object
fig = Figure(data=data, layout=layout)

# Define filename in relation to the sites chosen
filename = 's5_hist2dsplt-sites-{}-{}'.format(*ind_least_corr)

# (@) Send figure object to Plotly, show result in notebook
py.iplot(fig, filename=filename)
Out[59]:

The axes are shared (try zooming on the 2D histogram). It is interesting to see that the distribution of the Pierre Dupuy site is much more skewed than Parc/Duluth.

Plotly allows users to plot 2D histograms of similar in appearance to ones generated by the Contour graph object using Histogram2dContour,

In [60]:
help(Histogram2dContour)  # call help!
Help on class Histogram2dContour in module plotly.graph_objs.graph_objs:

class Histogram2dContour(PlotlyTrace)
 |  A dictionary-like object for representing a 2D histogram contour trace in
 |      plotly.
 |  
 |  Example:
 |  
 |      >>> import numpy as np
 |      >>> x = np.random.randn(500)
 |      >>> y = np.random.randn(500)+1
 |      >>> py.iplot([Histogram2dContour(x=x, y=y)])
 |  
 |  Online example:
 |  
 |      https://plot.ly/python/2D-Histograms/
 |  
 |  Quick method reference:
 |  
 |      Histogram2dContour.update(changes)
 |      Histogram2dContour.strip_style()
 |      Histogram2dContour.get_data()
 |      Histogram2dContour.to_graph_objs()
 |      Histogram2dContour.validate()
 |      Histogram2dContour.to_string()
 |      Histogram2dContour.force_clean()
 |  
 |  Valid keys:
 |  
 |      x [required=True] (value=list or 1d numpy array of numbers, strings,
 |      datetimes) (streamable):
 |          Sets the data sample to be binned on the x-axis and whose
 |          distribution (computed by Plotly) will correspond to the
 |          x-coordinates of this 2D histogram trace.
 |  
 |      y [required=True] (value=list or 1d numpy array of numbers, strings,
 |      datetimes) (streamable):
 |          Sets the data sample to be binned on the y-axis and whose
 |          distribution (computed by Plotly) will correspond to the
 |          y-coordinates of this 2D histogram trace.
 |  
 |      histnorm [required=False] (value='' | 'percent' | 'probability' |
 |      'density' | 'probability density'):
 |          Sets the type of normalization for this histogram trace. By default
 |          ('histnorm' set to '') the height of each bar displays the frequency
 |          of occurrence, i.e., the number of times this value was found in the
 |          corresponding bin. If set to 'percent', the height of each bar
 |          displays the percentage of total occurrences found within the
 |          corresponding bin. If set to 'probability', the height of each bar
 |          displays the probability that an event will fall into the
 |          corresponding bin. If set to 'density', the height of each bar is
 |          equal to the number of occurrences in a bin divided by the size of
 |          the bin interval such that summing the area of all bins will yield
 |          the total number of occurrences. If set to 'probability density',
 |          the height of each bar is equal to the number of probability that an
 |          event will fall into the corresponding bin divided by the size of
 |          the bin interval such that summing the area of all bins will yield
 |          1.
 |  
 |      histfunc [required=False] (value='count' | 'sum' | 'avg' | 'min' |
 |      'max'):
 |          Sets the binning function used for this histogram trace. The default
 |          value is 'count' where the histogram values are computed by counting
 |          the number of values lying inside each bin. With 'histfunc' set to
 |          'sum', 'avg', 'min' or 'max', the histogram values are computed
 |          using the sum, the average, the minimum or the 'maximum' of the
 |          values lying inside each bin respectively.
 |  
 |      name [required=False] (value=a string):
 |          The label associated with this trace. This name will appear in the
 |          legend, on hover and in the column header in the online spreadsheet.
 |  
 |      autobinx [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the x-axis bin parameters are picked
 |          automatically by Plotly. Once 'autobinx' is set to False, the x-axis
 |          bins parameters can be declared in 'xbins' object.
 |  
 |      nbinsx [required=False] (value=number: x > 0):
 |          Specifies the number of x-axis bins. No need to set 'autobinx' to
 |          False for 'nbinsx' to apply.
 |  
 |      xbins [required=False] (value=XBins object | dictionary-like object):
 |          Links a dictionary-like object defining the parameters of x-axis
 |          bins of this trace, for example, the bin width and the bins'
 |          starting and  ending value. Has an effect only if 'autobinx' is set
 |          to False.
 |  
 |          For more, run `help(plotly.graph_objs.XBins)`
 |  
 |      autobiny [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the y-axis bin parameters are picked
 |          automatically by Plotly. Once 'autobiny' is set to False, the y-axis
 |          bins parameters can be declared in 'ybins' object.
 |  
 |      nbinsy [required=False] (value=number: x > 0):
 |          Specifies the number of y-axis bins. No need to set 'autobiny' to
 |          False for 'nbinsy' to apply.
 |  
 |      ybins [required=False] (value=YBins object | dictionary-like object):
 |          Links a dictionary-like object defining the parameters of y-axis
 |          bins of this trace, for example, the bin width and the bins'
 |          starting and  ending value. Has an effect only if 'autobiny' is set
 |          to False.
 |  
 |          For more, run `help(plotly.graph_objs.YBins)`
 |  
 |      autocontour [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the contour parameters are picked
 |          automatically by Plotly. If False, declare the contours parameters
 |          in 'contours'.
 |  
 |      ncontours [required=False] (value=number: x > 1):
 |          Specifies the number of contours lines in the contour plot. No need
 |          to set 'autocontour' to False for 'ncontours' to apply.
 |  
 |      contours [required=False] (value=Contours object | dictionary-like
 |      object):
 |          Links a dictionary-like object defining the parameters of the
 |          contours of this trace.
 |  
 |          For more, run `help(plotly.graph_objs.Contours)`
 |  
 |      line [required=False] (value=Line object | dictionary-like object)
 |      (streamable):
 |          Links a dictionary-like object containing line parameters for
 |          contour lines of this contour trace (including line width, dash,
 |          color and smoothing level). Has no an effect if 'showlines' is set
 |          to False in 'contours'.
 |  
 |          For more, run `help(plotly.graph_objs.Line)`
 |  
 |      colorscale [required=False] (value=list or 1d numpy array of value-color
 |      pairs | 'Greys' | 'Greens' | 'Bluered' | 'Hot' | 'Picnic' | 'Portland' |
 |      'Jet' | 'RdBu' | 'Blackbody' | 'Earth' | 'Electric' | 'YIOrRd' |
 |      'YIGnBu'):
 |          Sets and/or defines the color scale for this trace. The string
 |          values are pre-defined color scales. For custom color scales, define
 |          a list or 1d numpy array of value-color pairs where, the first
 |          element of the pair corresponds to a normalized value of z from 0-1,
 |          i.e. (z-zmin)/ (zmax-zmin), and the second element of pair
 |          corresponds to a color. Use with 'zauto', 'zmin' and 'zmax to fine-
 |          tune the map from 'z' to rendered colors.
 |  
 |          Examples:
 |              'Greys' | [[0, 'rgb(0,0,0)'], [0.5, 'rgb(65, 182, 196)'], [1,
 |              'rgb(255,255,255)']]
 |  
 |      reversescale [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the color scale will be reversed.
 |  
 |      showscale [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the color scale associated with this mapping
 |          will be shown alongside the figure.
 |  
 |      colorbar [required=False] (value=ColorBar object | dictionary-like
 |      object):
 |          Links a dictionary-like object defining the parameters of the color
 |          bar associated with this trace (including its title, length and
 |          width).
 |  
 |          For more, run `help(plotly.graph_objs.ColorBar)`
 |  
 |      zauto [required=False] (value=a boolean: True | False):
 |          Toggle whether or not the default values of 'zmax' and 'zmax' can be
 |          overwritten.
 |  
 |      zmin [required=False] (value=number):
 |          Sets the minimum 'z' data value to be resolved by the color scale.
 |          Its default value is the minimum of the 'z' data values. This value
 |          will be used as the minimum in the color scale normalization. For
 |          more info see 'colorscale'.
 |  
 |      zmax [required=False] (value=number):
 |          Sets the maximum 'z' data value to be resolved by the color scale.
 |          Its default value is the maximum of the 'z' data values. This value
 |          will be used as the maximum in the color scale normalization. For
 |          more info see 'colorscale'.
 |  
 |      opacity [required=False] (value=number: x in [0, 1]):
 |          Sets the opacity, or transparency, of the entire object, also known
 |          as the alpha channel of colors. If the object's color is given in
 |          terms of 'rgba' color model, 'opacity' is redundant.
 |  
 |      xaxis [required=False] (value='x1' | 'x2' | 'x3' | etc.):
 |          This key determines which x-axis the x-coordinates of this trace
 |          will reference in the figure.  Values 'x1' and 'x' reference to
 |          'xaxis' in 'layout', 'x2' references to 'xaxis2' in 'layout', and so
 |          on. Note that 'x1' will always refer to 'xaxis' or 'xaxis1' in
 |          'layout', they are the same.
 |  
 |      yaxis [required=False] (value='y1' | 'y2' | 'y3' | etc.):
 |          This key determines which y-axis the y-coordinates of this trace
 |          will reference in the figure.  Values 'y1' and 'y' reference to
 |          'yaxis' in 'layout', 'y2' references to 'yaxis2' in 'layout', and so
 |          on. Note that 'y1' will always refer to 'yaxis' or 'yaxis1' in
 |          'layout', they are the same.
 |  
 |      showlegend [required=False] (value=a boolean: True | False):
 |          Toggle whether or not this trace will be labeled in the legend.
 |  
 |      stream [required=False] (value=Stream object | dictionary-like object):
 |          Links a dictionary-like object that initializes this trace as a
 |          writable-stream, for use with the streaming API.
 |  
 |          For more, run `help(plotly.graph_objs.Stream)`
 |  
 |      visible [required=False] (value=a boolean: True | False):
 |          Toggles whether or not this object will be visible on the rendered
 |          figure.
 |  
 |      xsrc [required=True] (value=a string equal to the unique identifier of a
 |      plotly grid column) (streamable):
 |          Sets the data sample to be binned on the x-axis and whose
 |          distribution (computed by Plotly) will correspond to the
 |          x-coordinates of this 2D histogram trace.
 |  
 |      ysrc [required=True] (value=a string equal to the unique identifier of a
 |      plotly grid column) (streamable):
 |          Sets the data sample to be binned on the y-axis and whose
 |          distribution (computed by Plotly) will correspond to the
 |          y-coordinates of this 2D histogram trace.
 |  
 |      type [required=False] (value='histogram2dcontour'):
 |          Plotly identifier for this data's trace type.
 |  
 |  Method resolution order:
 |      Histogram2dContour
 |      PlotlyTrace
 |      PlotlyDict
 |      __builtin__.dict
 |      __builtin__.object
 |  
 |  Methods inherited from PlotlyTrace:
 |  
 |  __init__(self, *args, **kwargs)
 |  
 |  to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80)
 |      Returns a formatted string showing graph_obj constructors.
 |      
 |      Example:
 |      
 |          print(obj.to_string())
 |      
 |      Keyword arguments:
 |      level (default = 0) -- set number of indentations to start with
 |      indent (default = 4) -- set indentation amount
 |      eol (default = '\n') -- set end of line character(s)
 |      pretty (default = True) -- curtail long list output with a '...'
 |      max_chars (default = 80) -- set max characters per line
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from PlotlyDict:
 |  
 |  __setitem__(self, key, value)
 |  
 |  force_clean(self, caller=True)
 |      Attempts to convert to graph_objs and call force_clean() on values.
 |      
 |      Calling force_clean() on a PlotlyDict will ensure that the object is
 |      valid and may be sent to plotly. This process will also remove any
 |      entries that end up with a length == 0.
 |      
 |      Careful! This will delete any invalid entries *silently*.
 |  
 |  get_data(self)
 |      Returns the JSON for the plot with non-data elements stripped.
 |  
 |  get_ordered(self, caller=True)
 |  
 |  strip_style(self)
 |      Strip style from the current representation.
 |      
 |      All PlotlyDicts and PlotlyLists are guaranteed to survive the
 |      stripping process, though they made be left empty. This is allowable.
 |      
 |      Keys that will be stripped in this process are tagged with
 |      `'type': 'style'` in graph_objs_meta.json.
 |      
 |      This process first attempts to convert nested collections from dicts
 |      or lists to subclasses of PlotlyList/PlotlyDict. This process forces
 |      a validation, which may throw exceptions.
 |      
 |      Then, each of these objects call `strip_style` on themselves and so
 |      on, recursively until the entire structure has been validated and
 |      stripped.
 |  
 |  to_graph_objs(self, caller=True)
 |      Walk obj, convert dicts and lists to plotly graph objs.
 |      
 |      For each key in the object, if it corresponds to a special key that
 |      should be associated with a graph object, the ordinary dict or list
 |      will be reinitialized as a special PlotlyDict or PlotlyList of the
 |      appropriate `kind`.
 |  
 |  update(self, dict1=None, **dict2)
 |      Update current dict with dict1 and then dict2.
 |      
 |      This recursively updates the structure of the original dictionary-like
 |      object with the new entries in the second and third objects. This
 |      allows users to update with large, nested structures.
 |      
 |      Note, because the dict2 packs up all the keyword arguments, you can
 |      specify the changes as a list of keyword agruments.
 |      
 |      Examples:
 |      # update with dict
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      update_dict = dict(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj.update(update_dict)
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      # update with list of keyword arguments
 |      obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))
 |      obj.update(title='new title', xaxis=dict(domain=[0,.8]))
 |      obj
 |      {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}
 |      
 |      This 'fully' supports duck-typing in that the call signature is
 |      identical, however this differs slightly from the normal update
 |      method provided by Python's dictionaries.
 |  
 |  validate(self, caller=True)
 |      Recursively check the validity of the keys in a PlotlyDict.
 |      
 |      The valid keys constitute the entries in each object
 |      dictionary in graph_objs_meta.json
 |      
 |      The validation process first requires that all nested collections be
 |      converted to the appropriate subclass of PlotlyDict/PlotlyList. Then,
 |      each of these objects call `validate` and so on, recursively,
 |      until the entire object has been validated.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from PlotlyDict:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from __builtin__.dict:
 |  
 |  __cmp__(...)
 |      x.__cmp__(y) <==> cmp(x,y)
 |  
 |  __contains__(...)
 |      D.__contains__(k) -> True if D has a key k, else False
 |  
 |  __delitem__(...)
 |      x.__delitem__(y) <==> del x[y]
 |  
 |  __eq__(...)
 |      x.__eq__(y) <==> x==y
 |  
 |  __ge__(...)
 |      x.__ge__(y) <==> x>=y
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __getitem__(...)
 |      x.__getitem__(y) <==> x[y]
 |  
 |  __gt__(...)
 |      x.__gt__(y) <==> x>y
 |  
 |  __iter__(...)
 |      x.__iter__() <==> iter(x)
 |  
 |  __le__(...)
 |      x.__le__(y) <==> x<=y
 |  
 |  __len__(...)
 |      x.__len__() <==> len(x)
 |  
 |  __lt__(...)
 |      x.__lt__(y) <==> x<y
 |  
 |  __ne__(...)
 |      x.__ne__(y) <==> x!=y
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __sizeof__(...)
 |      D.__sizeof__() -> size of D in memory, in bytes
 |  
 |  clear(...)
 |      D.clear() -> None.  Remove all items from D.
 |  
 |  copy(...)
 |      D.copy() -> a shallow copy of D
 |  
 |  fromkeys(...)
 |      dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
 |      v defaults to None.
 |  
 |  get(...)
 |      D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
 |  
 |  has_key(...)
 |      D.has_key(k) -> True if D has a key k, else False
 |  
 |  items(...)
 |      D.items() -> list of D's (key, value) pairs, as 2-tuples
 |  
 |  iteritems(...)
 |      D.iteritems() -> an iterator over the (key, value) items of D
 |  
 |  iterkeys(...)
 |      D.iterkeys() -> an iterator over the keys of D
 |  
 |  itervalues(...)
 |      D.itervalues() -> an iterator over the values of D
 |  
 |  keys(...)
 |      D.keys() -> list of D's keys
 |  
 |  pop(...)
 |      D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
 |      If key is not found, d is returned if given, otherwise KeyError is raised
 |  
 |  popitem(...)
 |      D.popitem() -> (k, v), remove and return some (key, value) pair as a
 |      2-tuple; but raise KeyError if D is empty.
 |  
 |  setdefault(...)
 |      D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
 |  
 |  values(...)
 |      D.values() -> list of D's values
 |  
 |  viewitems(...)
 |      D.viewitems() -> a set-like object providing a view on D's items
 |  
 |  viewkeys(...)
 |      D.viewkeys() -> a set-like object providing a view on D's keys
 |  
 |  viewvalues(...)
 |      D.viewvalues() -> an object providing a view on D's values
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from __builtin__.dict:
 |  
 |  __hash__ = None
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T

which shares the same style keys as Contour (more in subsection 5.3).

Colorbrewer color scales with Plotly

Next, we take a color scheme from the popular ColorBrewer website and convert it to Plotly syntax. Thanks to the colorbrewer Python package, ColorBrewer color schemes can be easily importing in a Python/IPython session. You can download the package using pip:

$ pip install colorbrewer

As we saw previously, a custom color scale in Plotly is simply a list of lists linked to the 'scl' key where the nested lists have the normalized level values as first item and the level colors as second item. So, consider the following function

In [61]:
import colorbrewer as cb  # (*) import colorbrewer
                          # (*) uses numpy as well

def convert_cb_to_scl(cb_color,N=5):
    '''
    cb_color (positional): colorbrewer color dictionary
    N (keyword): number of colors in color scale
    '''
    colors = cb_color[N]                   # get list of N color tuples from cb dict
    levels = np.linspace(0,1,N).tolist()   # get list of N levels 
    
    # Make color scale list of lists, conveting each tuple to 'rgb( , , )'
    scl_cb = []
    scl_cb += [[i, "rgb("+','.join(map(str,color))+")"] 
                for i,color in zip(levels,colors)]
    return scl_cb

Now, choose a color scheme on colorbrewer2.org. The names are listed near the EXPORT button in the middle of the page,

In [62]:
# Convert the Purples colorbrewer scale to Plotly syntax
scl_cb = convert_cb_to_scl(cb.Purples) 

and fill in an Histogram2dContour object. For this plot, color only the contour lines by setting 'coloring': 'lines' in Contours.

In [70]:
cbar_title = 'Number of occurences from Apr 1 to Aug 31'  # colorbar title

# Make Histogram2dContour object, with no hist. normalization (default)
trace1 = Histogram2dContour(
    x=z_day1,  # sample of the x-axis
    y=z_day2,  # sample of the y-axis
    xbins=XBins(bins),  # custom x-axis bins (as in fig 5.4a & 5.4b)
    ybins=YBins(bins),  # custom y-axis bins  
    colorscale=scl_cb,     # (!) colorbrewer color scale
    colorbar=ColorBar(
        title=cbar_title,   # set colorbar title
        titleside='right',  # place title below colorbar
        autotick=False,     # custom ticks & tick labels
        ticks=''            # no colorbar ticks 
    ),
    contours=Contours(coloring='lines'),  # (!) color only the lines
    line=Line(width=3)                    # (!) increse line width
)

data = Data([trace1])

With a similar layout to fig 5.4a:

In [71]:
title = 'Fig 5.4c: Joint frequency distribution<br>\
of daily cyclist counts at two Montreal sites in 2013'  # plot's title
x_title = 'Daily cyclist count at {}'.format(site1)     # x an y axis
y_title = 'Daily cyclist count at {}'.format(site2)     #  titles

# Make layout object
layout = Layout(
    title=title, # figure title
    font=Font(
        family='PT Sans Narrow, sans-serif',  # global font
        size=13
    ),
    xaxis=XAxis(
        title=x_title,    # set x-axis title
        range=xy_range,   # set x-axis range
        zeroline=False    # remove x=0 line
    ),
    yaxis=YAxis(
        title=y_title,    # set y-axis title 
        range=xy_range,   # set y-axis range (same as x-axis)
        zeroline=False    # remove y=0 line
    ),
    annotations=Annotations([  # make annotation citing the source
        make_anno()
    ]),
    showlegend=False,  # remove legend
    autosize=False,    # custom size
    width=650,         # figure width 
    height=520         #  and height
)

Finally, send the figure object to Plotly and get a plot:

In [72]:
# Make figure object
fig = Figure(data=data, layout=layout)

# Define filename in relation to the sites chosen
filename = 's5_hist2contour-sites-{}-{}'.format(*ind_least_corr)

# (@) Send figure object to Plotly, show result in notebook
py.iplot(fig, filename=filename)
Out[72]:



Go to [Section 6 --- Convert your Matplotlib plots to Plotly](https://plot.ly/python/matplotlib-to-plotly-tutorial)

Go to [Section 4 --- Histograms & Box Plots](https://plot.ly/python/histograms-and-box-plots-tutorial)

Go back to [top of page](https://plot.ly/python/heatmaps-contours-and-2dhistograms-tutorial#)

Go back to User Guide's [homepage](https://plot.ly/python/user-guide)


Got Questions or Feedback?

About Plotly

  • email: [email protected]
  • tweet: @plotlygraphs

About the User Guide

  • email: [email protected]
  • tweet: @etpinard

Notebook styling ideas

Big thanks to


In [66]:
# CSS styling within IPython notebook
from IPython.display import display, HTML
display(HTML(open('../custom.css').read()))