{ "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 }