Combining ready-made figures into one, with separation by color

There is an Excel document in which the waste is stored.
Waste of the type date, code, month, year, % - the percentage of waste per month and %y - per year.
I need to make two graphs, one with a breakdown by month, and the second by YTD with the total result for the year.
I made them, placed them in one figure and made shared_yaxes. A different thing is shared_yaxes, I really missed this in PowerBi.

Everything is fine, everything is beautiful. Exactly until the moment when I added a division by colors (processes). It turned out that if you do this, the first process will be displayed instead of all.

I’m pretty sure it’s because of the zero in the fig.add_trace(fig1[‘data’][0], row=1, col=1) line, but all the examples I’ve found contain this zero if removed or added enum, then I get an error.

With all this, I added a split figure 3 and it displays correctly.

How can I make sure that I have all the processes on the top graph, but at the same time I can add two graphs to one figure?

import dash
from dash import html, dcc
import pandas as pd
import plotly.express as px
from plotly.subplots import make_subplots

df = pd.read_excel(r'\\server\waste.xlsx', sheet_name='Sheet1')
df_monthly = df.groupby(['Month','Process'])['%']. sum().reset_index()
df_yearly = df.groupby(['Year','Process'])['%y']. sum().reset_index()

fig = make_subplots(rows=1, cols=2, column_widths=[0.90,0.10], shared_yaxes=True, subplot_titles=("Monthly waste","YTD"))

fig1 = px.bar(df_monthly, y="%", x="Month", color="Process", text="%")
fig2 = px.bar(df_yearly, x="Year", y = "%y", text = "%y", color="Process")

fig.add_trace(fig1['data'][0], row=1, col=1)
fig.add_trace(fig2['data'][0], row=1, col=2)

fig.update_traces(
        textposition="outside",
        texttemplate='%{text:.4}'
        )

fig3 = px.bar(df_monthly, y="%", x="Month", color="Process", text="%")

dash.register_page(__name__)

layout = html.Div(children=[
        dcc.Graph(figure=fig),
        dcc.Graph(figure=fig3)
])

Hi @uk141 unfortunately I did not understand what you are trying to achieve :grimacing:

See the chart above? There are only blue values.
I want to have not only blue, but other colors as well, while there are 2 charts in one line, separated by months and YTD.

In the above figure you plot waste vs month and the last column is the total waste, right?

Based on what?

On “Process”.
fig1 = px.bar(df_monthly, y=“%”, x=“Month”, color=“Process”, text=“%”)

I have a “process” column. If I do not divide by colors, then I get the correct statistics, but without division.
If I divide by colors, then I get only one process, but I want everything.

Could you provide your data, dummy values are OK. It depends on how your DataFrame looks like.

Here is an example with dummy values.
Code - will be used later.
Year, month - the month and year we are talking about
Process - the area responsible for the occurrence of waste
% - waste percentage for the month of this code
% - waste percentage for the year of this code

import dash
from dash import html, dcc
import pandas as pd
import plotly.express as px
from plotly.subplots import make_subplots

df = pd.DataFrame({
    "Code": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
    "Year":[2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022],
	"Month":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
	"Process":["Coating", "Coating", "Coating", "Coating", "Coating", "Coating", "Printing", "Printing", "Printing", "Printing", "Printing", "Printing", "Printing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Coating", "Coating", "Coating", "Coating", "Coating", "Coating", "Printing", "Printing", "Printing", "Printing", "Printing", "Printing", "Printing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Coating", "Coating", "Coating", "Coating", "Coating", "Coating", "Printing", "Printing", "Printing", "Printing", "Printing", "Printing", "Printing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Coating", "Coating", "Coating", "Coating", "Coating", "Coating", "Printing", "Printing", "Printing", "Printing", "Printing", "Printing", "Printing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing"],
    "%":[ 0.0313, 0.0026, 0.0296, 0.0068, 0.0198, 0.0113, 0.0120, 0.0186, 0.0090, 0.0159, 0.0019, 0.0109, 0.0299, 0.0170, 0.0027, 0.0253, 0.0041, 0.0251, 0.0163, 0.0271, 0.0194, 0.0236, 0.0332, 0.0177, 0.0323, 0.0299, 0.0073, 0.0081, 0.0176, 0.0230, 0.0094, 0.0040, 0.0297, 0.0131, 0.0067, 0.0013, 0.0263, 0.0287, 0.0183, 0.0209, 0.0312, 0.0246, 0.0275, 0.0317, 0.0102, 0.0146, 0.0313, 0.0178, 0.0138, 0.0045, 0.0155, 0.0172, 0.0229, 0.0168, 0.0016, 0.0041, 0.0028, 0.0004, 0.0066, 0.0044, 0.0188, 0.0070, 0.0034, 0.0276, 0.0317, 0.0213, 0.0088, 0.0101, 0.0218, 0.0009, 0.0038, 0.0174, 0.0185, 0.0280, 0.0179, 0.0196, 0.0291, 0.0216, 0.0124, 0.0240 ],
	"%y":[0.0078, 0.0006, 0.0074, 0.0017, 0.0049, 0.0028, 0.0030, 0.0047, 0.0023, 0.0040, 0.0005, 0.0027, 0.0075, 0.0043, 0.0007, 0.0063, 0.0010, 0.0063, 0.0041, 0.0068, 0.0049, 0.0059, 0.0083, 0.0044, 0.0081, 0.0075, 0.0018, 0.0020, 0.0044, 0.0057, 0.0024, 0.0010, 0.0074, 0.0033, 0.0017, 0.0003, 0.0066, 0.0072, 0.0046, 0.0052, 0.0078, 0.0062, 0.0069, 0.0079, 0.0026, 0.0037, 0.0078, 0.0045, 0.0034, 0.0011, 0.0039, 0.0043, 0.0057, 0.0042, 0.0004, 0.0010, 0.0007, 0.0001, 0.0016, 0.0011, 0.0047, 0.0017, 0.0008, 0.0069, 0.0079, 0.0053, 0.0022, 0.0025, 0.0054, 0.0002, 0.0009, 0.0043, 0.0046, 0.0070, 0.0045, 0.0049, 0.0073, 0.0054, 0.0031, 0.0060]
})
df_monthly = df.groupby(['Month','Process'])['%']. sum().reset_index()
df_yearly = df.groupby(['Year','Process'])['%y']. sum().reset_index()

fig = make_subplots(rows=1, cols=2, column_widths=[0.90,0.10], shared_yaxes=True, subplot_titles=("Monthly waste","YTD"))
fig1 = px.bar(df_monthly, y="%", x="Month", color="Process", text="%")
fig2 = px.bar(df_yearly, x="Year", y = "%y", text = "%y", color="Process")

fig.add_trace(fig1['data'][0], row=1, col=1)
fig.add_trace(fig2['data'][0], row=1, col=2)

fig.update_traces(
        textposition="outside",
        texttemplate='%{text:.4}'
        )
        
fig.update_layout(
    xaxis = dict(
    tickmode = 'linear',
    tick0 = 1
   )
)     

fig3 = px.bar(df_monthly, y="%", x="Month", color="Process", text="%")

dash.register_page(__name__)

layout = html.Div(children=[
        dcc.Graph(figure=fig),
        dcc.Graph(figure=fig3)
])

Ho did you create the “all blue” figure?

fig show only blue now.

I think because you are just add _trace with data[0] so it just returned one.
So I think you should do something as below:

fig = make_subplots(rows=1, cols=2, column_widths=[0.90,0.10], shared_yaxes=True, subplot_titles=("Monthly waste","YTD"))
fig1 = px.bar(df_monthly, y="%", x="Month", color="Process", text="%")
fig2 = px.bar(df_yearly, x="Year", y = "%y", text = "%y", color="Process")

fig.add_trace(fig1['data'][0], row=1, col=1)
fig.add_trace(fig1['data'][1], row=1, col=1)
fig.add_trace(fig1['data'][2], row=1, col=1)
fig.add_trace(fig2['data'][0], row=1, col=2)
fig.add_trace(fig2['data'][1], row=1, col=2)
fig.add_trace(fig2['data'][2], row=1, col=2)
fig.update_layout(
    xaxis = dict(
    tickmode = 'linear',
    tick0 = 1
   )
)
fig.update_layout(barmode='stack')
fig.update_traces(
        textposition="outside",
        texttemplate='%{text:.4}'
        )
fig.show()

1 Like

Finally I understand. You loose the layout of the single figures because you extract the data to then combine the two figures into one subplot

Since you are using Dash anyway, you could also do something like this:

Instead of using subplots just put the two different figures in a dcc.Graph() each

import dash
from dash import html, dcc
import pandas as pd
import plotly.express as px

app = dash.Dash(__name__)
df = pd.DataFrame({
    "Code": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1, 2, 3, 4, 5,
             6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
             11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
             15, 16, 17, 18, 19, 20],
    "Year": [2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022,
             2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022,
             2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022,
             2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022,
             2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022,
             2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022],
    "Month": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
              2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
              3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
    "Process": ["Coating", "Coating", "Coating", "Coating", "Coating", "Coating", "Printing",
                "Printing", "Printing", "Printing", "Printing", "Printing", "Printing",
                "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing",
                "Finishing", "Coating", "Coating", "Coating", "Coating", "Coating", "Coating",
                "Printing", "Printing", "Printing", "Printing", "Printing", "Printing", "Printing",
                "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing",
                "Finishing", "Coating", "Coating", "Coating", "Coating", "Coating", "Coating",
                "Printing", "Printing", "Printing", "Printing", "Printing", "Printing", "Printing",
                "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing",
                "Finishing", "Coating", "Coating", "Coating", "Coating", "Coating", "Coating",
                "Printing", "Printing", "Printing", "Printing", "Printing", "Printing", "Printing",
                "Finishing", "Finishing", "Finishing", "Finishing", "Finishing", "Finishing",
                "Finishing"],
    "%": [0.0313, 0.0026, 0.0296, 0.0068, 0.0198, 0.0113, 0.0120, 0.0186, 0.0090, 0.0159, 0.0019,
          0.0109, 0.0299, 0.0170, 0.0027, 0.0253, 0.0041, 0.0251, 0.0163, 0.0271, 0.0194, 0.0236,
          0.0332, 0.0177, 0.0323, 0.0299, 0.0073, 0.0081, 0.0176, 0.0230, 0.0094, 0.0040, 0.0297,
          0.0131, 0.0067, 0.0013, 0.0263, 0.0287, 0.0183, 0.0209, 0.0312, 0.0246, 0.0275, 0.0317,
          0.0102, 0.0146, 0.0313, 0.0178, 0.0138, 0.0045, 0.0155, 0.0172, 0.0229, 0.0168, 0.0016,
          0.0041, 0.0028, 0.0004, 0.0066, 0.0044, 0.0188, 0.0070, 0.0034, 0.0276, 0.0317, 0.0213,
          0.0088, 0.0101, 0.0218, 0.0009, 0.0038, 0.0174, 0.0185, 0.0280, 0.0179, 0.0196, 0.0291,
          0.0216, 0.0124, 0.0240],
    "%y": [0.0078, 0.0006, 0.0074, 0.0017, 0.0049, 0.0028, 0.0030, 0.0047, 0.0023, 0.0040, 0.0005,
           0.0027, 0.0075, 0.0043, 0.0007, 0.0063, 0.0010, 0.0063, 0.0041, 0.0068, 0.0049, 0.0059,
           0.0083, 0.0044, 0.0081, 0.0075, 0.0018, 0.0020, 0.0044, 0.0057, 0.0024, 0.0010, 0.0074,
           0.0033, 0.0017, 0.0003, 0.0066, 0.0072, 0.0046, 0.0052, 0.0078, 0.0062, 0.0069, 0.0079,
           0.0026, 0.0037, 0.0078, 0.0045, 0.0034, 0.0011, 0.0039, 0.0043, 0.0057, 0.0042, 0.0004,
           0.0010, 0.0007, 0.0001, 0.0016, 0.0011, 0.0047, 0.0017, 0.0008, 0.0069, 0.0079, 0.0053,
           0.0022, 0.0025, 0.0054, 0.0002, 0.0009, 0.0043, 0.0046, 0.0070, 0.0045, 0.0049, 0.0073,
           0.0054, 0.0031, 0.0060]
})
df_monthly = df.groupby(['Month', 'Process'])['%'].sum().reset_index()
df_yearly = df.groupby(['Year', 'Process'])['%y'].sum().reset_index()

fig1 = px.bar(df_monthly, y="%", x="Month", color="Process", text="%")
fig2 = px.bar(df_yearly, x="Year", y="%y", text="%y", color="Process")
fig3 = px.bar(df_monthly, y="%", x="Month", color="Process", text="%")


app.layout = html.Div(children=[
    html.Div(
        [
            dcc.Graph(figure=fig1, style={'display': 'inline-block', 'width': '85%'}),
            dcc.Graph(figure=fig2, style={'display': 'inline-block', 'width': '15%'})
        ],
    ),
    dcc.Graph(figure=fig3)
])

if __name__ == '__main__':
    app.run(debug=True)
2 Likes

The graphs look exactly the way I want.
And if tomorrow there are 4 processes, then the fourth one will not get on the charts. Is it possible to somehow transfer data there without specifying the code, but transfer all existing ones?
Is there a way to remove duplicate rows in the legend?

Forgive me @aimped, English is not my native language, and I often skipped foreign language lessons at school. Turns out it was a bad idea =)

It’s all good, you are doing a great job!

Me personally, I do not like working with subplots when using dash. It’s much easier to create the graphs separated from each other and put them into the page layout afterwards.

I think you can think about @AIMPED suggestion. Just make 2 figure with px.bar and then use dcc.Graph to show it.

1 Like

Thank you so much for your help guys =)

1 Like

@uk141 : If you still want to use subplot and don’t want to use hard code, I think you should find the numbers of Processes and use for loop to return chart. Something as below:

range_value = len(df['Process'].unique())
fig = make_subplots(rows=1, cols=2, column_widths=[0.90,0.10], shared_yaxes=True, subplot_titles=("Monthly waste","YTD"))
fig1 = px.bar(df_monthly, y="%", x="Month", color="Process", text="%")
fig2 = px.bar(df_yearly, x="Year", y = "%y", text = "%y", color="Process")
range_value = len(df['Process'].unique())
for i in range(0,range_value):
    fig.add_trace(fig1['data'][i], row=1, col=1)
    fig.add_trace(fig2['data'][i], row=1, col=2)
fig.update_layout(
    xaxis = dict(
    tickmode = 'linear',
    tick0 = 1
   )
)
fig.update_layout(barmode='stack')
fig.update_traces(
        textposition="outside",
        texttemplate='%{text:.4}'
        )
fig.show()