import plotly
plotly.__version__
'1.1.4'
import plotly.plotly as py
import plotly.tools as tls
from plotly.graph_objs import *
Let's start by retrieving the figure object associated with your original Plotly figure:
empet22 = py.get_figure("https://plot.ly/~empet/22/")
print empet22.to_string()
Figure( data=Data([ Bar( x=[39.0, 29.0, 33.0, 35.0, 39.0, 28.0, 33.0, 35.0, 31.0, 31.0, ...], y=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1...], orientation='h', text=['1936, Jesse DOUGLAS', '1936, Lars Valerian AHLFORS', '19...], marker=Marker( color='rgb(127,205,187)' ) ) ]), layout=Layout( title='The age of Fields Medalists at the time of medal award', font=Font( family='Raleway, sans-serif' ), showlegend=False, autosize=False, width=500, height=800, xaxis=XAxis( title='Age', range=[20, 41], gridwidth=2 ), yaxis=YAxis( title='The index of medalists sorted by award year' ), bargap=0.15 ) )
Next, call help on the Annotation
graph object:
help(Annotation)
# note that the next version of Plotly's Python API will have more extension
# help() documentation for several graph object including Annotation
Help on class Annotation in module plotly.graph_objs.graph_objs: class Annotation(PlotlyDict) | A dictionary-like object for representing an annotation in plotly. | | Annotations appear as notes on the final figure. You can set all the | features of the annotation text, background color, and location. | Additionally, these notes can be anchored to actual data or the page for | help with location after pan-and-zoom actions. | | This object is validated upon instantiation, therefore, you may see | exceptions getting thrown. These are intended to help users find the | origin of errors faster. The errors will usually contain information that | can be used to remedy the problem. | | Example: | | note = Annotation(text='what i want this to say is:<br>THIS!', | x=0, | y=0, | xref='paper', | yref='paper, | yanchor='bottom', | xanchor='left') | | | Quick method reference: | | Annotation.update(changes) | Annotation.strip_style() | Annotation.get_data() | Annotation.to_graph_objs() | Annotation.validate() | Annotation.to_string() | Annotation.force_clean() | | Valid keys: | | x [required=False] (value=number: x >= 0): | Sets the 'x' position of this annotations. | | y [required=False] (value=number: x >= 0): | Sets the 'y' position of this annotations. | | xref [required=False] (value='paper' | 'x1' | 'x2' | etc): | Sets the x coordinate for this object refers to. If you reference an | axis, e.g., 'x2', the object will move with pan-and-zoom to stay | fixed to this point. If you reference the 'paper', it remains fixed | regardless of pan-and-zoom. In other words, if set to 'paper', the | 'x' location refers to the distance from the left side of the | plotting area in normalized coordinates where 0=='left' and | 1=='right'. If set to refer to an xaxis' object, e.g., 'x1', 'x2', | 'x3', etc., the 'x' location will refer to the location in terms of | this axis. | | yref [required=False] (value='paper' | 'y1' | 'y2' | etc): | Sets the y coordinate for this object refers to. If you reference an | axis, e.g., 'y2', the object will move with pan-and-zoom to stay | fixed to this point. If you reference the 'paper', it remains fixed | regardless of pan-and-zoom. In other words, if set to 'paper', the | 'y' location refers to the distance from the left side of the | plotting area in normalized coordinates where 0=='bottom' and | 1=='top'. If set to refer to an yaxis' object, e.g., 'y1', 'y2', | 'y3', etc., the 'y' location will refer to the location in terms of | this axis. | | text [required=False] (value=string): | The text associated with this annotation. Plotly uses a subset of | HTML escape characters to do things like newline (<br>), bold | (<b></b>), italics (<i></i>), etc. | | Examples: | ['regular text', 'an annotation<br>spanning two lines', '<b>bold | text</b>'] | | font [required=False] (value=Font object | dictionary-like): | A dictionary-like object describing the font settings within this | annotation. | | For more, run `help(plotly.graph_objs.Font)` | | align [required=False] (value='left' | 'center' | 'right'): | Sets the alignment of the text in the annotation. | | showarrow [required=False] (value=boolean: True | False): | Toggle whether or not the arrow associated with this annotation with | be shown. | | arrowhead [required=False] (value=0 | 1 | 2 | 3 | 4 | 5 | 6 | 7): | Sets the arrowhead style. Has an effect only if 'showarrow' is set | to True. | | arrowsize [required=False] (value=number: x >= 0): | Scales the arrowhead's size. Has an effect only if 'showarrow' is | set to True. | | arrowwidth [required=False] (value=number: x > 0): | Sets the arrowhead's width (in pixels). Has an effect only if | 'showarrow' is set to True. | | arrowcolor [required=False] (value=string describing color): | Sets the color of the arrowhead. Has an effect only if 'showarrow' | is set to True. | | Examples: | ["'green'", "'rgb(0, 255, 0)'", "'rgba(0, 255, 0, 0.3)'", | "'hsl(120,100%,50%)'", "'hsla(120,100%,50%,0.3)'"] | | ax [required=False] (value=number): | Position of the annotation text relative to the arrowhead about the | x-axis. Has an effect only if 'showarrow' is set to True. | | ay [required=False] (value=number): | Position of the annotation text relative to the arrowhead about the | y-axis. Has an effect only if 'showarrow' is set to True. | | bordercolor [required=False] (value=string describing color): | The color of the enclosing boarder of this annotation. | | Examples: | ["'green'", "'rgb(0, 255, 0)'", "'rgba(0, 255, 0, 0.3)'", | "'hsl(120,100%,50%)'", "'hsla(120,100%,50%,0.3)'"] | | borderwidth [required=False] (value=number: x >= 0): | Sets the width of the boarder enclosing this annotation | | borderpad [required=False] (value=number: x in [0, 10]): | The amount of space (padding) between the text and the enclosing | boarder. | | bgcolor [required=False] (value=string describing color): | Sets the background (bg) color for this annotation. | | 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. | | xanchor [required=False] (value='left' | 'center' | 'right'): | This defines the horizontal location on the object referenced by the | 'x' (position) key. For example, if 'x'==1, 'xref'='paper', and | 'xanchor'='right', the rightmost portion of this object will line up | with the rightmost edge of the plotting area. | | yanchor [required=False] (value='bottom' | 'middle' | 'top'): | This defines the horizontal location on the object referenced by the | 'y' (position) key. For example, if 'y'==1, 'yref'='paper', and | 'yanchor'='top', the topmost portion of this object will line up | with the topmost edge of the plotting area. | | xatype [required=False] (value=): | more info coming soon | | yatype [required=False] (value=): | more info coming soon | | tag [required=False] (value=): | more info coming soon | | ref [required=False] (value=): | more info coming soon | | Method resolution order: | Annotation | PlotlyDict | __builtin__.dict | __builtin__.object | | Methods inherited from PlotlyDict: | | __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 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) | | ---------------------------------------------------------------------- | Data and other attributes inherited from PlotlyDict: | | __metaclass__ = <class 'plotly.graph_objs.graph_objs.DictMeta'> | A meta class for PlotlyDict class creation. | | The sole purpose of this meta class is to properly create the __doc__ | attribute so that running help(Obj), where Obj is a subclass of PlotlyDict, | will return information about key-value pairs for that object. | | ---------------------------------------------------------------------- | Methods inherited from __builtin__.dict: | | __cmp__(...) | x.__cmp__(y) <==> cmp(x,y) | | __contains__(...) | D.__contains__(k) -> True if D has a key k, else False | | __delitem__(...) | x.__delitem__(y) <==> del x[y] | | __eq__(...) | x.__eq__(y) <==> x==y | | __ge__(...) | x.__ge__(y) <==> x>=y | | __getattribute__(...) | x.__getattribute__('name') <==> x.name | | __getitem__(...) | x.__getitem__(y) <==> x[y] | | __gt__(...) | x.__gt__(y) <==> x>y | | __iter__(...) | x.__iter__() <==> iter(x) | | __le__(...) | x.__le__(y) <==> x<=y | | __len__(...) | x.__len__() <==> len(x) | | __lt__(...) | x.__lt__(y) <==> x<y | | __ne__(...) | x.__ne__(y) <==> x!=y | | __repr__(...) | x.__repr__() <==> repr(x) | | __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. | | 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
As the desired annotation includes two rather long <a>
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,
anno_text = "Source: medalist birth dates on \
<a href='http://www.mathunion.org/index.php?id=prizewinners'>[1]</a> and \
<a href='http://en.wikipedia.org/'>[2]</a>"
# (!) use " " to bound the text and ' ' to bound the hyperlinks
# make sure that the string continues on the first column after the line breaks (\)
Ok. Now fill in an Annotation
object:
annotation = Annotation(
showarrow=False, # no arrow, making 'x' and 'y' are the coord of the text
text=anno_text, # link the annotation text
xref='paper', # (!) use 'paper' coordinates for both 'x'
yref='paper', # and 'y'
x=0, # (!) corresponds to left edge of plotting area
y=1, # (1) " to top edge of plotting area
xanchor='left', # (!) 'x' corresponds to the text's left edge
yanchor='bottom', # (!) 'y' corresponds to the text's bottom edge
font=Font(
size=14 # increase the font size
)
)
In this case, I recommand using paper coordinates, as the annoation does not refer to a particular data point.
Setinng xref='x1'
and yref='y1'
would make 'x'
and 'y'
correspond to the coordinates of the axes. For example, something like:
annotation = Annotation(
showarrow=False,
text=anno_text,
xref='x1',
yref='y1',
x=30,
y=40,
)
would place the annotation at (x=30,y=40).
Moreover, note that axis-referenced annotations move when one zooms in or pans, whereas paper-referenced annotations are static.
Next, package the annoation into Annotations
, which is simply takes in a list of Annotation
object(s), and update the figure object:
annotations = Annotations([annotation])
# Update figure object
empet22['layout'].update(annotations=annotations)
print empet22.to_string() # print updated figure object
Figure( data=Data([ Bar( x=[39.0, 29.0, 33.0, 35.0, 39.0, 28.0, 33.0, 35.0, 31.0, 31.0, ...], y=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1...], orientation='h', text=['1936, Jesse DOUGLAS', '1936, Lars Valerian AHLFORS', '19...], marker=Marker( color='rgb(127,205,187)' ) ) ]), layout=Layout( title='The age of Fields Medalists at the time of medal award', font=Font( family='Raleway, sans-serif' ), showlegend=False, autosize=False, width=500, height=800, xaxis=XAxis( title='Age', range=[20, 41], gridwidth=2 ), yaxis=YAxis( title='The index of medalists sorted by award year' ), annotations=Annotations([ Annotation( x=0, y=1, xref='paper', yref='paper', text="Source: medalist birth dates on <a href='http://www.m...", font=Font( size=14 ), showarrow=False, xanchor='left', yanchor='bottom' ) ]), bargap=0.15 ) )
And now, send the updated figure object to Plotly!
py.iplot(empet22, filename="empet22-with-annotation", height=810)
# 'height' adjust the height of notebook iframe
About Plotly
Big thanks to
from IPython.display import display, HTML
import urllib2
url = 'https://raw.githubusercontent.com/plotly/python-user-guide/master/custom.css'
display(HTML(urllib2.urlopen(url).read()))