Text and Annotations in Python

How to add text labels and annotations to plots in python.


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.

Adding Text to Figures

As a general rule, there are two ways to add text labels to figures:

  1. Certain trace types, notably in the scatter family (e.g. scatter, scatter3d, scattergeo etc), support a text attribute, and can be displayed with or without markers.
  2. Standalone text annotations can be added to figures using fig.add_annotation(), with or without arrows, and they can be positioned absolutely within the figure, or they can be positioned relative to the axes of 2d or 3d cartesian subplots i.e. in data coordinates.

The differences between these two approaches are that:

  • Traces can optionally support hover labels and can appear in legends.
  • Text annotations can be positioned absolutely or relative to data coordinates in 2d/3d cartesian subplots only.
  • Traces cannot be positioned absolutely but can be positioned relative to data coordinates in any subplot type.
  • Traces also be used to draw shapes, although there is a shape equivalent to text annotations.

Text on scatter plots with Plotly Express

Here is an example that creates a scatter plot with text labels using Plotly Express.

In [1]:
import plotly.express as px

df = px.data.gapminder().query("year==2007 and continent=='Americas'")

fig = px.scatter(df, x="gdpPercap", y="lifeExp", text="country", log_x=True, size_max=60)

fig.update_traces(textposition='top center')

fig.update_layout(
    height=800,
    title_text='GDP and Life Expectancy (Americas, 2007)'
)

fig.show()
ArgentinaBoliviaBrazilCanadaChileColombiaCosta RicaCubaDominican RepublicEcuadorEl SalvadorGuatemalaHaitiHondurasJamaicaMexicoNicaraguaPanamaParaguayPeruPuerto RicoTrinidad and TobagoUnited StatesUruguayVenezuela10002345678910k23456065707580
GDP and Life Expectancy (Americas, 2007)gdpPercaplifeExp

Text on scatter plots with Graph Objects

In [2]:
import plotly.graph_objects as go

fig = go.Figure()

fig.add_trace(go.Scatter(
    x=[0, 1, 2],
    y=[1, 1, 1],
    mode="lines+markers+text",
    name="Lines, Markers and Text",
    text=["Text A", "Text B", "Text C"],
    textposition="top center"
))

fig.add_trace(go.Scatter(
    x=[0, 1, 2],
    y=[2, 2, 2],
    mode="markers+text",
    name="Markers and Text",
    text=["Text D", "Text E", "Text F"],
    textposition="bottom center"
))

fig.add_trace(go.Scatter(
    x=[0, 1, 2],
    y=[3, 3, 3],
    mode="lines+text",
    name="Lines and Text",
    text=["Text G", "Text H", "Text I"],
    textposition="bottom center"
))

fig.show()
Text AText BText CText DText EText FText GText HText I00.511.5211.522.53
Lines, Markers and TextMarkers and TextLines and Text

Text positioning 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.

Out[3]:

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.

Controlling Text Size with uniformtext

For the pie, bar-like, sunburst and treemap traces, it is possible to force all the text labels to have the same size thanks to the uniformtext layout parameter. The minsize attribute sets the font size, and the mode attribute sets what happens for labels which cannot fit with the desired fontsize: either hide them or show them with overflow.

Here is a bar chart with the default behavior which will scale down text to fit.

In [4]:
import plotly.express as px

df = px.data.gapminder(year=2007)
fig = px.bar(df, x='continent', y='pop', color="lifeExp", text='country',
             title="Default behavior: some text is tiny")
fig.update_traces(textposition='inside')
fig.show()
AfghanistanAlbaniaAlgeriaAngolaArgentinaAustraliaAustriaBahrainBangladeshBelgiumBeninBoliviaBosnia and HerzegovinaBotswanaBrazilBulgariaBurkina FasoBurundiCambodiaCameroonCanadaCentral African RepublicChadChileChinaColombiaComorosCongo, Dem. Rep.Congo, Rep.Costa RicaCote d'IvoireCroatiaCubaCzech RepublicDenmarkDjiboutiDominican RepublicEcuadorEgyptEl SalvadorEquatorial GuineaEritreaEthiopiaFinlandFranceGabonGambiaGermanyGhanaGreeceGuatemalaGuineaGuinea-BissauHaitiHondurasHong Kong, ChinaHungaryIcelandIndiaIndonesiaIranIraqIrelandIsraelItalyJamaicaJapanJordanKenyaKorea, Dem. Rep.Korea, Rep.KuwaitLebanonLesothoLiberiaLibyaMadagascarMalawiMalaysiaMaliMauritaniaMauritiusMexicoMongoliaMontenegroMoroccoMozambiqueMyanmarNamibiaNepalNetherlandsNew ZealandNicaraguaNigerNigeriaNorwayOmanPakistanPanamaParaguayPeruPhilippinesPolandPortugalPuerto RicoReunionRomaniaRwandaSao Tome and PrincipeSaudi ArabiaSenegalSerbiaSierra LeoneSingaporeSlovak RepublicSloveniaSomaliaSouth AfricaSpainSri LankaSudanSwazilandSwedenSwitzerlandSyriaTaiwanTanzaniaThailandTogoTrinidad and TobagoTunisiaTurkeyUgandaUnited KingdomUnited StatesUruguayVenezuelaVietnamWest Bank and GazaYemen, Rep.ZambiaZimbabweAsiaEuropeAfricaAmericasOceania00.5B1B1.5B2B2.5B3B3.5B4B
404550556065707580lifeExpDefault behavior: some text is tinycontinentpop

Here is the same figure with uniform text applied: the text for all bars is the same size, with a minimum size of 8. Any text at the minimum size which does not fit in the bar is hidden.

In [5]:
import plotly.express as px

df = px.data.gapminder(year=2007)
fig = px.bar(df, x='continent', y='pop', color="lifeExp", text='country',
             title="Uniform Text: min size is 8, hidden if can't fit")
fig.update_traces(textposition='inside')
fig.update_layout(uniformtext_minsize=8, uniformtext_mode='hide')
fig.show()
BrazilChinaIndiaIndonesiaUnited StatesAsiaEuropeAfricaAmericasOceania00.5B1B1.5B2B2.5B3B3.5B4B
404550556065707580lifeExpUniform Text: min size is 8, hidden if can't fitcontinentpop
In [6]:
import plotly.express as px

df = px.data.gapminder().query("continent == 'Asia' and year == 2007")
fig = px.pie(df, values='pop', names='country')
fig.update_traces(textposition='inside')
fig.update_layout(uniformtext_minsize=12, uniformtext_mode='hide')
fig.show()
34.6%29.1%5.86%4.44%3.95%3.34%2.39%2.24%1.82%1.71%
ChinaIndiaIndonesiaPakistanBangladeshJapanPhilippinesVietnamIranThailandKorea, Rep.MyanmarAfghanistanNepalSaudi ArabiaIraqMalaysiaKorea, Dem. Rep.TaiwanYemen, Rep.Sri LankaSyriaCambodiaHong Kong, ChinaIsraelJordanSingaporeWest Bank and GazaLebanonOmanMongoliaKuwaitBahrain

Controlling Maximum Text Size

The textfont_size parameter of the the pie, bar-like, sunburst and treemap traces can be used to set the maximum font size used in the chart. Note that the textfont parameter sets the insidetextfont and outsidetextfont parameter, which can also be set independently.

In [7]:
import plotly.express as px

df = px.data.gapminder().query("continent == 'Asia' and year == 2007")
fig = px.pie(df, values='pop', names='country')
fig.update_traces(textposition='inside', textfont_size=14)
fig.show()
34.6%29.1%5.86%4.44%3.95%3.34%2.39%2.24%1.82%1.71%1.29%1.25%0.837%0.758%0.724%0.721%0.651%0.611%0.608%0.583%0.535%0.507%0.371%0.183%0.169%0.159%0.119%0.105%0.103%0.0841%0.0754%0.0657%0.0186%
ChinaIndiaIndonesiaPakistanBangladeshJapanPhilippinesVietnamIranThailandKorea, Rep.MyanmarAfghanistanNepalSaudi ArabiaIraqMalaysiaKorea, Dem. Rep.TaiwanYemen, Rep.Sri LankaSyriaCambodiaHong Kong, ChinaIsraelJordanSingaporeWest Bank and GazaLebanonOmanMongoliaKuwaitBahrain

Text Annotations

Annotations can be added to a figure using fig.add_annotation().

In [8]:
import plotly.graph_objects as go

fig = go.Figure()

fig.add_trace(go.Scatter(
    x=[0, 1, 2, 3, 4, 5, 6, 7, 8],
    y=[0, 1, 3, 2, 4, 3, 4, 6, 5]
))


fig.add_trace(go.Scatter(
    x=[0, 1, 2, 3, 4, 5, 6, 7, 8],
    y=[0, 4, 5, 1, 2, 2, 3, 4, 2]
))

fig.add_annotation(x=2, y=5,
            text="Text annotation with arrow",
            showarrow=True,
            arrowhead=1)
fig.add_annotation(x=4, y=4,
            text="Text annotation without arrow",
            showarrow=False,
            yshift=10)

fig.update_layout(showlegend=False)

fig.show()
0123456780123456
Text annotation with arrowText annotation without arrow

Text Annotations with Log Axes

If the x or y positions of an annotation reference a log axis, you need to provide that position as a log10 value when adding the annotation. In this example, the yaxis is a log axis so we pass the log10 value of 1000 to the annotation's y position.

In [9]:
import plotly.graph_objects as go
import math

dates = [
    "2024-01-01",
    "2024-01-02",
    "2024-01-03",
    "2024-01-04",
    "2024-01-05",
    "2024-01-06",
]
y_values = [1, 30, 70, 100, 1000, 10000000]

fig = go.Figure(
    data=[go.Scatter(x=dates, y=y_values, mode="lines+markers")],
    layout=go.Layout(
        yaxis=dict(
            type="log",
        )
    ),
)

fig.add_annotation(
    x="2024-01-05",
    y=math.log10(1000),
    text="Log axis annotation",
    showarrow=True,
    xanchor="right",
)

fig.show()
Jan 12024Jan 2Jan 3Jan 4Jan 5Jan 6110100100010k100k1M10M
Log axis annotation

3D Annotations

In [10]:
import plotly.graph_objects as go

fig = go.Figure()

fig.add_trace(go.Scatter3d(
    x=["2017-01-01", "2017-02-10", "2017-03-20"],
    y=["A", "B", "C"],
    z=[1, 1000, 100000],
    name="z",
))

fig.update_layout(
    scene=dict(
        xaxis=dict(type="date"),
        yaxis=dict(type="category"),
        zaxis=dict(type="log"),
        annotations=[
        dict(
            showarrow=False,
            x="2017-01-01",
            y="A",
            z=0,
            text="Point 1",
            xanchor="left",
            xshift=10,
            opacity=0.7),
        dict(
            x="2017-02-10",
            y="B",
            z=4,
            text="Point 2",
            textangle=0,
            ax=0,
            ay=-75,
            font=dict(
                color="black",
                size=12
            ),
            arrowcolor="black",
            arrowsize=3,
            arrowwidth=1,
            arrowhead=1),
        dict(
            x="2017-03-20",
            y="C",
            z=5,
            ax=50,
            ay=0,
            text="Point 3",
            arrowhead=1,
            xanchor="left",
            yanchor="bottom"
        )]
    ),
)

fig.show()
Point 1Point 2Point 3

Font Color, Size, and Familiy

Use textfont to specify a font family, size, or color.

In [11]:
import plotly.graph_objects as go

fig = go.Figure()

fig.add_trace(go.Scatter(
    x=[0, 1, 2],
    y=[1, 1, 1],
    mode="lines+markers+text",
    name="Lines, Markers and Text",
    text=["Text A", "Text B", "Text C"],
    textposition="top right",
    textfont=dict(
        family="sans serif",
        size=18,
        color="crimson"
    )
))

fig.add_trace(go.Scatter(
    x=[0, 1, 2],
    y=[2, 2, 2],
    mode="lines+markers+text",
    name="Lines and Text",
    text=["Text G", "Text H", "Text I"],
    textposition="bottom center",
    textfont=dict(
        family="sans serif",
        size=18,
        color="LightSeaGreen"
    )
))

fig.update_layout(showlegend=False)

fig.show()
Text AText BText CText GText HText I00.511.5211.21.41.61.82

Font Style, Variant, and Weight

New in 5.22

You can also configure a font's variant, style, and weight on textfont. Here, we configure an italic style on the first bar, bold weight on the second, and small-caps as the font variant on the third.

In [12]:
import plotly.graph_objects as go
from plotly import data

df = data.medals_wide()

fig = go.Figure(
    data=[
        go.Bar(
            x=df.nation,
            y=df.gold,
            name="Gold",
            marker=dict(color="Gold"),
            text="Gold",
            textfont=dict(style="italic"),
        ),
        go.Bar(
            x=df.nation,
            y=df.silver,
            name="Silver",
            marker=dict(color="MediumTurquoise"),
            text="Silver",
            textfont=dict(weight="bold"),
        ),
        go.Bar(
            x=df.nation,
            y=df.bronze,
            name="Bronze",
            marker=dict(color="LightGreen"),
            text="Bronze",
            textfont=dict(variant="small-caps"),
        ),
    ],
    layout=dict(barcornerradius=15, showlegend=False),
)

fig.show()
GoldGoldGoldSilverSilverSilverBronzeBronzeBronzeSouth KoreaChinaCanada0510152025

Numeric Font Weight

New in 5.23

In the previous example, we set a font weight using a keyword value. You can also set font weight using a numeric value.

The font weights that are available depend on the font family that is set. If you set a font weight that isn't available for a particular font family, the weight will be rounded to the nearest available value.

In [13]:
import plotly.graph_objects as go
from plotly import data

df = data.medals_wide()

fig = go.Figure(
    data=[
        go.Bar(
            x=df.nation,
            y=df.gold,
            name="Gold",
            marker=dict(color="Gold"),
            text="Gold",
            textfont=dict(weight=900, size=17),
        ),
        go.Bar(
            x=df.nation,
            y=df.silver,
            name="Silver",
            marker=dict(color="MediumTurquoise"),
            text="Silver",
            textfont=dict(size=17),
        ),
            go.Bar(
            x=df.nation,
            y=df.bronze,
            name="Bronze",
            marker=dict(color="LightGreen"),
            text="Bronze",
            textfont=dict(size=17),
        ),
    ],
    layout=dict(barcornerradius=15, showlegend=False),
)

fig.show()
GoldGoldGoldSilverSilverSilverBronzeBronzeBronzeSouth KoreaChinaCanada0510152025

scattergl traces do not support all numeric font weights. When you specify a numeric font weight on scattergl, weights up to 500 are mapped to the keyword font weight "normal", while weights above 500 are mapped to "bold".

Text Case

New in 5.23

You can configure text case using the textfont.textcase property. In this example, we set textfont.textcase="upper" to transform the text on all bars to uppercase.

In [14]:
import plotly.graph_objects as go
from plotly import data

df = data.gapminder()

grouped = df[df.year == 2007].loc[df[df.year == 2007].groupby('continent')['lifeExp'].idxmax()]

fig = go.Figure(
    data=go.Bar(
        x=grouped['lifeExp'],
        y=grouped['continent'],
        text=grouped['country'],
        orientation='h',
        textfont=dict(
            family="sans serif",
            size=14,
            # Here we set textcase to "upper.
            # Set to lower" for lowercase text, or "word caps" to capitalize the first letter of each word
            textcase="upper"

        )
    ),
    layout=go.Layout(
        title_text='Country with Highest Life Expectancy per Continent, 2007',
        yaxis=dict(showticklabels=False)
    )
)

fig.show()
ReunionCanadaJapanIcelandAustralia01020304050607080
Country with Highest Life Expectancy per Continent, 2007

Text Lines

New in 5.23

You can add decoration lines to text using the textfont.lineposition property. This property accepts "under", "over", and "through", or a combination of these separated by a +.

In [15]:
import plotly.graph_objects as go
from plotly import data

df = data.gapminder()

grouped = df[df.year == 2002].loc[df[df.year == 2002].groupby('continent')['lifeExp'].idxmax()]

fig = go.Figure(
    data=go.Bar(
        x=grouped['lifeExp'],
        y=grouped['continent'],
        text=grouped['country'],
        orientation='h',
        marker_color='MediumSlateBlue',
        textfont=dict(
            lineposition="under" # combine different line positions with a "+" to add more than one: "under+over"
        )
    ),
    layout=go.Layout(
        title_text='Country with Highest Life Expectancy per Continent, 2002',
        yaxis=dict(showticklabels=False)
    )
)

fig.show()
ReunionCanadaJapanSwitzerlandAustralia01020304050607080
Country with Highest Life Expectancy per Continent, 2002

Text Shadow

New in 5.23

You can apply a shadow effect to text using the textfont.shadow property. This property accepts shadow specifications in the same format as the text-shadow CSS property.

In [16]:
import plotly.graph_objects as go
from plotly import data

df = data.gapminder()

grouped = df[df.year == 1997].loc[df[df.year == 1997].groupby('continent')['lifeExp'].idxmax()]

fig = go.Figure(
    data=go.Bar(
        x=grouped['lifeExp'],
        y=grouped['continent'],
        text=grouped['country'],
        orientation='h',
        textfont=dict(
            shadow="1px 1px 2px pink"
        )
    ),
    layout=go.Layout(
        title_text='Country with Highest Life Expectancy per Continent, 1997',
        yaxis=dict(showticklabels=False)
    )
)

fig.show()
ReunionCanadaJapanSwedenAustralia01020304050607080
Country with Highest Life Expectancy per Continent, 1997

Styling and Coloring Annotations

In [17]:
import plotly.graph_objects as go

fig = go.Figure()

fig.add_trace(go.Scatter(
    x=[0, 1, 2, 3, 4, 5, 6, 7, 8],
    y=[0, 1, 3, 2, 4, 3, 4, 6, 5]
))

fig.add_trace(go.Scatter(
    x=[0, 1, 2, 3, 4, 5, 6, 7, 8],
    y=[0, 4, 5, 1, 2, 2, 3, 4, 2]
))

fig.add_annotation(
        x=2,
        y=5,
        xref="x",
        yref="y",
        text="max=5",
        showarrow=True,
        font=dict(
            family="Courier New, monospace",
            size=16,
            color="#ffffff"
            ),
        align="center",
        arrowhead=2,
        arrowsize=1,
        arrowwidth=2,
        arrowcolor="#636363",
        ax=20,
        ay=-30,
        bordercolor="#c7c7c7",
        borderwidth=2,
        borderpad=4,
        bgcolor="#ff7f0e",
        opacity=0.8
        )

fig.update_layout(showlegend=False)
fig.show()
0123456780123456
max=5

Text Font as an Array - Styling Each Text Element

In [18]:
import plotly.graph_objects as go

fig = go.Figure()

fig.add_trace(go.Scattergeo(
    lat=[45.5, 43.4, 49.13, 51.1, 53.34, 45.24, 44.64, 48.25, 49.89, 50.45],
    lon=[-73.57, -79.24, -123.06, -114.1, -113.28, -75.43, -63.57, -123.21, -97.13,
         -104.6],
    marker={
        "color": ["MidnightBlue", "IndianRed", "MediumPurple", "Orange", "Crimson",
                  "LightSeaGreen", "RoyalBlue", "LightSalmon", "DarkOrange", "MediumSlateBlue"],
        "line": {
            "width": 1
        },
        "size": 10
    },
    mode="markers+text",
    name="",
    text=["Montreal", "Toronto", "Vancouver", "Calgary", "Edmonton", "Ottawa",
          "Halifax",
          "Victoria", "Winnepeg", "Regina"],
    textfont={
        "color": ["MidnightBlue", "IndianRed", "MediumPurple", "Gold", "Crimson",
                  "LightSeaGreen",
                  "RoyalBlue", "LightSalmon", "DarkOrange", "MediumSlateBlue"],
        "family": ["Arial, sans-serif", "Balto, sans-serif", "Courier New, monospace",
                   "Droid Sans, sans-serif", "Droid Serif, serif",
                   "Droid Sans Mono, sans-serif",
                   "Gravitas One, cursive", "Old Standard TT, serif",
                   "Open Sans, sans-serif",
                   "PT Sans Narrow, sans-serif", "Raleway, sans-serif",
                   "Times New Roman, Times, serif"],
        "size": [22, 21, 20, 19, 18, 17, 16, 15, 14, 13]
    },
    textposition=["top center", "middle left", "top center", "bottom center",
                  "top right",
                  "middle left", "bottom right", "bottom left", "top right",
                  "top right"]
))

fig.update_layout(
    title_text="Canadian cities",
    geo=dict(
        lataxis=dict(range=[40, 70]),
        lonaxis=dict(range=[-130, -55]),
        scope="north america"
    )
)

fig.show()
MontrealTorontoVancouverCalgaryEdmontonOttawaHalifaxVictoriaWinnepegRegina
Canadian cities

HTML Tags in Text

The text attribute supports the following HTML tags: <br>,<b>,<a>, <em>, <sup> and <span>. In version 5.23 and later, <s> and <u>are also supported.

In [19]:
import plotly.graph_objects as go

fig = go.Figure(
    data=[
        go.Scatter(
            x=[0, 1, 2, 3, 4, 5, 6, 7, 8],
            y=[0, 1, 3, 2, 4, 3, 4, 6, 5],
            mode="lines+markers",
            name="Series 1",
        ),
        go.Scatter(
            x=[0, 1, 2, 3, 4, 5, 6, 7, 8],
            y=[0, 4, 5, 1, 2, 2, 3, 4, 2],
            mode="lines+markers",
            name="Series 2",
        ),
    ],
    layout=go.Layout(
        annotations=[
            dict(
                x=2,
                y=5,
                text="Text annotation using <b>bolded text</b>, <i>italicized text</i>, <u>underlined text</u>, <br>and a new line",
                showarrow=True,
                arrowhead=1,
            ),
            dict(
                x=4,
                y=4,
                text="Text annotation with <a href='https://dash.plotly.com'>a link</a>.",
                showarrow=False,
                yshift=10,
            ),
        ],
        showlegend=False,
    ),
)

fig.show()
0123456780123456
Text annotation using bolded text, italicized text, underlined text, and a new lineText annotation with a link.

Positioning Text Annotations Absolutely

By default, text annotations have xref and yref set to "x" and "y", respectively, meaning that their x/y coordinates are with respect to the axes of the plot. This means that panning the plot will cause the annotations to move. Setting xref and/or yref to "paper" will cause the x and y attributes to be interpreted in paper coordinates.

Try panning or zooming in the following figure:

In [20]:
import plotly.express as px

fig = px.scatter(x=[1, 2, 3], y=[1, 2, 3], title="Try panning or zooming!")

fig.add_annotation(text="Absolutely-positioned annotation",
                  xref="paper", yref="paper",
                  x=0.3, y=0.3, showarrow=False)

fig.show()
11.522.5311.522.53
Try panning or zooming!xyAbsolutely-positioned annotation

Adding Annotations Referenced to an Axis

To place annotations relative to the length or height of an axis, the string ' domain' can be added after the axis reference in the xref or yref fields. For example:

In [21]:
import plotly.express as px
import plotly.graph_objects as go

df = px.data.wind()
fig = px.scatter(df, y="frequency")

# Set a custom domain to see how the ' domain' string changes the behaviour
fig.update_layout(xaxis=dict(domain=[0, 0.5]), yaxis=dict(domain=[0.25, 0.75]))

fig.add_annotation(
    xref="x domain",
    yref="y domain",
    # The arrow head will be 25% along the x axis, starting from the left
    x=0.25,
    # The arrow head will be 40% along the y axis, starting from the bottom
    y=0.4,
    text="An annotation referencing the axes",
    arrowhead=2,
)

fig.show()
050100012
indexfrequencyAn annotation referencing the axes

Specifying the Text's Position Absolutely

The text coordinates / dimensions of the arrow can be specified absolutely, as long as they use exactly the same coordinate system as the arrowhead. For example:

In [22]:
import plotly.express as px
import plotly.graph_objects as go

df = px.data.wind()
fig = px.scatter(df, y="frequency")

fig.update_layout(xaxis=dict(domain=[0, 0.5]), yaxis=dict(domain=[0.25, 0.75]))
fig.add_annotation(
    xref="x domain",
    yref="y",
    x=0.75,
    y=1,
    text="An annotation whose text and arrowhead reference the axes and the data",
    # If axref is exactly the same as xref, then the text's position is
    # absolute and specified in the same coordinates as xref.
    axref="x domain",
    # The same is the case for yref and ayref, but here the coordinates are data
    # coordinates
    ayref="y",
    ax=0.5,
    ay=2,
    arrowhead=2,
)

fig.show()
050100012
indexfrequencyAn annotation whose text and arrowhead reference the axes and the data

Customize Displayed Text with a Text Template

To show an arbitrary text in your chart you can use texttemplate, which is a template string used for rendering the information, and will override textinfo. This template string can include variables in %{variable} format, numbers in d3-format's syntax, and date in d3-time-format's syntax. texttemplate customizes the text that appears on your plot vs. hovertemplate that customizes the tooltip text.

In [23]:
import plotly.graph_objects as go

fig = go.Figure(go.Pie(
    values = [40000000, 20000000, 30000000, 10000000],
    labels = ["Wages", "Operating expenses", "Cost of sales", "Insurance"],
    texttemplate = "%{label}: %{value:$,s} <br>(%{percent})",
    textposition = "inside"))

fig.show()
Wages: $40.0000M (40%)Cost of sales: $30.0000M (30%)Operating expenses: $20.0000M (20%)Insurance: $10.0000M (10%)
WagesCost of salesOperating expensesInsurance

Customize Text Template

The following example uses textfont to customize the added text.

In [24]:
import plotly.graph_objects as go

fig = go.Figure(go.Scatterternary(
    a = [3, 2, 5],
    b = [2, 5, 2],
    c = [5, 2, 2],
    mode = "markers+text",
    text = ["A", "B", "C"],
    texttemplate = "%{text}<br>(%{a:.2f}, %{b:.2f}, %{c:.2f})",
    textposition = "bottom center",
    textfont = {'family': "Times", 'size': [18, 21, 20], 'color': ["IndianRed", "MediumPurple", "DarkOrange"]}
))

fig.show()
A(3.00, 2.00, 5.00)B(2.00, 5.00, 2.00)C(5.00, 2.00, 2.00)00.20.40.60.8110.80.60.40.2010.80.60.40.20
Component AComponent BComponent C

Set Date in Text Template

The following example shows how to show date by setting axis.type in funnel charts. As you can see textinfo and texttemplate have the same functionality when you want to determine 'just' the trace information on the graph.

In [25]:
from plotly import graph_objects as go

fig = go.Figure()

fig.add_trace(go.Funnel(
    name = 'Montreal',
    orientation = "h",
    y = ["2018-01-01", "2018-07-01", "2019-01-01", "2020-01-01"],
    x = [100, 60, 40, 20],
    textposition = "inside",
    texttemplate = "%{y| %a. %_d %b %Y}"))

fig.add_trace(go.Funnel(
    name = 'Vancouver',
    orientation = "h",
    y = ["2018-01-01", "2018-07-01", "2019-01-01", "2020-01-01"],
    x = [90, 70, 50, 10],
    textposition = "inside",
    textinfo = "label"))

fig.update_layout(yaxis = {'type': 'date'})

fig.show()
Mon. 1 Jan 2018 Sun. 1 Jul 2018 Tue. 1 Jan 2019 Wed. 1 Jan 2020Jan 1, 2018Jul 1, 2018Jan 1, 2019Jan 1, 2020Jan 2020Jul 2019Jan 2019Jul 2018Jan 2018
MontrealVancouver

Reference

See https://plotly.com/python/reference/layout/annotations/ 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