Thank you, it works now! I also realized that the top 5 anime given the year input will not work with my current script, so I had to remove the arguments and pass it an empty dict or list instead. I also realized that you can only have 1 function after your callbacks, although I’m not sure if this is the case or if you can have multiple functions but I probably just didn’t know how.
Oh and I’m using vs code.
Anyway, for everyone else that’s interested in looking the full working code, here you go:
from dash import Dash, dcc, html, Output, Input
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.figure_factory as ff
import pandas as pd
# df = pd.read_csv('anime_data_upto_mar_2023_production.csv')
df = pd.read_csv('https://github.com/mangarahutagalung/anime-dash-plotly/blob/main/anime_data_upto_mar_2023_production.csv?raw=true')
print(df.iloc[:5, 5:8])
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# The Bootstrap grid has twelve columns, and six responsive tiers.
# The width of your columns can be specified in terms of how many of the twelve grid columns it should span, or you can allow the columns to expand or shrink to fit either their content or the available space in the row.
app.layout = dbc.Container([
dbc.Row([
dbc.Col([
dcc.Markdown('# Anime Stats Dashboard', style={'textAlign': 'left', 'color': 'black'})
], width=12)
]),
dbc.Row([
dbc.Col([
dcc.Markdown('### Your one-stop dashboard for anime stats!', style={'textAlign': 'left', 'color': 'black'})
], width=12)
]),
dbc.Row([
html.Div(html.Hr(style={'borderWidth': "0.5vh", "color": "#146C94"}))
]),
dbc.Row([
dbc.Col([
dcc.Markdown('#### Select aired year range'),
year_slider := dcc.RangeSlider(min=df.year.min(), max=df.year.max(), value=[1980, 2022], step=1,
marks={'1961': '1961', '1970': '1970', '1980': '1980',
'1990': '1990', '2000': '2000','2010': '2010',
'2020': '2020', '2024': '2024'},
tooltip={"placement": "bottom", "always_visible": True}
)
], width=12)
]),
dbc.Row([
dbc.Col([
dcc.Markdown('##### Top 5 Anime by Score based on selected year range', style={'textAlign': 'left', 'color': 'black'})
], width=12)
], style={'marginTop': '20px'}),
dbc.Row([
dbc.Col([
dbc.Card(
[
dbc.CardImg(id = 'rank1_img',
src={},
top=True, style={'height': '300px', 'width': '200px'}),
dbc.CardBody(
[
dcc.Link(
html.H4(
id = 'rank1_title',
children={},
className="card-title",
style={'fontSize': '18px'}
),
id = 'rank1_url',
href='',
target="_blank",
style={'color': 'black'}
),
html.P(
id = 'rank1_synopsis',
children={},
className="card-text",
style={'fontSize': '13px'}
),
dcc.Link(
dbc.Button("YouTube Trailer",
color="secondary",
style={'fontSize': '16px'}),
id = 'rank1_trailer',
href='',
target="_blank")
]
),
],
style={"width": "13rem"}
)
]
),
dbc.Col([
dbc.Card(
[
dbc.CardImg(id = 'rank2_img',
src={},
top=True, style={'height': '300px', 'width': '200px'}),
dbc.CardBody(
[
dcc.Link(
html.H4(
id = 'rank2_title',
children={},
className="card-title",
style={'fontSize': '18px'}
),
id = 'rank2_url',
href='',
target="_blank",
style={'color': 'black'}
),
html.P(
id = 'rank2_synopsis',
children={},
className="card-text",
style={'fontSize': '13px'}
),
dcc.Link(
dbc.Button("YouTube Trailer",
color="secondary",
style={'fontSize': '16px'}),
id = 'rank2_trailer',
href= '',
target="_blank")
]
),
],
style={"width": "13rem"}
)
]
),
dbc.Col([
dbc.Card(
[
dbc.CardImg(id = 'rank3_img',
src=df.sort_values(by='score', ascending=False).iloc[2]['images_webp_url'],
top=True, style={'height': '300px', 'width': '200px'}),
dbc.CardBody(
[
dcc.Link(
html.H4(
id = 'rank3_title',
children={},
className="card-title",
style={'fontSize': '18px'}
),
id = 'rank3_url',
href='',
target="_blank",
style={'color': 'black'}
),
html.P(
id = 'rank3_synopsis',
children={},
className="card-text",
style={'fontSize': '13px'}
),
dcc.Link(
dbc.Button("YouTube Trailer",
color="secondary",
style={'fontSize': '16px'}),
id = 'rank3_trailer',
href= '',
target="_blank")
]
),
],
style={"width": "13rem"}
)
]
),
dbc.Col([
dbc.Card(
[
dbc.CardImg(id = 'rank4_img',
src={},
top=True, style={'height': '300px', 'width': '200px'}),
dbc.CardBody(
[
dcc.Link(
html.H4(
id = 'rank4_title',
children={},
className="card-title",
style={'fontSize': '18px'}
),
id = 'rank4_url',
href='',
target="_blank",
style={'color': 'black'}
),
html.P(
id = 'rank4_synopsis',
children={},
className="card-text",
style={'fontSize': '13px'}
),
dcc.Link(
dbc.Button("YouTube Trailer",
color="secondary",
style={'fontSize': '16px'}),
id = 'rank4_trailer',
href='',
target="_blank")
]
),
],
style={"width": "13rem"}
)
]
),
dbc.Col([
dbc.Card(
[
dbc.CardImg(id = 'rank5_img',
src={},
top=True, style={'height': '300px', 'width': '200px'}),
dbc.CardBody(
[
dcc.Link(
html.H4(
id = 'rank5_title',
children={},
className="card-title",
style={'fontSize': '18px'}
),
id = 'rank5_url',
href='',
target="_blank",
style={'color': 'black'}
),
html.P(
id = 'rank5_synopsis',
children={},
className="card-text",
style={'fontSize': '13px'}
),
dcc.Link(
dbc.Button("YouTube Trailer",
color="secondary",
style={'fontSize': '16px'}),
id = 'rank5_trailer',
href= '',
target="_blank")
]
),
],
style={"width": "13rem"}
)
]
),
]),
dbc.Row([
dbc.Col([
score_hist := dcc.Graph(id='fig',
figure={})
], width=12)
]),
dbc.Row([
dbc.Col([
year_by_score := dcc.Graph(id='fig2',
figure={})
], width=12)
])
])
@app.callback(
[Output(component_id=score_hist, component_property='figure'),
Output(component_id=year_by_score, component_property='figure'),
Output(component_id='rank1_img', component_property='src'),
Output(component_id='rank1_title', component_property='children'),
Output(component_id='rank1_synopsis', component_property='children'),
Output(component_id='rank1_url', component_property='href'),
Output(component_id='rank1_trailer', component_property='href'),
Output(component_id='rank2_img', component_property='src'),
Output(component_id='rank2_title', component_property='children'),
Output(component_id='rank2_synopsis', component_property='children'),
Output(component_id='rank2_url', component_property='href'),
Output(component_id='rank2_trailer', component_property='href'),
Output(component_id='rank3_img', component_property='src'),
Output(component_id='rank3_title', component_property='children'),
Output(component_id='rank3_synopsis', component_property='children'),
Output(component_id='rank3_url', component_property='href'),
Output(component_id='rank3_trailer', component_property='href'),
Output(component_id='rank4_img', component_property='src'),
Output(component_id='rank4_title', component_property='children'),
Output(component_id='rank4_synopsis', component_property='children'),
Output(component_id='rank4_url', component_property='href'),
Output(component_id='rank4_trailer', component_property='href'),
Output(component_id='rank5_img', component_property='src'),
Output(component_id='rank5_title', component_property='children'),
Output(component_id='rank5_synopsis', component_property='children'),
Output(component_id='rank5_url', component_property='href'),
Output(component_id='rank5_trailer', component_property='href')
],
Input(component_id=year_slider, component_property='value')
)
def update_front(year_value):
print(year_value)
dff = df[(df.year >= year_value[0]) & (df.year <= year_value[1])]
rank1_img = dff.sort_values(by='score', ascending=False).iloc[0]['images_webp_url']
rank1_title = dff.sort_values(by='score', ascending=False).iloc[0]['title']
rank1_synopsis = dff.sort_values(by='score', ascending=False).iloc[0]['synopsis'][:100] + '...'
rank1_url = dff.sort_values(by='score', ascending=False).iloc[0]['url'] if \
isinstance(dff.sort_values(by='score', ascending=False).iloc[0]['url'], str) \
else 'https://myanimelist.net/'
rank1_trailer = dff.sort_values(by='score', ascending=False).iloc[0]['trailer_url'] if \
isinstance(dff.sort_values(by='score', ascending=False).iloc[0]['trailer_url'], str) \
else 'https://www.youtube.com/watch?v='
rank2_img = dff.sort_values(by='score', ascending=False).iloc[1]['images_webp_url']
rank2_title = dff.sort_values(by='score', ascending=False).iloc[1]['title']
rank2_synopsis = dff.sort_values(by='score', ascending=False).iloc[1]['synopsis'][:100] + '...'
rank2_url = dff.sort_values(by='score', ascending=False).iloc[1]['url'] if \
isinstance(dff.sort_values(by='score', ascending=False).iloc[1]['url'], str) \
else 'https://myanimelist.net/'
rank2_trailer = dff.sort_values(by='score', ascending=False).iloc[1]['trailer_url'] if \
isinstance(dff.sort_values(by='score', ascending=False).iloc[1]['trailer_url'], str) \
else 'https://www.youtube.com/watch?v='
rank3_img = dff.sort_values(by='score', ascending=False).iloc[2]['images_webp_url']
rank3_title = dff.sort_values(by='score', ascending=False).iloc[2]['title']
rank3_synopsis = dff.sort_values(by='score', ascending=False).iloc[2]['synopsis'][:100] + '...'
rank3_url = dff.sort_values(by='score', ascending=False).iloc[2]['url'] if \
isinstance(dff.sort_values(by='score', ascending=False).iloc[2]['url'], str) \
else 'https://myanimelist.net/'
rank3_trailer = dff.sort_values(by='score', ascending=False).iloc[2]['trailer_url'] if \
isinstance(dff.sort_values(by='score', ascending=False).iloc[2]['trailer_url'], str) \
else 'https://www.youtube.com/watch?v='
rank4_img = dff.sort_values(by='score', ascending=False).iloc[3]['images_webp_url']
rank4_title = dff.sort_values(by='score', ascending=False).iloc[3]['title']
rank4_synopsis = dff.sort_values(by='score', ascending=False).iloc[3]['synopsis'][:100] + '...'
rank4_url = dff.sort_values(by='score', ascending=False).iloc[3]['url'] if \
isinstance(dff.sort_values(by='score', ascending=False).iloc[3]['url'], str) \
else 'https://myanimelist.net/'
rank4_trailer = dff.sort_values(by='score', ascending=False).iloc[3]['trailer_url'] if \
isinstance(dff.sort_values(by='score', ascending=False).iloc[3]['trailer_url'], str) \
else 'https://www.youtube.com/watch?v='
rank5_img = dff.sort_values(by='score', ascending=False).iloc[4]['images_webp_url']
rank5_title = dff.sort_values(by='score', ascending=False).iloc[4]['title']
rank5_synopsis = dff.sort_values(by='score', ascending=False).iloc[4]['synopsis'][:100] + '...'
rank5_url = dff.sort_values(by='score', ascending=False).iloc[4]['url'] if \
isinstance(dff.sort_values(by='score', ascending=False).iloc[4]['url'], str) \
else 'https://myanimelist.net/'
rank5_trailer = dff.sort_values(by='score', ascending=False).iloc[4]['trailer_url'] if \
isinstance(dff.sort_values(by='score', ascending=False).iloc[4]['trailer_url'], str) \
else 'https://www.youtube.com/watch?v='
fig = px.histogram(dff,
x="year",
nbins=20,
color_discrete_sequence=['#146C94']
)
fig.update_layout(title_text='Anime count by year',
title_x=0.5,
xaxis_title='Year',
yaxis_title='Count',
legend_title='Year',
font_family='Sans-Serif')
fig2 = ff.create_distplot([dff['score']],
group_labels=['score'],
bin_size=0.5,
colors=['#146C94']
)
fig2.update_layout(title_text='Anime score distribution',
title_x=0.5,
xaxis_title='Score',
yaxis_title='Density',
showlegend=False
)
return fig, fig2, rank1_img, rank1_title, rank1_synopsis, rank1_url, rank1_trailer, \
rank2_img, rank2_title, rank2_synopsis, rank2_url, rank2_trailer, \
rank3_img, rank3_title, rank3_synopsis, rank3_url, rank3_trailer, \
rank4_img, rank4_title, rank4_synopsis, rank4_url, rank4_trailer, \
rank5_img, rank5_title, rank5_synopsis, rank5_url, rank5_trailer
if __name__ == '__main__':
app.run_server(debug=True, port=8006)