{
"cells": [
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/var/folders/b4/lwfgccm95kqd2skcwvrt2fr00000gn/T/ipykernel_289/426293969.py:99: FutureWarning:\n",
"\n",
"Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n",
"\n"
]
},
{
"data": {
"text/html": [
"\n",
" \n",
" "
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/ruimelo/Documents/GitHub/eda/app/core.py:21: SettingWithCopyWarning:\n",
"\n",
"\n",
"A value is trying to be set on a copy of a slice from a DataFrame\n",
"\n",
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
"\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Text Value: None\n"
]
}
],
"source": [
"import os\n",
"import plotly.express as px\n",
"import plotly.graph_objects as go\n",
"import pandas as pd\n",
"from dash import Dash, html, dcc, Input, Output, callback, dash_table\n",
"import plotly.express as px\n",
"import numpy as np\n",
"from plotly.subplots import make_subplots\n",
"import core\n",
"\n",
"df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder_unfiltered.csv')\n",
"debug = False\n",
"\n",
"external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']\n",
"\n",
"app = Dash(__name__, external_stylesheets=external_stylesheets)\n",
"\n",
"app.layout = html.Div([\n",
" dcc.Location(id='url', refresh=False),\n",
" html.Div(id='page-content')\n",
"], style={\n",
" 'background-color': '#333', # Dark background color\n",
" 'color': '#fff', # Text color\n",
" 'min-height': '100vh', # Ensure it covers the full viewport height\n",
" 'padding': '20px' # Add some padding\n",
"})\n",
"\n",
"server = app.server\n",
"\n",
"raw_wine_similarity_df = pd.read_csv('data/sogrape_wine.csv')\n",
"raw_wine_similarity_df = raw_wine_similarity_df.iloc[:3, :]\n",
"\n",
"wine_similarity_df = pd.read_csv('data/wine_similarity.csv')\n",
"wine_list = wine_similarity_df['NAME'].unique()\n",
"# wine_list.sort()\n",
"geo = pd.read_csv('data/processed_wineyards.csv')\n",
"wine_regions=list(geo['Region'].unique()) + ['all']\n",
"wine_country = list(geo['Country'].unique()) + ['all']\n",
"# local_type = list(geo['LOCAL TYPE'].unique()) + ['all']\n",
"\n",
"user_rating_df = pd.read_csv('data/simulated_ratings.csv')\n",
"user_rating_df.set_index('user', inplace=True)\n",
"user_rating_df['user'] = user_rating_df.index\n",
"user_ids = user_rating_df['user']\n",
"\n",
"raw_ratings = pd.read_csv('data/raw_simulated_ratings.csv')\n",
"# crop to 5 rows and 7 columns\n",
"raw_ratings = raw_ratings.iloc[:5, :7]\n",
"\n",
"TEMPORARY_WINE_RECOMMENDATION_FORM_INFO = {}\n",
"\n",
"\n",
"\n",
"## Layout ##\n",
"dashboard_layout = html.Div([\n",
" html.H1(children='Wineyards around the world', style={'textAlign': 'center', 'color': '#fff', 'padding': '20px'}),\n",
" \n",
" html.Div(\n",
" [\n",
" html.Div(\n",
" [\n",
" html.H4(children='Country', style={'textAlign': 'center', 'color': '#fff'}),\n",
" dcc.Dropdown(wine_country, wine_country[-1], id='dropdown-wc', style={'color': '#000'}),\n",
" ], className='six columns', style={'padding': '10px'}\n",
" ),\n",
" html.Div(\n",
" [\n",
" html.H4(children='Region', style={'textAlign': 'center', 'color': '#fff'}),\n",
" dcc.Dropdown(['all'], 'all', id='dropdown-wr', style={'color': '#000'}),\n",
" ], className='six columns', style={'padding': '10px'}\n",
" )\n",
" ], className='row', style={'background-color': '#444', 'border-radius': '10px', 'margin': '10px'}),\n",
" \n",
" dcc.Graph(id='world-map-fig', style={'margin': '20px'}),\n",
" \n",
" html.Div(\n",
" [\n",
" html.Div(\n",
" [\n",
" html.H4(children='Wine Recommender', style={'textAlign': 'center', 'color': '#fff'}),\n",
" dcc.Dropdown(wine_list, wine_list[0], id='dropdown-selection', style={'color': '#000'}),\n",
" html.P(id='wine-recommendation', style={'textAlign': 'center', 'color': '#fff'}),\n",
" ], className='three columns', style={'padding': '10px'}\n",
" ),\n",
" html.Div(\n",
" [\n",
" html.P(children='Data Example', style={'textAlign': 'left', 'color': '#fff'}),\n",
" dash_table.DataTable(\n",
" data=raw_wine_similarity_df.to_dict('records'),\n",
" columns=[{'id': c, 'name': c} for c in raw_wine_similarity_df.columns],\n",
" style_header={'backgroundColor': '#444', 'color': '#fff'},\n",
" style_cell={'backgroundColor': '#333', 'color': '#fff'}\n",
" )\n",
" ], className='nine columns', style={'padding': '10px'}\n",
" )\n",
" ], className='row', style={'background-color': '#444', 'border-radius': '10px', 'margin': '10px'}),\n",
" \n",
" html.H4(children=\"Wine Recommender based on users' feedback\", style={'textAlign': 'center', 'color': '#fff', 'padding': '20px'}),\n",
" \n",
" html.Div(\n",
" [\n",
" html.Div(\n",
" [\n",
" dcc.Dropdown(user_ids, user_ids[0], id='dropdown-selection-user', style={'color': '#000'}),\n",
" html.P(id='wine-recommendation-from-user', style={'textAlign': 'center', 'color': '#fff'}),\n",
" ], className='six columns', style={'padding': '10px'}\n",
" ),\n",
" html.Div(\n",
" [\n",
" html.P(children='Data Example', style={'textAlign': 'left', 'color': '#fff'}),\n",
" dash_table.DataTable(\n",
" data=raw_ratings.to_dict('records'),\n",
" columns=[{'id': c, 'name': c} for c in raw_ratings.columns],\n",
" style_header={'backgroundColor': '#444', 'color': '#fff'},\n",
" style_cell={'backgroundColor': '#333', 'color': '#fff'}\n",
" )\n",
" ], className='six columns', style={'padding': '10px'}\n",
" ),\n",
" ], className='row', style={'background-color': '#444', 'border-radius': '10px', 'margin': '10px'}),\n",
" \n",
" html.H4(children=\"Wine Preferences Form\", style={'textAlign': 'center', 'color': '#fff', 'padding': '20px'}),\n",
" \n",
" html.Div(\n",
" [\n",
" html.Div(\n",
" [\n",
" dcc.Dropdown(wine_list, wine_list[0], id='dropdown-selection-wine-form', style={'color': '#000'}),\n",
" dcc.Input(id='input-wine-rating', type='number', placeholder='Enter wine rating', min=1, max=5, style={'margin-top': '10px'}),\n",
" ], className='six columns', style={'padding': '10px'}\n",
" ),\n",
" html.Div(\n",
" [\n",
" html.Button('Submit', id='submit-button', n_clicks=0, style={'margin-top': '10px', 'background-color': '#444', 'color': '#fff'}),\n",
" ], className='six columns', style={'padding': '10px'}\n",
" ),\n",
" ], className='row', style={'background-color': '#444', 'border-radius': '10px', 'margin': '10px'}),\n",
" \n",
" html.Div(id='recommended-wine-rating-info', style={'textAlign': 'center', 'color': '#fff', 'padding': '10px'}),\n",
" html.P(id='recommend-wine-from-form-text', style={'textAlign': 'center', 'color': '#fff'}),\n",
" \n",
" html.Div(\n",
" [\n",
" html.Button('Reset', id='recommend-wine-from-form-reset', n_clicks=0, style={'margin': '10px', 'background-color': '#444', 'color': '#fff'}),\n",
" html.Button('Recommend Wine', id='recommend-wine-from-form', n_clicks=0, style={'margin': '10px', 'background-color': '#444', 'color': '#fff'}),\n",
" ], style={'textAlign': 'center'}\n",
" ),\n",
" \n",
" html.Div(id='recommended-wine-form-output', style={'textAlign': 'center', 'color': '#fff', 'padding': '10px'}),\n",
"], style={\n",
" 'background-image': 'url(\"/assets/background.jpg\")',\n",
" 'background-size': 'cover',\n",
" 'font-family': 'Fantasy',\n",
" 'color': '#999',\n",
" 'padding': '20px'\n",
"})\n",
"@app.callback(\n",
" Output('recommend-wine-from-form-reset', 'n_clicks'),\n",
" Input('recommend-wine-from-form-reset', 'n_clicks'),\n",
")\n",
"def reset_form(n_clicks):\n",
" if n_clicks > 0:\n",
" TEMPORARY_WINE_RECOMMENDATION_FORM_INFO.clear()\n",
" return 0\n",
"\n",
"@app.callback(\n",
" Output('recommended-wine-rating-info', 'children'),\n",
" Output('submit-button', 'n_clicks'),\n",
" Output('recommend-wine-from-form-text', 'children'),\n",
" Input('submit-button', 'n_clicks'),\n",
" Input('dropdown-selection-wine-form', 'value'),\n",
" Input('input-wine-rating', 'value'),\n",
" Input('recommend-wine-from-form-text', 'children'),\n",
")\n",
"def update_output(n_clicks, wine_name, rating, text_value):\n",
" if n_clicks > 0:\n",
" print(f\"Text Value: {text_value}\")\n",
" TEMPORARY_WINE_RECOMMENDATION_FORM_INFO[wine_name] = rating\n",
" if not text_value:\n",
" text_value = \"|\"\n",
" text_value += f\"{wine_name}: {rating} | \"\n",
" return f'You rated {wine_name} with a score of {rating}', 0, text_value\n",
" return '', 0, text_value\n",
"\n",
"@app.callback(\n",
" Output('recommended-wine-form-output', 'children'),\n",
" Output('recommend-wine-from-form', 'n_clicks'),\n",
" Input('recommend-wine-from-form', 'n_clicks'),\n",
")\n",
"def recommend_wine_from_form(n_clicks):\n",
" if n_clicks > 0:\n",
" user = \"temporary_user\"\n",
" user_rating_df.loc[user] = TEMPORARY_WINE_RECOMMENDATION_FORM_INFO\n",
" user_rating_df.fillna(0, inplace=True)\n",
" user_rating_df['user'] = user_rating_df.index\n",
" user_rating_df['cluster'] = core.get_most_similar_user_clust(user_rating_df, user)\n",
"\n",
"\n",
" wine_recommendation_from_user = core.recommend_wine_from_users(user_rating_df, user, 3)\n",
" wine_recommendation_from_user = f\"Based on user form, we recommend: \"+\"; \".join(wine_recommendation_from_user)\n",
" return wine_recommendation_from_user, 0\n",
" return '', 0\n",
"\n",
"\n",
"@app.callback(\n",
" Output('dropdown-wr', 'options'),\n",
" Input('dropdown-wc', 'value')\n",
")\n",
"def set_wine_type_options(selected_wine_type):\n",
" # Return the options based on the selected wine country\n",
" pattern = r'.*' if selected_wine_type == 'all' else rf'{selected_wine_type}'\n",
" return list(geo[geo['Country'].str.match(pattern, na=False)]['Region'].unique()) + ['all']\n",
"\n",
"\n",
"wiki_layout = html.Div([\n",
" dcc.Link('Dashboard', href='/'),\n",
"\n",
" html.H1('About this project'),\n",
"\n",
" html.Div([\n",
" html.Div([\n",
"\n",
" html.H3('What is this project about?'),\n",
"\n",
" html.P('We are a group of 4 Computer Science Engineering Students with a solid Artificial Intelligence background.'),\n",
" html.P('This project aims to showcase AI applications for improving Wine Tourism for SOGRAPE.'),\n",
"\n",
"\n",
" html.H3('\\'Bout us'),\n",
" html.Img(src='/assets/tourdevino_logo.webp', style={'width': '40%', 'height': 'auto', 'display': 'block', 'margin-left': 'auto', 'margin-right': 'auto'}),\n",
" html.P('This project was developed by a team of 4, in the context of the SOGRAPE 2024 hackathon.'),\n",
" html.P('The team members are:'),\n",
" html.H4('Rui Melo'),\n",
" html.H4('André Catarino'),\n",
" html.H4('Dinis Costa'),\n",
" html.H4('Paulo Fidalgo'),\n",
"\n",
"\n",
" ], className='six columns'),], className='row'),\n",
"],\n",
"style={'background-color': '#333', 'font-family': 'Fantasy', 'color': '#999', 'padding': '10px'}\n",
"\n",
")\n",
"\n",
"# Update the index\n",
"@callback(Output('page-content', 'children'), Input('url', 'pathname'))\n",
"def display_page(pathname):\n",
" if pathname == '/':\n",
" return dashboard_layout\n",
" elif pathname == '/wiki':\n",
" return wiki_layout\n",
" else:\n",
" return '404'\n",
" # You could also return a 404 \"URL not found\" page here\n",
"\n",
"@app.callback(\n",
" Output('wine-recommendation', 'children'),\n",
" Input('dropdown-selection', 'value')\n",
")\n",
"def update_recommendation(value):\n",
" if value:\n",
" recommended_wines = core.get_top_5_similar_wines(value, wine_similarity_df)[1:]\n",
" return f\"Based on ´{value}´, we recommend: \"+\"; \".join(recommended_wines)\n",
" return ''\n",
"\n",
"\n",
"\n",
"\n",
"@app.callback(\n",
" Output('world-map-fig', 'figure'),\n",
" Output('wine-recommendation-from-user', 'children'),\n",
" Input('dropdown-wr', 'value'),\n",
" Input('dropdown-wc', 'value'),\n",
" Input('dropdown-selection-user', 'value')\n",
")\n",
"def update_graph(wr,wc, user_value):\n",
" ## Wine Recommendation from users feedback\n",
"\n",
" wine_recommendation_from_user = core.recommend_wine_from_users(user_rating_df, user_value, 3)\n",
" wine_recommendation_from_user = f\"Based on user information, we recommend: \"+\"; \".join(wine_recommendation_from_user)\n",
"\n",
" ### World Map of wineyards ###\n",
"\n",
" geo_df = pd.read_csv('data/processed_wineyards.csv')\n",
" wr = r'.*' if wr == 'all' else rf'{wr}'\n",
" wc = r'.*' if wc == 'all' else rf'{wc}'\n",
" geo_df = geo_df[geo_df['Region'].str.contains(wr, case=False, na=False, regex=True) & geo_df['Country'].str.contains(wc, case=False, na=False, regex=True)]\n",
"\n",
"\n",
" world_map_fig = px.scatter_map(geo_df,\n",
" lat=geo_df['coord_x'],\n",
" lon=geo_df['coord_y'],\n",
" hover_name=geo_df['name'],\n",
" zoom=4,\n",
" hover_data={\n",
" 'IsTouristic': True,\n",
" 'Wine Type': True,\n",
" 'Country': True,\n",
" 'Region': True,\n",
" 'Address': True,\n",
"\n",
" },\n",
" title='Wineyards around the world',\n",
" )\n",
" \n",
" world_map_fig.update_layout(height=800, width=1200)\n",
"\n",
" \n",
"\n",
"\n",
" return world_map_fig, wine_recommendation_from_user\n",
"\n",
"\n",
"if __name__ == \"__main__\":\n",
" app.run_server(host=\"0.0.0.0\", port=\"8050\", debug=debug)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "atc-smart-shower-YhjpRjjr-py3.10",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.14"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}