Given a dataframe with 2 groups: (group1, group2), that have values > and < than 0: plot:
My current code however is not coloring as i would expect, and the legend is shown with the same color:
import pandas as pd
import numpy as np
import plotly.express as px
df = pd.DataFrame( {
"x" : [1,2,3],
"group1" : [np.nan, 1, -0.5],
"group2" : [np.nan, -0.2, 1],
}).set_index("x")
df_ = df.reset_index().melt(id_vars = 'x')
fig = px.bar(df_, x='x', y='value', color='variable', barmode='group')
fig.update_traces(marker_color=['red' if val < 0 else 'green' for val in df_['value']], marker_line_color='black', marker_line_width=1.5)
fig.show()
To stick with plotly.express
, I would add a column to your dataframe, e.g. df_['positive']
with a boolean, and then color your plot by this variable.
It would look like this:
import pandas as pd
import numpy as np
import plotly.express as px
df = pd.DataFrame( {
"x" : [1,2,3],
"group1" : [np.nan, 1, -0.5],
"group2" : [np.nan, -0.2, 1],
}).set_index("x")
df_ = df.reset_index().melt(id_vars = 'x')
df_['positive'] = (df_['value']>=0)
fig = px.bar(df_, x='x', y='value',barmode = 'group',
color='positive',
color_discrete_map={
True: 'green',
False: 'red'
}
)
fig.update_traces(marker_line_color='black', marker_line_width=1.5)
fig.show('browser')
If you want to keep the colors AND the group distinction within plotly.express
, one way could be to add patterns...
df = pd.DataFrame( {
"x" : [1,2,3],
"group1" : [np.nan, 1, -0.5],
"group2" : [np.nan, -0.2, 1],
}).set_index("x")
df_ = df.reset_index().melt(id_vars = 'x')
positive = (df_['value']>=0)
df_['positive'] = positive
df_['sign'] = ['positive' if x else 'negative' for x in df_['positive']]
# Each compbination of color and patterns
fig = px.bar(df_, x='x', y='value',barmode = 'group',
color='sign',
color_discrete_map={
'positive': 'green',
'negative': 'red'
},
pattern_shape="variable")
fig.update_layout(legend_title="Groups & Signs", bargap=0.5,bargroupgap=0.1)
fig.show('browser')
# Only patterns in legend
fig = px.bar(df_, x='x', y='value', color='variable',
barmode='group',pattern_shape="variable")
fig.update_layout(legend_title="Groups", bargap=0.5,bargroupgap=0.1)
fig.for_each_trace(
lambda trace: trace.update(marker_color=np.where(df_.loc[df_['variable'].eq(trace.name), 'value'] < 0, 'red', 'green'))
)
fig.show('browser')
which outputs : However I was not able to 'remove' the green color from the legend...