4

I am trying to create a line charts with text labels on the chart itself but it is not working. It is working perfectly fine in scatter plot with the text parameter which you can see below.

code -

import plotly.express as px

fig = px.scatter(crime2,
                 x='murder',
                 y='burglary',
                 size='population',
                 text='state')  # add figure label
fig.update_layout(xaxis_title='Murder Rate',
                  yaxis_title='Burglary Rate')
fig.update_traces(marker=dict(color='red'))
fig.show()

scatter plot with figure text labels

But it's not working with line chart. code for line chart -

fig = px.line(covid_subset,
              x='date',
              y='total_cases',
              color='location',
              text='location'
)
fig.update_layout(title='Cumulative Confirmed covid-19 cases')
fig.show()

line chart with text label

As you can see instead of show the country label on the line chart only at one place it kept showing all over the line.

I might missing some parameter but I don't know what is it.

This is what I am trying to do -

covid line chart

rpanai
  • 12,515
  • 2
  • 42
  • 64
bhola prasad
  • 675
  • 7
  • 22

2 Answers2

3

This is actually how the parameter text is supposed to work: show a text all the time it appears on the given column. I have in mind two possible workarounds one with a trick and the other with annotations. These are not ideal solutions but you can start from here.

Get Data

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

url = "https://github.com/owid/covid-19-data/raw/master/public/data/owid-covid-data.csv"
df = pd.read_csv(url)

countries = ["Brazil", "Germany", "India", "Indonesia", "Italy",
             "Mexico", "New Zealand", "Norway", "South Africa",
             "South Korea", "United States"]

df = df[df["location"].isin(countries)].reset_index(drop=True)

Annotations

grp = df.groupby("location")[["date", "total_cases"]].last().reset_index()

annotations = []
for i, row in grp.iterrows():
    annotations.append(
    dict(x=row["date"],
         y=row["total_cases"],
         text=row["location"],
        xref="x",
        yref="y",
        showarrow=True,
#         arrowhead=7,
        ax=50,
        ay=0
        ))
    
    
fig = px.line(df,
              x='date',
              y='total_cases',
              color='location',
)
fig.update_layout(title='Cumulative Confirmed covid-19 cases',
                  title_x=0.5,
                  showlegend=False,
                  annotations=annotations)
fig.show()

enter image description here

Trick

df["date"] = df["date"].astype("M8")

grp = df.groupby("location")[["date", "total_cases"]]\
        .last().reset_index()
grp["text"] = grp["location"].copy()

grp["date"] = grp["date"] + pd.offsets.DateOffset(days=5)

df1 = pd.concat([df, grp], ignore_index=True, sort=False)\
        .sort_values(["location", "date"]).reset_index(drop=True)

df1["text"] = np.where(df1["text"].isnull(), "", df1["text"])

fig = px.line(df1,
              x='date',
              y='total_cases',
              color='location',
              text="text",
              hover_data={"text":False}
)
fig.update_traces(textposition='top center') 
fig.update_layout(title='Cumulative Confirmed covid-19 cases',
                  title_x=0.5,
                  showlegend=False,)
fig.show()

enter image description here

rpanai
  • 12,515
  • 2
  • 42
  • 64
  • 1
    Thanks, really appreciate that you go above and beyond to pull the data from owid github repo and made the plot to explain it – bhola prasad Jul 24 '20 at 05:27
3

Here's a slightly more compact/DRY alternative:

import plotly.express as px

df = px.data.gapminder().query("continent == 'Oceania'")

fig = px.line(df, x="year", y="lifeExp", color="country")
fig.for_each_trace(lambda t: fig.add_annotation(
    x=t.x[-1], y=t.y[-1], text=t.name, 
    font_color=t.line.color,
    ax=5, ay=0, xanchor="left", showarrow=False
))
fig.update_layout(showlegend=False)

fig.show()

enter image description here

nicolaskruchten
  • 26,384
  • 8
  • 83
  • 101
  • 1
    Nice. But here what will be great to have something like Our World in Data. What I mean is that with many traces it will be hard to distinguish one annotation from the other. – rpanai Jul 24 '20 at 15:50
  • 2
    Yep. Text avoidance is a very challenging problem, and something that would need to be handled in Plotly.js but we will likely need a sponsor for that: not something we can take on on our own at the moment. – nicolaskruchten Jul 24 '20 at 16:20