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...