✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
📊 Dash 2.0 is Arriving. Register here.

Using dcc.upload with px.scatter and px.scatter_3d

Hi there,
I have successfully used dcc.upload with px.scatter (code below), however when I use dcc.upload for px.scatter_3D I get the error ‘NoneType’ object has no attribute ‘split’. I am not sure how to get rid of the error as my codes are identical so am confused as to why it works in a 2D scatter but not 3D.
Any help would be appreciated! Thank you! :slight_smile:

1)px.scatter

import base64
import io
import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.express as px
import flask

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
server = flask.Flask(__name__)
app = dash.Dash(__name__, external_stylesheets=external_stylesheets, server=server)

app.layout = html.Div([
    html.Div([dcc.Upload(
        id='data-table-upload',
        children=html.Div(['Drag and Drop or ',
                           html.A('Select Files')
                           ]),
        style={
            'width': '70%',
            'height': '60px',
            'lineHeight': '60px',
            'borderWidth': '1px',
            'borderStyle': 'dashed',
            'borderRadius': '5px',
            'textAlign': 'center',
            'margin': '10px 15%'
        },
        multiple=False
    ),
    ]),
    html.Div([dcc.Graph(id='my-graph')], style={'display': 'inline-block', 'width': '70%', 'height':'75%'}),

    html.Div([
        html.Div([html.Label(["Select X variable:",
                              dcc.Dropdown(id='xaxis-anim', multi=False, placeholder="Select an option for X")],
                             className="six columns"
                             )], style={'width': '170%', 'display': 'inline-block'}),
        html.Div([html.Label(["Select Y variable:",
                              dcc.Dropdown(id='yaxis-anim', multi=False, placeholder='Select an option for Y')],
                             className="six columns"
                             ), ], style={'width': '170%', 'display': 'inline-block'}),
        html.Div([html.Label(
            ["Select Size variable:",
             dcc.Dropdown(id='saxis-anim', multi=False, placeholder='Select an option for Size')],
            className="six columns"
        )], style={'width': '170%', 'display': 'inline-block'}),
        html.Div([html.Label(
            ["Select Color variable:",
             dcc.Dropdown(id="caxis-anim", multi=False, placeholder='Select an option for Color')],
            className="six columns"
        )], style={'width': '170%', 'display': 'inline-block'})
    ],
        style={'display': 'inline-block', 'width': '23%', })

])


def parse_contents(contents, filename):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            return pd.read_csv(
                io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            return pd.read_excel(io.BytesIO(decoded))
        elif 'txt' or 'tsv' in filename:
            return pd.read_csv(
                io.StringIO(decoded.decode('utf-8')), delimiter=r'\s+'
            )
    except Exception as e:
        print(e)
        return html.Div([
            'There was an error processing this file.'
        ])


# POPULATE X AXIS DROPDOWN ANIM
@app.callback(Output('xaxis-anim', 'options'),
              [Input('data-table-upload', 'contents')],
              [State('data-table-upload', 'filename')])
def populate_xaxis_dropdown(contents, filename):
    df = parse_contents(contents, filename)
    return [{'label': i, 'value': i} for i in df.columns]


# POPULATE Y AXIS DROPDOWN ANIM
@app.callback(Output('yaxis-anim', 'options'),
              [Input('data-table-upload', 'contents')],
              [State('data-table-upload', 'filename')])
def populate_yaxis_dropdown(contents, filename):
    df = parse_contents(contents, filename)
    return [{'label': i, 'value': i} for i in df.columns]


# POPULATE C AXIS DROPDOWN ANIM
@app.callback(Output('caxis-anim', 'options'),
              [Input('data-table-upload', 'contents')],
              [State('data-table-upload', 'filename')])
def populate_caxis_dropdown(contents, filename):
    df = parse_contents(contents, filename)
    return [{'label': i, 'value': i} for i in df.columns]


# POPULATE S AXIS DROPDOWN ANIM
@app.callback(Output('saxis-anim', 'options'),
              [Input('data-table-upload', 'contents')],
              [State('data-table-upload', 'filename')])
def populate_saxis_dropdown(contents, filename):
    df = parse_contents(contents, filename)
    return [{'label': i, 'value': i} for i in df.columns]


@app.callback(Output('my-graph', 'figure'),
              [Input('data-table-upload', 'contents'),
               Input('xaxis-anim', 'value'),
               Input('yaxis-anim', 'value'),
               Input('caxis-anim', 'value'),
               Input('saxis-anim', 'value')],
              [State('data-table-upload', 'filename')]
              )
def update_figure(contents, x, y, color, size, filename):
    df = parse_contents(contents, filename)
    return px.scatter(df, x=df[x], y=df[y], title="", animation_frame="Pressure (bar)",
                      animation_group=df.columns[0], size=df[size], color=df[color],
                      hover_name=df.columns[0], color_continuous_scale='Viridis',
                      hover_data={}, template="none",
                      ).update_xaxes(showgrid=False, title=x, autorange=True, ticks='outside',
                                     showline=True, showspikes=True, mirror=True).update_yaxes(
        showgrid=False, title=y, autorange=True, ticks='outside', showspikes=True,
        showline=True, mirror=True ).update_layout(
        clickmode='event+select', hovermode='closest', margin={}, autosize=True
    ).update_traces(marker=dict(opacity=0.7, showscale=True, line=dict(width=0.5, color='DarkSlateGrey'),
                                colorbar=dict(title=color)))


app.run_server(debug=False)

  1. px.scatter_3d
import plotly.express as px
import pandas as pd
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import flask
import json
from textwrap import dedent as d
import base64
import io

server = flask.Flask(__name__)
app = dash.Dash(__name__, server=server)

styles = {
    'pre': {
    }
}
tabs_styles = {}
tab_style = {
}

tab_selected_style = {
}

app.layout = html.Div(
    [
        html.H1("Adsorption and Advanced Materials Group", style={'textAlign': 'center', 'size': '18',
                                                                  'font-family': 'Arial'}),
        html.Div(" ", style={'textAlign': 'center', 'size': '14'}),
        html.Div([
            dcc.Tabs([
                dcc.Tab(label='MOF explorer', style=tab_style, selected_style=tab_selected_style,
                        children=[
                            html.Div([dcc.Upload(
                                id='data-table-upload',
                                children=html.Div(['Drag and Drop or ',
                                                   html.A('Select Files')
                                                   ]),
                                style={
                                    'width': '70%',
                                    'height': '60px',
                                    'lineHeight': '60px',
                                    'borderWidth': '1px',
                                    'borderStyle': 'dashed',
                                    'borderRadius': '5px',
                                    'textAlign': 'center',
                                    'margin': '10px 15%'
                                },
                                multiple=False
                            ),
                            ]),
                            html.Div([dcc.Graph(id="graph"
                                                ), html.Div([
                                dcc.Markdown(d("""
                                ***Click Data
                                Click on points in the graph.
                                """)),
                                html.Pre(id='click-data', style=styles['pre']),
                            ], style={'fontSize': 14, 'font-family': ' Arial', 'padding': 50, 'float': 'left'}
                            )],
                                     style={"width": "70vw", "display": "inline-block"}),
                            html.Div([
                                html.Div([html.Label(["Select X variable:",
                                                      dcc.Dropdown(id='xaxis-3D', multi=False,
                                                                   placeholder="Select an option for X",

                                                                   )],
                                                     className="six columns"
                                                     )], style={'width': '170%', 'display': 'inline-block'}),
                                html.Div([html.Label(["Select Y variable:",
                                                      dcc.Dropdown(id='yaxis-3D', multi=False,

                                                                   placeholder='Select an option for Y')],
                                                     className="six columns"
                                                     ), ], style={'width': '170%', 'display': 'inline-block'}),
                                html.Div([html.Label(["Select Z variable:",
                                                      dcc.Dropdown(id='zaxis-3D', multi=False,

                                                                   placeholder='Select an option for Z')],
                                                     className="six columns"
                                                     ), ], style={'width': '170%', 'display': 'inline-block'}),
                                html.Div([html.Label(
                                    ["Select Size variable:",
                                     dcc.Dropdown(id='saxis-3D', multi=False, placeholder='Select an option for Size',

                                                  )],
                                    className="six columns"
                                )], style={'width': '170%', 'display': 'inline-block'}),
                                html.Div([html.Label(
                                    ["Select Color variable:",
                                     dcc.Dropdown(id="caxis-3D", multi=False,

                                                  placeholder='Select an option for Color')],
                                    className="six columns"
                                )], style={'width': '170%', 'display': 'inline-block'})
                            ],
                                style={'display': 'inline-block', 'width': '23%', })
                            ,

                        ]),
                dcc.Tab(label='Statistical Analysis', style=tab_style, selected_style=tab_selected_style,
                        children=[
                            dcc.Graph(id='stat-plot')
                        ])], style=tabs_styles)
        ])
    ], style={}  # style for outter div
)


def parse_contents(contents, filename):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            return pd.read_csv(
                io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            return pd.read_excel(io.BytesIO(decoded))
        elif 'txt' or 'tsv' in filename:
            return pd.read_csv(
                io.StringIO(decoded.decode('utf-8')), delimiter=r'\s+'
            )
    except Exception as e:
        print(e)
        return html.Div([
            'There was an error processing this file.'
        ])


# POPULATE X AXIS DROPDOWN 3D
@app.callback(Output('xaxis-3D', 'options'),
              [Input('data-table-upload', 'contents')],
              [State('data-table-upload', 'filename')])
def populate_xaxis_dropdown(contents, filename):
    df = parse_contents(contents, filename)
    return [{'label': i, 'value': i} for i in df.columns]


# POPULATE Y AXIS DROPDOWN 3D
@app.callback(Output('yaxis-3D', 'options'),
              [Input('data-table-upload', 'contents')],
              [State('data-table-upload', 'filename')])
def populate_yaxis_dropdown(contents, filename):
    df = parse_contents(contents, filename)
    return [{'label': i, 'value': i} for i in df.columns]


# POPULATE Z AXIS DROPDOWN 3D
@app.callback(Output('zaxis-3D', 'options'),
              [Input('data-table-upload', 'contents')],
              [State('data-table-upload', 'filename')])
def populate_zaxis_dropdown(contents, filename):
    df = parse_contents(contents, filename)
    return [{'label': i, 'value': i} for i in df.columns]


# POPULATE S AXIS DROPDOWN 3D
@app.callback(Output('saxis-3D', 'options'),
              [Input('data-table-upload', 'contents')],
              [State('data-table-upload', 'filename')])
def populate_saxis_dropdown(contents, filename):
    df = parse_contents(contents, filename)
    return [{'label': i, 'value': i} for i in df.columns]


# POPULATE C AXIS DROPDOWN 3D
@app.callback(Output('caxis-3D', 'options'),
              [Input('data-table-upload', 'contents')],
              [State('data-table-upload', 'filename')])
def populate_caxis_dropdown(contents, filename):
    df = parse_contents(contents, filename)
    return [{'label': i, 'value': i} for i in df.columns]


@app.callback(Output("graph", "figure"),
              [Input('xaxis-3D', "value"),
               Input('yaxis-3D','value'),
               Input('zaxis-3D','value'),
               Input('caxis-3D','value'),
               Input('saxis-3D','value'),
               Input('data-table-upload', 'contents')],
              [State('data-table-upload', 'filename')])
def make_figure(x, y, z, color, size, contents, filename):
    df = parse_contents(contents, filename)
    return px.scatter_3d(df, x=df[x], y=df[y], z=df[z], title="MOF Explorer", animation_frame="Pressure (bar)",
                         animation_group="DDEC code", size=df[size], color=df[color],
                         hover_name=df.columns[0], color_continuous_scale='Viridis',
                         hover_data={}, template="plotly_white",
                         ).update_xaxes(showgrid=False, title=x, autorange=True).update_yaxes(
        showgrid=False, title=y, autorange=True).update_layout(
        clickmode='event+select', hovermode='closest', margin={'l': 50, 'b': 80, 't': 50, 'r': 10}, autosize=True
    ).update_traces(marker=dict(opacity=0.7, showscale=True, line=dict(width=0.5, color='DarkSlateGrey'),
                                colorbar=dict(title=color)))


@app.callback(
    Output('click-data', 'children'),
    [Input('graph', 'clickData'),
     ])
def display_click_data(clickData):
    return json.dumps(clickData, indent=2)


app.run_server(debug=True)