Plotly and IPython: Multiple Axes, Subplots, and Insets

Background

Plotly (https://plot.ly) is a collaborative data analysis and graphing platform. Plotly's IPython Graphing Library (https://plot.ly/api/python) interfaces Plotly's online graphing tools with your IPython notebook environment. Send data to your Plotly account, embed the graphs in your IPython notebook, and share them in your web browser. Style with code or with our online interface; share your work publicly with a url or privately among other Plotly members; access your graphs from anywhere.

Learn More

Let us know what you think

In [49]:
import plotly
p = plotly.plotly('IPython.Demo', '1fw3zw2o13')
In [50]:
p.verbose=False
import numpy as np

Gallery

In [51]:
iris = {
"setosa": {
    "sepal width": [3.5, 3, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.4, 3, 3, 4, 4.4, 3.9, 3.5, 3.8, 3.8, 3.4, 3.7, 3.6, 3.3, 3.4, 3, 3.4, 3.5, 3.4, 3.2, 3.1, 3.4, 4.1, 4.2, 3.1, 3.2, 3.5, 3.6, 3, 3.4, 3.5, 2.3, 3.2, 3.5, 3.8, 3, 3.8, 3.2, 3.7, 3.3], 
    "petal width": [0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.2, 0.5, 0.2, 0.2, 0.4, 0.2, 0.2, 0.2, 0.2, 0.4, 0.1, 0.2, 0.2, 0.2, 0.2, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2, 0.6, 0.4, 0.3, 0.2, 0.2, 0.2, 0.2], 
    "sepal length": [5.1, 4.9, 4.7, 4.6, 5, 5.4, 4.6, 5, 4.4, 4.9, 5.4, 4.8, 4.8, 4.3, 5.8, 5.7, 5.4, 5.1, 5.7, 5.1, 5.4, 5.1, 4.6, 5.1, 4.8, 5, 5, 5.2, 5.2, 4.7, 4.8, 5.4, 5.2, 5.5, 4.9, 5, 5.5, 4.9, 4.4, 5.1, 5, 4.5, 4.4, 5, 5.1, 4.8, 5.1, 4.6, 5.3, 5], 
    "petal length": [1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.6, 1.4, 1.1, 1.2, 1.5, 1.3, 1.4, 1.7, 1.5, 1.7, 1.5, 1, 1.7, 1.9, 1.6, 1.6, 1.5, 1.4, 1.6, 1.6, 1.5, 1.5, 1.4, 1.5, 1.2, 1.3, 1.4, 1.3, 1.5, 1.3, 1.3, 1.3, 1.6, 1.9, 1.4, 1.6, 1.4, 1.5, 1.4]
    }, 
"versicolor": {
    "sepal width": [3.2, 3.2, 3.1, 2.3, 2.8, 2.8, 3.3, 2.4, 2.9, 2.7, 2, 3, 2.2, 2.9, 2.9, 3.1, 3, 2.7, 2.2, 2.5, 3.2, 2.8, 2.5, 2.8, 2.9, 3, 2.8, 3, 2.9, 2.6, 2.4, 2.4, 2.7, 2.7, 3, 3.4, 3.1, 2.3, 3, 2.5, 2.6, 3, 2.6, 2.3, 2.7, 3, 2.9, 2.9, 2.5, 2.8], 
    "petal width": [1.4, 1.5, 1.5, 1.3, 1.5, 1.3, 1.6, 1, 1.3, 1.4, 1, 1.5, 1, 1.4, 1.3, 1.4, 1.5, 1, 1.5, 1.1, 1.8, 1.3, 1.5, 1.2, 1.3, 1.4, 1.4, 1.7, 1.5, 1, 1.1, 1, 1.2, 1.6, 1.5, 1.6, 1.5, 1.3, 1.3, 1.3, 1.2, 1.4, 1.2, 1, 1.3, 1.2, 1.3, 1.3, 1.1, 1.3], 
    "sepal length": [7, 6.4, 6.9, 5.5, 6.5, 5.7, 6.3, 4.9, 6.6, 5.2, 5, 5.9, 6, 6.1, 5.6, 6.7, 5.6, 5.8, 6.2, 5.6, 5.9, 6.1, 6.3, 6.1, 6.4, 6.6, 6.8, 6.7, 6, 5.7, 5.5, 5.5, 5.8, 6, 5.4, 6, 6.7, 6.3, 5.6, 5.5, 5.5, 6.1, 5.8, 5, 5.6, 5.7, 5.7, 6.2, 5.1, 5.7], 
    "petal length": [4.7, 4.5, 4.9, 4, 4.6, 4.5, 4.7, 3.3, 4.6, 3.9, 3.5, 4.2, 4, 4.7, 3.6, 4.4, 4.5, 4.1, 4.5, 3.9, 4.8, 4, 4.9, 4.7, 4.3, 4.4, 4.8, 5, 4.5, 3.5, 3.8, 3.7, 3.9, 5.1, 4.5, 4.5, 4.7, 4.4, 4.1, 4, 4.4, 4.6, 4, 3.3, 4.2, 4.2, 4.2, 4.3, 3, 4.1]
    }, 
"virginica": {
    "sepal width": [3.3, 2.7, 3, 2.9, 3, 3, 2.5, 2.9, 2.5, 3.6, 3.2, 2.7, 3, 2.5, 2.8, 3.2, 3, 3.8, 2.6, 2.2, 3.2, 2.8, 2.8, 2.7, 3.3, 3.2, 2.8, 3, 2.8, 3, 2.8, 3.8, 2.8, 2.8, 2.6, 3, 3.4, 3.1, 3, 3.1, 3.1, 3.1, 2.7, 3.2, 3.3, 3, 2.5, 3, 3.4, 3], 
    "petal width": [2.5, 1.9, 2.1, 1.8, 2.2, 2.1, 1.7, 1.8, 1.8, 2.5, 2, 1.9, 2.1, 2, 2.4, 2.3, 1.8, 2.2, 2.3, 1.5, 2.3, 2, 2, 1.8, 2.1, 1.8, 1.8, 1.8, 2.1, 1.6, 1.9, 2, 2.2, 1.5, 1.4, 2.3, 2.4, 1.8, 1.8, 2.1, 2.4, 2.3, 1.9, 2.3, 2.5, 2.3, 1.9, 2, 2.3, 1.8], 
    "sepal length": [6.3, 5.8, 7.1, 6.3, 6.5, 7.6, 4.9, 7.3, 6.7, 7.2, 6.5, 6.4, 6.8, 5.7, 5.8, 6.4, 6.5, 7.7, 7.7, 6, 6.9, 5.6, 7.7, 6.3, 6.7, 7.2, 6.2, 6.1, 6.4, 7.2, 7.4, 7.9, 6.4, 6.3, 6.1, 7.7, 6.3, 6.4, 6, 6.9, 6.7, 6.9, 5.8, 6.8, 6.7, 6.7, 6.3, 6.5, 6.2, 5.9], 
    "petal length": [6, 5.1, 5.9, 5.6, 5.8, 6.6, 4.5, 6.3, 5.8, 6.1, 5.1, 5.3, 5.5, 5, 5.1, 5.3, 5.5, 6.7, 6.9, 5, 5.7, 4.9, 6.7, 4.9, 5.7, 6, 4.8, 4.9, 5.6, 5.8, 6.1, 6.4, 5.6, 5.1, 5.6, 6.1, 5.6, 5.5, 4.8, 5.4, 5.6, 5.1, 5.1, 5.9, 5.7, 5.2, 5, 5.2, 5.4, 5.1]
    }
}

attr = iris['setosa'].keys()
colors = {'setosa': 'rgb(31, 119, 180)', 'versicolor': 'rgb(255, 127, 14)', 'virginica': 'rgb(44, 160, 44)'}

data = []
for i in range(4):
    for j in range(4):
        for flower in iris.keys():
            data.append({"name": flower, 
                         "x": iris[flower][attr[i]], "y": iris[flower][attr[j]],
                         "type":"scatter","mode":"markers",'marker': {'color': colors[flower], 'opacity':0.7},
                         "xaxis": "x"+(str(i) if i!=0 else ''), "yaxis": "y"+(str(j) if j!=0 else '')})
padding = 0.04;
domains = [[i*padding + i*(1-3*padding)/4, i*padding + ((i+1)*(1-3*padding)/4)] for i in range(4)]

layout = {
    "xaxis":{"domain":domains[0], "title":attr[0], 'zeroline':False,'showline':False,'ticks':'', 'titlefont':{'color': "rgb(67, 67, 67)"},'tickfont':{'color': 'rgb(102,102,102)'}},
    "yaxis":{"domain":domains[0], "title":attr[0], 'zeroline':False,'showline':False,'ticks':'', 'titlefont':{'color': "rgb(67, 67, 67)"},'tickfont':{'color': 'rgb(102,102,102)'}},
    "xaxis1":{"domain":domains[1], "title":attr[1], 'zeroline':False,'showline':False,'ticks':'', 'titlefont':{'color': "rgb(67, 67, 67)"},'tickfont':{'color': 'rgb(102,102,102)'}},
    "yaxis1":{"domain":domains[1], "title":attr[1], 'zeroline':False,'showline':False,'ticks':'', 'titlefont':{'color': "rgb(67, 67, 67)"},'tickfont':{'color': 'rgb(102,102,102)'}},
    "xaxis2":{"domain":domains[2], "title":attr[2], 'zeroline':False,'showline':False,'ticks':'', 'titlefont':{'color': "rgb(67, 67, 67)"},'tickfont':{'color': 'rgb(102,102,102)'}},
    "yaxis2":{"domain":domains[2], "title":attr[2], 'zeroline':False,'showline':False,'ticks':'', 'titlefont':{'color': "rgb(67, 67, 67)"},'tickfont':{'color': 'rgb(102,102,102)'}},
    "xaxis3":{"domain":domains[3], "title":attr[3], 'zeroline':False,'showline':False,'ticks':'', 'titlefont':{'color': "rgb(67, 67, 67)"},'tickfont':{'color': 'rgb(102,102,102)'}},
    "yaxis3":{"domain":domains[3], "title":attr[3], 'zeroline':False,'showline':False,'ticks':'', 'titlefont':{'color': "rgb(67, 67, 67)"},'tickfont':{'color': 'rgb(102,102,102)'}},
    "showlegend":False,
    "width": 800,
    "height": 700,
    "title":"Iris flower data set",
    "titlefont":{'color':'rgb(67,67,67)', 'size': 20}
    }

p.iplot(data,layout=layout, width=850,height=750)



Out[51]:

This graph is interactive! Try it out:

  • roll over points to see values
  • click-drag to zoom
  • click-drag the number line on the axes to translate
  • shift-click-drag to pan
  • double-click to autoscale
In [52]:
x0 = np.concatenate([np.random.randn(100), np.random.randn(100)+6])
y0 = np.random.rayleigh(size=200)
data = [
    {
     "x": x0,
     "y": y0,
     "type": "histogram2d"
     },
    {
     "y": y0,
     "type": "histogramy",
     "xaxis": "x2",
     "yaxis": "y",
     "bardir": "h",
     "marker":{"color":"rgb(31, 119, 180)"}
     },
    {
     "x":x0,
     "type": "histogramx",
     "xaxis": "x",
     "yaxis": "y3",
     "marker":{"color":"rgb(31, 119, 180)"}     
     }
]
layout = {
    "showlegend":False,
    "width":900,
    "height": 700,
    "xaxis":{
        "domain":[0,0.8],
        
        "showgrid":False,
        "showline":False,
        "zeroline":False
    },
    "yaxis":{
        "domain":[0,0.8],
        
        "showgrid":False,
        "showline":False,
        "zeroline":False        
    },
    "xaxis2":{
        "domain":[0.82,1.0],
        
        "showgrid":False,
        "showline":False,
        "zeroline":False        
    },
    "yaxis3":{
        "domain":[0.82,1.0],
        
        "showgrid":False,
        "showline":False,
        "zeroline":False        
    }
}
p.iplot(data,layout=layout,width=950,height=750)



Out[52]:

Simple Examples

In [62]:
data = [
   {
    "x":[1,2,3],
    "y":[40,50,60],
      "name":"yaxis data"
   },
   {
      "x":[2,3,4],
      "y":[4,5,6],
      "yaxis":"y2", # this will reference the yaxis2 object in the layout object
      "name": "yaxis2 data"
   }   
];
layout = {
   "yaxis":{
      "title": "yaxis title", # optional
   },
   "yaxis2":{
      "title": "yaxis2 title", # optional
      "titlefont":{
         "color":"rgb(148, 103, 189)"
      },
      "tickfont":{
         "color":"rgb(148, 103, 189)"
      },
      "overlaying":"y",
      "side":"right",
   }, 
   "title": "Double Y Axis Example",
}
p.iplot(data, layout=layout)



Out[62]:
In [66]:
c = ['#1f77b4', # muted blue
                '#ff7f0e', # safety orange
                '#2ca02c', # cooked asparagus green
                '#d62728', # brick red
                '#9467bd', # muted purple
                '#8c564b', # chestnut brown
                '#e377c2', # raspberry yogurt pink
                '#7f7f7f', # middle gray
                '#bcbd22', # curry yellow-green
                '#17becf']; #blue-teal

data = [
    {
    "x":[1,2,3],
    "y":[4,5,6],
    "name":"yaxis1 data"
   },
   {
      "x":[2,3,4],
      "y":[40,50,60],
      "name":"yaxis2 data",
      "yaxis":"y2" # this references the "yaxis2" object in layout
   },
   {
      "x":[3,4,5],
      "y":[400,500,600],
      "name":"yaxis3 data",
      "yaxis":"y3"
    },
    {
    "x":[4,5,6],
    "y":[40000,50000,60000],
    "name":"yaxis4 data",
    "yaxis":"y4"    
   },
    {
    "x":[5,6,7],
    "y":[400000,500000,600000],
    "name":"yaxis5 data",
    "yaxis":"y5"    
   },
    {
    "x":[6,7,8],
    "y":[4000000,5000000,6000000],
    "name":"yaxis6 data",
    "yaxis":"y6"    
   },
]
layout = {
    "width":800,
    "xaxis":{
        "domain":[0.3,0.7]
    },
   "yaxis":{
      "title": "yaxis title",
      "titlefont":{
         "color":c[0]
      },
      "tickfont":{
         "color":c[0]
      },
   },
   "yaxis2":{
      "overlaying":"y",
      "side":"left",
      "anchor":"free",
      "position":0.15,
      
      "title": "yaxis2 title",
      "titlefont":{
         "color":c[1]
      },
      "tickfont":{
         "color":c[1]
      },
   },
   "yaxis3":{
      "overlaying":"y",
      "side":"left",
      "anchor":"free",
      "position":0,
      
      "title": "yaxis3 title",
      "titlefont":{
         "color":c[2]
      },
      "tickfont":{
         "color":c[2]
      },
   },

   "yaxis4":{     
      "overlaying":"y",
      "side":"right",
      "anchor":"x",
      
      "title": "yaxis4 title",
      "titlefont":{
         "color":c[3]
      },
      "tickfont":{
         "color":c[3]
      },      
   },

   "yaxis5":{     
      "overlaying":"y",
      "side":"right",
      "anchor":"free",
      "position":0.85,

      "title": "yaxis5 title",
      "titlefont":{
         "color":c[4]
      },
      "tickfont":{
         "color":c[4]
      },      
   },

   "yaxis6":{     
      "overlaying":"y",
      "side":"right",
      "anchor":"free",
      "position":1.0,

      "title": "yaxis6 title",
      "titlefont":{
         "color":c[5]
      },
      "tickfont":{
         "color":c[5]
      },      
    },
    "title": "multiple y-axes example"
}
p.iplot(data, layout=layout)



Out[66]:

Simple Subplots

In [55]:
data = [
    {
    "x":[1,2,3],
    "y":[4,5,6],
   },
   {
      "x":[20,30,40],
      "y":[50,60,70],
      "xaxis":"x2",
      "yaxis":"y2"
   }
]

layout = {
    "xaxis":{
        "domain":[0,0.45] # i.e. let the first x-axis span the first 45% of the plot width
    },
    "xaxis2":{
        "domain":[0.55,1] # i.e. let the second x-axis span the latter 45% of the plot width
    },
    "yaxis2":{
        "anchor":"x2" # i.e. bind the second y-axis to the start of the second x-axis
    }
}
p.iplot(data, layout=layout)



Out[55]:

Custom Sized

In [56]:
data = [
    {
    "x":[1,2,3],
    "y":[4,5,6],
   },
   {
      "x":[20,30,40],
      "y":[50,60,70],
      "xaxis":"x2",
      "yaxis":"y2"
   }
]

layout = {
    "xaxis":{
        "domain":[0,0.7] # i.e. let the first x-axis span the first 70% of the plot width
    },
    "xaxis2":{
        "domain":[0.8,1] # i.e. let the second x-axis span the latter 20% of the plot width
    },
    "yaxis2":{
        "anchor":"x2" # i.e. bind the second y-axis to the start of the second x-axis
    }
}
p.iplot(data, layout=layout)



Out[56]:

Create any number of subplots in any size by moving around the axes

Control the position and length of the axes with the "domain" attribute

In [57]:
data = [
    {
    "x":[1,2,3],
    "y":[4,5,6],
   },
   {
      "x":[20,30,40],
      "y":[50,60,70],
      "xaxis":"x2",
      "yaxis":"y2"
   },
   {
      "x":[300,400,500],
      "y":[600,700,800],
      "xaxis":"x3",
      "yaxis":"y3"
   },
   {
      "x":[4000,5000,6000],
      "y":[7000,8000,9000],
      "xaxis":"x4",
      "yaxis":"y4"
   } 
]

layout = {
    "xaxis":{
        "domain":[0,0.45] # let the first x-axis span the first 45% of the plot width
    },
    "yaxis":{
        "domain":[0,0.45] # # and let the first y-axis span the first 45% of the plot height
    },
    "xaxis2":{
        "domain":[0.55,1] # and let the second x-axis span the latter 45% of the plot width
    },
    "yaxis2":{
        "domain":[0,0.45], # and let the second y-axis span the first 45% of the plot height
        "anchor":"x2" # bind the horizontal position of the second y-axis to the start of the second x-axis
    },
    "xaxis3":{
        "domain":[0,0.45],
        "anchor":"y3" # bind the vertical position of this axis to the start of yaxis3
    },
    "yaxis3":{
        "domain":[0.55,1],
    },
    "xaxis4":{
        "domain":[0.55,1],
        "anchor":"y4", # bind the vertical position of this axis to the start of yaxis4
    },
    "yaxis4":{
        "domain":[0.55,1],
        "anchor":"x4" # bind the horizontal position of this axis to the start of xaxis4
    }    
}
p.iplot(data, layout=layout)



Out[57]:

Let subplots share axes

In [63]:
data = [
    {
    "x":[1,2,3],
    "y":[2,3,4],
   },
   {
      "x":[20,30,40],
      "y":[5,5,5],
      "xaxis":"x2",
      "yaxis":"y"
   },
   {
      "x":[2,3,4],
      "y":[600,700,800],
      "xaxis":"x",
      "yaxis":"y3"
   },
   {
      "x":[4000,5000,6000],
      "y":[7000,8000,9000],
      "xaxis":"x4",
      "yaxis":"y4"
   } 
]

layout = {
    "xaxis":{
        "domain":[0,0.45] # let the first x-axis span the first 45% of the plot width
    },
    "yaxis":{
        "domain":[0,0.45] # and let the first y-axis span the first 45% of the plot height
    },
    "xaxis2":{
        "domain":[0.55,1] # and let the second x-axis span the latter 45% of the plot width
    },
    "yaxis3":{
        "domain":[0.55,1],
    },
    "xaxis4":{
        "domain":[0.55,1],
        "anchor":"y4", # bind the vertical position of this axis to the start of yaxis4
    },
    "yaxis4":{
        "domain":[0.55,1],
        "anchor":"x4" # bind the horizontal position of this axis to the start of xaxis4
    }    
}
p.iplot(data, layout=layout)



Out[63]:
Woah, hold up. Check out what's going on here: the bottom two plots share the same y-axis, the two stacked plots on the left share the same x-axis and the plot in the top right has its own x and y axes. Try zooming (click-and-drag), panning (shift-click-drag), auto-scaling (double-click), or axis panning (click-and-drag on the axes number lines) around in the different plots and see how the axes respond!

Stacked

In [59]:
data = [{'x': [0,1,2], 'y': [10,11,12]},
        {'x': [2,3,4], 'y': [100,110,120], 'yaxis': 'y2', 'xaxis': 'x2'},
        {'x': [3,4,5], 'y': [1000,1100,1200], 'yaxis': 'y3', 'xaxis': 'x3'}]
layout={
    'yaxis': {'domain': [0,0.8/3.]},
    'yaxis2': {'domain':[0.8/3+0.1,2*0.8/3+0.1]},
    'yaxis3': {'domain':[2*0.8/3+0.2,1]},
    'xaxis2': {'anchor':'y2'},
    'xaxis3': {'anchor':'y3'},
    'legend': {'traceorder': 'reversed'}
}
    
p.iplot(data,layout=layout)



Out[59]:

Stacked with Coupled X-Axis

In [60]:
data = [{'x': [0,1,2], 'y': [10,11,12]},
        {'x': [2,3,4], 'y': [100,110,120], 'yaxis': 'y2'},
        {'x': [3,4,5], 'y': [1000,1100,1200], 'yaxis': 'y3'}]
layout={
    'yaxis': {'domain': [0,1./3.]},
    'yaxis2': {'domain':[1./3,2./3.]},
    'yaxis3': {'domain':[2./3.,1]},
    'legend': {'traceorder': 'reversed'}
}
    
p.iplot(data,layout=layout)



Out[60]:
Each subplot shares the same x-axis, so when you pan (shift-click-drag) or zoom (click-drag) all the plots respond. Kinda sweet, right?

Insets

Since we have full control of the position and length of the axes, we can create inset plots by just adding another pair of axes, shortening them up, and placing them in the top right corner.

In [61]:
data = [
    {
    "x":[1,2,3],
    "y":[4,3,2],
   },
   {
      "x":[20,30,40],
      "y":[30,40,50],
      "xaxis":"x2",
      "yaxis":"y2"
   }
]
layout = {
    "xaxis2": {
        "domain": [0.6, 0.95],
        "anchor": "y2"
    },
    "yaxis2":{
        "domain": [0.6, 0.95],
        "anchor": "x2"
    }
}
p.iplot(data, layout=layout)



Out[61]:
Back to top