Search code examples
pythonexpressplotlyfacetaxis-labels

Plotly: How to hide axis titles in a plotly express figure with facets?


Is there a simple way to hide the repeated axis titles in a faceted chart using plotly express? I tried setting

visible=True

In the code below, but that also hid the y axis tick labels (the values). Ideally, I would like to set hiding the repeated axes titles a default for faceted plots in general (or even better, just defaulting to showing a single x and y axis title for the entire faceted figure.

Here is the test code:

import pandas as pd
import numpy as np
import plotly.express as px
import string

# create a dataframe
cols = list(string.ascii_letters)
n = 50

df = pd.DataFrame({'Date': pd.date_range('2021-01-01', periods=n)})

# create data with vastly different ranges
for col in cols:
    start = np.random.choice([1, 10, 100, 1000, 100000])
    s = np.random.normal(loc=0, scale=0.01*start, size=n)
    df[col] = start + s.cumsum()

# melt data columns from wide to long
dfm = df.melt("Date")

fig = px.line(
    data_frame=dfm,
    x = 'Date',
    y = 'value',
    facet_col = 'variable',
    facet_col_wrap=6,
    facet_col_spacing=0.05,
    facet_row_spacing=0.035,
    height = 1000,
    width = 1000,
    title = 'Value vs. Date'
)

fig.update_yaxes(matches=None, showticklabels=True, visible=True)
fig.update_annotations(font=dict(size=16))
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))

enter image description here

Final Code (accepted answer). Note plotly >= 4.9

import pandas as pd
import numpy as np
import plotly.express as px
import string
import plotly.graph_objects as go

# create a dataframe
cols = list(string.ascii_letters)
n = 50

df = pd.DataFrame({'Date': pd.date_range('2021-01-01', periods=n)})

# create data with vastly different ranges
for col in cols:
    start = np.random.choice([1, 10, 100, 1000, 100000])
    s = np.random.normal(loc=0, scale=0.01*start, size=n)
    df[col] = start + s.cumsum()

# melt data columns from wide to long
dfm = df.melt("Date")

fig = px.line(
    data_frame=dfm,
    x = 'Date',
    y = 'value',
    facet_col = 'variable',
    facet_col_wrap=6,
    facet_col_spacing=0.05,
    facet_row_spacing=0.035,
    height = 1000,
    width = 1000,
    title = 'Value vs. Date'
)

fig.update_yaxes(matches=None, showticklabels=True, visible=True)
fig.update_annotations(font=dict(size=16))
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))

# hide subplot y-axis titles and x-axis titles
for axis in fig.layout:
    if type(fig.layout[axis]) == go.layout.YAxis:
        fig.layout[axis].title.text = ''
    if type(fig.layout[axis]) == go.layout.XAxis:
        fig.layout[axis].title.text = ''
        
# keep all other annotations and add single y-axis and x-axis title:
fig.update_layout(
    # keep the original annotations and add a list of new annotations:
    annotations = list(fig.layout.annotations) + 
    [go.layout.Annotation(
            x=-0.07,
            y=0.5,
            font=dict(
                size=16, color = 'blue'
            ),
            showarrow=False,
            text="single y-axis title",
            textangle=-90,
            xref="paper",
            yref="paper"
        )
    ] +
    [go.layout.Annotation(
            x=0.5,
            y=-0.08,
            font=dict(
                size=16, color = 'blue'
            ),
            showarrow=False,
            text="Dates",
            textangle=-0,
            xref="paper",
            yref="paper"
        )
    ]
)

fig.show()

Solution

  • This answer has five parts:

    1. Hide subplot titles (not 100% sure you wanted to do that though...)
    2. Hide y-axis tick values using fig.layout[axis].tickfont = dict(color = 'rgba(0,0,0,0)')
    3. Set single axis labels using go.layout.Annotation(xref="paper", yref="paper")
    4. the plotly figure
    5. Complete code snippet at the end

    One very important take-away here is that you can edit any element produced with a px function using plotly.graph_object references, like go.layout.XAxis.


    1. Hide subplot titles

    If you're otherwise happy with the way you've set up your fig, you can just include

    for anno in fig['layout']['annotations']:
        anno['text']=''
        
    fig.show()
    

    2. Hide yaxis text

    You can set the yaxis tickfont to transparent using the following in a loop

    fig.layout[axis].tickfont = dict(color = 'rgba(0,0,0,0)')
    

    That exact line is included in the snippet below that also removes y-axis title for every subplot.

    3. Single axis labels

    The removal of axis labels and inclusion of a single label requires a bit more work, but here's a very flexible setup that does exactly what you need and more if you'd like to edit your new labels in any way:

    # hide subplot y-axis titles and x-axis titles
    for axis in fig.layout:
        if type(fig.layout[axis]) == go.layout.YAxis:
            fig.layout[axis].title.text = ''
        if type(fig.layout[axis]) == go.layout.XAxis:
            fig.layout[axis].title.text = ''
            
    # keep all other annotations and add single y-axis and x-axis title:
    fig.update_layout(
        # keep the original annotations and add a list of new annotations:
        annotations = list(fig.layout.annotations) + 
        [go.layout.Annotation(
                x=-0.07,
                y=0.5,
                font=dict(
                    size=16, color = 'blue'
                ),
                showarrow=False,
                text="single y-axis title",
                textangle=-90,
                xref="paper",
                yref="paper"
            )
        ] +
        [go.layout.Annotation(
                x=0.5,
                y=-0.08,
                font=dict(
                    size=16, color = 'blue'
                ),
                showarrow=False,
                text="Dates",
                textangle=-0,
                xref="paper",
                yref="paper"
            )
        ]
    )
    
    fig.show()
    

    4. Plot

    enter image description here

    5. Complete code:

    import pandas as pd
    import numpy as np
    import plotly.express as px
    import string
    import plotly.graph_objects as go
    
    # create a dataframe
    cols = list(string.ascii_letters)
    cols[0]='zzz'
    n = 50
    
    df = pd.DataFrame({'Date': pd.date_range('2021-01-01', periods=n)})
    
    # create data with vastly different ranges
    for col in cols:
        start = np.random.choice([1, 10, 100, 1000, 100000])
        s = np.random.normal(loc=0, scale=0.01*start, size=n)
        df[col] = start + s.cumsum()
    
    # melt data columns from wide to long
    dfm = df.melt("Date")
    
    fig = px.line(
        data_frame=dfm,
        x = 'Date',
        y = 'value',
        facet_col = 'variable',
        facet_col_wrap=6,
        #facet_col_spacing=0.05,
        #facet_row_spacing=0.035,
        height = 1000,
        width = 1000,
        title = 'Value vs. Date'
    )
    
    fig.update_yaxes(matches=None, showticklabels=True, visible=True)
    fig.update_annotations(font=dict(size=16))
    fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))
    
    # subplot titles
    for anno in fig['layout']['annotations']:
        anno['text']=''
    
    # hide subplot y-axis titles and x-axis titles
    for axis in fig.layout:
        if type(fig.layout[axis]) == go.layout.YAxis:
            fig.layout[axis].title.text = ''
        if type(fig.layout[axis]) == go.layout.XAxis:
            fig.layout[axis].title.text = ''
            
    # keep all other annotations and add single y-axis and x-axis title:
    fig.update_layout(
        # keep the original annotations and add a list of new annotations:
        annotations = list(fig.layout.annotations) + 
        [go.layout.Annotation(
                x=-0.07,
                y=0.5,
                font=dict(
                    size=16, color = 'blue'
                ),
                showarrow=False,
                text="single y-axis title",
                textangle=-90,
                xref="paper",
                yref="paper"
            )
        ] +
        [go.layout.Annotation(
                x=0.5,
                y=-0.08,
                font=dict(
                    size=16, color = 'blue'
                ),
                showarrow=False,
                text="Dates",
                textangle=-0,
                xref="paper",
                yref="paper"
            )
        ]
    )
    
    
    fig.show()