Setting line color with seversl dropdowns

Hi,

I’m trying to plot some data data using an interactive Dash app and I’m having some trouble with setting the right line colors.

Basically I’m trying to create line plots of measurement data. I have a polars dataframe with the following columns:
Subject: The subject ID as string
Trial: The type of measurement as string
Step: The current step of the measurement as float
Parameter: The parameter from the measurement as string
Resampled: Wether or not the data is resampled as boolean
Value: The value of the parameter as float

Each line in the dataframe contains one observation. I use polars because the callback is faster compared to pandas.

I have created a Dash app with dropdowns for Subject, Trial, Parameter and Resampled and want to plot a line plot with Value on the y-axis and Step on the x-axis. Since the measurements vary in time I have each measurement as raw values with varying amout of steps and in a resampled format where all measurements have 1000 steps. Since I always want a subject to have the same color if I plot several subjects I have created a color_map.

This is my code:

# load df
df = pd.read_pickle('df.pkl')

# convert to polars
df_pl = pl.from_pandas(df)

# function for plotting
def plot_all(df, port=np.random.randint(8000,8050), mode='external'):
    
    appAll = JupyterDash(__name__)
    
    appAll.layout = html.Div(
        ['Subject:',
         dcc.Dropdown(
             id='subject',
             options = sorted([{'label': x, 'value': x} for x in df['Subject'].unique()], key = lambda x: x['label']),
             multi=True,
             placeholder='Subject'),
         'Trial:',
          dcc.Dropdown(
              id='trial',
              options = sorted([{'label': x, 'value': x} for x in df['Trial'].unique()], key = lambda x: x['label']),
              placeholder='Trial'),
          'Parameter:',
           dcc.Dropdown(
               id='param',
               options = sorted([{'label': x, 'value': x} for x in df['Parameter'].unique()], key = lambda x: x['label']),
               multi=False,
               placeholder='Parameter'),
           'Resampling:',
            dcc.Dropdown(
                id='resampling',
                options = sorted([{'label': str(x), 'value': x} for x in df['Resampled'].unique()], key = lambda x: x['label']),
                multi=False,
                placeholder='Resampling'),
            dcc.Graph(id='graph')
         ]
        )
      
    @appAll.callback(
        Output('graph', 'figure'),
        Input('subject', 'value'),
        Input('trial', 'value'),
        Input('param', 'value'),
        Input('resampling', 'value'),
        )
    def update_graph(subject, trial, param, resampling):
        
        css_colors = ['AntiqueWhite', 'Aqua', 'Aquamarine', 'Black', 'Blue', 'BlueViolet', 'Brown', 'BurlyWood', 'CadetBlue', 'Charteuse', 'Chocolate', 'Coral', 'CornflowerBlue',
                      'Crimson', 'DarkBlue', 'DarkCyan', 'DarkGoldenRod', 'DarkGray', 'DarkGreen', 'DarkKhaki', 'DarkMagenta', 'DarkOliveGreen', 'DarkRed', 'DarkOrange',
                      'DarkSlateGray', 'DeepPink', 'DodgerBlue', 'HotPink', 'GreenYellow', 'Purple', 'Yellow', 'Red']

        # colors
        color_discrete_map = {subject: css_colors[i] for i, subject in enumerate(sorted(df['Subject'].unique()))}
        
        # plot
        figAll = px.line(data_frame=df.filter((df['Subject'].is_in(subject)) & (df['Trial'] == trial) & (df['Parameter'] == param) & (df['Resampled'].is_in(resampling))), x='Step', y='Value', color='Subject', color_discrete_map=color_discrete_map, line_dash='Parameter')
       
        figAll.update_layout()
                
        return figAll
    
    appAll.run_server(port=port, mode=mode)
      

plot_all(df_pl)

Now this works for the first trial with the raw data:

However if I select another trial all lines are black, but the legend still shows the right colors:

Furthermore, if I select ‘True’ in the resampled dropdown the lines are again black, also for the first trial which has the right color for ‘False’:

Im new to plotly and dash so I’m sorry if this is a stupid question, but I just cant figure out why the color works sometimes and sometimes not. I would really appreciate some help or feedback on this matter as it’s driving me crazy.

Thank you in advance!

Best regards
Michael

Hi @MichaelLBM, welcome to the forums.

I did some testing. It seems, that plotly has some problems with capital letters within the color strings. Try converting your colors to str.lower() and try again.

css_colors = [color.lower() for color in css_colors]

I think, this might be a bug.

import plotly.express as px

css_colors = ['AntiqueWhite', 'Aqua', 'Aquamarine', 'Black', 'Blue', 'BlueViolet', 'Brown', 'BurlyWood', 'CadetBlue', 'Charteuse', 'Chocolate', 'Coral', 'CornflowerBlue',
              'Crimson', 'DarkBlue', 'DarkCyan', 'DarkGoldenRod', 'DarkGray', 'DarkGreen', 'DarkKhaki', 'DarkMagenta', 'DarkOliveGreen', 'DarkRed', 'DarkOrange',
              'DarkSlateGray', 'DeepPink', 'DodgerBlue', 'HotPink', 'GreenYellow', 'Purple', 'Yellow', 'Red']

css_colors = [color.lower() for color in css_colors]

# colors
color_discrete_map = {subject: css_colors[i] for i, subject in enumerate(sorted(df['continent'].unique()))}

df = px.data.gapminder()
fig = px.line(df, x="year", y="lifeExp", color='continent', color_discrete_map=color_discrete_map)
fig.show()


mrep colors

1 Like

Hi @AIMPED,

thanks for your reply. I just tried your solution and it works!

Just by adding this line my code now works exactely as intended:

css_colors = [color.lower() for color in css_colors]

I never would have thought of that on my own.

1 Like

Perfect, glad I could help. You actually found a bug, a github issue is on the way. :upside_down_face:

thank you for reporting this, @MichaelLBM and thank you @AIMPED for the solution.

I just reported the bug on the Plotly.js repo.