41

I want to change the variable/label names in plotly express in python. I first create a plot:

import pandas as pd
import plotly.express as px

d = {'col1': [1, 2, 3], 'col2': [3, 4, 5]}
df = pd.DataFrame(data=d)
fig = px.line(df, x=df.index, y=['col1', 'col2'])
fig.show()

Which yields:

enter image description here

I want to change the label names from col1 to hello and from col2 to hi. I have tried using labels in the figure, but I cannot get it to work:

fig = px.line(df, x=df.index, y=['col1', 'col2'], labels={'col1': "hello", 'col2': "hi"})
fig.show()

But this seems to do nothing, while not producing an error. Obviously I could achieve my goals by changing the column names, but the actual plot i'm trying to create doesn't really allow for that since it comes from several different dataframes.

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
emil banning
  • 475
  • 1
  • 4
  • 8
  • Great answer, and it does the job. I was hoping that the functionality that you have built, was already part of the plotly express module, but what I understand from your answer this is not the case? – emil banning Oct 16 '20 at 06:49
  • [GH tracking issue](https://github.com/plotly/plotly.py/issues/3049#issuecomment-1279361636) – Janosh Oct 14 '22 at 19:08

5 Answers5

41

The answer:

Without changing the data source, a complete replacement of names both in the legend, legendgroup and hovertemplate will require:

newnames = {'col1':'hello', 'col2': 'hi'}
fig.for_each_trace(lambda t: t.update(name = newnames[t.name],
                                      legendgroup = newnames[t.name],
                                      hovertemplate = t.hovertemplate.replace(t.name, newnames[t.name])
                                     )
                  )

Plot:

enter image description here

The details:

Using

fig.for_each_trace(lambda t: t.update(name = newnames[t.name]))

...you can change the names in the legend without ghanging the source by using a dict

newnames = {'col1':'hello', 'col2': 'hi'}

...and map new names to the existing col1 and col2 in the following part of the figure structure (for your first trace, col1):

{'hovertemplate': 'variable=col1<br>index=%{x}<br>value=%{y}<extra></extra>',
'legendgroup': 'col1',
'line': {'color': '#636efa', 'dash': 'solid'},
'mode': 'lines',
'name': 'hello',   # <============================= here!
'orientation': 'v',
'showlegend': True,
'type': 'scatter',
'x': array([0, 1, 2], dtype=int64),
'xaxis': 'x',
'y': array([1, 2, 3], dtype=int64),
'yaxis': 'y'},

But as you can see, this doesn't do anything with 'legendgroup': 'col1', nor 'hovertemplate': 'variable=col1<br>index=%{x}<br>value=%{y}<extra></extra>' And depending on the complexity of your figure, this can pose a problem. So I would add legendgroup = newnames[t.name] and hovertemplate = t.hovertemplate.replace(t.name, newnames[t.name])into the mix.

Complete code:

import pandas as pd
import plotly.express as px
from itertools import cycle

d = {'col1': [1, 2, 3], 'col2': [3, 4, 5]}
df = pd.DataFrame(data=d)
fig = px.line(df, x=df.index, y=['col1', 'col2'])

newnames = {'col1':'hello', 'col2': 'hi'}
fig.for_each_trace(lambda t: t.update(name = newnames[t.name],
                                      legendgroup = newnames[t.name],
                                      hovertemplate = t.hovertemplate.replace(t.name, newnames[t.name])
                                     )
                  )
vestland
  • 55,229
  • 37
  • 187
  • 305
  • Thanks for the solution, it works for the names in the legend itself. When moving the mouse over the curves howerer the names displayed in the boxes are still the old ones not the new ones. Any idea how to solve that as well? – Mathador Apr 09 '21 at 13:37
  • 1
    Here is the solution, the function `customLegend` needs to be extended as follows: def customLegendPlotly(fig, nameSwap): for i, dat in enumerate(fig.data): for elem in dat: if elem == 'hovertemplate': fig.data[i].hovertemplate = fig.data[i].hovertemplate.replace(fig.data[i].name, nameSwap[fig.data[i].name]) for elem in dat: if elem == 'name': fig.data[i].name = nameSwap[fig.data[i].name] return fig – Mathador Apr 13 '21 at 14:19
30

Add the "name" parameter: go.Scatter(name=...)

Source https://plotly.com/python/figure-labels/

fig = go.Figure()

fig.add_trace(go.Scatter(
    x=[0, 1, 2, 3, 4, 5, 6, 7, 8],
    y=[0, 1, 2, 3, 4, 5, 6, 7, 8],
    name="Name of Trace 1"       # this sets its legend entry
))


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

fig.update_layout(
    title="Plot Title",
    xaxis_title="X Axis Title",
    yaxis_title="X Axis Title",
    legend_title="Legend Title",
    font=dict(
        family="Courier New, monospace",
        size=18,
        color="RebeccaPurple"
    )
)

fig.show()

enter image description here

Nic Scozzaro
  • 6,651
  • 3
  • 42
  • 46
13

This piece of code is more concise.

import pandas as pd
import plotly.express as px

df = pd.DataFrame(data={'col1': [1, 2, 3], 'col2': [3, 4, 5]})

series_names = ["hello", "hi"]

fig = px.line(data_frame=df)

for idx, name in enumerate(series_names):
    fig.data[idx].name = name
    fig.data[idx].hovertemplate = name

fig.show()
Andi
  • 3,196
  • 2
  • 24
  • 44
1

If you're looking for something even more concise, this function does the job-

def custom_legend_name(new_names):
    for i, new_name in enumerate(new_names):
        fig.data[i].name = new_name

Then before fig.show(), just pass a list consisting of the names you want, to the function, like this custom_legend_name(['hello', 'hi'])

Here's what the complete code would look like-

def custom_legend_name(new_names):
    for i, new_name in enumerate(new_names):
        fig.data[i].name = new_name
        

import pandas as pd
import plotly.express as px

d = {'col1': [1, 2, 3], 'col2': [3, 4, 5]}
df = pd.DataFrame(data=d)
fig = px.line(df, x=df.index, y=['col1', 'col2'])
custom_legend_name(['hello','hi'])
fig.show()
callmeanythingyouwant
  • 1,789
  • 4
  • 15
  • 40
0
import pandas as pd
import plotly.express as px

d = {'col1': [1, 2, 3], 'col2': [3, 4, 5]}
df = pd.DataFrame(data=d)
fig = px.line(df, x=df.index, y=['col1', 'col2'])

After you need to create dictionary called 'new' (custom name) and map the orginal trace names to custom names.

new = {'col1':'Front hello', 'col2': 'hi'}
fig.for_each_trace(lambda t: t.update(name = new[t.name]))
fig.show()

enter image description here