Closed nicolaskruchten closed 2 days ago
See also related https://github.com/plotly/plotly.js/issues/3614, https://github.com/plotly/plotly.js/issues/1835, https://github.com/plotly/plotly.js/issues/1015. I'd like to keep the current issue as the master tracking one for this work, so we can close out others and refer to this one as needed.
I see this issue is marked as closed but I'm having trouble tracking resolution. Could you point me in the right direction, please?
See also related #3614, #1835, #1015. I'd like to keep the current issue as the master tracking one for this work, so we can close out others and refer to this one as needed.
This issue is actually still open :)
Is there any update on this issue?
This issue is going to be worked on in the next couple of months.
Thanks @nicolaskruchten
Hello, could you please tell me if this feature is still expected to be available soon?
We will be working on it in the near future but I can't publicly commit to a timeline at this time.
We will be working on it in the near future but I can't publicly commit to a timeline at this time.
Are there any updates on this?
For anyone trying to do this, whilst waiting for the official feature you can get the same outcome by creating the second stackgroup on another yaxis and playing with the traces offsets.
@RenaudLN or anyone else, can you show us code to produce the figure above or similar?
@RenaudLN Yes, could you please share the code for your plot?
@araichev @Alexander-Serov Here is a minimum reproducible example with Python. Note that the offsets are suited to this monthly data and will have to be adjusted with other inputs.
import numpy as np
import pandas as pd
import plotly.graph_objects as go
# Create dummy data indexed by month and with multi-columns [product, revenue]
index = pd.date_range("2020", "2021", freq="MS", closed="left")
df = pd.concat(
[
pd.DataFrame(
np.random.rand(12, 3) * 1.25 + 0.25,
index=index,
columns=["Revenue1", "Revenue2", "Revenue3"]
),
pd.DataFrame(
np.random.rand(12, 3) + 0.5,
index=index,
columns=["Revenue1", "Revenue2", "Revenue3"]
),
],
axis=1,
keys=["Product1", "Product2"]
)
# Create a figure with the right layout
fig = go.Figure(
layout=go.Layout(
height=600,
width=1000,
barmode="relative",
yaxis_showticklabels=False,
yaxis_showgrid=False,
yaxis_range=[0, df.groupby(axis=1, level=0).sum().max().max() * 1.5],
# Secondary y-axis overlayed on the primary one and not visible
yaxis2=go.layout.YAxis(
visible=False,
matches="y",
overlaying="y",
anchor="x",
),
font=dict(size=24),
legend_x=0,
legend_y=1,
legend_orientation="h",
hovermode="x",
margin=dict(b=0,t=10,l=0,r=10)
)
)
# Define some colors for the product, revenue pairs
colors = {
"Product1": {
"Revenue1": "#F28F1D",
"Revenue2": "#F6C619",
"Revenue3": "#FADD75",
},
"Product2": {
"Revenue1": "#2B6045",
"Revenue2": "#5EB88A",
"Revenue3": "#9ED4B9",
}
}
# Add the traces
for i, t in enumerate(colors):
for j, col in enumerate(df[t].columns):
if (df[t][col] == 0).all():
continue
fig.add_bar(
x=df.index,
y=df[t][col],
# Set the right yaxis depending on the selected product (from enumerate)
yaxis=f"y{i + 1}",
# Offset the bar trace, offset needs to match the width
# The values here are in milliseconds, 1billion ms is ~1/3 month
offsetgroup=str(i),
offset=(i - 1) * 1000000000,
width=1000000000,
legendgroup=t,
legendgrouptitle_text=t,
name=col,
marker_color=colors[t][col],
marker_line=dict(width=2, color="#333"),
hovertemplate="%{y}<extra></extra>"
)
fig.show()
Is there any update with this issue? Would be great to have implemented!
Is there any update on this feature? Looks like it has been asked for in one form or another for 8 years
@araichev Is this different than multicategory? I recently made a similar chart to the screenshot above
`function onlyUnique(value, index, array) { return array.indexOf(value) === index; }
// Example data for the x-axis, normally you would fetch this from your data set var categories = [ ["2023-12-01", "Dog"], ["2023-12-02", "Cat"], ["2023-12-03", "Mouse"], ["2023-12-04", "Dog"], ["2023-12-05", "Cat"], ["2023-12-06", "Mouse"], ["2023-12-07", "Dog"], ["2023-12-08", "Cat"], ["2023-12-09", "Mouse"] ];
let dates = categories.map(c => { return c[0]; })
let animals = categories.map(c => { return c[1] })
dates = dates.filter(onlyUnique); animals = animals.filter(onlyUnique);
let xDates = []; dates.forEach(d => { animals.forEach(c => { xDates.push(d); }) })
let xAnimals = []; dates.forEach(d => { animals.forEach(c => { xAnimals.push(c); }) })
var yValuesA = xAnimals.map(() => Math.random() 0.95 + 0.05); var yValuesB = xAnimals.map(() => Math.random() 0.95 + 0.05);
var data = [ { "marker": { "color": [ "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)", "rgb(25, 80, 22)", "rgb(15, 60, 90)", "rgb(113, 13, 14)", "rgb(127, 63, 0)" ], "opacity": 0.5 }, "name": "Test data A", "showlegend": false, "type": "bar", "x": [ xDates, xAnimals ], "y": yValuesA, }, { "marker": { "color": 'darkblue', "opacity": 0.5 }, "name": "Test data B", "showlegend": false, "type": "bar", "x": [ xDates, xAnimals ], "y": yValuesB, }, ];
var layout = { paper_bgcolor: "lightblue", plot_bgcolor: "lightgrey", margin: { "t": 20, "r": 20, "b": 120, "l": 20, // "pad": 0 }, barmode: "stack", xaxis: { "anchor": "y", "type": "multicategory", "tickangle": "auto", "autotickangles": [ 90 ], "tickfont": { "size": 9 }, "showdividers": true, "tickson": "boundaries", "ticklen": 14, "dividercolor": "grey", "dividerwidth": 1, "range": [ -0.5, 83.5 ], "autorange": true }, yaxis: { type: 'linear', range: [0,1], } }
// console.log('data', data); // console.log('layout', layout); // console.log('xDates', xDates); // console.log('xAnimals', xAnimals)
Plotly.newPlot('myDiv', data, layout);`
Resolved in #7009.
We need to permit mixed stacked and grouped bars.
We will implement this with a new
bar.stackgroup
attribute as spec'ed here: https://github.com/plotly/plotly.js/issues/3402