3

I have this dataset-

              group             sub_group    value    date
0           Animal                  Cats       12     today
1           Animal                  Dogs       32     today
2           Animal                 Goats       38     today
3           Animal                  Fish        1     today
4            Plant                  Tree       48     today
5           Object                   Car       55     today
6           Object                Garage       61     today
7           Object            Instrument       57     today
8           Animal                  Cats       44     yesterday
9           Animal                  Dogs       12     yesterday
10          Animal                 Goats       18     yesterday
11          Animal                  Fish        9     yesterday
12           Plant                  Tree        8     yesterday
13          Object                   Car       12     yesterday
14          Object                Garage       37     yesterday
15          Object            Instrument       77     yesterday

I want to have two series in a barchart. I want to have one series for today and I want to have another series for yesterday. Within each series, I want the bars to be split up by their sub-groups. For example, there would be one bar called "Animal - today" and it would sum up to 83 and, within that bar, there would be cats, dogs, etc.

I want to make a chart that is very similar to chart shown under "Bar charts with Long Format Data" on the docs, except that I have two series.

This is what I tried-

fig = make_subplots(rows = 1, cols = 1)

fig.add_trace(go.Bar(
            y = df[df['date'] == 'today']['amount'],
            x = df[df['date'] == 'today']['group'],
            color = df[df['date'] == 'today']['sub_group']
        ),
    row = 1, col = 1
)

fig.add_trace(go.Bar(
            y = df[df['date'] == 'yesterday']['amount'],
            x = df[df['date'] == 'yesterday']['group'],
            color = df[df['date'] == 'yesterday']['sub_group']
        ),
    row = 1, col = 1
)

fig.show()
 

I added a bounty because I want to be able to add the chart as a trace in my subplot.

Cauder
  • 2,157
  • 4
  • 30
  • 69

4 Answers4

2

I think your code will draw the intended graph except for the color settings, but if you want to separate each stacked graph by color, you will need to do some tricks. There may be another way to do this, but create two express graphs by date and reuse that data. To create that x-axis, add a column with the code that makes the group column a category. the second group needs to be shifted on the x-axis, so I add +0.5 to the x-axis. Set the array ([0.25,1.25,2.25]) and string to center the x-axis scale on the created graph. Finally, duplicate legend items are made unique.

# group id add
df['gr_id'] = df['group'].astype('category').cat.codes

import plotly.express as px
import plotly.graph_objects as go

fig_t = px.bar(df.query('date == "today"'), x="gr_id", y="amount", color='sub_group')
fig_y = px.bar(df.query('date == "yesterday"'), x="gr_id", y="amount", color='sub_group')

fig = go.Figure()

for t in fig_t.data:
    fig.add_trace(go.Bar(t))
    
for i,y in enumerate(fig_y.data):
    y['x'] = y['x'] + 0.5
    fig.add_trace(go.Bar(y))

fig.update_layout(bargap=0.05, barmode='stack')
fig.update_xaxes(tickvals=[0.25,1.25,2.25], ticktext=['Animal','Plant','Pbject'])

names = set()
fig.for_each_trace(
    lambda trace:
        trace.update(showlegend=False)
        if (trace.name in names) else names.add(trace.name))

fig.update_layout(legend_tracegroupgap=0)
fig.show()

enter image description here

EDIT: This is achieved by using the pre-loaded subplotting functionality built into express.

import plotly.express as px

px.bar(df, x='group', y='amount', color='sub_group', facet_col='date')

enter image description here

r-beginners
  • 31,170
  • 3
  • 14
  • 32
  • Is it possible to have this be as subplot? The dashboard is all subplots – Cauder Nov 06 '22 at 11:38
  • Added code and graphs for subplots. – r-beginners Nov 07 '22 at 00:56
  • I added this to my trace: fig.add_trace(px.bar(df, x='group', y='amount', color='sub_group'), row = 1, col = 1) and got this error: Invalid element(s) received for the 'data' property of Invalid elements include: [Figure({ – Cauder Nov 12 '22 at 19:01
  • My response was incomplete and I have corrected the code. Please run my code once again. And the error in your comment, was it added to the code in the question? Please update the question to indicate which one you added about. – r-beginners Nov 13 '22 at 01:44
1

I Know This is Kinda late, maybe not as useful, but you could use Dataclasses

from dataclasses import dataclass

@dataclass
class DataObject:
    value: str
    index: int

@dataclass
class TwoDayData:

    today: DataObject
    yesterday: DataObject
    

data = DataObject(value="hello", index=1)
data_yesterday = DataObject(value="Mom", index=1)

two_day_point = TwoDayData(today=data, yesterday=data_yesterday)

print(two_day_point.yesterday, two_day_point.today)
print(two_day_point.yesterday.index, two_day_point.today.index)

-1

I didn't see your expected Output so I followed my prediction. Try to see if you got it right:

import plotly.graph_objects as go
from plotly.subplots import make_subplots
fig = make_subplots(rows = 1, cols = 2)

fig.add_trace(go.Bar(x=[tuple(df[df['date'] == 'today']['group']),
                        tuple(df[df['date'] == 'today']['sub_group'])],
                     y=list(df[df['date'] == 'today']['value']),
                     name='today'),
                row = 1, col = 1)

fig.add_trace(go.Bar(x=[tuple(df[df['date'] == 'yesterday']['group']),
                        tuple(df[df['date'] == 'yesterday']['sub_group'])],
                     y=list(df[df['date'] == 'yesterday']['value']),
                     name='yesterday'),
                row = 1, col = 2)                
                
fig.show()

And below is the Output: enter image description here

hoa tran
  • 1,391
  • 1
  • 5
  • 14
  • Not quite, it should be similar to the othre person's answer where the groups should be represented in stacked bars – Cauder Nov 12 '22 at 18:55
-1

I find it more aesthetically pleasing to put data like this into figures with multi-categorical axes.

fig = make_subplots(rows = 1, cols = 1)

for sg in df['sub_group'].unique():
    fig.append_trace(go.Bar(x=[df['date'][df['sub_group']==sg], df['group'][df['sub_group']==sg]],
                            y=df['value'][df['sub_group']==sg],
                            name=sg,
                            text=sg),
                     col=1,
                     row=1
                     )
fig.update_layout(barmode='stack')

fig.show()

enter image description here

amance
  • 883
  • 4
  • 14