CompleteNeewb
CompleteNeewb

Reputation: 60

Plotly subplot does not like looped bar plots?

I'm trying to create a simple pdf of a subplot consisting of one bar chart and one data table:

The Bar and table function works but when i try and create a subplot plotly gives the following error:

ValueError:
    Invalid element(s) received for the 'data' property of        
        Invalid elements include

I wrote the following: Does it not like that i looped the bar traces?

I first create functions to build the bar chart and data table:

import plotly
import plotly.graph_objects as go
import plotly.figure_factory as ff
import os
import numpy as np
from plotly.subplots import make_subplots
import pandas as pd


def build_barchart(df,columns):

    x = df.City.unique() # City column should always be the x axis
    fig = go.Figure()
    fig.update_layout(barmode='stack')
    for column in columns:
        Y=df[column].tolist()
        fig.add_trace(go.Bar(name=column,x=x,y=Y))

    return fig 

def build_table(df):

    table = ff.create_table(df)
    return table

def create_pdf(df,columns):

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

    fig.add_trace(
        build_barchart(df,columns),
        row=1, col=1
    )

    fig.add_trace(
        build_table(df),
        row=1, col=2
    )


    if not os.path.exists("images"):
        os.mkdir("images")


    fig.write_image("images/fig1.pdf")
    return

After creating the build functions i try and use them...

df = pd.read_csv('DATA.csv', delimiter=';')
columns=['%Something','%Dogs','%Cats','%Cars']

table = build_table(df)
bars =  build_barchart(df,columns)

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

fig.add_trace(
    bars,
    row=1, col=1
)

fig.add_trace(
    table,
    row=1, col=2
)

fig.show()

test data

City;%Something;%Dogs;%Cats;%Cars;Nr Alarms;Nr Block
USA;60;10;5;25;1;1
CANADA;20;10;5;65;2;2
MEXICO;90;5;5;0;3;3
SWEDEN;10;10;5;75;4;4

Upvotes: 1

Views: 237

Answers (2)

rpanai
rpanai

Reputation: 13437

Please don't take it as an answer. Given that your code has some pitfalls I'm adding a polished version. In particular in case you have duplicated countries x = df.City.astype('str').unique() is not going to work well with Y and you should arrange/check your data before to plot.

import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots

df = pd.DataFrame({
 'City': {0: 'USA', 1: 'CANADA', 2: 'MEXICO', 3: 'SWEDEN'},
 '%Something': {0: 60, 1: 20, 2: 90, 3: 10},
 '%Dogs': {0: 10, 1: 10, 2: 5, 3: 10},
 '%Cats': {0: 5, 1: 5, 2: 5, 3: 5},
 '%Cars': {0: 25, 1: 65, 2: 0, 3: 75},
 'Nr Alarms': {0: 1, 1: 2, 2: 3, 3: 4},
 'Nr Block': {0: 1, 1: 2, 2: 3, 3: 4}})

def build_subplot(df, columns=None):
    if columns is None:
        columns =  df.columns
    # only columns starting with %
    columns = [col for col in columns if col.startswith("%")]

    fig = make_subplots(rows=1, cols=2,
        specs=[
            [{"type": "bar"},{"type": "table"}]
            ]
        )
    fig.update_layout(barmode='stack')

    for column in columns:
        fig.append_trace(
            go.Bar(x=df["City"],
                   y=df[column],
                   name=column),
            row=1,col=1)

    fig.add_trace(
        go.Table(
            header=dict(
                values=df.columns,
                font=dict(size=10),
                align="left"
            ),
            cells=dict(
                values=df.T.values.tolist(),
                align = "left")
        ),
        row=1, col=2
        )


    return fig


build_subplot(df, ['%Something', '%Dogs', 'Nr Block'])

enter image description here

Addendum: I think it will look better if you can have your subplot with 1 column and 2 rows as some details from the table could be hard to read.

Upvotes: 1

CompleteNeewb
CompleteNeewb

Reputation: 60

Figured out what i did wrong!

Instead of using plotly.figure_factory's create_table() i used plotly.graph_objects Table()

I also had to define the type of figure used in the creation of the subplot. The final solution for creating the subplot looks like this:

def build_subplot(df,columns):

    x = df.City.astype('str').unique()
    fig = make_subplots(rows=1, cols=2,
        specs=[
            [{"type": "bar"},{"type": "table"}]
            ]
        )
    fig.update_layout(barmode='stack')

    for column in columns:
        Y=df[column].tolist()
        fig.append_trace(go.Bar(name=column,x=x,y=Y),row=1,col=1)

    fig.add_trace(
        go.Table(
            header=dict(
                values=df.columns,
                font=dict(size=10),
                align="left"
            ),
            cells=dict(
                values=[df[k].tolist() for k in df.columns],
                align = "left")
        ),
        row=1, col=2
        )


    return fig 

I hope this helps someone else :)

Upvotes: 0

Related Questions