Show Sidebar Hide Sidebar

Plotly User Guide in Python

Plotly User Guide for Python

Python API User Guide

So you've just finished the Getting Started document and now you're looking to find out more. In this guide, we'll go through some of the internals of Plotly, as well as some tips and general practices that will allow you generate amazing data visualizations in no time.

What is Plotly?:

Plotly at its core is a data visualization toolbox. Under every plotly graph is a JSON object, which is a dictionary like data structure. Simply by changing the values of some keywords in this object, we can get vastly different and ever more detailed plots. For example:

In [79]:
import plotly.plotly as py
import plotly.graph_objs as go

trace1 = go.Scatter(x=[1,2,3], y=[4,5,6], marker={'color': 'red', 'symbol': 104, 'size': "10"}, 
                    mode="markers+lines",  text=["one","two","three"], name='1st Trace')
                                               
data=go.Data([trace1])
layout=go.Layout(title="First Plot", xaxis={'title':'x1'}, yaxis={'title':'x2'})
figure=go.Figure(data=data,layout=layout)
py.iplot(figure, filename='pyguide_1')
Out[79]:
In [80]:
figure
Out[80]:
{'data': [{'marker': {'color': 'red', 'size': '10', 'symbol': 104},
   'mode': 'markers+lines',
   'name': '1st Trace',
   'text': ['one', 'two', 'three'],
   'type': 'scatter',
   'x': [1, 2, 3],
   'y': [4, 5, 6]}],
 'layout': {'title': 'First Plot',
  'xaxis': {'title': 'x1'},
  'yaxis': {'title': 'x2'}}}

We can see that the figure that we're plotting with py.iplot is actually just a dictionary-like object. Moreover, we can customize and alter this plot simply by adding/defining the values of the possible keywords associated with scatter plots.

Let's say we want to change the title of our scatter plot to Plot update, while at the same time, make the scatter plot blue instead of red.

In [81]:
figure.update(dict(layout=dict(title='Plot update'), data=dict(marker=dict(color='blue'))))
py.iplot(figure, filename='pyguide_2')
Out[81]:

Moreover, Plotly plots are interactive, meaning you can manually explore the data by panning, selecting, zooming on the graphing surface (among other possible actions, try panning the axes!). We are also continually expanding the expressiveness of the Plotly package so we're able to graph and visualize all sorts of data.

In no time you will be able to figure out how to make plots the way you want them, and with the information that you want to be shared with those you want. For example we can take a quick look at how we would define the objects required to generate a scatterplot comparing life expectancies and GDP Per Capita between two different continents.

In [82]:
import pandas as pd
import plotly.plotly as py
import plotly.graph_objs as go

df = pd.read_csv('https://raw.githubusercontent.com/yankev/test/master/life-expectancy-per-GDP-2007.csv')

americas = df[(df.continent=='Americas')]
europe = df[(df.continent=='Europe')]

trace_comp0 = go.Scatter(
    x=americas.gdp_percap,
    y=americas.life_exp,
    mode='markers',
    marker=dict(size=12,
                line=dict(width=1),
                color="navy"
               ),
    name='Americas',
    text=americas.country,
    )

trace_comp1 = go.Scatter(
    x=europe.gdp_percap,
    y=europe.life_exp,
    mode='markers',
    marker=dict(size=12,
                line=dict(width=1),
                color="red"
               ),
    name='Europe',
    text=europe.country,
        )

data_comp = [trace_comp0, trace_comp1]
layout_comp = go.Layout(
    title='Life Expectancy v. Per Capita GDP, 2007',
    hovermode='closest',
    xaxis=dict(
        title='GDP per capita (2000 dollars)',
        ticklen=5,
        zeroline=False,
        gridwidth=2,
    ),
    yaxis=dict(
        title='Life Expectancy (years)',
        ticklen=5,
        gridwidth=2,
    ),
)
fig_comp = go.Figure(data=data_comp, layout=layout_comp)
py.iplot(fig_comp, filename='life-expectancy-per-GDP-2007')
Out[82]:

Hopefully this gives you an idea how plots are created with the Plotly Python Library. We'll go into more detail regarding the different parts that make up the plot in later sections. But for now, I hope you can see the customizability that's possible, and how we can define these graphs programmatically.

The Source of Plotly's Power

All the graphs and plots which Plotly generates are actually the product of our javascript library plotly.js. Whether you see Plotly graphs in a browser, or an IPython notebook, all the visualizations and interactiveness is made possible by plotly.js. Built on top of d3.js and stack.gl, plotly.js is a high-level, declarative charting library. plotly.js ships with 20 chart types, including 3D charts, statistical graphs, and SVG maps.

Working with the Python API

The Python API is a package designed to interact with the Plotly.js library in order to allow Python users to create plots in their preferred environment. This way, the package will provide functions and graph objects that will simplify the process of generating plots, which would amount to properly defining keywords in a JSON object (as seen above). To this end, the Python API provides functions and graph objects which will allow us to create our plots functionally. So let's break this down.

In [83]:
import plotly.plotly as py
import plotly.graph_objs as go

These are the two main modules that we will need in order to generate our Plotly graphs.

  • plotly.plotly contains the functions that will help us communicate with the Plotly servers
  • plotly.graph_objs contains the functions that will generate graph objects for us.

Note: If we examine the code from the example in the previous section, we can see these parts in action.

Below we will examine the different aspects/objects that define a plot in Plotly. These are:

  • Data
  • Layout
  • Figure

Data

In [84]:
data
Out[84]:
[{'marker': {'color': 'red', 'size': '10', 'symbol': 104},
  'mode': 'markers+lines',
  'name': '1st Trace',
  'text': ['one', 'two', 'three'],
  'type': 'scatter',
  'x': [1, 2, 3],
  'y': [4, 5, 6]}]

We see that data is actually a list object in Python. Data will actually contain all the traces that you wish to plot. Now the question may be, what is a trace? A trace is just the name we give a collection of data and the specifications of which we want that data plotted. Notice that a trace will also be an object itself, and these will be named according to how you want the data displayed on the plotting surface. Hence,

In [85]:
go.Scatter(x=[1,2,3], y=[4,5,6], marker={'color': 'red', 'symbol': 104, 'size': "10"}, 
                                               mode="markers+lines",  text=["one","two","three"])
Out[85]:
{'marker': {'color': 'red', 'size': '10', 'symbol': 104},
 'mode': 'markers+lines',
 'text': ['one', 'two', 'three'],
 'type': 'scatter',
 'x': [1, 2, 3],
 'y': [4, 5, 6]}

defines a trace producing a scatter plot. Moreover it defines the data that we want plotted, which are 3 data points (1,4), (2,5), (3,6), as well as a miriad of specifications related to plotting this data. In this example we wanted the points to be plotted as hollow x's with lines joining them, all in red.

In addition, we can add another Scatter object to our data list. We can do this by defining a new Scatter object, and including this in our definition of our data object.

In [86]:
#First let's make up some cool data to plot:
import numpy as np
x = np.arange(1,3.2,0.2)
y = 6*np.sin(x)
y
Out[86]:
array([ 5.04882591,  5.59223452,  5.91269838,  5.99744162,  5.84308579,
        5.45578456,  4.85097842,  4.05277908,  3.09300823,  2.0099289 ,
        0.84672005])
In [87]:
trace2 = go.Scatter(x=x, y=y, marker={'color': 'blue', 'symbol': 'star', 'size': 10}, mode='markers', name='2nd trace')
data = go.Data([trace1, trace2])
data
Out[87]:
[{'marker': {'color': 'red', 'size': '10', 'symbol': 104},
  'mode': 'markers+lines',
  'name': '1st Trace',
  'text': ['one', 'two', 'three'],
  'type': 'scatter',
  'x': [1, 2, 3],
  'y': [4, 5, 6]},
 {'marker': {'color': 'blue', 'size': 10, 'symbol': 'star'},
  'mode': 'markers',
  'name': '2nd trace',
  'type': 'scatter',
  'x': array([ 1. ,  1.2,  1.4,  1.6,  1.8,  2. ,  2.2,  2.4,  2.6,  2.8,  3. ]),
  'y': array([ 5.04882591,  5.59223452,  5.91269838,  5.99744162,  5.84308579,
          5.45578456,  4.85097842,  4.05277908,  3.09300823,  2.0099289 ,
          0.84672005])}]
In [88]:
plot2 = py.iplot(go.Figure(data=data, layout=layout), filename='pyguide_3')
plot2
Out[88]:

Layout

The Layout object will define the look of the plot, and plot features which are unrelated to the data. So we will be able to change things like the title, axis titles, spacing, font and even draw shapes on top of your plot! In our case,

In [89]:
layout=go.Layout(title="First Plot", xaxis={'title':'x1'}, yaxis={'title':'x2'})
layout
Out[89]:
{'title': 'First Plot', 'xaxis': {'title': 'x1'}, 'yaxis': {'title': 'x2'}}
Annotations

We added a plot title as well as titles for all the axes. For fun we could add some text annotation as well in order to indicate the maximum point that's been plotted on the current plotting surface.

In [90]:
layout.update(dict(annotations=[go.Annotation(text="Highest Point", x=3, y=6)]))
py.iplot(go.Figure(data=data, layout=layout), filename='pyguide_4')
Out[90]:
Shapes

Let's add a rectangular block to highlight the section where trace 1 is above trace2.

In [91]:
layout.update(dict(shapes = [
        # 1st highlight during Feb 4 - Feb 6
        {
            'type': 'rect',
            # x-reference is assigned to the x-values
            'xref': 'x',
            # y-reference is assigned to the plot paper [0,1]
            'yref': 'y',
            'x0': '1',
            'y0': 0,
            'x1': '2',
            'y1': 7,
            'fillcolor': '#d3d3d3',
            'opacity': 0.2,
            'line': {
                'width': 0,
            }
        }]
        ))

py.iplot(go.Figure(data=data, layout=layout), filename='pyguide_5')
Out[91]:

Of course, all this can be found in the Layout section of the Reference Page.

Figure

Finally, we get to the figure object. go.Figure just creates the final object to be plotted, and simply just creates a dictionary-like object that contains both the data object and the layout object.

In [92]:
go.Figure(data=data, layout=layout)
Out[92]:
{'data': [{'marker': {'color': 'red', 'size': '10', 'symbol': 104},
   'mode': 'markers+lines',
   'name': '1st Trace',
   'text': ['one', 'two', 'three'],
   'type': 'scatter',
   'x': [1, 2, 3],
   'y': [4, 5, 6]},
  {'marker': {'color': 'blue', 'size': 10, 'symbol': 'star'},
   'mode': 'markers',
   'name': '2nd trace',
   'type': 'scatter',
   'x': array([ 1. ,  1.2,  1.4,  1.6,  1.8,  2. ,  2.2,  2.4,  2.6,  2.8,  3. ]),
   'y': array([ 5.04882591,  5.59223452,  5.91269838,  5.99744162,  5.84308579,
           5.45578456,  4.85097842,  4.05277908,  3.09300823,  2.0099289 ,
           0.84672005])}],
 'layout': {'annotations': [{'text': 'Highest Point', 'x': 3, 'y': 6}],
  'shapes': [{'fillcolor': '#d3d3d3',
    'line': {'width': 0},
    'opacity': 0.2,
    'type': 'rect',
    'x0': '1',
    'x1': '2',
    'xref': 'x',
    'y0': 0,
    'y1': 7,
    'yref': 'y'}],
  'title': 'First Plot',
  'xaxis': {'title': 'x1'},
  'yaxis': {'title': 'x2'}}}

Why graph_objs?

After viewing the outputs of these functions (ie: the objects), we can see that they are just lists or dictionaries. But they're a little more than that. Though they do inherit properties from dictionaries (traces, and layout) and lists (figure), they provide a bit more functionality as we'll soon see. Not to mention the fact that it's much simpler to create plots in this functional fashion compared to manually writing up a dictionary.

The first neat option about using graph_objs is that you can call help on them.

In [93]:
help(go.Figure)
Help on class Figure in module plotly.graph_objs.graph_objs:

class Figure(PlotlyDict)
 |  Valid attributes for 'figure' at path [] under parents ():
 |  
 |      ['layout', 'data']
 |  
 |  Run `<figure-object>.help('attribute')` on any of the above.
 |  '<figure-object>' is the object at []
 |  
 |  Method resolution order:
 |      Figure
 |      PlotlyDict
 |      __builtin__.dict
 |      PlotlyBase
 |      __builtin__.object
 |  
 |  Methods defined here:
 |  
 |  __init__(self, *args, **kwargs)
 |  
 |  append_trace(self, trace, row, col)
 |      Add a data traces to your figure bound to axes at the row, col index.
 |      
 |      The row, col index is generated from figures created with
 |      plotly.tools.make_subplots and can be viewed with Figure.print_grid.
 |      
 |      :param (dict) trace: The data trace to be bound.
 |      :param (int) row: Subplot row index (see Figure.print_grid).
 |      :param (int) col: Subplot column index (see Figure.print_grid).
 |      
 |      Example:
 |      # stack two subplots vertically
 |      fig = tools.make_subplots(rows=2)
 |      
 |      This is the format of your plot grid:
 |      [ (1,1) x1,y1 ]
 |      [ (2,1) x2,y2 ]
 |      
 |      fig.append_trace(Scatter(x=[1,2,3], y=[2,1,2]), 1, 1)
 |      fig.append_trace(Scatter(x=[1,2,3], y=[2,1,2]), 2, 1)
 |  
 |  get_data(self, flatten=False)
 |      Returns the JSON for the plot with non-data elements stripped.
 |      
 |      Flattening may increase the utility of the result.
 |      
 |      :param (bool) flatten: {'a': {'b': ''}} --> {'a.b': ''}
 |      :returns: (dict|list) Depending on (flat|unflat)
 |  
 |  print_grid(self)
 |      Print a visual layout of the figure's axes arrangement.
 |      
 |      This is only valid for figures that are created
 |      with plotly.tools.make_subplots.
 |  
 |  to_dataframe(self)
 |      Create a pandas dataframe with trace names and keys as column names.
 |      
 |      :return: (DataFrame)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from PlotlyDict:
 |  
 |  __copy__(self)
 |  
 |  __deepcopy__(self, memodict={})
 |  
 |  __dir__(self)
 |      Dynamically return the existing and possible attributes.
 |  
 |  __getattr__(self, key)
 |      Python only calls this when key is missing!
 |  
 |  __getitem__(self, key)
 |      Calls __missing__ when key is not found. May mutate object.
 |  
 |  __missing__(self, key)
 |      Mimics defaultdict. This is called from __getitem__ when key DNE.
 |  
 |  __setattr__(self, key, value)
 |      Maps __setattr__ onto __setitem__
 |  
 |  __setitem__(self, key, value, _raise=True)
 |      Validates/Converts values which should be Graph Objects.
 |  
 |  force_clean(self, **kwargs)
 |      Recursively remove empty/None values.
 |  
 |  get_ordered(self, **kwargs)
 |      Return a predictable, OrderedDict version of self.
 |  
 |  help(self, attribute=None, return_help=False)
 |      Print help string for this object or an attribute of this object.
 |      
 |      :param (str) attribute: A valid attribute string for this object.
 |      :param (bool) return_help: Return help_string instead of printing it?
 |      :return: (None|str)
 |  
 |  strip_style(self)
 |      Recursively 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. Note that a key tagged as
 |      style, but with an array as a value may still be considered data.
 |  
 |  to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80)
 |      Returns a formatted string showing graph_obj constructors.
 |      
 |      :param (int) level: The number of indentations to start with.
 |      :param (int) indent: The indentation amount.
 |      :param (str) eol: The end of line character(s).
 |      :param (bool) pretty: Curtail long list output with a '..' ?
 |      :param (int) max_chars: The max characters per line.
 |      
 |      Example:
 |      
 |          print(obj.to_string())
 |  
 |  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.
 |  
 |  ----------------------------------------------------------------------
 |  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
 |  
 |  __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
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from PlotlyBase:
 |  
 |  to_graph_objs(self, **kwargs)
 |      Everything is cast into graph_objs. Here for backwards compat.
 |  
 |  validate(self)
 |      Everything is *always* validated now. keep for backwards compat.

In [94]:
help(go.Scatter)
Help on class Scatter in module plotly.graph_objs.graph_objs:

class Scatter(PlotlyDict)
 |  Valid attributes for 'scatter' at path [] under parents ():
 |  
 |      ['textposition', 'uid', 'stream', 'ysrc', 'hoverinfo', 'xsrc',
 |      'visible', 'marker', 'y0', 'tsrc', 'line', 'fill', 'showlegend',
 |      'error_x', 'error_y', 'rsrc', 'xaxis', 'text', 'type', 't', 'opacity',
 |      'textfont', 'legendgroup', 'textpositionsrc', 'textsrc', 'dx', 'dy',
 |      'x0', 'name', 'yaxis', 'connectgaps', 'r', 'mode', 'y', 'x',
 |      'fillcolor']
 |  
 |  Run `<scatter-object>.help('attribute')` on any of the above.
 |  '<scatter-object>' is the object at []
 |  
 |  Method resolution order:
 |      Scatter
 |      PlotlyDict
 |      __builtin__.dict
 |      PlotlyBase
 |      __builtin__.object
 |  
 |  Methods inherited from PlotlyDict:
 |  
 |  __copy__(self)
 |  
 |  __deepcopy__(self, memodict={})
 |  
 |  __dir__(self)
 |      Dynamically return the existing and possible attributes.
 |  
 |  __getattr__(self, key)
 |      Python only calls this when key is missing!
 |  
 |  __getitem__(self, key)
 |      Calls __missing__ when key is not found. May mutate object.
 |  
 |  __init__(self, *args, **kwargs)
 |  
 |  __missing__(self, key)
 |      Mimics defaultdict. This is called from __getitem__ when key DNE.
 |  
 |  __setattr__(self, key, value)
 |      Maps __setattr__ onto __setitem__
 |  
 |  __setitem__(self, key, value, _raise=True)
 |      Validates/Converts values which should be Graph Objects.
 |  
 |  force_clean(self, **kwargs)
 |      Recursively remove empty/None values.
 |  
 |  get_data(self, flatten=False)
 |      Returns the JSON for the plot with non-data elements stripped.
 |  
 |  get_ordered(self, **kwargs)
 |      Return a predictable, OrderedDict version of self.
 |  
 |  help(self, attribute=None, return_help=False)
 |      Print help string for this object or an attribute of this object.
 |      
 |      :param (str) attribute: A valid attribute string for this object.
 |      :param (bool) return_help: Return help_string instead of printing it?
 |      :return: (None|str)
 |  
 |  strip_style(self)
 |      Recursively 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. Note that a key tagged as
 |      style, but with an array as a value may still be considered data.
 |  
 |  to_string(self, level=0, indent=4, eol='\n', pretty=True, max_chars=80)
 |      Returns a formatted string showing graph_obj constructors.
 |      
 |      :param (int) level: The number of indentations to start with.
 |      :param (int) indent: The indentation amount.
 |      :param (str) eol: The end of line character(s).
 |      :param (bool) pretty: Curtail long list output with a '..' ?
 |      :param (int) max_chars: The max characters per line.
 |      
 |      Example:
 |      
 |          print(obj.to_string())
 |  
 |  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.
 |  
 |  ----------------------------------------------------------------------
 |  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
 |  
 |  __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
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from PlotlyBase:
 |  
 |  to_graph_objs(self, **kwargs)
 |      Everything is cast into graph_objs. Here for backwards compat.
 |  
 |  validate(self)
 |      Everything is *always* validated now. keep for backwards compat.

As you can see, calling help shows us all the attributes that the Scatter object takes as paremeters. Also because the scatter object is based off of a dictionary, you can see all the different methods that are attached to this object as well. For example, we've seen the use of the update method above.

Focussing more on the parameters, we can see that the objects have key-word/name validation. What this means is that it'll raise an exception that provides us some detail of where we went wrong.

In [95]:
go.Scatter(markers=dict(color='blue'))
---------------------------------------------------------------------------
PlotlyDictKeyError                        Traceback (most recent call last)
<ipython-input-95-f20e7994a2f4> in <module>()
----> 1 go.Scatter(markers=dict(color='blue'))

/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/plotly/graph_objs/graph_objs.pyc in __init__(self, *args, **kwargs)
    373         d = {key: val for key, val in dict(*args, **kwargs).items()}
    374         for key, val in d.items():
--> 375             self.__setitem__(key, val, _raise=_raise)
    376 
    377     def __dir__(self):

/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/plotly/graph_objs/graph_objs.pyc in __setitem__(self, key, value, _raise)
    424                 if _raise:
    425                     path = self._get_path() + (key, )
--> 426                     raise exceptions.PlotlyDictKeyError(self, path)
    427                 return
    428 

PlotlyDictKeyError: 'markers' is not allowed in 'scatter'

Path To Error: ['markers']

Valid attributes for 'scatter' at path [] under parents []:

    ['textposition', 'uid', 'stream', 'ysrc', 'hoverinfo', 'xsrc',
    'visible', 'marker', 'y0', 'tsrc', 'line', 'fill', 'showlegend',
    'error_x', 'error_y', 'rsrc', 'xaxis', 'text', 'type', 't', 'opacity',
    'textfont', 'legendgroup', 'textpositionsrc', 'textsrc', 'dx', 'dy',
    'x0', 'name', 'yaxis', 'connectgaps', 'r', 'mode', 'y', 'x',
    'fillcolor']

Run `<scatter-object>.help('attribute')` on any of the above.
'<scatter-object>' is the object at []

As you can see, it tells us that markers is not a key in scatter. Instead as we browse the list, we see that what we wanted was actually marker (singular, without the s), which is a keyword. Thus this little feature makes for much easier debugging and correction.

Now let's talk about the methods that come along with these objects. The one of most importance would be the update method. The difference here between the regular update method for dictionaries is that it allows for nested updates. Let me show you what that means.

In [ ]:
#Here we have a scatter object:
scatter_trace = go.Scatter(marker=dict(color='blue'))
In [ ]:
#We can add some information to it like data (x, and y), as well as update the sybmol we want the markers to be
scatter_trace.update(dict(x=[1,2,3],y=[4,5,6], marker=dict(symbol='star')))
scatter_trace
In [ ]:
figure = go.Figure(data=[scatter_trace], layout=layout)
py.iplot(figure, filename='pyguide_5')

Notice that we were able to add the data as well as add the extra feature for the markers. However if we let scatter_trace be just a standard dictionary then we will not be able to just add another feature for the marker in this way. Instead, the value for marker will be replaced with the dictionary we choose to update with.

In [ ]:
scatter_trace = {'marker': {'color': 'blue'},
                 'type': 'scatter',
                 ''}

Looking at Examples

Examples are one of the best ways to get started and get your feet wet. Through the examples you can get a good idea of what a certain type of plot is used for, and what can be possible with it.

Moreover, the code in the examples are self-contained, meaning you can just copy and paste the code block and run it in your Python script or Ipython Notebook. But if you happen to run into an issue running the example, please let us know at our Community Forums. By examining the code, you can further understand and experience the procedure in which Plotly plots are created. Something important to look at would be the data used in these examples; Because certain plots are only able to handle certain types of data (e.g: histograms are only useful for quantitative data), you will get an idea of the limitations and purpose of different plot types. In addition, you can see the effect certain parameters have on the data visualization and hopefully give you a sense of what's possible beyond the standard/default.

It's a good place to look for what's possible in Plotly. A brief look at the page you can find sections and examples on types of plots you didn't know existed, or layout options that you had no idea were possible and within reach. Just take a look at all these guys:

Scientific Charts

What's more you can find layout options that will allow you to create plots with multiple axes and plots. Check this out: Layout Options

As an example, say we looked at two different types of plots in the heatmap and the box plots, now equipped with the knowledge of subplots, we can easily two and two together in order to put both these on the same plotting surface (for no other reason than that we can). Let's first load the packages, and then set up the data for our heatmap trace.

In [96]:
from plotly import tools
import numpy as np
import plotly.plotly as py
import plotly.graph_objs as go

heatmap = go.Heatmap(
        z=[[1, 20, 30],
           [20, 1, 60],
           [30, 60, 1]],
        showscale=False
        )

Next we'll set up the trace object for our wind rose chart, and note I'm just copying code from the example pages for each of these plot types.

In [97]:
y0 = np.random.randn(50)
y1 = np.random.randn(50)+1

box_1 = go.Box(
    y=y0
)
box_2 = go.Box(
    y=y1
)
data = [heatmap, box_1, box_2]
In [116]:
fig = tools.make_subplots(rows=2, cols=2, specs=[[{}, {}], [{'colspan': 2}, None]],
                          subplot_titles=('First Subplot','Second Subplot', 'Third Subplot'))

fig.append_trace(box_1, 1, 1)
fig.append_trace(box_2, 1, 2)
fig.append_trace(heatmap, 2, 1)

fig['layout'].update(height=600, width=600, title='i <3 subplots')

py.iplot(fig, filename='box_heatmap1')
This is the format of your plot grid:
[ (1,1) x1,y1 ]  [ (1,2) x2,y2 ]
[ (2,1) x3,y3           -      ]

Out[116]:

This looks great, however we'd like for our subplots to be on the same plotting surface. So let's take a look at the dictionary representation of our figure, and customize it using what we've learned before.

In [99]:
fig
Out[99]:
{'data': [{'type': 'box',
   'xaxis': 'x1',
   'y': array([-0.91373828,  1.20546486, -0.096304  ,  2.37294867,  0.75779673,
          -0.85565264, -0.21226529, -0.15192424,  0.6870414 , -0.90325114,
           0.77816331, -2.14903403,  0.23682143,  0.47138943, -0.26381095,
          -1.72174484,  0.70897631,  1.19831382,  0.6537401 , -0.17682102,
          -0.74564104, -0.97780188, -1.87756116, -0.29443922,  0.45824652,
          -0.80421393, -0.41012153, -1.04762769,  0.42932349,  1.2102797 ,
           0.10064935,  0.38721905, -1.69759714,  0.30360933,  0.18920693,
           0.88070821,  0.06445955,  0.2453985 ,  0.42510519, -0.03765171,
           0.47967058,  1.37685937, -0.72184219,  0.65808692, -0.36645823,
           0.52223803, -0.03703202,  0.09859009,  0.46216406,  0.90797845]),
   'yaxis': 'y1'},
  {'type': 'box',
   'xaxis': 'x2',
   'y': array([ 1.39114565,  2.42361719,  0.74492841,  0.5796092 ,  0.70920041,
           1.84970903,  1.28910587,  2.46293187,  0.46195123, -0.01825562,
           2.60459886,  0.03786005,  1.11958395, -0.20198951, -1.09348176,
           1.8939656 , -0.72453807,  1.45243595,  2.39173323,  1.56600484,
           1.78916462,  1.61941803,  2.25792077,  0.89589498,  1.0673083 ,
           1.0942342 ,  0.42048992, -0.35346571,  0.59505795,  2.17376683,
           2.13342539,  0.59371436,  0.32297912,  0.35487172, -0.19119881,
           1.43115097,  0.2614727 ,  0.90561162,  1.84856626,  1.49876699,
           0.3717146 ,  0.03332516,  0.16060302, -1.63113126,  0.28004198,
           0.59134313,  1.76526806, -0.04537056,  1.8133062 ,  0.98513375]),
   'yaxis': 'y2'},
  {'showscale': False,
   'type': 'heatmap',
   'xaxis': 'x3',
   'yaxis': 'y3',
   'z': [[1, 20, 30], [20, 1, 60], [30, 60, 1]]}],
 'layout': {'annotations': [{'font': {'size': 16},
    'showarrow': False,
    'text': 'First Subplot',
    'x': 0.225,
    'xanchor': 'center',
    'xref': 'paper',
    'y': 1.0,
    'yanchor': 'bottom',
    'yref': 'paper'},
   {'font': {'size': 16},
    'showarrow': False,
    'text': 'Second Subplot',
    'x': 0.775,
    'xanchor': 'center',
    'xref': 'paper',
    'y': 1.0,
    'yanchor': 'bottom',
    'yref': 'paper'},
   {'font': {'size': 16},
    'showarrow': False,
    'text': 'Third Subplot',
    'x': 0.5,
    'xanchor': 'center',
    'xref': 'paper',
    'y': 0.375,
    'yanchor': 'bottom',
    'yref': 'paper'}],
  'height': 600,
  'title': 'i <3 subplots',
  'width': 600,
  'xaxis1': {'anchor': 'y1', 'domain': [0.0, 0.45]},
  'xaxis2': {'anchor': 'y2', 'domain': [0.55, 1.0]},
  'xaxis3': {'anchor': 'y3', 'domain': [0.0, 1.0]},
  'yaxis1': {'anchor': 'x1', 'domain': [0.625, 1.0]},
  'yaxis2': {'anchor': 'x2', 'domain': [0.625, 1.0]},
  'yaxis3': {'anchor': 'x3', 'domain': [0.0, 0.375]}}}

We actually see that the second boxplot has its own xaxis and yaxis. Thus we should unify it with the same axis as the first subplot. Then from the layout section, we should remove the additional xaxis and yaxis that are drawn for us. You can perform these steps seperately to see what I mean, but in this guide, I'll just show you the result of this edit/customization.

In [117]:
fig.data[1].yaxis = 'y1'
fig.data[1].xaxis = 'x1'
del fig.layout['xaxis2']
del fig.layout['yaxis2']

Now we still have to remove the annotation for the Second Subplot title, asell as the First Subplot title, and then extend the range of xaxis1 to the entire plotting surface.

In [118]:
del fig.layout.annotations[0]   #deletes annotation for `First Subplot`
del fig.layout.annotations[0]   #deletes annotation for `Second Subplot` because of shift
fig.layout.xaxis1.domain = [0.0, 1]

And voila! We just put together some examples that we've never seen before, and customized out plot using what we learned throughout the guide!

In [122]:
py.iplot(fig, filename='box-heatmap-fixed')
Out[122]:

Using the Reference Page

At this point you may have a good idea of how you want to visualize your data, and which type of plot you would like to use. You've taken a look at some examples of this plot type, but there are still some details that you would like to add or change. Now is the time for you to check out the Reference Page! The reference page details all the parameters that can be set for every type of plot that is possible in Plotly (ie: all the trace objects). In addition it also provides details on the possible parameters that are available to change in the Layout object as well.

something

When you first load the page you will see a menu on the left which is segregated into Plot Objects and Layout. This exemplifies the two components of every Plotly figure. So for example if you knew you wanted to change something related to the visualization of the data, then you would look at the first section. If instead you were interested in a general aesthetic feature of the graph then the Layout will probably be your best option.

Now for example, if you decided to create a scatter plot, then you would choose Scatter under Plot Objects, and that will take you to the the section for Scatter. On your immediate right you will be able to see a breakdown of the Scatter section, which includes all the parameters and sub-parameters at your disposal.

Issues and Questions

So you've developed a better understanding of Plotly now, and you're starting to create cooler plots and visualizations for different projects you're working on. If you ever happen to get stuck with certain use cases or features in Plotly, you can let us know at our Community Forums. Community Support Moreover if you sign up for a Pro Plan, we also offer e-mail and intercom support as well. Finally if you think you've caught a bug or if something just doesn't function the way it should, you can create an issue on our Github Repo.

Still need help?
Contact Us

For guaranteed 24 hour response turnarounds, upgrade to a Developer Support Plan.