1

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

user9532692
  • 584
  • 7
  • 28

1 Answers1

1

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

Derek O
  • 16,770
  • 4
  • 24
  • 43
  • Thanks so much for your help! I changed the weekend to start from Friday to have the Friday-Saturday line colored as weekend by setting `practice_df.index[i].weekday() >= 4`, but it colors Friday point as weekend as well. So I wonder if it's possible to 1) have Friday point still colored different from weekend points and 2) connect dots with a straight line instead of a stair-like line. Please refer to my edits in the question section above. Again, thanks so much for your contribution :) – user9532692 Jun 23 '22 at 04:35
  • 1
    @user9532692 you can fix the dots being connected with a straight line by getting rid of the argument `line_shape="hv"`. i am not sure about making Fridays differently colored from the weekends, but it should be possible, probably by passing an array of colors to `go.Scatter` – i'll circle back to this when i have the chance later – Derek O Jun 24 '22 at 05:04