import pandas as pd
from dash import Dash, html, dcc, Input, Output, State, no_update,callback
import plotly.graph_objects as go
import dash_bootstrap_components as dbc
import numpy as np
import math
import data.create_list_maincard_content as ccl #creates list of cardbodies for maincard
# using the vizro theme
vizro_bootstrap = "https://cdn.jsdelivr.net/gh/mckinsey/vizro@main/vizro-core/src/vizro/static/css/vizro-bootstrap.min.css?v=2"
#colors used in some visuals like the barchart
#order = [default light blue, default light red, selected yellow, selected red, related yellow, related red]
colors = ['#d0ebff', "#fcc2d7", "#fcc419", "#f03e3e","#ffec99","#ff8787"]
app = Dash(__name__, suppress_callback_exceptions=True, external_stylesheets=[dbc.themes.BOOTSTRAP, dbc.icons.FONT_AWESOME, vizro_bootstrap])
# Load film data
#df_films= edd.etl_movies()
df_films = pd.read_csv('films_compleet.csv')
# Create list of unique films used in related movies and for menu creation
films_list = list(df_films['film'].sort_values().unique())
#create the list with the content for the overview card, used by the navigation and cardbody on maincard Pixar
content_maincard = ccl.create_maincard_content(df_films)
#most visuals wered designed of overall and specific movie information
#to speed up adjustments to overall, often selected_movie is set to All.
#wrapper for some visuals to get rid of the toolbar
def GraphWithoutModeBar(**kwargs):
return dcc.Graph(config={'displayModeBar': False}, **kwargs)
def create_timeline(start,end):
timerange = [start,end]
selected_movie = 'All'
#dummy is for creating a dot on y=0 for every year a movie was released.
df_films['dummy'] = 0
fig = go.Figure( data=go.Scatter(
x=df_films['release_year'],
y=df_films['dummy'],
mode='markers',
marker=dict(
color='#c5f6fa',
)
))
fig.update_xaxes(showgrid=False, zeroline=False,tickfont_color=colors[0],range=timerange)
fig.update_layout(yaxis_title=None )
fig.update_yaxes(showticklabels=False,range=[-10, 100], showgrid=False, zeroline=False)
fig.update_layout(
margin=dict(l=100, r=100, t=20, b=10,pad=10),
autosize=False,
#width=800,
width=700,
height=200,
showlegend=False
)
#background needs to be transparent
fig.update_layout({
'plot_bgcolor': 'rgba(0, 0, 0, 0)',
'paper_bgcolor': 'rgba(12, 49, 85,1)',
})
fig.update_traces(
hoverinfo="none",
hovertemplate=None )
#CREATE AN ANNOTATION AND LINE FOR EVERY MOVIE ON THE TIMELINE#
for index, row in df_films.iterrows():
fig.add_annotation(x=row['release_year'],
y=20 + ((index%3) * 40),
#text=f"{row['film']} ({row['release_year']})",
text = row['film'],
showarrow=False,
bgcolor = colors[2] if (row['release_year'] == 1995 and selected_movie == "All") else \
colors[2] if selected_movie == row['film'] else colors[0] ,
borderpad = 4,
font=dict(color='black')
)
fig.add_shape(type="line",
x0=row['release_year'], y0=10, x1=row['release_year'], y1=20 + ((index%3) * 30),
line=dict(
color=colors[0],
width=1,
dash="dashdot",
)
)
#ADD ANNOTATION FOR DISNEY ACQUIRES PIXAR
if start == 2005:
fig.add_annotation(x= 2005,
y=80,
#text=f"{row['film']} ({row['release_year']})",
text = "<b>2006</b>: Disney <br>"+
"acquires Pixar",
showarrow=False,
bgcolor = colors[5],
borderpad = 4,
font=dict(color='#333')
)
#wrapper function for dcc.graph which removes the complete toolbar for the timeline
return GraphWithoutModeBar(figure=fig, id='timeline_'+str(start), clear_on_unhover=True)
# Function to create Pixar start card
def create_card_pixar_start(df):
##This function creates the overview card for Pixar
##The toolbar makes it possible to navigate through the story
##And displays the content
return dbc.Card(
[
html.Div(
[
#THIS IS WHERE THE MAIN CONTENT ON THE LEFT LANDS
html.Div(id="pagination-contents" ),
])
],
)
# CARD USED FOR HOVER IN TIMELINE?
def create_card_main_movie(film):
src_local = film['local_poster_path'].values[0] # Extract path
img_rt = 'assets/images/rotten-tomatoes.png'
img_imdb = 'assets/images/imdb-32.png'
img_mt = 'assets/images/metacritic-32.png'
return dbc.Card(
[
dbc.Row(
[
dbc.Col(
dbc.CardImg(
src=src_local,
alt=f"poster {film['film'].values[0]}",
title=f"poster {film['film'].values[0]}",
className="img-fluid rounded-start",
),
className="col-md-6",
),
dbc.Col([
dbc.CardBody(
[
html.Div([
html.Img(src=img_rt, className = "make-grey", alt='logo rotten tomatoes', title='Rotten Tomatoes Score'),
html.Small(f"{film['rotten_tomatoes_score'].iloc[0]}/100 "),
html.Img(src=img_mt,className = "make-grey", alt='logo metacritic', title='Metacritic Score'),
html.Small(f" {film['metacritic_score'].iloc[0]}/100 "),
html.Img(src=img_imdb,className = "make-grey", alt='logo imdb', title='IMDB Score'),
html.Small(f" {film['imdb_score'].iloc[0]}/10 "),
html.Span(f" {film['cinema_score'].iloc[0]}", className="text-warning fs-2")
],className = 'd-flex', style={"alignItems": "center", "justifyContent":"space-between"}),
html.Div([
html.H2(film['film'].values[0], className="card-title"),
html.H3(f"Release date: {film['release_date'].values[0]}",
className="",
),
html.Small(
film['plot'].values[0],
className="card-text text-muted",
),
], style={"textAlign":"center"}),
html.H4('Series?', style={"textAlign":"right"})
],style={"display":"flex","flexDirection":"column","flexWrap":"wrap", "justifyContent":"space-between"}
),
create_series_grid(film)
],className="col-md-6" ,style={"display":"flex","flexDirection":"column","flexWrap":"wrap", "justifyContent":"space-between"}),
],
className="g-0",
)
],
className="mb-3",
)
#FIND RELATED MOVIES FOR A SERIES
def get_related_films(selected_movie, series_id):
#selected movie is what it is, series is the seriesnumber
#this returns a df for the rest of the series films
related_movies = df_films.loc[(df_films['serie_number']==series_id) & (df_films['film'] != selected_movie)]\
.sort_values('sort_date', ascending=True)
return related_movies
#CREATE SMALL GRID FOR RELATED MOVIES
def create_series_grid(film):
#is it a serie? there is no serie_id 100 and probably will never be, 100 means no
#serie_num_related is the number of related movies excl current film
series_id = 100 if film['serie_num_related'].iloc[0] == 0 else film['serie_number'].iloc[0]
series_grid = []
if series_id < 100:
series_grid = []
exclude_current = int(film['number'].iloc[0])
#find related movies and exclude the current selected movie
related_movies = df_films.loc[(df_films['serie_number']==series_id) & (df_films['number'] != exclude_current)]\
.sort_values('sort_date', ascending=True)
#create a related_movies grid for the selected movie, not a serie just returns
#an empty list with a greyed out red image.
for index, row in related_movies.iterrows():
picture = row['local_poster_path']
card = dbc.Card(
[
dbc.CardImg(src=picture, top=True, title=row['film'], className="make-grey"),
], style={"marginLeft":".5rem"},
className="w-25 p-0",
)
series_grid.append(card)
else:
card = dbc.Card(
[
dbc.CardImg(src="assets/images/no-series.png", top=True, title="not part of a series"),
], style={"marginLeft":".5rem"},
className="w-25 p-0",
)
series_grid.append(card)
relatedMovies = html.Div([
html.Div(series_grid, style={"display":"flex", "flexDirection":"row", "justifyContent":"flex-end"})
], style={"marginTop":"1rem"})
return relatedMovies
#CREATE BOXOFFICE RELATIVE BARCHART
def create_boxoffice_barchart(selected_movie = 'All'):
#the moneychart in the tabs. Moneybars for the selected movie are deep yellow
#if the movie is part of a series, the bars for the related movies are light yellow
#fun to see the numbers for the series.
#related is filled with the number of related movies
related = 0 if selected_movie == "All" else df_films.query("film == @selected_movie")['serie_num_related'].iloc[0]
related_films_list = []
if related > 0 :
#get the serie number
serie_number = df_films.query("film == @selected_movie")['serie_number'].iloc[0]
#get related films and put them in a list to use for the box_colors
related_films = get_related_films(selected_movie, serie_number)
related_films_list = list(related_films['film'])
box_colors = df_films['film'].apply(lambda x : colors[2] if x == selected_movie
else colors[4] if x in related_films_list else colors[0])
budget_colors = df_films['film'].apply(lambda x : colors[3] if x == selected_movie
else colors[5] if x in related_films_list else colors[1])
x= df_films['release_year']
money_customdata = np.stack((df_films['film'], df_films['release_year'], df_films['screen_budget'], df_films['screen_box_office_worldwide'],\
df_films['return on budget $'], df_films['profitable'],df_films['budget_rank'], df_films['box_ww_rank']), axis=-1)
fig = go.Figure()
fig.add_trace(go.Bar(x=x,
y=df_films['box_office_worldwide'],
text=df_films['screen_box_office_worldwide'],
marker_color=box_colors,
texttemplate = df_films['screen_box_office_worldwide']
))
fig.add_trace(go.Bar(x=x,
y=-df_films['budget'],
text=df_films['screen_budget'],
marker_color=budget_colors,
texttemplate = df_films['screen_budget']
))
fig.update_traces(customdata = money_customdata,
hovertemplate = "<b>%{customdata[0]} (%{customdata[1]})</b><br>"+
"<br>"+\
"Box office worldwide: %{customdata[3]} (rank: %{customdata[7]})<br>"+\
"Est budget: %{customdata[2]}<br>"+\
"Profitable: %{customdata[5]}<extra></extra>",
hoverlabel=dict(
bgcolor=colors[4]
)
)
# fig.update_traces(textfont_size=12, textangle=0, textposition="outside", cliponaxis=False)
fig.update_layout(barmode='relative', title_text='Relative Barmode', xaxis_range=[1994,2026])
fig.update_xaxes(showgrid=False, zeroline=False,tickfont_color='#ffffff')
fig.update_layout(yaxis_title=None)
fig.update_yaxes(showticklabels=False, showgrid=False, zeroline=False)
fig.update_layout(
margin=dict(l=10, r=10, t=40, b=0,pad=30),
autosize=True,
#width='100%',
height=500,
showlegend=False,
title=""
)
#background needs to be transparent
fig.update_layout({
'plot_bgcolor': 'rgba(0, 0, 0, 0)',
#'paper_bgcolor': 'rgba(11, 114, 133,1)'
'paper_bgcolor': 'rgba(12, 49, 85,1)'
})
fig.add_hline(y=0, line_dash="dot", line_width=1, opacity=1, line_color="White")
#inline title
fig.add_annotation(x=1998,
y=1200000000,
text = "Box Office World Wide",
showarrow=False,
bgcolor = "rgba(255,255,255,0)",
borderpad = 4,
font=dict(color='#d0ebff')
)
fig.add_annotation(x=1998,
y=-300000000,
text = "Est. budget",
showarrow=False,
bgcolor = "rgba(255,255,255,0)",
borderpad = 4,
font=dict(color='#fcc2d7')
)
return dcc.Graph(figure=fig)
#CREATE THE AWARDS CHART
def create_awards_chart(selected_movie):
dff = df_films[df_films['won_count'] > 0].reset_index()
#print(dff['won_list'][1])
#total nominations = won_count + nominated_count, being nominated counts the number of not won
dff['total_nominated'] = dff['won_count'] + dff['nominated_count']
oscar_active = 'https://github.com/tigi/maven-pixar-challenge/blob/main/assets/images/oscar-hot.png?raw=true'
oscar_grey = 'https://github.com/tigi/maven-pixar-challenge/blob/main/assets/images/oscar-grey-hot.png?raw=true'
oscar_none = 'assets/images/None.png'
#shift y is used to move the oscarimages in the 0 direction.
#the awards_number column contains 1,2,3 etc used as y
shift_y = .2
# Convert won_list to separate rows
expanded_rows = []
for _, row in dff.iterrows():
film = row["film"]
year = row["release_year"]
won_awards = row["won_list"].split(", ") if row["won_list"] else []
for idx, award in enumerate(won_awards, start=1):
expanded_rows.append([film, year, award, idx])
# Create the new expanded DataFrame for wins
#stream_wins = pd.DataFrame(expanded_rows, columns=["film", "release_year", "award","position"])
stream1=dff[['film','release_year','won_list', 'total_nominated', 'nominated_list']].copy()
#stream1.loc[:, 'won_list'] = stream1['won_list'].str.split(',').str[0]
stream1['position'] = 1
### add a string for customdata count nominations for award_type
#stream1 = stream1.merge(extra_info[["film", "extra-info"]], on="film", how="left").reset_index(drop=True)
##customdata on stream 1 for hover
stream1_customdata = np.stack((stream1['film'], stream1['won_list'],\
stream1['total_nominated'] ,stream1['nominated_list'],stream1['release_year']), axis=-1)
#print(stream1_customdata)
stream2=dff[['film','release_year','won_list','won_count', 'total_nominated', 'nominated_list']].copy()
stream2['position'] = 2 #second row in viz for second oscar
#stack custom data
stream2_customdata = np.stack((stream2['film'], stream2['won_list'],\
stream2['total_nominated'],stream2['nominated_list'], stream2['release_year']), axis=-1)
# print(stream2_customdata)
# Create figure
fig = go.Figure()
#create invisible bars which will act as trigger for the customtemplate
#with additional info
#the traces have names, used in update_traces to assign the correct
#customtemplate with data to the right bar.
fig.add_trace(go.Bar(x=stream1['release_year'],
y=stream1['position']+ .5,
marker_color="rgba(255,255,255,0)",
marker_line_color='rgba(255,255,255,0)',
name='oscar1',
))
fig.add_trace(go.Bar(x=stream2['release_year']+0.25,
y=stream2['position']+ .5,
marker_color="rgba(255,255,255,0)",
marker_line_color='rgba(255,255,255,0)',
name='oscar2',
))
#add hoverdata per trace, same data, different input customdata
#background color lightyellow, color black
fig.update_traces(customdata = stream1_customdata,
hovertemplate = "<b>%{customdata[0]} (%{customdata[4]})</b> <br>"+
"<br>"+\
"Nominations: %{customdata[2]}<br>"+\
"Won: <b>%{customdata[1]}</b><br>"+\
"Lost: %{customdata[3]}<extra>Three props</extra>",
selector = ({'name':'oscar1'}),
hoverlabel=dict( bgcolor=colors[4] )
)
fig.update_traces(customdata = stream2_customdata,
hovertemplate = "<b>%{customdata[0]} (%{customdata[4]})</b> <br>"+
"<br>"+\
"Nominations: %{customdata[2]}<br>"+\
"Won: <b>%{customdata[1]}</b><br>"+\
"Lost: %{customdata[3]}<extra>Three props</extra>",
selector = ({'name':'oscar2'}),
hoverlabel=dict( bgcolor=colors[4] )
)
#create a row of oscars on the first row (y=1) (stream1)
for i, x in enumerate(stream1['release_year']):
fig.add_layout_image(
dict(
source=oscar_active if (stream1['film'][i] == selected_movie or selected_movie == "All") else oscar_grey,
xref="x",
yref="y",
x = x,
y=stream1['position'][i] - shift_y,
sizex=2,
sizey=2,
sizing="contain",
opacity=1,
layer="below",
xanchor="center",
yanchor="middle")
)
#and stream 2, same but 1-pixel image oscar_none for the release_years where
#no second oscar was won. Max oscars per movie is 2.
#this oscar_none is needed to get the indexes right.
for i, x in enumerate(stream2['release_year']):
fig.add_layout_image(
dict(
source=oscar_none if stream2['won_count'][i] == 1 else oscar_active if (stream2['film'][i] == selected_movie or selected_movie == "All") else oscar_grey,
xref="x",
yref="y",
x = x + .25,
y=stream2['position'][i] - shift_y,
sizex=2,
sizey=2,
sizing="contain",
opacity=1,
layer="below",
xanchor="center",
yanchor="middle")
)
fig.update_layout(xaxis_range=[1994, 2026], yaxis_range=[0,3],
)
fig.update_xaxes(showgrid=False, zeroline=False,tickfont_color='#ffffff')
fig.update_layout(yaxis_title=None)
fig.update_yaxes(showticklabels=False, showgrid=False, zeroline=False)
fig.update_layout(
margin=dict(l=0, r=0, t=0, b=0,pad=10),
autosize=False,
#width='100%',
height=350,
showlegend=False,
)
#background needs to be transparent
fig.update_layout({
'plot_bgcolor': 'rgba(0, 0, 0, 0)',
#'paper_bgcolor': 'rgba(11, 114, 133,1)'
'paper_bgcolor': 'rgba(12, 49, 85,1)'
})
return GraphWithoutModeBar(figure=fig)
#CHAIN THREE TIMELINES TOGETHER BY DECADE
#fIXED WIDTH BECAUSE OF THE "STUITERBAL" EFFECT
def output_timeline():
output_timeline = dbc.Card(
[
dbc.CardHeader(html.H2("Pixar movie release timeline")),
dbc.CardBody(
[
html.H4('1995 - 2004'),
create_timeline(1995,2004),
dcc.Tooltip(id="tooltip-first-decade-1995", direction="bottom",style={"zIndex": 1000}),
html.Hr(),
html.H4('2005 - 2014'),
create_timeline(2005,2014),
dcc.Tooltip(id="tooltip-first-decade-2005", direction="top",style={"zIndex": 1000}),
html.Hr(),
html.H4('2015 - 2024'),
create_timeline(2015,2024),
dcc.Tooltip(id="tooltip-first-decade-2015", direction="top",style={"zIndex": 1000}),
]
)
],
style={},
)
return output_timeline
#CREATE OSCAR VISUAL + PUBLIC OVERALL RECOGNITION
def output_recognition():
weighted_rt_score = round((df_films['rotten_tomatoes_score'] * df_films['rotten_tomatoes_counts']).sum() / df_films['rotten_tomatoes_counts'].sum(),0)
weighted_metacritic_score = round((df_films['metacritic_score'] * df_films['metacritic_counts']).sum() / df_films['metacritic_counts'].sum(),0)
weighted_imdb_score = round((df_films['imdb_score'] * df_films['imdb_counts']).sum() / df_films['imdb_counts'].sum(),0)
img_rt = 'assets/images/rotten-tomatoes.png'
img_imdb = 'assets/images/imdb-32.png'
img_mt = 'assets/images/metacritic-32.png'
img_cinema = 'assets/images/a-grade.png'
output_recognition = dbc.Card(
[
dbc.CardHeader(html.H2("No guts, no glory!")),
dbc.CardBody(
[
html.H3('Pixar Academy Award wins*'),
html.P("Hover Oscar for some details, winner takes the stage, only award winning movies are shown."),
create_awards_chart('All'),
html.Hr(),
html.Br(),
html.H3('We love these movies, Oscar or not, 28 movies in 3 averaged numbers and a letter.'),
html.Br(),
#the things we do for flexbox
html.Div([
html.Div([
html.Img(src=img_rt, alt='logo rotten tomatoes', title='Rotten Tomatoes Score', style={'marginRight':'5px'}),
html.Span(f"{weighted_rt_score:.0f} / 100 (Rotten Tomatoes)", style={'color':'white', 'fontWeight':'bold'}),
]),
html.Div([
html.Img(src=img_mt, alt='logo metacritic', title='Metacritic Score', style={'marginRight':'5px'}),
html.Span(f" {weighted_metacritic_score:.0f} / 100 (Metacritic)", style={'color':'white', 'fontWeight':'bold'}),
]),
html.Div([ html.Img(src=img_imdb,alt='logo imdb', title='IMDB Score', style={'marginRight':'5px'}),
html.Span(f" {weighted_imdb_score:.0f} / 10 ", style={'color':'white', 'fontWeight':'bold'}),
]),
html.Div([
html.Img(src=img_cinema,alt='cinema score', title='Cinema score', style={'marginRight':'5px'}),
html.Span(' Cinema score (A to F)', style={'color':'white', 'fontWeight':'bold', 'padding':'4px 0'})
])
],className = 'd-flex', style={"alignItems": "center", "justifyContent":"space-around"}),
]
),
dbc.CardFooter(html.Small("* The Oscars drawn in the visual are all related to the award category Animated Feature film. An animated feature film has a running time of more than 40 minutes. In an animated film, animation must figure in no less than 75 percent of the picture's running time. In addition, a narrative animated film must have a significant number of the major characters animated.")),
],
style={},
)
return output_recognition
#CREATE RELATIVE BARCHART (DOESN'T RESET WELL) OF BOXOFFICE WW VS EST BUDGET
def output_money_absolute():
output_recognition = dbc.Card(
[
dbc.CardHeader(html.H2("Money makes the world go round! or not?")),
dbc.CardBody(
[
html.Small("Be warned: these are numbers by year, sometimes one bar is divided into two movies!"),
html.Small("Hover over a number, or what looks like a number, no glasses provided but there is a zoom function (upper right corner), to see the movie money summary. Rank is ordered by Box Office Worldwide revenue high to low. Profitable is no when box office < 2 times budget, maybe when between 2 to 3 times budget."),
create_boxoffice_barchart('All')
]
),
],
style={},
)
return output_recognition
app.layout = dbc.Container(
[
# # Persistent store
# dcc.Store(id="store-selected-movie", storage_type="local"),
# dcc.Store(id="store-selected-tab", storage_type="local"),
dbc.Row([
#maincard
dbc.Col([
#navigation over the full width of the first card
html.Div([
dbc.RadioItems(
id="select-page",
className="btn-group elevation-1",
inputClassName="btn-check",
labelClassName="btn btn-outline-primary",
labelCheckedClassName="active",
options=[
{"label": "Pixar Overview", "value": 1},
{"label": "Winner takes it all", "value": 2},
{"label": "Money matters", "value": 3},
],
value=1,
),
], className='d-flex', style={'justifyContent':'flex-end', 'marginLeft': '2rem'}),
html.Div(create_card_pixar_start(df_films), id="main-movie"),
], className = 'col-sm-12 col-md-6 ', style={"alignContent":"flex-start", "marginTop":"2rem"}),
#the visuals on the tabs Oscars and Money
dbc.Col([
#create_tabs('All'),
html.Div (id="supporting_content")
]
, className = 'col-sm-12 col-md-5', style={"alignContent":"flex-start","marginTop":"2rem"}
)
])
], style = {}, fluid=True,
)
@app.callback(
Output("tooltip-first-decade-1995", "show"),
Output("tooltip-first-decade-1995", "bbox"),
Output("tooltip-first-decade-1995", "children"),
Input("timeline_1995", "hoverData"),
)
def display_hover(hoverData):
if hoverData is None:
return False, no_update, no_update
# demo only shows the first point, but other points may also be available
pt = hoverData["points"][0]
bbox = pt["bbox"]
num = pt["pointNumber"]
df_row = df_films.iloc[num]
img_src = df_row['local_poster_path']
name = df_row['film']
year = df_row['release_year']
children = [
#create_card_main_movie(name),
html.Div([
html.Img(src=img_src, style={"width": "150px"}),
html.H2(f"{name} ({year})", style={"color": "black","textAlign":"center","fontSize":"12px"}),
], style={'width': '150px', 'zIndex':'1000'})
]
return True, bbox, children
@app.callback(
Output("tooltip-first-decade-2005", "show"),
Output("tooltip-first-decade-2005", "bbox"),
Output("tooltip-first-decade-2005", "children"),
Input("timeline_2005", "hoverData"),
)
def display_hover_2005(hoverData):
if hoverData is None:
return False, no_update, no_update
# demo only shows the first point, but other points may also be available
pt = hoverData["points"][0]
bbox = pt["bbox"]
num = pt["pointNumber"]
df_row = df_films.iloc[num]
img_src = df_row['local_poster_path']
name = df_row['film']
year = df_row['release_year']
children = [
#create_card_main_movie(name),
html.Div([
html.Img(src=img_src, style={"width": "150px"}),
html.H2(f"{name} ({year})", style={"color": "black","textAlign":"center","fontSize":"12px"}),
], style={'width': '150px', 'zIndex':'1000'})
]
return True, bbox, children
@app.callback(
Output("tooltip-first-decade-2015", "show"),
Output("tooltip-first-decade-2015", "bbox"),
Output("tooltip-first-decade-2015", "children"),
Input("timeline_2015", "hoverData"),
)
def display_hover_2015(hoverData):
if hoverData is None:
return False, no_update, no_update
# demo only shows the first point, but other points may also be available
pt = hoverData["points"][0]
bbox = pt["bbox"]
num = pt["pointNumber"]
df_row = df_films.iloc[num]
img_src = df_row['local_poster_path']
name = df_row['film']
year = df_row['release_year']
children = [
#create_card_main_movie(name),
html.Div([
html.Img(src=img_src, style={"width": "150px"}),
html.H2(f"{name} ({year})", style={"color": "black","textAlign":"center","fontSize":"12px"}),
], style={'width': '150px', 'zIndex':'1000'})
]
return True, bbox, children
@app.callback(
Output("pagination-contents", "children"),
Output("supporting_content", "children"),
[Input("select-page", "value")],
)
def change_page(page):
#this functions more like a memorything
#mapping_page = {1:'timeline',2:'oscars',3:'money'}
if page:
#contentlist starts at index 0
#fill right part of screen based on selected page.
#remember page 1 = contentlist 0 = content_maincard[0]
match page:
case 1:
supportcontent = output_timeline()
return content_maincard[page-1], supportcontent
case 2:
supportcontent = output_recognition()
return content_maincard[page-1], supportcontent
case 3:
supportcontent = output_money_absolute()
return content_maincard[page-1], supportcontent
case _:
return content_maincard[0], output_timeline()
else:
#initialize on start, pick first cardbody
return content_maincard[0], output_timeline()
# Run the app
if __name__ == "__main__":
app.run(debug=True)