{ "metadata": { "name": "", "signature": "sha256:82d8c4825ae82d31a06f9351cbac79b72197f51df6960bb6a550564daf5a1115" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Plotly Annotations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import plotly \n", "plotly.__version__" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 1, "text": [ "'1.1.4'" ] } ], "prompt_number": 1 }, { "cell_type": "code", "collapsed": false, "input": [ "import plotly.plotly as py\n", "import plotly.tools as tls\n", "from plotly.graph_objs import *" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "Let's start by retrieving the figure object associated with your original Plotly figure:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "empet22 = py.get_figure(\"https://plot.ly/~empet/22/\")" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "print empet22.to_string()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Figure(\n", " data=Data([\n", " Bar(\n", " x=[39.0, 29.0, 33.0, 35.0, 39.0, 28.0, 33.0, 35.0, 31.0, 31.0, ...],\n", " y=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1...],\n", " orientation='h',\n", " text=['1936, Jesse DOUGLAS', '1936, Lars Valerian AHLFORS', '19...],\n", " marker=Marker(\n", " color='rgb(127,205,187)'\n", " )\n", " )\n", " ]),\n", " layout=Layout(\n", " title='The age of Fields Medalists at the time of medal award',\n", " font=Font(\n", " family='Raleway, sans-serif'\n", " ),\n", " showlegend=False,\n", " autosize=False,\n", " width=500,\n", " height=800,\n", " xaxis=XAxis(\n", " title='Age',\n", " range=[20, 41],\n", " gridwidth=2\n", " ),\n", " yaxis=YAxis(\n", " title='The index of medalists sorted by award year'\n", " ),\n", " bargap=0.15\n", " )\n", ")\n" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, call help on the `Annotation` graph object:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "help(Annotation) \n", "\n", "# note that the next version of Plotly's Python API will have more extension \n", "# help() documentation for several graph object including Annotation" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Help on class Annotation in module plotly.graph_objs.graph_objs:\n", "\n", "class Annotation(PlotlyDict)\n", " | A dictionary-like object for representing an annotation in plotly.\n", " | \n", " | Annotations appear as notes on the final figure. You can set all the\n", " | features of the annotation text, background color, and location.\n", " | Additionally, these notes can be anchored to actual data or the page for\n", " | help with location after pan-and-zoom actions.\n", " | \n", " | This object is validated upon instantiation, therefore, you may see\n", " | exceptions getting thrown. These are intended to help users find the\n", " | origin of errors faster. The errors will usually contain information that\n", " | can be used to remedy the problem.\n", " | \n", " | Example:\n", " | \n", " | note = Annotation(text='what i want this to say is:
THIS!',\n", " | x=0,\n", " | y=0,\n", " | xref='paper',\n", " | yref='paper,\n", " | yanchor='bottom',\n", " | xanchor='left')\n", " | \n", " | \n", " | Quick method reference:\n", " | \n", " | Annotation.update(changes)\n", " | Annotation.strip_style()\n", " | Annotation.get_data()\n", " | Annotation.to_graph_objs()\n", " | Annotation.validate()\n", " | Annotation.to_string()\n", " | Annotation.force_clean()\n", " | \n", " | Valid keys:\n", " | \n", " | x [required=False] (value=number: x >= 0):\n", " | Sets the 'x' position of this annotations.\n", " | \n", " | y [required=False] (value=number: x >= 0):\n", " | Sets the 'y' position of this annotations.\n", " | \n", " | xref [required=False] (value='paper' | 'x1' | 'x2' | etc):\n", " | Sets the x coordinate for this object refers to. If you reference an\n", " | axis, e.g., 'x2', the object will move with pan-and-zoom to stay\n", " | fixed to this point. If you reference the 'paper', it remains fixed\n", " | regardless of pan-and-zoom. In other words, if set to 'paper', the\n", " | 'x' location refers to the distance from the left side of the\n", " | plotting area in normalized coordinates where 0=='left' and\n", " | 1=='right'. If set to refer to an xaxis' object, e.g., 'x1', 'x2',\n", " | 'x3', etc., the 'x' location will refer to the location in terms of\n", " | this axis.\n", " | \n", " | yref [required=False] (value='paper' | 'y1' | 'y2' | etc):\n", " | Sets the y coordinate for this object refers to. If you reference an\n", " | axis, e.g., 'y2', the object will move with pan-and-zoom to stay\n", " | fixed to this point. If you reference the 'paper', it remains fixed\n", " | regardless of pan-and-zoom. In other words, if set to 'paper', the\n", " | 'y' location refers to the distance from the left side of the\n", " | plotting area in normalized coordinates where 0=='bottom' and\n", " | 1=='top'. If set to refer to an yaxis' object, e.g., 'y1', 'y2',\n", " | 'y3', etc., the 'y' location will refer to the location in terms of\n", " | this axis.\n", " | \n", " | text [required=False] (value=string):\n", " | The text associated with this annotation. Plotly uses a subset of\n", " | HTML escape characters to do things like newline (
), bold\n", " | (), italics (), etc.\n", " | \n", " | Examples:\n", " | ['regular text', 'an annotation
spanning two lines', 'bold\n", " | text']\n", " | \n", " | font [required=False] (value=Font object | dictionary-like):\n", " | A dictionary-like object describing the font settings within this\n", " | annotation.\n", " | \n", " | For more, run `help(plotly.graph_objs.Font)`\n", " | \n", " | align [required=False] (value='left' | 'center' | 'right'):\n", " | Sets the alignment of the text in the annotation.\n", " | \n", " | showarrow [required=False] (value=boolean: True | False):\n", " | Toggle whether or not the arrow associated with this annotation with\n", " | be shown.\n", " | \n", " | arrowhead [required=False] (value=0 | 1 | 2 | 3 | 4 | 5 | 6 | 7):\n", " | Sets the arrowhead style. Has an effect only if 'showarrow' is set\n", " | to True.\n", " | \n", " | arrowsize [required=False] (value=number: x >= 0):\n", " | Scales the arrowhead's size. Has an effect only if 'showarrow' is\n", " | set to True.\n", " | \n", " | arrowwidth [required=False] (value=number: x > 0):\n", " | Sets the arrowhead's width (in pixels). Has an effect only if\n", " | 'showarrow' is set to True.\n", " | \n", " | arrowcolor [required=False] (value=string describing color):\n", " | Sets the color of the arrowhead. Has an effect only if 'showarrow'\n", " | is set to True.\n", " | \n", " | Examples:\n", " | [\"'green'\", \"'rgb(0, 255, 0)'\", \"'rgba(0, 255, 0, 0.3)'\",\n", " | \"'hsl(120,100%,50%)'\", \"'hsla(120,100%,50%,0.3)'\"]\n", " | \n", " | ax [required=False] (value=number):\n", " | Position of the annotation text relative to the arrowhead about the\n", " | x-axis. Has an effect only if 'showarrow' is set to True.\n", " | \n", " | ay [required=False] (value=number):\n", " | Position of the annotation text relative to the arrowhead about the\n", " | y-axis. Has an effect only if 'showarrow' is set to True.\n", " | \n", " | bordercolor [required=False] (value=string describing color):\n", " | The color of the enclosing boarder of this annotation.\n", " | \n", " | Examples:\n", " | [\"'green'\", \"'rgb(0, 255, 0)'\", \"'rgba(0, 255, 0, 0.3)'\",\n", " | \"'hsl(120,100%,50%)'\", \"'hsla(120,100%,50%,0.3)'\"]\n", " | \n", " | borderwidth [required=False] (value=number: x >= 0):\n", " | Sets the width of the boarder enclosing this annotation\n", " | \n", " | borderpad [required=False] (value=number: x in [0, 10]):\n", " | The amount of space (padding) between the text and the enclosing\n", " | boarder.\n", " | \n", " | bgcolor [required=False] (value=string describing color):\n", " | Sets the background (bg) color for this annotation.\n", " | \n", " | Examples:\n", " | [\"'green'\", \"'rgb(0, 255, 0)'\", \"'rgba(0, 255, 0, 0.3)'\",\n", " | \"'hsl(120,100%,50%)'\", \"'hsla(120,100%,50%,0.3)'\"]\n", " | \n", " | opacity [required=False] (value=number: x in [0, 1]):\n", " | Sets the opacity, or transparency, of the entire object, also known\n", " | as the alpha channel of colors. If the object's color is given in\n", " | terms of 'rgba' color model, 'opacity' is redundant.\n", " | \n", " | xanchor [required=False] (value='left' | 'center' | 'right'):\n", " | This defines the horizontal location on the object referenced by the\n", " | 'x' (position) key. For example, if 'x'==1, 'xref'='paper', and\n", " | 'xanchor'='right', the rightmost portion of this object will line up\n", " | with the rightmost edge of the plotting area.\n", " | \n", " | yanchor [required=False] (value='bottom' | 'middle' | 'top'):\n", " | This defines the horizontal location on the object referenced by the\n", " | 'y' (position) key. For example, if 'y'==1, 'yref'='paper', and\n", " | 'yanchor'='top', the topmost portion of this object will line up\n", " | with the topmost edge of the plotting area.\n", " | \n", " | xatype [required=False] (value=):\n", " | more info coming soon\n", " | \n", " | yatype [required=False] (value=):\n", " | more info coming soon\n", " | \n", " | tag [required=False] (value=):\n", " | more info coming soon\n", " | \n", " | ref [required=False] (value=):\n", " | more info coming soon\n", " | \n", " | Method resolution order:\n", " | Annotation\n", " | PlotlyDict\n", " | __builtin__.dict\n", " | __builtin__.object\n", " | \n", " | Methods inherited from PlotlyDict:\n", " | \n", " | __init__(self, *args, **kwargs)\n", " | \n", " | force_clean(self, caller=True)\n", " | Attempts to convert to graph_objs and call force_clean() on values.\n", " | \n", " | Calling force_clean() on a PlotlyDict will ensure that the object is\n", " | valid and may be sent to plotly. This process will also remove any\n", " | entries that end up with a length == 0.\n", " | \n", " | Careful! This will delete any invalid entries *silently*.\n", " | \n", " | get_data(self)\n", " | Returns the JSON for the plot with non-data elements stripped.\n", " | \n", " | get_ordered(self, caller=True)\n", " | \n", " | strip_style(self)\n", " | Strip style from the current representation.\n", " | \n", " | All PlotlyDicts and PlotlyLists are guaranteed to survive the\n", " | stripping process, though they made be left empty. This is allowable.\n", " | \n", " | Keys that will be stripped in this process are tagged with\n", " | `'type': 'style'` in the INFO dictionary listed in graph_objs_meta.py.\n", " | \n", " | This process first attempts to convert nested collections from dicts\n", " | or lists to subclasses of PlotlyList/PlotlyDict. This process forces\n", " | a validation, which may throw exceptions.\n", " | \n", " | Then, each of these objects call `strip_style` on themselves and so\n", " | on, recursively until the entire structure has been validated and\n", " | stripped.\n", " | \n", " | to_graph_objs(self, caller=True)\n", " | Walk obj, convert dicts and lists to plotly graph objs.\n", " | \n", " | For each key in the object, if it corresponds to a special key that\n", " | should be associated with a graph object, the ordinary dict or list\n", " | will be reinitialized as a special PlotlyDict or PlotlyList of the\n", " | appropriate `kind`.\n", " | \n", " | to_string(self, level=0, indent=4, eol='\\n', pretty=True, max_chars=80)\n", " | Returns a formatted string showing graph_obj constructors.\n", " | \n", " | Example:\n", " | \n", " | print obj.to_string()\n", " | \n", " | Keyword arguments:\n", " | level (default = 0) -- set number of indentations to start with\n", " | indent (default = 4) -- set indentation amount\n", " | eol (default = '\n", " | ') -- set end of line character(s)\n", " | pretty (default = True) -- curtail long list output with a '...'\n", " | max_chars (default = 80) -- set max characters per line\n", " | \n", " | update(self, dict1=None, **dict2)\n", " | Update current dict with dict1 and then dict2.\n", " | \n", " | This recursively updates the structure of the original dictionary-like\n", " | object with the new entries in the second and third objects. This\n", " | allows users to update with large, nested structures.\n", " | \n", " | Note, because the dict2 packs up all the keyword arguments, you can\n", " | specify the changes as a list of keyword agruments.\n", " | \n", " | Examples:\n", " | # update with dict\n", " | obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))\n", " | update_dict = dict(title='new title', xaxis=dict(domain=[0,.8]))\n", " | obj.update(update_dict)\n", " | obj\n", " | {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}\n", " | \n", " | # update with list of keyword arguments\n", " | obj = Layout(title='my title', xaxis=XAxis(range=[0,1], domain=[0,1]))\n", " | obj.update(title='new title', xaxis=dict(domain=[0,.8]))\n", " | obj\n", " | {'title': 'new title', 'xaxis': {'range': [0,1], 'domain': [0,.8]}}\n", " | \n", " | This 'fully' supports duck-typing in that the call signature is\n", " | identical, however this differs slightly from the normal update\n", " | method provided by Python's dictionaries.\n", " | \n", " | validate(self, caller=True)\n", " | Recursively check the validity of the keys in a PlotlyDict.\n", " | \n", " | The valid keys constitute the entries in each object\n", " | dictionary in INFO stored in graph_objs_meta.py.\n", " | \n", " | The validation process first requires that all nested collections be\n", " | converted to the appropriate subclass of PlotlyDict/PlotlyList. Then,\n", " | each of these objects call `validate` and so on, recursively,\n", " | until the entire object has been validated.\n", " | \n", " | ----------------------------------------------------------------------\n", " | Data descriptors inherited from PlotlyDict:\n", " | \n", " | __dict__\n", " | dictionary for instance variables (if defined)\n", " | \n", " | __weakref__\n", " | list of weak references to the object (if defined)\n", " | \n", " | ----------------------------------------------------------------------\n", " | Data and other attributes inherited from PlotlyDict:\n", " | \n", " | __metaclass__ = \n", " | A meta class for PlotlyDict class creation.\n", " | \n", " | The sole purpose of this meta class is to properly create the __doc__\n", " | attribute so that running help(Obj), where Obj is a subclass of PlotlyDict,\n", " | will return information about key-value pairs for that object.\n", " | \n", " | ----------------------------------------------------------------------\n", " | Methods inherited from __builtin__.dict:\n", " | \n", " | __cmp__(...)\n", " | x.__cmp__(y) <==> cmp(x,y)\n", " | \n", " | __contains__(...)\n", " | D.__contains__(k) -> True if D has a key k, else False\n", " | \n", " | __delitem__(...)\n", " | x.__delitem__(y) <==> del x[y]\n", " | \n", " | __eq__(...)\n", " | x.__eq__(y) <==> x==y\n", " | \n", " | __ge__(...)\n", " | x.__ge__(y) <==> x>=y\n", " | \n", " | __getattribute__(...)\n", " | x.__getattribute__('name') <==> x.name\n", " | \n", " | __getitem__(...)\n", " | x.__getitem__(y) <==> x[y]\n", " | \n", " | __gt__(...)\n", " | x.__gt__(y) <==> x>y\n", " | \n", " | __iter__(...)\n", " | x.__iter__() <==> iter(x)\n", " | \n", " | __le__(...)\n", " | x.__le__(y) <==> x<=y\n", " | \n", " | __len__(...)\n", " | x.__len__() <==> len(x)\n", " | \n", " | __lt__(...)\n", " | x.__lt__(y) <==> x x!=y\n", " | \n", " | __repr__(...)\n", " | x.__repr__() <==> repr(x)\n", " | \n", " | __setitem__(...)\n", " | x.__setitem__(i, y) <==> x[i]=y\n", " | \n", " | __sizeof__(...)\n", " | D.__sizeof__() -> size of D in memory, in bytes\n", " | \n", " | clear(...)\n", " | D.clear() -> None. Remove all items from D.\n", " | \n", " | copy(...)\n", " | D.copy() -> a shallow copy of D\n", " | \n", " | fromkeys(...)\n", " | dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.\n", " | v defaults to None.\n", " | \n", " | get(...)\n", " | D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.\n", " | \n", " | has_key(...)\n", " | D.has_key(k) -> True if D has a key k, else False\n", " | \n", " | items(...)\n", " | D.items() -> list of D's (key, value) pairs, as 2-tuples\n", " | \n", " | iteritems(...)\n", " | D.iteritems() -> an iterator over the (key, value) items of D\n", " | \n", " | iterkeys(...)\n", " | D.iterkeys() -> an iterator over the keys of D\n", " | \n", " | itervalues(...)\n", " | D.itervalues() -> an iterator over the values of D\n", " | \n", " | keys(...)\n", " | D.keys() -> list of D's keys\n", " | \n", " | pop(...)\n", " | D.pop(k[,d]) -> v, remove specified key and return the corresponding value.\n", " | If key is not found, d is returned if given, otherwise KeyError is raised\n", " | \n", " | popitem(...)\n", " | D.popitem() -> (k, v), remove and return some (key, value) pair as a\n", " | 2-tuple; but raise KeyError if D is empty.\n", " | \n", " | setdefault(...)\n", " | D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D\n", " | \n", " | values(...)\n", " | D.values() -> list of D's values\n", " | \n", " | viewitems(...)\n", " | D.viewitems() -> a set-like object providing a view on D's items\n", " | \n", " | viewkeys(...)\n", " | D.viewkeys() -> a set-like object providing a view on D's keys\n", " | \n", " | viewvalues(...)\n", " | D.viewvalues() -> an object providing a view on D's values\n", " | \n", " | ----------------------------------------------------------------------\n", " | Data and other attributes inherited from __builtin__.dict:\n", " | \n", " | __hash__ = None\n", " | \n", " | __new__ = \n", " | T.__new__(S, ...) -> a new object with type S, a subtype of T\n", "\n" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "As the desired annotation includes two rather long `` HTML tags, I recommand linking your annotation text to a variable. That way you don't have to worry about Python and/or your web browser erroneously formating tabs and spaces. So," ] }, { "cell_type": "code", "collapsed": false, "input": [ "anno_text = \"Source: medalist birth dates on \\\n", "[1] and \\\n", "[2]\"\n", "\n", "# (!) use \" \" to bound the text and ' ' to bound the hyperlinks\n", "# make sure that the string continues on the first column after the line breaks (\\)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ok. Now fill in an `Annotation` object:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "annotation = Annotation(\n", " showarrow=False, # no arrow, making 'x' and 'y' are the coord of the text\n", " text=anno_text, # link the annotation text\n", " xref='paper', # (!) use 'paper' coordinates for both 'x'\n", " yref='paper', # and 'y'\n", " x=0, # (!) corresponds to left edge of plotting area\n", " y=1, # (1) \" to top edge of plotting area\n", " xanchor='left', # (!) 'x' corresponds to the text's left edge\n", " yanchor='bottom', # (!) 'y' corresponds to the text's bottom edge\n", " font=Font(\n", " size=14 # increase the font size\n", " )\n", ")" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case, I recommand using paper coordinates, as the annoation does not refer to a particular data point. \n", "\n", "Setinng `xref='x1'` and `yref='y1'` would make `'x'` and `'y'` correspond to the coordinates of the axes. For example, something like:\n", "\n", " annotation = Annotation(\n", " showarrow=False, \n", " text=anno_text, \n", " xref='x1', \n", " yref='y1', \n", " x=30, \n", " y=40, \n", " )\n", " \n", "would place the annotation at (x=30,y=40).\n", "\n", "Moreover, note that axis-referenced annotations move when one zooms in or pans, whereas paper-referenced annotations are static." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, package the annoation into `Annotations`, which is simply takes in a list of `Annotation` object(s), and update the figure object:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "annotations = Annotations([annotation])\n", "\n", "# Update figure object\n", "empet22['layout'].update(annotations=annotations)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "print empet22.to_string() # print updated figure object" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Figure(\n", " data=Data([\n", " Bar(\n", " x=[39.0, 29.0, 33.0, 35.0, 39.0, 28.0, 33.0, 35.0, 31.0, 31.0, ...],\n", " y=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1...],\n", " orientation='h',\n", " text=['1936, Jesse DOUGLAS', '1936, Lars Valerian AHLFORS', '19...],\n", " marker=Marker(\n", " color='rgb(127,205,187)'\n", " )\n", " )\n", " ]),\n", " layout=Layout(\n", " title='The age of Fields Medalists at the time of medal award',\n", " font=Font(\n", " family='Raleway, sans-serif'\n", " ),\n", " showlegend=False,\n", " autosize=False,\n", " width=500,\n", " height=800,\n", " xaxis=XAxis(\n", " title='Age',\n", " range=[20, 41],\n", " gridwidth=2\n", " ),\n", " yaxis=YAxis(\n", " title='The index of medalists sorted by award year'\n", " ),\n", " annotations=Annotations([\n", " Annotation(\n", " x=0,\n", " y=1,\n", " xref='paper',\n", " yref='paper',\n", " text=\"Source: medalist birth dates on " ], "metadata": {}, "output_type": "display_data", "text": [ "" ] } ], "prompt_number": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " \n", "
\n", "\n", "

Got Questions or Feedback?

\n", "\n", "About
Plotly\n", "\n", "* email: feedback@plot.ly \n", "* tweet: \n", "@plotlygraphs\n", "\n", "

Notebook styling ideas

\n", "\n", "Big thanks to\n", "\n", "* Cam Davidson-Pilon\n", "* Lorena A. Barba\n", "\n", "
" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from IPython.display import display, HTML\n", "import urllib2\n", "url = 'https://raw.githubusercontent.com/plotly/python-user-guide/master/custom.css'\n", "display(HTML(urllib2.urlopen(url).read()))" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "\n" ], "metadata": {}, "output_type": "display_data", "text": [ "" ] } ], "prompt_number": 11 } ], "metadata": {} } ] }