Patterns, Hatching, Texture in Python

How to use patterns (also known as hatching or texture) with bar charts.


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.

New in 5.0, with support for pie, sunburst, icicle, funnelarea, and treemap charts in 5.15

Bar charts, histograms, polar bar charts, area charts, pie charts, sunburst charts, funnelarea charts, icicle charts, and treemap charts, have large markers or areas which support not only a fill color, but also an optional pattern (also known as "hatching" or "texture"). This can be used for a variety of reasons:

  • to double-encode variables (i.e. using both color and pattern) to improve accessibility for visually-impaired end-users
  • to encode an additional variable beyond just using color
  • to make charts that are easier to print in black and white

Patterned Charts with Plotly Express

the px.bar(), px.histogram(), px.bar_polar() and px.area() functions support the pattern_shape argument. In the chart below, we double-encode nation using color and pattern:

In [1]:
import plotly.express as px
df = px.data.medals_long()

fig = px.bar(df, x="medal", y="count", color="nation", pattern_shape="nation")
fig.show()
In [2]:
import plotly.express as px
df = px.data.medals_long()

fig = px.area(df, x="medal", y="count", color="nation", pattern_shape="nation")
fig.show()

In the chart below we use px.histogram() instead of px.bar() to aggregate multiple values together, and encode one variable (sex) using both color and x-position and another (smoker) using patterns:

In [3]:
import plotly.express as px

df = px.data.tips()
fig = px.histogram(df, x="sex", y="total_bill", color="sex", pattern_shape="smoker")
fig.show()

Controlling Pattern Assignment

In the charts above, the first value of the variable assigned pattern_shape gets the empty pattern, but this (and indeed every pattern-to-variable assignment) can be controlled using pattern_shape_sequence and pattern_shape_map, analogously to the way discrete colors can be mapped using Plotly Express.

Here we use pattern_shape_sequence to replace the defaults and include a pattern-shape for the first variable:

In [4]:
import plotly.express as px
df = px.data.medals_long()

fig = px.bar(df, x="medal", y="count", color="nation",
             pattern_shape="nation", pattern_shape_sequence=[".", "x", "+"])
fig.show()

Here we use pattern_shape_map to explictly assign a shape to each value of nation, regardless of order:

In [5]:
import plotly.express as px
df = px.data.medals_long()

fig = px.bar(df, x="medal", y="count", color="nation",
             pattern_shape="nation", pattern_shape_map={
             "China": ".", "Canada": "/", "South Korea": "+"
             })
fig.show()

Black on White Patterns for Print

When creating figures meant to be printed on black and white printers, it is better to replace the fill-color with the pattern, rather than to overlay it. This can be controlled with the <trace>.marker.pattern.fillmode attribute, which defaults to "overlay" but can be set to "replace" instead. Changing this attribute, and using a simpler default template and color scheme gives the following output:

In [6]:
import plotly.express as px
df = px.data.medals_long()

fig = px.bar(df, x="medal", y="count", color="nation",
             pattern_shape="nation", pattern_shape_sequence=[".", "x", "+"],
             template="simple_white"
            )
fig.update_traces(
    marker=dict(color="black", line_color="black", pattern_fillmode="replace")
)
fig.show()

Of course, this setting can be used without making the figure monochrome as well:

In [7]:
import plotly.express as px
df = px.data.medals_long()

fig = px.bar(df, x="medal", y="count", color="nation",
             pattern_shape="nation", pattern_shape_sequence=[".", "x", "+"],
            )
fig.update_traces(
    marker=dict(line_color="grey", pattern_fillmode="replace")
)
fig.show()

Patterns using Graph Objects

If Plotly Express does not provide a good starting point, it is also possible to use the more generic go.Bar class from plotly.graph_objects.

In [8]:
import plotly.graph_objects as go

fig = go.Figure()

fig.add_trace(go.Bar(x=["a","b"], y=[1,2], marker_pattern_shape="."))
fig.add_trace(go.Bar(x=["a","b"], y=[3,1], marker_pattern_shape="x"))
fig.add_trace(go.Bar(x=["a","b"], y=[2,3], marker_pattern_shape="+"))

fig.show()

Reference

See https://plotly.com/python/reference/bar/ for more information and chart attribute options!

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