Gráficas interactivas con plotly

En un artículo anterior ya vimos como pasar las gráficas creadas con matplotlib a plotly para obtener cierto nivel de interacción con los datos en la web. Ahora, lo que vamos a ver es cómo crear gráficas directamente con plotly. Para ello vamos a utilizar:

  • pandas 0.14.1, para trabajar con tablas de datos.
  • plotly 1.2.6, para crear las gráficas.

Importamos los paquetes de la manera habitual en cada caso.


In [1]:
import pandas as pd
import plotly.plotly as py
from plotly.graph_objs import *

En el caso de Plotly hemos importado además unos objetos graph_objs que nos serán de ayuda a la hora de crear las gráficas. Trabajar con la API de Plotly en Python se resume en trabajar con listas y diccionarios de Python. Los graph_objs de Plotly nos ayudarán a trabajar con estas listas y diccionarios proporcionando ayuda y validando los datos y parámetros introducidos.

Entre los objetos que importamos tenemos los bloques principales de trabajo:

  • Figure, diccionario que representa la figura a representar en plotly.
  • Data, lista para englobar todos los trazos a representar en una gráfica, ya sean tipo Scatter, Heatmap, Box, etc.
  • Layout, diccionario que define los detalles de la disposición de la figura.

In [2]:
help(Figure)


Help on class Figure in module plotly.graph_objs.graph_objs:

class Figure(PlotlyDict)
 |  A dictionary-like object representing a figure to be rendered in plotly.
 |  
 |      This is the container for all things to be rendered in a figure.
 |  
 |      For help with setting up subplots, run:
 |      `help(plotly.tools.get_subplots)`
 |  
 |      
 |  Quick method reference:
 |  
 |      Figure.update(changes)
 |      Figure.strip_style()
 |      Figure.get_data()
 |      Figure.to_graph_objs()
 |      Figure.validate()
 |      Figure.to_string()
 |      Figure.force_clean()
 |  
 |  Valid keys:
 |  
 |      data [required=False] (value=Data object | array-like of one or several
 |      dictionaries):
 |          A list-like array of the data trace(s) that is/are to be visualized.
 |  
 |          For more, run `help(plotly.graph_objs.Data)`
 |  
 |      layout [required=False] (value=Layout object | dictionary-like):
 |          A dictionary-like object that contains the layout parameters (e.g.
 |          information about the axis, global settings and layout information
 |          related to the rendering of the figure).
 |  
 |          For more, run `help(plotly.graph_objs.Layout)`
 |  
 |  Method resolution order:
 |      Figure
 |      PlotlyDict
 |      builtins.dict
 |      builtins.object
 |  
 |  Methods defined here:
 |  
 |  __init__(self, *args, **kwargs)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from PlotlyDict:
 |  
 |  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 the INFO dictionary listed in graph_objs_meta.py.
 |      
 |      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 = '
 |      ') -- 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 INFO stored in graph_objs_meta.py.
 |      
 |      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 builtins.dict:
 |  
 |  __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)
 |  
 |  __setitem__(...)
 |      x.__setitem__(i, y) <==> x[i]=y
 |  
 |  __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.
 |  
 |  items(...)
 |      D.items() -> a set-like object providing a view on D's items
 |  
 |  keys(...)
 |      D.keys() -> a set-like object providing a view on 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() -> an object providing a view on D's values
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from builtins.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 [3]:
help(Data)


Help on class Data in module plotly.graph_objs.graph_objs:

class Data(PlotlyList)
 |  A list of traces to be shown on a plot/graph.
 |  
 |      Any operation that can be done with a standard list may be used with Data.
 |      Instantiation requires an iterable (just like list does), for example:
 |  
 |      Data([Scatter(), Heatmap(), Box()])
 |  
 |      Valid entry types: (dict or any subclass of Trace, i.e., Scatter, Box, etc.)
 |  
 |      
 |  Quick method reference:
 |  
 |      Data.update(changes)
 |      Data.strip_style()
 |      Data.get_data()
 |      Data.to_graph_objs()
 |      Data.validate()
 |      Data.to_string()
 |      Data.force_clean()
 |  
 |  Method resolution order:
 |      Data
 |      PlotlyList
 |      builtins.list
 |      builtins.object
 |  
 |  Methods defined here:
 |  
 |  to_graph_objs(self, caller=True)
 |      Change any nested collections to subclasses of PlotlyDict/List.
 |      
 |      Procedure:
 |          1. Attempt to convert all entries to a subclass of PlotlyTrace.
 |          2. Call `to_graph_objects` on each of these entries.
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from PlotlyList:
 |  
 |  __init__(self, *args)
 |  
 |  force_clean(self, caller=True)
 |      Attempts to convert to graph_objs and calls force_clean() on entries.
 |      
 |      Calling force_clean() on a PlotlyList will ensure that the object is
 |      valid and may be sent to plotly. This process will remove any entries
 |      that end up with a length == 0. It will also remove itself from
 |      enclosing trivial structures if it is enclosed by a collection with
 |      length 1, meaning the data is the ONLY object in the collection.
 |      
 |      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 the INFO dictionary listed in graph_objs_meta.py.
 |      
 |      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_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 = '
 |      ') -- 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, changes, make_copies=False)
 |      Update current list with changed_list, which must be iterable.
 |      The 'changes' should be a list of dictionaries, however,
 |      it is permitted to be a single dict object.
 |      
 |      Because mutable objects contain references to their values, updating
 |      multiple items in a list will cause the items to all reference the same
 |      original set of objects. To change this behavior add
 |      `make_copies=True` which makes deep copies of the update items and
 |      therefore break references.
 |  
 |  validate(self, caller=True)
 |      Recursively check the validity of the entries in a PlotlyList.
 |      
 |      PlotlyList may only contain suclasses of PlotlyDict, or dictionary-like
 |      objects that can be re-instantiated as subclasses of PlotlyDict.
 |      
 |      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 list has been validated.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from PlotlyList:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from builtins.list:
 |  
 |  __add__(...)
 |      x.__add__(y) <==> x+y
 |  
 |  __contains__(...)
 |      x.__contains__(y) <==> y in x
 |  
 |  __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
 |  
 |  __iadd__(...)
 |      x.__iadd__(y) <==> x+=y
 |  
 |  __imul__(...)
 |      x.__imul__(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
 |  
 |  __mul__(...)
 |      x.__mul__(n) <==> x*n
 |  
 |  __ne__(...)
 |      x.__ne__(y) <==> x!=y
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __reversed__(...)
 |      L.__reversed__() -- return a reverse iterator over the list
 |  
 |  __rmul__(...)
 |      x.__rmul__(n) <==> n*x
 |  
 |  __setitem__(...)
 |      x.__setitem__(i, y) <==> x[i]=y
 |  
 |  __sizeof__(...)
 |      L.__sizeof__() -- size of L in memory, in bytes
 |  
 |  append(...)
 |      L.append(object) -> None -- append object to end
 |  
 |  clear(...)
 |      L.clear() -> None -- remove all items from L
 |  
 |  copy(...)
 |      L.copy() -> list -- a shallow copy of L
 |  
 |  count(...)
 |      L.count(value) -> integer -- return number of occurrences of value
 |  
 |  extend(...)
 |      L.extend(iterable) -> None -- extend list by appending elements from the iterable
 |  
 |  index(...)
 |      L.index(value, [start, [stop]]) -> integer -- return first index of value.
 |      Raises ValueError if the value is not present.
 |  
 |  insert(...)
 |      L.insert(index, object) -- insert object before index
 |  
 |  pop(...)
 |      L.pop([index]) -> item -- remove and return item at index (default last).
 |      Raises IndexError if list is empty or index is out of range.
 |  
 |  remove(...)
 |      L.remove(value) -> None -- remove first occurrence of value.
 |      Raises ValueError if the value is not present.
 |  
 |  reverse(...)
 |      L.reverse() -- reverse *IN PLACE*
 |  
 |  sort(...)
 |      L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE*
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from builtins.list:
 |  
 |  __hash__ = None
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T


In [4]:
help(Layout)


Help on class Layout in module plotly.graph_objs.graph_objs:

class Layout(PlotlyDict)
 |  A dictionary-like object holding plot settings for plotly figures.
 |  
 |      
 |  Quick method reference:
 |  
 |      Layout.update(changes)
 |      Layout.strip_style()
 |      Layout.get_data()
 |      Layout.to_graph_objs()
 |      Layout.validate()
 |      Layout.to_string()
 |      Layout.force_clean()
 |  
 |  Valid keys:
 |  
 |      title [required=False] (value=string):
 |          The title of the figure.
 |  
 |      titlefont [required=False] (value=Font object | dictionary-like):
 |          A dictionary-like object describing the font settings of the
 |          figure's title.
 |  
 |          For more, run `help(plotly.graph_objs.Font)`
 |  
 |      font [required=False] (value=Font object | dictionary-like):
 |          A dictionary-like object describing the global font settings for
 |          this figure (e.g. all axis titles and labels).
 |  
 |          For more, run `help(plotly.graph_objs.Font)`
 |  
 |      showlegend [required=False] (value=boolean: True | False):
 |          Toggle whether or not the legend will be shown in this figure.
 |  
 |      autosize [required=False] (value=boolean: True | False):
 |          Toggle whether or not the dimensions of the figure are automatically
 |          picked by Plotly. Plotly picks figure's dimensions as a function of
 |          your machine's display resolution. Once 'autosize' is set to False,
 |          the figure's dimensions can be set with 'width' and 'height'.
 |  
 |      width [required=False] (value=number: x > 0):
 |          Sets the width in pixels of the figure you are generating.
 |  
 |      height [required=False] (value=number: x > 0):
 |          Sets the height in pixels of the figure you are generating.
 |  
 |      xaxis [required=False] (value=XAxis object | dictionary-like):
 |          A dictionary-like object describing an x-axis (i.e. an horizontal
 |          axis). The first XAxis object can be entered into layout by linking
 |          it to 'xaxis' OR 'xaxis1', both keys are identical to Plotly.   To
 |          create references other x-axes, you need to define them in the
 |          layout dictionary-like object using keys 'xaxis2', 'xaxis3' and so
 |          on.
 |  
 |          For more, run `help(plotly.graph_objs.XAxis)`
 |  
 |      yaxis [required=False] (value=YAxis object | dictionary-like):
 |          A dictionary-like object describing an y-axis (i.e. an vertical
 |          axis). The first YAxis object can be entered into layout by linking
 |          it to 'yaxis' OR 'yaxis1', both keys are identical to Plotly.   To
 |          create references other y-axes, you need to define them in the
 |          layout dictionary-like object using keys 'yaxis2', 'yaxis3' and so
 |          on.
 |  
 |          For more, run `help(plotly.graph_objs.YAxis)`
 |  
 |      legend [required=False] (value=Legend object | dictionary-like):
 |          A dictionary-like object containing the legend parameters for this
 |          figure.
 |  
 |          For more, run `help(plotly.graph_objs.Legend)`
 |  
 |      annotations [required=False] (value=Annotations object | array-like of
 |      one or several dictionaries):
 |          A list-like object that contains one or multiple annotation
 |          dictionaries.
 |  
 |          For more, run `help(plotly.graph_objs.Annotations)`
 |  
 |      margin [required=False] (value=Margin object | dictionary-like):
 |          A dictionary-like object containing the margin parameters for this
 |          figure.
 |  
 |          For more, run `help(plotly.graph_objs.Margin)`
 |  
 |      paper_bgcolor [required=False] (value=string describing color):
 |          Sets the color of the figure's paper (i.e. area representing the
 |          canvas of the figure).
 |  
 |          Examples:
 |              ["'green'", "'rgb(0, 255, 0)'", "'rgba(0, 255, 0, 0.3)'",
 |              "'hsl(120,100%,50%)'", "'hsla(120,100%,50%,0.3)'"]
 |  
 |      plot_bgcolor [required=False] (value=string describing color):
 |          Sets the background color of the plot (i.e. the area laying inside
 |          this figure's axes.
 |  
 |          Examples:
 |              ["'green'", "'rgb(0, 255, 0)'", "'rgba(0, 255, 0, 0.3)'",
 |              "'hsl(120,100%,50%)'", "'hsla(120,100%,50%,0.3)'"]
 |  
 |      hovermode [required=False] (value='closest' | 'x' | 'y'):
 |          Sets this figure's behavior when a user hovers over it. When set to
 |          'x', all data sharing the same 'x' coordinate will be shown on
 |          screen with corresponding trace labels. When set to 'y' all data
 |          sharing the same 'y' coordainte will be shown on the screen with
 |          corresponding trace labels. When set to 'closest', information about
 |          the data point closest to where the viewer is hovering will appear.
 |  
 |      dragmode [required=False] (value='zoom' | 'pan'):
 |          Sets this figure's behavior when a user preforms a mouse 'drag' in
 |          the plot area. When set to 'zoom', a portion of the plot will be
 |          highlighted, when the viewer exits the drag, this highlighted
 |          section will be zoomed in on. When set to 'pan', data in the plot
 |          will move along with the viewers dragging motions. A user can always
 |          depress the 'shift' key to access the whatever functionality has not
 |          been set as the default.
 |  
 |      separators [required=False] (value=a two-character string):
 |          Sets the decimal (the first character) and thousands (the second
 |          character) separators to be displayed on this figure's tick labels
 |          and hover mode. This is meant for internationalization purposes. For
 |          example, if 'separator' is set to ', ', then decimals are separated
 |          by commas and thousands by spaces. One may have to set
 |          'exponentformat' to 'none' in the corresponding axis object(s) to
 |          see the effects.
 |  
 |      barmode [required=False] (value='stack' | 'group' | 'overlay'):
 |          For bar and histogram plots only. This sets how multiple bar objects
 |          are plotted together. In other words, this defines how bars at the
 |          same location appear on the plot. If set to 'stack' the bars are
 |          stacked on top of one another. If set to 'group', the bars are
 |          plotted next to one another, centered around the shared location. If
 |          set to 'overlay', the bars are simply plotted over one another, you
 |          may need to set the opacity to see this.
 |  
 |      bargap [required=False] (value=number: x >= 0):
 |          For bar and histogram plots only. Sets the gap between bars (or sets
 |          of bars) at different locations.
 |  
 |      bargroupgap [required=False] (value=number: x >= 0):
 |          For bar and histogram plots only. Sets the gap between bars in the
 |          same group. That is, when multiple bar objects are plotted and share
 |          the same locations, this sets the distance between bars at each
 |          location.
 |  
 |      boxmode [required=False] (value='overlay' | 'group'):
 |          For box plots only. Sets how groups of box plots appear. If set to
 |          'overlay', a group of boxes will be plotted directly on top of one
 |          another at their specified location. If set to 'group', the boxes
 |          will be centered around their shared location, but they will not
 |          overlap.
 |  
 |      radialaxis [required=False] (value=RadialAxis object | dictionary-like):
 |          A dictionary-like object describing the radial axis in a polar plot.
 |  
 |          For more, run `help(plotly.graph_objs.RadialAxis)`
 |  
 |      angularaxis [required=False] (value=AngularAxis object | dictionary-
 |      like):
 |          A dictionary-like object describing the angular axis in a polar
 |          plot.
 |  
 |          For more, run `help(plotly.graph_objs.AngularAxis)`
 |  
 |      direction [required=False] (value='clockwise' | 'counterclockwise'):
 |          For polar plots only. Sets the direction corresponding to positive
 |          angles.
 |  
 |      orientation [required=False] (value=number: x in [-360, 360]):
 |          For polar plots only. Rotates the entire polar by the given angle.
 |  
 |      hidesources [required=False] (value=boolean: True | False):
 |          Toggle whether or not an annotation citing the data source is placed
 |          at the bottom-right corner of the figure.This key has an effect only
 |          on graphs that have been generated from forked graphs from plot.ly.
 |  
 |  Method resolution order:
 |      Layout
 |      PlotlyDict
 |      builtins.dict
 |      builtins.object
 |  
 |  Methods defined here:
 |  
 |  __init__(self, *args, **kwargs)
 |  
 |  force_clean(self, caller=True)
 |      Attempts to convert to graph_objs and call force_clean() on values.
 |      
 |      Calling force_clean() on a Layout 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*.
 |      
 |      This method differs from the parent (PlotlyDict) method in that it
 |      must check for an infinite number of possible axis keys, i.e. 'xaxis',
 |      'xaxis1', 'xaxis2', 'xaxis3', etc. Therefore, it cannot make a call
 |      to super...
 |  
 |  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 = '
 |      ') -- 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:
 |  
 |  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 the INFO dictionary listed in graph_objs_meta.py.
 |      
 |      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.
 |  
 |  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 INFO stored in graph_objs_meta.py.
 |      
 |      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 builtins.dict:
 |  
 |  __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)
 |  
 |  __setitem__(...)
 |      x.__setitem__(i, y) <==> x[i]=y
 |  
 |  __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.
 |  
 |  items(...)
 |      D.items() -> a set-like object providing a view on D's items
 |  
 |  keys(...)
 |      D.keys() -> a set-like object providing a view on 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() -> an object providing a view on D's values
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from builtins.dict:
 |  
 |  __hash__ = None
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T

Como vemos, Figure y Layout son objetos de tipo diccionario y Data es un objeto de tipo lista. En el caso de Data, el orden es importante pues determina el orden de composición de los trazos, empezando por el primero objeto en Data. Por ejemplo, representar una línea sobre una barras no produce, normalmente, el mismo resultado que representar unas barras sobre una línea.

En Plotly cada tipo de gráfica tiene su propio objeto (trace graph object) como son Scatter, Bar o Histogram.


In [5]:
help(Scatter)


Help on class Scatter in module plotly.graph_objs.graph_objs:

class Scatter(PlotlyTrace)
 |  A dictionary-like object for representing a scatter plot in plotly.
 |  
 |      Example:
 |  
 |          py.plot([Scatter(name='tacters', x=[1,4,2,3], y=[1,6,2,1])])
 |  
 |      
 |  Quick method reference:
 |  
 |      Scatter.update(changes)
 |      Scatter.strip_style()
 |      Scatter.get_data()
 |      Scatter.to_graph_objs()
 |      Scatter.validate()
 |      Scatter.to_string()
 |      Scatter.force_clean()
 |  
 |  Valid keys:
 |  
 |      x [required= when 'y','r' and 't' are unset] (value=array-like of
 |      numbers, strings, datetimes) (streamable):
 |          The x coordinates of the points of this scatter trace. If 'x' is
 |          linked to an list or array of strings, then the x coordinates are
 |          integers [0,1,2,3, ...] labeled on the x-axis by the list or array
 |          of strings linked to 'x'.
 |  
 |      y [required= when 'x','r' and 't' are unset] (value=array-like of
 |      numbers, strings, datetimes) (streamable):
 |          The y coordinates of the points of this scatter trace. If 'y' is
 |          linked to an list or array of strings, then the y coordinates are
 |          integers [0,1,2,3, ...] labeled on the y-axis by the list or array
 |          of strings linked to 'y'.
 |  
 |      r [required= when making a Polar Chart] (value=array-like of numbers)
 |      (streamable):
 |          For Polar charts only. The radial coordinates of the points in this
 |          polar scatter trace about the origin.
 |  
 |      t [required= when making a Polar Chart] (value=array-like of numbers,
 |      strings, datetimes) (streamable):
 |          For Polar charts only. The angular coordinates of the points in this
 |          polar scatter trace. By default, the angular coordinates are in
 |          degrees (0 to 360) where the angles are measured clockwise about the
 |          right-hand side of the origin. To change this behavior, modify
 |          'range' in AngularAxis or/and 'direction' in Layout. If 't' is
 |          linked to an array-like of strings, then the angular coordinates are
 |          [0, 360\N, 2*360/N, ...] where N is the number of coordinates given
 |          labeled by the array-like of strings linked to 't'.
 |  
 |      mode [required=False] (value='lines' | 'markers' | 'text' |
 |      'lines+markers' | 'lines+text' | 'markers+text' | 'lines+markers+text'):
 |          Plotting mode (or style) for the scatter plot. If the mode includes
 |          'text' then the 'text' will appear at the (x,y) points, otherwise it
 |          will appear on hover.
 |  
 |      name [required=False] (value=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.
 |  
 |      text [required=False] (value=array-like of strings) (streamable):
 |          The text elements associated with each (x,y) pair in this scatter
 |          trace. If the scatter 'mode' does not include 'text' then text
 |          elements will appear on hover only. In contrast, if 'text' is
 |          included in 'mode', the entries in 'text' will be rendered on the
 |          plot at the locations specified in part by their corresponding (x,y)
 |          coordinate pair and the 'textposition' key.
 |  
 |      error_y [required=False] (value=ErrorY object | dictionary-like)
 |      (streamable):
 |          A dictionary-like object describing the vetical error bars (i.e.
 |          along the y-axis) that can be drawn from the (x, y) coordinates.
 |  
 |          For more, run `help(plotly.graph_objs.ErrorY)`
 |  
 |      error_x [required=False] (value=ErrorX object | dictionary-like)
 |      (streamable):
 |          A dictionary-like object describing the horizontal error bars (i.e.
 |          along the x-axis) that can be drawn from the (x, y) coordinates.
 |  
 |          For more, run `help(plotly.graph_objs.ErrorX)`
 |  
 |      marker [required=False] (value=Marker object | dictionary-like)
 |      (streamable):
 |          A dictionary-like object containing marker style parameters for this
 |          scatter trace. Has an effect only if 'mode' contains 'markers'.
 |  
 |          For more, run `help(plotly.graph_objs.Marker)`
 |  
 |      line [required=False] (value=Line object | dictionary-like)
 |      (streamable):
 |          A dictionary-like object containing line style parameters for this
 |          scatter trace. Has an effect only if 'mode' contains 'lines'.
 |  
 |          For more, run `help(plotly.graph_objs.Line)`
 |  
 |      textposition [required=False] (value='top left' | 'top' (or 'top
 |      center')| 'top right' | 'left' (or 'middle left') | '' (or 'middle
 |      center') |'right' (or 'middle right') |'bottom left' | 'bottom' (or
 |      'bottom center') |'bottom right'):
 |          Sets the position of the text elements in the 'text' key with
 |          respect to the data points. By default, the text elements are
 |          plotted directly at the (x,y) coordinates.
 |  
 |      textfont [required=False] (value=Font object | dictionary-like):
 |          A dictionary-like object describing the font style of this scatter
 |          trace's text elements. Has only an effect if 'mode' is set and
 |          includes 'text'.
 |  
 |          For more, run `help(plotly.graph_objs.Font)`
 |  
 |      connectgaps [required=False] (value=boolean: True | False):
 |          Toggle whether or not missing data points (i.e. '' or NaNs) linked
 |          to 'x' and/or 'y', are added in by Plotly using linear
 |          interpolation.
 |  
 |      fill [required=False] (value='none' | 'tozeroy' | 'tonexty' | 'tozerox'
 |      | 'tonextx):
 |          Use to make area-style charts. Determines which area to fill with a
 |          solid color.By default, the area will appear in a more-transparent
 |          shape of the line color (or of the marker color if 'mode' does not
 |          contains 'lines').
 |  
 |      fillcolor [required=False] (value=string describing color):
 |          Sets the color that will appear in the specified fill area (set in
 |          'fill'). Has no effect if 'fill' is set to 'none'.
 |  
 |          Examples:
 |              ["'green'", "'rgb(0, 255, 0)'", "'rgba(0, 255, 0, 0.3)'",
 |              "'hsl(120,100%,50%)'", "'hsla(120,100%,50%,0.3)'"]
 |  
 |      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
 |          layout['xaxis'], 'x2' references layout['xaxis2'], and so on. Note
 |          that 'x1' will always refer to layout['xaxis'] or layout['xaxis1'],
 |          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
 |          layout['yaxis'], 'y2' references layout['yaxis2'], and so on. Note
 |          that 'y1' will always refer to layout['yaxis'] or layout['yaxis1'],
 |          they are the same.
 |  
 |      showlegend [required=False] (value=boolean: True | False):
 |          Toggle whether or not this trace will be labeled in the legend.
 |  
 |      stream [required=False] (value=Stream object | dictionary-like):
 |          The stream dictionary-like object that initializes traces as
 |          writable-streams, for use with the real-time streaming API. Learn
 |          more here: https://plot.ly/python/streaming/
 |  
 |          For more, run `help(plotly.graph_objs.Stream)`
 |  
 |      visible [required=False] (value=boolean: True | False):
 |          Toggles whether or not this object will actually be visible in the
 |          rendered figure.
 |  
 |      type [required=False] (value=scatter):
 |          Plotly identifier for this data's trace type.  This defines how this
 |          data dictionary will be handled.  For example, 'scatter' type
 |          expects  x and y data-arrays corresponding to (x, y) coordinates
 |          whereas a 'histogram' only requires a single x or y array  and a
 |          'heatmap' type requires a z matrix.
 |  
 |  Method resolution order:
 |      Scatter
 |      PlotlyTrace
 |      PlotlyDict
 |      builtins.dict
 |      builtins.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 = '
 |      ') -- 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:
 |  
 |  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 the INFO dictionary listed in graph_objs_meta.py.
 |      
 |      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 INFO stored in graph_objs_meta.py.
 |      
 |      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 builtins.dict:
 |  
 |  __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)
 |  
 |  __setitem__(...)
 |      x.__setitem__(i, y) <==> x[i]=y
 |  
 |  __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.
 |  
 |  items(...)
 |      D.items() -> a set-like object providing a view on D's items
 |  
 |  keys(...)
 |      D.keys() -> a set-like object providing a view on 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() -> an object providing a view on D's values
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from builtins.dict:
 |  
 |  __hash__ = None
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T

Ejemplo práctico: aeropuerto de Heathrow

Hecha la presentación de Plotly pasamos a un ejemplo práctico de uso de la herramienta. Para ello tomaremos datos de estadísticas de tráfico del aeropuerto de Heathrow, el tercer mayor del mundo por tráfico de pasajeros.

Datos estadísticos

Los datos son proporcionados en un fichero Excel que podemos importar con Pandas.


In [6]:
pasajeros = pd.io.excel.read_excel('07-Heathrow_Monthly_Traffic_Statistics_(Jan_2005-Jul_2014).xls',
                                   sheetname=0, # tomamos la primera hoja del archivo
                                   header=2, # la cebecera empieza en la fila 3
                                   index_col=0) # empleamos las fechas como indices
pasajeros.head(5)


Out[6]:
Heathrow Southampton Glasgow Aberdeen Non-London Airports UK Total
Month
2005-01-01 5141123 99945 504138 186378 790461 5931584
2005-02-01 4753591 109120 506851 189925 805896 5559487
2005-03-01 5708627 131983 603225 227621 962829 6671456
2005-04-01 5573022 145749 641107 232191 1019047 6592069
2005-05-01 5636621 168971 795732 242493 1207196 6843817

In [7]:
mercancias = pd.io.excel.read_excel('07-Heathrow_Monthly_Traffic_Statistics_(Jan_2005-Jul_2014).xls',
                                    sheetname=5, # tomamos la sexta hoja del archivo
                                    header=2, # la cebecera empieza en la fila 3
                                    index_col=0) # empleamos las fechas como indices
mercancias.head(5)


Out[7]:
Heathrow Southampton Glasgow Aberdeen Non-London Airports UK Total
Month
2005-01-01 98781.175 16.237 491.582 304.274 812.093 99593.268
2005-02-01 99555.454 16.554 545.170 310.282 872.006 100427.460
2005-03-01 109387.896 18.830 578.286 368.156 965.272 110353.168
2005-04-01 108057.553 18.277 569.431 321.004 908.712 108966.265
2005-05-01 110612.691 17.466 661.753 369.324 1048.543 111661.234

Como podemos ver, se trata de una serie temporal. Y puesto que los datos se proporcionan mes a mes, podríamos deshacernos del día del mes indicandole a Pandas que se trata de un periodo de frecuencia mensual con to_period. Pero no es necesario, pues como veremos más adelante, Plotly es capaz de intuir que queremos representar los datos mes a mes.


In [8]:
pasajeros.to_period('M').head(2)


Out[8]:
Heathrow Southampton Glasgow Aberdeen Non-London Airports UK Total
Month
2005-01 5141123 99945 504138 186378 790461 5931584
2005-02 4753591 109120 506851 189925 805896 5559487

Representación gráfica de los datos

Si ya hemos guardado nuestras credenciales de Plotly en el ordenador, al importar el paquete como

import plotly.plotly as py

ya nos logueamos automáticamente en el servidor sin tener que acceder mediante

py.sign_in('username', 'api_key')

Una figura (Figure) Plotly se compone de los datos a representar (Data) y de un formato (Layout), y estos a su vez no son más que un conjunto de listas y diccionarios que Plotly se encargará de convertir a un formato JSON. Como hemos mencionado arriba, Plotly proporciona una serie de graph_objs que nos facilitarán la tarea de componer gráficas interactivas y que veremos a continuación.

Data

Empezamos por el conjunto de datos a representar. En este caso vamos a representar el tráfico mensual de pasajeros en los aeropuertos británicos del grupo Heathrow, participada al 25% por Ferrovial, que incluye los aeropuertos de:

  • London Heathrow Airport
  • Southampton Airport
  • Glasgow Airport
  • Aberdeen Airport

Para representar estos datos nos valdremos de la herramienta Data que, como hemos visto anteriormente, admite una lista de objetos. En nuestro caso, líneas. Para ello nos valdremos de Scatter (dispersión) al cual pasaremos los siguentes parámetros:

  • name, nombre que damos a la línea, en nuestro caso, el nombre del aeropuerto.
  • x, array con los meses del año que corresponden al index de nuestro DataFrame.
  • y, array con el número de pasajeros correspondientes a cada aeropuerto.
  • mode, cadena de texto que indica el tipo de representación que queremos, ya sea 'lines', 'markers', 'text' o una combinación de ellos como podría ser 'lines+markers'.

Puesto que se trata de una lista con cuatro líneas a representar, haremos uso de las list comprehensions de Python.


In [9]:
p_data = Data([Scatter(name=col,
                       x=pasajeros.index,
                       y=pasajeros[col],
                       mode='lines') for col in pasajeros.columns.values[:4]])

Layout

Ya con los datos a representar definidos, ahora podemos pasar a retocar el layout de la figura. Para ello vamos a añadir un título a la gráfica y a los ejes x e y. Otra cosa que haremos también es encuadrar la gráfica con

showline=True, mirror='ticks', linewidth=2

y reducir los margenes derecho r y superior t para aprovechar mejor el espacio.


In [10]:
p_layout = Layout(title='Tráfico mensual de pasajeros en aeropuertos del grupo Heathrow',
                  xaxis=XAxis(title='Mes', showgrid=False, showline=True, mirror='ticks', linewidth=2),
                  yaxis=YAxis(title='Pasajeros', zeroline=False, showline=True, mirror='ticks', linewidth=2),
                  margin=Margin(r=20, t=80))

Figure

Una vez ya tenemos los datos y el layout podemos pasar a componer la figura y subirla al servidor.


In [11]:
p_fig = Figure(data=p_data, layout=p_layout)
p_plot = py.iplot(p_fig, filename='pybonacci/heathrow-pasajeros')


Diccionarios y listas

Tanto Figure como Layout, XAxis, YAxis y Margin se podrían substituir por la expresión dict() pues, como ya hemos mencionados, Plotly trabaja con diccionarios y listas de Python. Sin embargo, el utilizar estas herramientas de plotly.graph_objs nos da acceso a la ayuda, y nos permite validar los parámetros introducidos.


In [12]:
m_data = Data([Scatter(name=col,
                       x=mercancias.index,
                       y=mercancias[col],
                       mode='lines') for col in pasajeros.columns.values[:4]])

In [13]:
m_layout = Layout(title='Tráfico mensual de mercancías en aeropuertos del grupo Heathrow',
                  xaxis=XAxis(title='Mes', showgrid=False, showline=True, mirror='ticks', linewidth=2),
                  yaxis=YAxis(title='Mercancías (t)', zeroline=False, showline=True, mirror='ticks', lineheight=2),
                  margin=Margin(r=20, t=80))


---------------------------------------------------------------------------
PlotlyDictKeyError                        Traceback (most recent call last)
<ipython-input-13-65aedde64980> in <module>()
      1 m_layout = Layout(title='Tráfico mensual de mercancías en aeropuertos del grupo Heathrow',
      2                   xaxis=XAxis(title='Mes', showgrid=False, showline=True, mirror='ticks', linewidth=2),
----> 3                   yaxis=YAxis(title='Mercancías (t)', zeroline=False, showline=True, mirror='ticks', lineheight=2),
      4                   margin=Margin(r=20, t=80))

C:\Miniconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in __init__(self, *args, **kwargs)
    536             if (class_name != 'PlotlyTrace') and (class_name != 'Trace'):
    537                 self['type'] = NAME_TO_KEY[class_name]
--> 538         self.validate()
    539         if self.__class__.__name__ == 'PlotlyDict':
    540             warnings.warn("\nThe PlotlyDict class is a base class of "

C:\Miniconda3\lib\site-packages\plotly\graph_objs\graph_objs.py in validate(self, caller)
    784                     raise exceptions.PlotlyDictKeyError(obj=self,
    785                                                         key=key,
--> 786                                                         notes=notes)
    787 
    788     def to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80):

PlotlyDictKeyError: Invalid key, 'lineheight', for class, 'YAxis'.

Run 'help(plotly.graph_objs.YAxis)' for more information.

Path To Error:
['lineheight']

Additional Notes:
Couldn't find uses for key: 'lineheight'

Si hubiesemos hecho lo mismo con dict(), el error hubiese pasado desapercibido hasta el final.


In [14]:
m_layout = dict(title='Tráfico mensual de mercancías en aeropuertos del grupo Heathrow',
                xaxis=dict(title='Mes', showgrid=False, showline=True, mirror='ticks', linewidth=2),
                yaxis=dict(title='Mercancías (t)', zeroline=False, showline=True, mirror='ticks', linewidth=2),
                margin=dict(r=20, t=80))

In [15]:
m_fig = Figure(data=m_data, layout=m_layout)
m_plot = py.iplot(m_fig, filename='pybonacci/heathrow-mercancias')


Interpretación de los datos

Disponemos de una muestra lo suficientemente grande como desaprovechar la oportunidad de extraer alguna conclusión al respecto. Y contamos con la ventaja de poder hacer zoom en los datos, lo cual resulta especialmente útil en le tráfico de mercancías, donde el aeropuerto de Heathrow está varios órdenes de magnitud por encima del resto.

Pasajeros

Vemos claramente que en los meses de verano hay un aumento del número de pasajeros en todos los aeropuertos del grupo. También se aprecia un ligero repunte en el mes de diciembre con motivo, previsiblemente, de las vacaciones de navidad. Esto lo podemos visualizar de otra manera mediante un Heatmap del aeropuerto de Heathrow.

Para ello vamos a utilizar el paquete calendar que nos permitirá crear una lista con los nombres de los meses; y Numpy para crear una lista con los años.


In [16]:
import calendar
import numpy as np

Para representar el Heatmap necesitaremos agrupar los datos por años o meses, en función del eje y que tomemos. En este caso hemos decido representar los meses en el eje de ordenadas, por lo tanto agruparemos los datos por meses. Para ello nos valdremos de una función anónima.


In [17]:
gb = lambda x: x.month

In [18]:
data = Data([Heatmap(x=np.arange(2005,2015),
                     y=calendar.month_abbr[1:],
                     z=[grp['Heathrow'] for key, grp in pasajeros.groupby(gb)],
                     colorscale='Portland')])

En el eje x hemos colocado los años, en el eje y los meses, y la intensidad del color viene determinada por el número de pasajeros.

Con Layout añadimos el título de la gráfica y los nombres de los ejes, y también podemos especificar el tamaño de la gráfica deshabilitando el autosize y definiendo nuestro propio ancho y alto.


In [19]:
layout = Layout(title='Tráfico de pasajeros en el aeropuerto de Heathrow',
                autosize=False,
                width=550,
                height=550,
                xaxis=XAxis(title='Año', showgrid=False),
                yaxis=YAxis(title='Mes', showgrid=False))

Ya podemos publicar nuestra gráfica de la manera habitual.


In [20]:
heatmap_plot = py.iplot(Figure(data=data,layout=layout), filename='pybonacci/heathrow-heatmap')


Mercancías

Si en el transporte de pasajeros hay un patrón claro, el transporte de mercancías por avión no muestra signos de estacionalidad. Para verlo mejor podríamos volver a emplear un Heatmap, pero vamos a hacerlo con un diagrama de caja Box para el aeropuerto de Heathrow.

Aprovecharemos nuevamente la agrupación por meses que hemos empleado para el Heatmap de pasajeros. Nuevamente hacemos uso de las list comprehensions de Python para crear una lista de bloques, cada uno correspondiente a un mes. Lo mismo podríamos conseguirlo sin crear una lista y sin necesidad de agrupar si en vez de asignar un name asignamos un único array x con el valor del mes correspondiente a cada y. Con boxpoints='all' lo que hacemos es mostrar los puntos de la muestra al lado de cada bloque.


In [21]:
data = Data([Box(name=calendar.month_abbr[key],
                 y=grp['Heathrow'].values,
                 boxpoints='all') for key, grp in mercancias.groupby(gb)])

Añadimos, como es costumbre, un título a la gráfica y aprovechamos para ocultar la leyenda y ajustar los margenes.


In [22]:
layout = Layout(title='Tráfico de mercancías en el aeropuerto de Heathrow (2005-2014)',
                showlegend=False,
                margin=Margin(r=20, t=90))

In [23]:
box_plot = py.iplot(Figure(data=data, layout=layout), filename='pybonacci/heathrow-box')


Pasajeros vs mercancías

Hasta ahora hemos visto por separado los datos de pasajeros y mercancías. Compararemos en una única gráfica los datos del aeropuerto de Glasgow. Para facilitar la visualización y compensar la diferencia de magnitud utilizaremos múltiples ejes y, de paso, emplearemos diferentes representaciones para el tráfico de pasajeros y el de mercancías.

Los pasajeros los representaremos mediante líneas y puntos 'lines+markers' y le asignamos el segundo eje y 'y2', pues vamos a querer que nos lo represente por encima de las barras de tráfico de mercancías. El orden en Plotly es importante. Vamos a representar las lineas de color dorado primero como horizontales y luego verticales de un valor a otro con shape='hv'. Los puntos serán de un color dorado más claro con el borde también dorado.


In [24]:
pas = Scatter(name='Pasajeros',
              x=pasajeros.index,
              y=pasajeros['Glasgow'],
              yaxis='y2',
              mode='lines+markers',
              line=Line(shape='hv', color='darkgoldenrod'),
              marker=Marker(color='goldenrod',
                            line=Line(color='darkgoldenrod', width=2)))

Por su parte, el tráfico de mercancías lo representaremos como barras verticales de color gris claro. Por defecto se le asigna el primer eje y.


In [25]:
mer = Bar(name='Mercancías',
          x=pasajeros.index,
          y=mercancias['Glasgow'],
          marker=Marker(color='lightgray'))

Creamos la lista con los elementos a representar.


In [26]:
data = Data([mer, pas])

Por último configuramos el layout añadiendo un título a la gráfica y configurando los ejes.


In [27]:
layout = Layout(title='Tráfico de pasajeros y mercancías en el aeropuerto de Glasgow',
                showlegend=False,
                xaxis=XAxis(title='Mes'),
                yaxis=YAxis(title='Mercancías (t)',
                            showgrid=False),
                yaxis2=YAxis(title='Pasajeros',
                             showgrid=False,
                             overlaying='y',
                             side='right'))

Incluimos también una nota de texto indicando la fuente de los datos. Plotly nos permite untilizar un subconjunto de etiquetas HTML para dar formato a los textos para por ejemplo incluir nuevas líneas (<br>) o añadir hipervínculos (<a href='...'></a>) que podremos utilizar en cualquier texto de la gráfica (títulos y anotaciones).


In [28]:
fuente = Annotation(text="Fuente: <a href=\
                          'http://www.heathrowairport.com/about-us/investor-centre/results-and-performance/traffic-statistics'\
                          >LHR Airports Limited</a>",
                    xref='paper', # empleamos coordenadas 'paper', con ello la nota no se moverá al mover los ejes.
                    yref='paper',
                    x=0,
                    y=-0.15,
                    showarrow=False)

Actualizamos el diccionario de layout de la gráfica.


In [29]:
layout.update(annotations=Annotations([fuente]))

In [30]:
ma_plot = py.iplot(Figure(data=data, layout=layout), filename='pybonacci/heathrow-multipleaxis')


Mucho más

Aquí sólo hemos mostrado una pequeña parte del potencial de Plotly. Todo aquel que quiere ampliar detalles encontrará mucha más información en el API library de Plotly. También se pueden sacar buenas ideas del graphing news feed viendo lo que publican otros usuarios.

No dudeis en contactar con nosotros o el equipo de Plotly por email o Twitter para cualquier duda o sugerencia.