Creating and Updating Figures in Python
Creating and Updating Figures with Plotly's Python graphing library
New to Plotly?
Plotly is a free and open-source graphing library for Python. We recommend you read our Getting Started guide for the latest installation or upgrade instructions, then move on to our Plotly Fundamentals tutorials or dive straight in to some Basic Charts tutorials.
The plotly
Python package exists to create, manipulate and render graphical figures (i.e. charts, plots, maps and diagrams) represented by data structures also referred to as figures. The rendering process uses the Plotly.js JavaScript library under the hood although Python developers using this module very rarely need to interact with the Javascript library directly, if ever. Figures can be represented in Python either as dicts or as instances of the plotly.graph_objects.Figure
class, and are serialized as text in JavaScript Object Notation (JSON) before being passed to Plotly.js.
Note: the recommended entry-point into the plotly package is the high-level plotly.express module, also known as Plotly Express, which consists of Python functions which return fully-populated
plotly.graph_objects.Figure
objects. This page exists to document the structure of the data structure that these objects represent for users who wish to understand more about how to customize them, or assemble them from otherplotly.graph_objects
components.
Figures As Dictionaries¶
At a low level, figures can be represented as dictionaries and displayed using functions from the plotly.io
module. The fig
dictionary in the example below describes a figure. It contains a single bar
trace and a title.
fig = dict({
"data": [{"type": "bar",
"x": [1, 2, 3],
"y": [1, 3, 2]}],
"layout": {"title": {"text": "A Figure Specified By Python Dictionary"}}
})
# To display the figure defined by this dict, use the low-level plotly.io.show function
import plotly.io as pio
pio.show(fig)
Figures as Graph Objects¶
The plotly.graph_objects
module provides an automatically-generated hierarchy of classes called "graph objects" that may be used to represent figures, with a top-level class plotly.graph_objects.Figure
.
Note that the recommended alternative to working with Python dictionaries is to create entire figures at once using Plotly Express and to manipulate the resulting
plotly.graph_objects.Figure
objects as described in this page, wherever possible, rather than to assemble figures bottom-up from underlying graph objects. See "When to use Graph Objects".
Graph objects have several benefits compared to plain Python dictionaries.
- Graph objects provide precise data validation. If you provide an invalid property name or an invalid property value as the key to a graph object, an exception will be raised with a helpful error message describing the problem. This is not the case if you use plain Python dictionaries and lists to build your figures.
- Graph objects contain descriptions of each valid property as Python docstrings, with a full API reference available. You can use these docstrings in the development environment of your choice to learn about the available properties as an alternative to consulting the online Full Reference.
- Properties of graph objects can be accessed using both dictionary-style key lookup (e.g.
fig["layout"]
) or class-style property access (e.g.fig.layout
). - Graph objects support higher-level convenience functions for making updates to already constructed figures (
.update_layout()
,.add_trace()
etc) as described below. - Graph object constructors and update methods accept "magic underscores" (e.g.
go.Figure(layout_title_text="The Title")
rather thandict(layout=dict(title=dict(text="The Title")))
) for more compact code, as described below. - Graph objects support attached rendering (
.show()
) and exporting functions (.write_image()
) that automatically invoke the appropriate functions from theplotly.io
module.
Below you can find an example of one way that the figure in the example above could be specified using a graph object instead of a dictionary.
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Bar(x=[1, 2, 3], y=[1, 3, 2])],
layout=go.Layout(
title=go.layout.Title(text="A Figure Specified By A Graph Object")
)
)
fig.show()
You can also create a graph object figure from a dictionary representation by passing the dictionary to the go.Figure
constructor.
import plotly.graph_objects as go
dict_of_fig = dict({
"data": [{"type": "bar",
"x": [1, 2, 3],
"y": [1, 3, 2]}],
"layout": {"title": {"text": "A Figure Specified By A Graph Object With A Dictionary"}}
})
fig = go.Figure(dict_of_fig)
fig.show()
Converting Graph Objects To Dictionaries and JSON¶
Graph objects can be turned into their Python dictionary representation using the fig.to_dict()
method. You can also retrieve the JSON string representation of a graph object using the fig.to_json()
method.
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Bar(x=[1, 2, 3], y=[1, 3, 2])],
layout=go.Layout(height=600, width=800)
)
fig.layout.template = None # to slim down the output
print("Dictionary Representation of A Graph Object:\n\n" + str(fig.to_dict()))
print("\n\n")
print("JSON Representation of A Graph Object:\n\n" + str(fig.to_json()))
print("\n\n")
Representing Figures in Dash¶
Dash is the best way to build analytical apps in Python using Plotly figures. To run the app below, run pip install dash
, click "Download" to get the code and run python app.py
.
Get started with the official Dash docs and learn how to effortlessly style & deploy apps like this with Dash Enterprise.
Sign up for Dash Club → Free cheat sheets plus updates from Chris Parmer and Adam Schroeder delivered to your inbox every two months. Includes tips and tricks, community apps, and deep dives into the Dash architecture. Join now.
Creating Figures¶
This section summarizes several ways to create new graph object figures with the plotly.py
graphing library.
The recommended way to create figures and populate them is to use Plotly Express but this page documents various other options for completeness
Plotly Express¶
Plotly Express (included as the plotly.express
module) is a high-level data visualization API that produces fully-populated graph object figures in single function-calls.
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species", title="A Plotly Express Figure")
# If you print the figure, you'll see that it's just a regular figure with data and layout
# print(fig)
fig.show()
Graph Objects Figure
Constructor¶
As demonstrated above, you can build a complete figure by passing trace and layout specifications to the plotly.graph_objects.Figure
constructor. These trace and layout specifications can be either dictionaries or graph objects.
In the following example, the traces are specified using graph objects and the layout is specified as a dictionary.
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Bar(x=[1, 2, 3], y=[1, 3, 2])],
layout=dict(title=dict(text="A Figure Specified By A Graph Object"))
)
fig.show()
Figure Factories¶
Figure factories (included in plotly.py
in the plotly.figure_factory
module) are functions that produce graph object figures, often to satisfy the needs of specialized domains. Here's an example of using the create_quiver()
figure factory to construct a graph object figure that displays a 2D quiver plot.
import numpy as np
import plotly.figure_factory as ff
x1,y1 = np.meshgrid(np.arange(0, 2, .2), np.arange(0, 2, .2))
u1 = np.cos(x1)*y1
v1 = np.sin(x1)*y1
fig = ff.create_quiver(x1, y1, u1, v1)
fig.show()
Make Subplots¶
The plotly.subplots.make_subplots()
function produces a graph object figure that is preconfigured with a grid of subplots that traces can be added to. The add_trace()
function will be discussed more below.
from plotly.subplots import make_subplots
fig = make_subplots(rows=1, cols=2)
fig.add_trace(go.Scatter(y=[4, 2, 1], mode="lines"), row=1, col=1)
fig.add_trace(go.Bar(y=[2, 1, 3]), row=1, col=2)
fig.show()
Updating Figures¶
Regardless of how a graph object figure was constructed, it can be updated by adding additional traces to it and modifying its properties.
Adding Traces¶
New traces can be added to a graph object figure using the add_trace()
method. This method accepts a graph object trace (an instance of go.Scatter
, go.Bar
, etc.) and adds it to the figure. This allows you to start with an empty figure, and add traces to it sequentially. The append_trace()
method does the same thing, although it does not return the figure.
import plotly.graph_objects as go
fig = go.Figure()
fig.add_trace(go.Bar(x=[1, 2, 3], y=[1, 3, 2]))
fig.show()
You can also add traces to a figure produced by a figure factory or Plotly Express.
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species",
title="Using The add_trace() method With A Plotly Express Figure")
fig.add_trace(
go.Scatter(
x=[2, 4],
y=[4, 8],
mode="lines",
line=go.scatter.Line(color="gray"),
showlegend=False)
)
fig.show()
Adding Traces To Subplots¶
If a figure was created using plotly.subplots.make_subplots()
, then supplying the row
and col
arguments to add_trace()
can be used to add a trace to a particular subplot.
from plotly.subplots import make_subplots
fig = make_subplots(rows=1, cols=2)
fig.add_trace(go.Scatter(y=[4, 2, 1], mode="lines"), row=1, col=1)
fig.add_trace(go.Bar(y=[2, 1, 3]), row=1, col=2)
fig.show()
This also works for figures created by Plotly Express using the facet_row
and or facet_col
arguments.
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species", facet_col="species",
title="Adding Traces To Subplots Witin A Plotly Express Figure")
reference_line = go.Scatter(x=[2, 4],
y=[4, 8],
mode="lines",
line=go.scatter.Line(color="gray"),
showlegend=False)
fig.add_trace(reference_line, row=1, col=1)
fig.add_trace(reference_line, row=1, col=2)
fig.add_trace(reference_line, row=1, col=3)
fig.show()
Add Trace Convenience Methods¶
As an alternative to the add_trace()
method, graph object figures have a family of methods of the form add_{trace}
(where {trace}
is the name of a trace type) for constructing and adding traces of each trace type.
Here is the previous subplot example, adapted to add the scatter trace using fig.add_scatter()
and to add the bar trace using fig.add_bar()
.
from plotly.subplots import make_subplots
fig = make_subplots(rows=1, cols=2)
fig.add_scatter(y=[4, 2, 1], mode="lines", row=1, col=1)
fig.add_bar(y=[2, 1, 3], row=1, col=2)
fig.show()
Magic Underscore Notation¶
To make it easier to work with nested properties, graph object constructors and many graph object methods support magic underscore notation.
This allows you to reference nested properties by joining together multiple nested property names with underscores.
For example, specifying the figure title in the figure constructor without magic underscore notation requires setting the layout
argument to dict(title=dict(text="A Chart"))
.
Similarly, setting the line color of a scatter trace requires setting the marker
property to dict(color="crimson")
.
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Scatter(y=[1, 3, 2], line=dict(color="crimson"))],
layout=dict(title=dict(text="A Graph Objects Figure Without Magic Underscore Notation"))
)
fig.show()
With magic underscore notation, you can accomplish the same thing by passing the figure constructor a keyword argument named layout_title_text
, and by passing the go.Scatter
constructor a keyword argument named line_color
.
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Scatter(y=[1, 3, 2], line_color="crimson")],
layout_title_text="A Graph Objects Figure With Magic Underscore Notation"
)
fig.show()
Magic underscore notation is supported throughout the graph objects API, and it can often significantly simplify operations involving deeply nested properties.
Note: When you see keyword arguments with underscores passed to a graph object constructor or method, it is almost always safe to assume that it is an application of magic underscore notation. We have to say "almost always" rather than "always" because there are a few property names in the plotly schema that contain underscores: error_x, error_y, error_z, copy_xstyle, copy_ystyle, copy_zstyle, paper_bgcolor, and plot_bgcolor. These were added back in the early days of the library (2012-2013) before we standardized on banning underscores from property names.
Updating Figure Layouts¶
Graph object figures support an update_layout()
method that may be used to update multiple nested properties of a figure's layout.
Here is an example of updating the text and font size of a figure's title using update_layout()
.
import plotly.graph_objects as go
fig = go.Figure(data=go.Bar(x=[1, 2, 3], y=[1, 3, 2]))
fig.update_layout(title_text="Using update_layout() With Graph Object Figures",
title_font_size=30)
fig.show()
Note that the following update_layout()
operations are equivalent:
fig.update_layout(title_text="update_layout() Syntax Example",
title_font_size=30)
fig.update_layout(title_text="update_layout() Syntax Example",
title_font=dict(size=30))
fig.update_layout(title=dict(text="update_layout() Syntax Example"),
font=dict(size=30))
fig.update_layout({"title": {"text": "update_layout() Syntax Example",
"font": {"size": 30}}})
fig.update_layout(title=go.layout.Title(text="update_layout() Syntax Example",
font=go.layout.title.Font(size=30)))
Updating Traces¶
Graph object figures support an update_traces()
method that may be used to update multiple nested properties of one or more of a figure's traces.
To show some examples, we will start with a figure that contains bar
and scatter
traces across two subplots.
from plotly.subplots import make_subplots
fig = make_subplots(rows=1, cols=2)
fig.add_scatter(y=[4, 2, 3.5], mode="markers",
marker=dict(size=20, color="LightSeaGreen"),
name="a", row=1, col=1)
fig.add_bar(y=[2, 1, 3],
marker=dict(color="MediumPurple"),
name="b", row=1, col=1)
fig.add_scatter(y=[2, 3.5, 4], mode="markers",
marker=dict(size=20, color="MediumPurple"),
name="c", row=1, col=2)
fig.add_bar(y=[1, 3, 2],
marker=dict(color="LightSeaGreen"),
name="d", row=1, col=2)
fig.show()
Note that both scatter
and bar
traces have a marker.color
property to control their coloring. Here is an example of using update_traces()
to modify the color of all traces.
from plotly.subplots import make_subplots
fig = make_subplots(rows=1, cols=2)
fig.add_scatter(y=[4, 2, 3.5], mode="markers",
marker=dict(size=20, color="LightSeaGreen"),
name="a", row=1, col=1)
fig.add_bar(y=[2, 1, 3],
marker=dict(color="MediumPurple"),
name="b", row=1, col=1)
fig.add_scatter(y=[2, 3.5, 4], mode="markers",
marker=dict(size=20, color="MediumPurple"),
name="c", row=1, col=2)
fig.add_bar(y=[1, 3, 2],
marker=dict(color="LightSeaGreen"),
name="d", row=1, col=2)
fig.update_traces(marker=dict(color="RoyalBlue"))
fig.show()
The update_traces()
method supports a selector
argument to control which traces should be updated. Only traces with properties that match the selector will be updated. Here is an example of using a selector to only update the color of the bar
traces.
from plotly.subplots import make_subplots
fig = make_subplots(rows=1, cols=2)
fig.add_scatter(y=[4, 2, 3.5], mode="markers",
marker=dict(size=20, color="LightSeaGreen"),
name="a", row=1, col=1)
fig.add_bar(y=[2, 1, 3],
marker=dict(color="MediumPurple"),
name="b", row=1, col=1)
fig.add_scatter(y=[2, 3.5, 4], mode="markers",
marker=dict(size=20, color="MediumPurple"),
name="c", row=1, col=2)
fig.add_bar(y=[1, 3, 2],
marker=dict(color="LightSeaGreen"),
name="d", row=1, col=2)
fig.update_traces(marker=dict(color="RoyalBlue"),
selector=dict(type="bar"))
fig.show()
Magic underscore notation can be used in the selector to match nested properties. Here is an example of updating the color of all traces that were formally colored "MediumPurple"
.
from plotly.subplots import make_subplots
fig = make_subplots(rows=1, cols=2)
fig.add_scatter(y=[4, 2, 3.5], mode="markers",
marker=dict(size=20, color="LightSeaGreen"),
name="a", row=1, col=1)
fig.add_bar(y=[2, 1, 3],
marker=dict(color="MediumPurple"),
name="b", row=1, col=1)
fig.add_scatter(y=[2, 3.5, 4], mode="markers",
marker=dict(size=20, color="MediumPurple"),
name="c", row=1, col=2)
fig.add_bar(y=[1, 3, 2],
marker=dict(color="LightSeaGreen"),
name="d", row=1, col=2)
fig.update_traces(marker_color="RoyalBlue",
selector=dict(marker_color="MediumPurple"))
fig.show()
For figures with subplots, the update_traces()
method also supports row
and col
arguments to control which traces should be updated. Only traces in the specified subplot row and column will be updated. Here is an example of updating the color of all traces in the second subplot column.
from plotly.subplots import make_subplots
fig = make_subplots(rows=1, cols=2)
fig.add_scatter(y=[4, 2, 3.5], mode="markers",
marker=dict(size=20, color="LightSeaGreen"),
name="a", row=1, col=1)
fig.add_bar(y=[2, 1, 3],
marker=dict(color="MediumPurple"),
name="b", row=1, col=1)
fig.add_scatter(y=[2, 3.5, 4], mode="markers",
marker=dict(size=20, color="MediumPurple"),
name="c", row=1, col=2)
fig.add_bar(y=[1, 3, 2],
marker=dict(color="LightSeaGreen"),
name="d", row=1, col=2)
fig.update_traces(marker=dict(color="RoyalBlue"),
col=2)
fig.show()
The update_traces()
method can also be used on figures produced by figure factories or Plotly Express. Here's an example of updating the regression lines produced by Plotly Express to be dotted.
import pandas as pd
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species",
facet_col="species", trendline="ols", title="Using update_traces() With Plotly Express Figures")
fig.update_traces(
line=dict(dash="dot", width=4),
selector=dict(type="scatter", mode="lines"))
fig.show()
Overwrite Existing Properties When Using Update Methods¶
update_layout()
and update_traces()
have an overwrite
keyword argument, defaulting to False, in which case updates are applied recursively to the existing nested property structure. When set to True, the prior value of existing properties is overwritten with the provided value.
In the example below, the red color of markers is overwritten when updating marker
in update_traces()
with overwrite=True
. Note that setting instead marker_opacity
with the magic underscore would not overwrite marker_color
because properties would be overwritten starting only at the level of marker.opacity
.
import plotly.graph_objects as go
fig = go.Figure(go.Bar(x=[1, 2, 3], y=[6, 4, 9],
marker_color="red")) # will be overwritten below
fig.update_traces(overwrite=True, marker={"opacity": 0.4})
fig.show()
Conditionally Updating Traces¶
Suppose the updates that you want to make to a collection of traces depend on the current values of certain trace properties. The update_traces()
method cannot handle this situation, but the for_each_trace()
method can!
As its first argument, the for_each_trace()
method accepts a function that accepts and updates one trace at a time. Like update_traces()
, for_each_trace()
also accepts selector
, row
, and col
arguments to control which traces should be considered.
Here is an example of using for_each_trace()
to convert the only markers for the "setosa"
to square symbols in a Plotly Express Figure.
Note that this is possible because Plotly Express figures are made up of a separate trace for each column in the input data frame
import pandas as pd
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species",
title="Conditionally Updating Traces In A Plotly Express Figure With for_each_trace()")
fig.for_each_trace(
lambda trace: trace.update(marker_symbol="square") if trace.name == "setosa" else (),
)
fig.show()
Updating Figure Axes¶
Graph object figures support update_xaxes()
and update_yaxes()
methods that may be used to update multiple nested properties of one or more of a figure's axes. Here is an example of using update_xaxes()
to disable the vertical grid lines across all subplots in a figure produced by Plotly Express.
import pandas as pd
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species",
facet_col="species", title="Using update_xaxes() With A Plotly Express Figure")
fig.update_xaxes(showgrid=False)
fig.show()
There are also for_each_xaxis()
and for_each_yaxis()
methods that are analogous to the for_each_trace()
method described above. For non-cartesian subplot types (e.g. polar), there are additional update_{type}
and for_each_{type}
methods (e.g. update_polar()
, for_each_polar()
).
Other Update Methods¶
Figures created with the plotly.py graphing library also support:
- the
update_layout_images()
method in order to update background layout images, update_annotations()
in order to update annotations,- and
update_shapes()
in order to update shapes.
Chaining Figure Operations¶
All of the figure update operations described above are methods that return a reference to the figure being modified. This makes it possible the chain multiple figure modification operations together into a single expression.
Here is an example of a chained expression that creates:
- a faceted scatter plot with OLS trend lines using Plotly Express,
- sets the title font size using
update_layout()
, - disables vertical grid lines using
update_xaxes()
, - updates the width and dash pattern of the trend lines using
update_traces()
, - and then displays the figure using
show()
.
import plotly.express as px
df = px.data.iris()
(px.scatter(df, x="sepal_width", y="sepal_length", color="species",
facet_col="species", trendline="ols",
title="Chaining Multiple Figure Operations With A Plotly Express Figure")
.update_layout(title_font_size=24)
.update_xaxes(showgrid=False)
.update_traces(
line=dict(dash="dot", width=4),
selector=dict(type="scatter", mode="lines"))
).show()
Property Assignment¶
Trace and layout properties can be updated using property assignment syntax. Here is an example of setting the figure title using property assignment.
import plotly.graph_objects as go
fig = go.Figure(data=go.Bar(x=[1, 2, 3], y=[1, 3, 2]))
fig.layout.title.text = "Using Property Assignment Syntax With A Graph Object Figure"
fig.show()
And here is an example of updating the bar outline using property assignment.
import plotly.graph_objects as go
fig = go.Figure(data=go.Bar(x=[1, 2, 3], y=[1, 3, 2]))
fig.data[0].marker.line.width = 4
fig.data[0].marker.line.color = "black"
fig.show()
What About Dash?¶
Dash is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.
Learn about how to install Dash at https://dash.plot.ly/installation.
Everywhere in this page that you see fig.show()
, you can display the same figure in a Dash application by passing it to the figure
argument of the Graph
component from the built-in dash_core_components
package like this:
import plotly.graph_objects as go # or plotly.express as px
fig = go.Figure() # or any Plotly Express function e.g. px.bar(...)
# fig.add_trace( ... )
# fig.update_layout( ... )
from dash import Dash, dcc, html
app = Dash()
app.layout = html.Div([
dcc.Graph(figure=fig)
])
app.run_server(debug=True, use_reloader=False) # Turn off reloader if inside Jupyter