Hi all,
This is my first post on here, I am having trouble with my app so any help would be greatly appreciated. I think I posted all the info needed, if you need any additional information ill get it posted as soon as I can, Thanks!
app setup:
The app is from a pokemon dataset and there are 2 dropdown menus for type1 and type2, where type 2 is updated after selection on type 1 and the plot defaults to plotting all the data. There are 3 plots, 1 scatterplot of attack/defense, 1 histogram of hp and a pie chart of the proportion of the selection that are legendary pokemon.
summary:
I deployed a plotly dash app on render, however the data is not being uploaded into the plots. I am using the exact code that i built the apps on both Pycharm and Jupyter notebooks and the app works great, but not on the website. The dropdown selections contain the labels, but the plots do not update when a selection is made.
error:
Apr 13 12:35:11 PM pie_chart = px.pie(legendary_counts, values=legendary_counts.legendary, names=legendary_counts.index)
Apr 13 12:35:11 PM File “/opt/render/project/src/.venv/lib/python3.10/site-packages/pandas/core/generic.py”, line 5989, in getattr
Apr 13 12:35:11 PM return object.getattribute(self, name)
Apr 13 12:35:11 PM AttributeError: ‘DataFrame’ object has no attribute ‘legendary’
Is it a problem with the pie chart? When I went back through the code, the dataframe does have ‘legendary’. Ive been chasing this error for days and havent been able to resolve the error.
app url: https://pokemon-stats-app.onrender.com/
code:
data management and manipulation
import pandas as pd
import numpy as npmatplotlib and seaborn
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import seaborn as sns
#plotly
import plotly as py
import plotly.express as px
import plotly.graph_objects as go
import dash
from dash import dcc
from dash.dependencies import Input, Output
from dash import htmlcreate dash app
app = dash.Dash(name)
#create server name used for dash-app
server = app.server#import dataset
file = pd.read_csv(‘https://raw.githubusercontent.com/Dave-314/Pokemon-Stats-Dash-App/main/Pokemon.csv’)
pokedata = pd.DataFrame(file)change NaN to read ‘None’ because not all pokemon have 2 types
pokedata[‘Type 2’].fillna(‘None’, inplace=True)
change ‘#’ column name to ‘Number’
pokedata.rename(columns={‘#’: ‘number’}, inplace=True)
#column names: remove spaces, replace ‘.’ with underscore, convert to all lower case
pokedata.columns = pokedata.columns.str.replace(’ ‘, ‘’, regex=False)
pokedata.columns = pokedata.columns.str.replace(’.', ‘_’, regex=False)
pokedata.columns = pokedata.columns.str.lower()create dash app with multiple chained callbacks to Pokemon Type1
get unique pokemon type1 and sort alphabetically to input to dropdown options
pokesorted = pokedata.sort_values([‘type1’, ‘name’], ascending=True)
unique_type1 = pokedata[‘type1’].unique()
unique_type1.sort()create dictionary for dash dropdown labels and values
type1_dd_list = [{‘label’: x, ‘value’: x} for x in unique_type1]
create app layout
app.layout = html.Div([
overall app title
html.H1(‘Pokemon Stats’),
html.Div(
# divide app into 2 inline-blockschildren=[
html.Div( # first inline-block children=[ # type 1 dropdown scatter plot html.H2('Select Pokemon Type'), html.Div( children=[ # first dropdown for type1 html.H3('First type:'), dcc.Dropdown(id='type1_dd', options=type1_dd_list, style={'width': '200px', 'margin': '0 auto'} )], # format type1 dropdown as inline block with type2 dropdown style={'display': 'inline-block', 'align': 'center'} ), html.Div( children=[ # second dropdown for type2 html.H3('Optional second type: '), dcc.Dropdown(id='type2_dd', style={'width': '200px', 'margin': '0 auto'} ) ], # format type2 dropdown as inline block with type1 dropdown style={'display': 'inline-block', 'align': 'center', 'margin': '50px'} ), # scatter plot for type1 and/or type2 dcc.Graph(id='type_scatter') ], # format right side inline block style={'display': 'inline-block', 'width': '700px', 'height': '500px', 'text-align': 'center'} ), html.Div( # second inline-block children=[ # top plot as a histogram html.H2('Histogram of Hit Points (hp)'), dcc.Graph(id='histogram'), # bottom plot as pie chart html.H2('Percentage Legendary'), dcc.Graph(id='pie_chart') ], # format left inline block style={'display': 'inline-block', 'width': '700px', 'height': '10px', 'vertical-align': 'top', 'text-align': 'center'} ), ]
)
],format overall layout of app
style={‘text-align’: ‘center’})
create callback to update type2 dropdown from ‘type1_dd’
@app.callback(
options is used for output of the chained dropdown for type2
Output(component_id=‘type2_dd’, component_property=‘options’),
Input(component_id=‘type1_dd’, component_property=‘value’)
)function to fiter and update scatter plot from type1_dd
def update_type2_dd(type2_dd):
poke = pokesorted.copy(deep=True)find combinations of type1 and type2
type1_type2 = poke[[‘type1’, ‘type2’]].drop_duplicates()
relevant_type2_dd_options = type1_type2[type1_type2[‘type1’] == type2_dd][‘type2’].values.tolist()create type2_dd dictionary of labels and values
formatted_relevant_type2_dd_options = [{‘label’: x, ‘value’: x} for x in relevant_type2_dd_options]
return formatted_relevant_type2_dd_optionscreate callback for scatterpolot to update with type1 and filter when selecting type2
all 3 plots will update when type1 is selected and will update again when type2 is selected
@app.callback(
[Output(component_id=‘type_scatter’, component_property=‘figure’),
Output(component_id=‘histogram’, component_property=‘figure’),
Output(component_id=‘pie_chart’, component_property=‘figure’)],
[Input(component_id=‘type1_dd’, component_property=‘value’),
Input(component_id=‘type2_dd’, component_property=‘value’)]
)
def update_scatter_type2(type1_dd, type2_dd):
type2_title = ‘All’
poke = pokesorted.copy(deep=True)if type1_dd:
type1_title = type1_dd
poke = poke[poke[‘type1’] == type1_dd]if type2 is not selected do not filter the dataset further
if type2_dd:
type2_title = type2_dd
poke = poke[poke[‘type2’] == type2_dd]scatter plot
type_scatter = px.scatter(data_frame=poke, x=poke.attack, y=poke.defense,
custom_data=[poke.name],
hover_data=[poke.name],
color=poke.legendary)
type_scatter.update_xaxes(range=[0, 200])
type_scatter.update_yaxes(range=[0, 250])histogram
histogram = px.histogram(poke, x=‘hp’, nbins=20)
histogram.update_xaxes(range=[0, 250])pie chart
for legendary variable: get value counts, convert to dataframe and rename index
legendary_counts = pd.DataFrame(poke[‘legendary’].value_counts()).rename(index={False: ‘Not >Legendary’,
True: ‘Legendary’})
pie_chart = px.pie(legendary_counts, values=legendary_counts.legendary, >names=legendary_counts.index)
return type_scatter, histogram, pie_chartif name == ‘main’:
app.run_server(debug=True)