user9532692
user9532692

Reputation: 706

Plotly: different colors in one line

I am trying to distinguish weekends from weekdays by either 1) shading the region 2) coloring points with different colors or 3) setting x-axis label marked different for weekend.

Here I am trying the 2nd option — coloring data points for weekend differently. I first created an additional column (Is_Weekday) for distinguish weekends from weekdays. However, it’s not drawn on the same line, but rather draws two lines with different colors. I would like them to be in one line but with different color for values on weekends.

image

Here’s my code for reproducible data:

import pandas as pd
from datetime import datetime
import plotly.express as px

np.random.seed(42)
rng = pd.date_range('2022-04-10', periods=21, freq='D')
practice_df = pd.DataFrame({ 'Date': rng, 'Val' : np.random.randn(len(rng))}) 
practice_df = practice_df.set_index('Date')

weekend_list = []
for i in range(len(practice_df)):
    if practice_df.index[i].weekday() > 4:
        weekend_list.append(True)
    else:
        weekend_list.append(False)

practice_df['IsWeekend'] = weekend_list

fig = px.line(temp_df, 
              x=temp_df.index, y='cnt', 
              color = 'Is_Weekend',
              markers=True)
fig.show()

What I want to do would look something like this but coloring data points/line for weekends differently.

image2


Edit:

Thanks so much to @Derek_O, I was able to color weekend with my original dataset. But I'd want to color the friday-saturday line also colored as weekend legend, so I set practice_df.index[i].weekday() >= 4 instead of practice_df.index[i].weekday() > 4.

  1. But would it be possible to have the Friday point to be the same as weekdays.
  2. Also, is it possible to have a straight line connecting the points, not like stairs?
  3. Otherwise, it'd also work if we could shade weekend region like the image at the bottom.

image3 image4

Upvotes: 1

Views: 1696

Answers (1)

Derek O
Derek O

Reputation: 19520

Borrowing from @Rob Raymond's answer here, we can loop through the practice_df two elements at a time, adding a trace to the fig for each iteration of the loop.

We also only want to show the legend category the first time it occurs (so that the legend entries only show each category like True or False once), which is why I've created a new column called "showlegend" that determines whether the legend is shown or not.

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

np.random.seed(42)
rng = pd.date_range('2022-04-10', periods=21, freq='D')
practice_df = pd.DataFrame({ 'Date': rng, 'Val' : np.random.randn(len(rng))}) 
practice_df = practice_df.set_index('Date')

weekend_list = []
for i in range(len(practice_df)):
    if practice_df.index[i].weekday() > 4:
        weekend_list.append(True)
    else:
        weekend_list.append(False)

practice_df['IsWeekend'] = weekend_list

weekend_color_map = {True:0, False:1}
weekend_name_map = {True:"True", False:"False"}
practice_df['color'] = practice_df['IsWeekend'].map(weekend_color_map)
practice_df['name'] = practice_df['IsWeekend'].map(weekend_name_map)

## use the color column since weekend corresponds to 0, nonweekend corresponds to 1
first_weekend_idx = practice_df['color'].loc[practice_df['color'].idxmin()]
first_nonweekend_idx = practice_df['color'].loc[practice_df['color'].idxmax()]
practice_df["showlegend"] = False
showlegendIdx = practice_df.columns.get_indexer(["showlegend"])[0]
practice_df.iat[first_weekend_idx, showlegendIdx] = True
practice_df.iat[first_nonweekend_idx, showlegendIdx] = True
practice_df["showlegend"] = practice_df["showlegend"].astype(object)

fig = go.Figure(
    [
        go.Scatter(
            x=practice_df.index[tn : tn + 2],
            y=practice_df['Val'][tn : tn + 2],
            mode='lines+markers',
            # line_shape="hv",
            line_color=px.colors.qualitative.Plotly[practice_df['color'][tn]],
            name=practice_df['name'][tn],
            legendgroup=practice_df['name'][tn],
            showlegend=practice_df['showlegend'][tn],
        )
        for tn in range(len(practice_df))
    ]
)

fig.update_layout(legend_title_text='Is Weekend')

fig.show()

enter image description here

Upvotes: 2

Related Questions