Hi @Peilin ,
I think a second condition like that be achieved you could achieved by adding pattern_shape='Shift'
.
And YES, using pattern_shape
will not draw black/white bar, it just add some pattern.
It will not meet your requirements.
# set Shift column as pattern shape
fig = px.timeline(df, x_start="Start", x_end="Finish", y="Task", color="Task",pattern_shape="Shift",color_discrete_map=color_seq)
But after set pattern_shape
property, you can modify the traces pattern and color data using for_each_trace
.
For initial value I will set for Night shift (black) by checking out if there is no pattern applied it will set color black
and the others are according to the color_seq
.
# For initial value change to Night shift (black)
fig.for_each_trace(lambda trace: trace.update(marker_color="black",marker_pattern_shape="") if not trace.marker.pattern.shape else trace.update(marker_pattern_shape=""))
Create value to get list of color when option is selected , “day” or “night” shift.
def get_shift_color(shift_name):
if shift_name == "day":
# get color for Day shift
return [color_seq[data.y[0]] if data.marker.color == "black" else "white" for data in fig.data]
elif shift_name == "night":
# get back the color for Night shift from initial value
return ["black" if data.marker.color == "black" else data.marker.color for data in fig.data]
Lastly, implement dropdown menu that will modify the data of each trace (color and shape) using method="restyle"
.
# create dropdown button
buttons = []
for idx,shift_name in enumerate(df.Shift.unique().tolist()):
print(shift_name)
button = dict(label=shift_name,
method="restyle",
args=[{"marker.color": get_shift_color(shift_name),"marker.pattern.shape": ""} ],
)
buttons.append(button)
# set dropdown using update figure layout
fig.update_layout(
updatemenus=[
dict(
active=0, # default option is index 0 (night shift)
buttons=buttons,
)
])
The result will be like this.
The complete code here.
df = pd.DataFrame([
dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28', Resource="Alex", Shift="night"),
dict(Task="Job B", Start='2009-03-05', Finish='2009-04-15', Resource="Alex", Shift="day"),
dict(Task="Job D", Start='2009-04-18', Finish='2009-04-15', Resource="Alex", Shift="day"),
dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30', Resource="Max", Shift="night"),
dict(Task="Job B", Start='2009-06-20', Finish='2009-07-10', Resource="Max", Shift="night"),
dict(Task="Job B", Start='2009-07-20', Finish='2009-08-30', Resource="Max", Shift="night"),
])
color_seq = {"Job A": "red", "Job B": "blue", "Job C": "green", "Job D": "magenta"}
# set Shift column as pattern shape
fig = px.timeline(df, x_start="Start", x_end="Finish", y="Task", color="Task",pattern_shape="Shift",color_discrete_map=color_seq)
# For initial value change to Night shift (black)
fig.for_each_trace(lambda trace: trace.update(marker_color="black",marker_pattern_shape="") if not trace.marker.pattern.shape else trace.update(marker_pattern_shape=""))
def get_shift_color(shift_name):
if shift_name == "day":
# get color for Day shift
return [color_seq[data.y[0]] if data.marker.color == "black" else "white" for data in fig.data]
elif shift_name == "night":
# get back the color for Night shift from initial value
return ["black" if data.marker.color == "black" else data.marker.color for data in fig.data]
# create dropdown button
buttons = []
for idx,shift_name in enumerate(df.Shift.unique().tolist()):
print(shift_name)
button = dict(label=shift_name,
method="restyle",
args=[{"marker.color": get_shift_color(shift_name),"marker.pattern.shape": ""} ],
)
buttons.append(button)
# set dropdown using update figure layout
fig.update_layout(
updatemenus=[
dict(
active=0, # default option is index 0 (night shift)
buttons=buttons,
)
])
fig.show()
Hope this help.