{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/b4/lwfgccm95kqd2skcwvrt2fr00000gn/T/ipykernel_23769/1782084106.py:82: 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:20: 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": [ "0\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/Users/ruimelo/Documents/GitHub/eda/app/core.py:20: 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", "/Users/ruimelo/Documents/GitHub/eda/app/core.py:31: 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", "[2024-09-17 19:32:00,521] ERROR in app: Exception on /_dash-update-component [POST]\n", "Traceback (most recent call last):\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/flask/app.py\", line 1473, in wsgi_app\n", " response = self.full_dispatch_request()\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/flask/app.py\", line 882, in full_dispatch_request\n", " rv = self.handle_user_exception(e)\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/flask/app.py\", line 880, in full_dispatch_request\n", " rv = self.dispatch_request()\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/flask/app.py\", line 865, in dispatch_request\n", " return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/dash/dash.py\", line 1376, in dispatch\n", " ctx.run(\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/dash/_callback.py\", line 514, in add_context\n", " raise err\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/dash/_callback.py\", line 503, in add_context\n", " output_value = _invoke_callback(func, *func_args, **func_kwargs)\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/dash/_callback.py\", line 43, in _invoke_callback\n", " return func(*args, **kwargs) # %% callback invoked %%\n", " File \"/var/folders/b4/lwfgccm95kqd2skcwvrt2fr00000gn/T/ipykernel_23769/1782084106.py\", line 158, in recommend_wine_from_form\n", " user_rating_df['cluster'] = core.get_most_similar_user_clust(user_rating_df, user)\n", " File \"/Users/ruimelo/Documents/GitHub/eda/app/core.py\", line 34, in get_most_similar_user_clust\n", " cluster_avg = cluster_avg[new_user_ratings.index]\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/pandas/core/series.py\", line 1153, in __getitem__\n", " return self._get_with(key)\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/pandas/core/series.py\", line 1194, in _get_with\n", " return self.loc[key]\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/pandas/core/indexing.py\", line 1191, in __getitem__\n", " return self._getitem_axis(maybe_callable, axis=axis)\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/pandas/core/indexing.py\", line 1420, in _getitem_axis\n", " return self._getitem_iterable(key, axis=axis)\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/pandas/core/indexing.py\", line 1360, in _getitem_iterable\n", " keyarr, indexer = self._get_listlike_indexer(key, axis)\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/pandas/core/indexing.py\", line 1558, in _get_listlike_indexer\n", " keyarr, indexer = ax._get_indexer_strict(key, axis_name)\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/pandas/core/indexes/base.py\", line 6200, in _get_indexer_strict\n", " self._raise_if_missing(keyarr, indexer, axis_name)\n", " File \"/Users/ruimelo/anaconda3/envs/gan-nlp/lib/python3.10/site-packages/pandas/core/indexes/base.py\", line 6252, in _raise_if_missing\n", " raise KeyError(f\"{not_found} not in index\")\n", "KeyError: \"['user'] not in index\"\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Dedicado 2.0\n", "user temporary_user\n", "Name: temporary_user, dtype: object\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", "])\n", "\n", "server = app.server\n", "\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", "\n", "dashboard_layout = html.Div([\n", " # dcc.Link('About this project', href='/wiki'),\n", " html.H1(children='Wineyards around the world', style={'textAlign':'center'}),\n", " html.H1(children='Country', style={'textAlign':'center'}),\n", " dcc.Dropdown(wine_country, wine_country[-1], id='dropdown-wc'),\n", " html.H1(children='Region', style={'textAlign':'center'}),\n", " dcc.Dropdown(['all'],'all', id='dropdown-wr'),\n", " dcc.Graph(id='world-map-fig'),\n", "\n", " \n", " \n", " html.Div(\n", " [\n", " html.Div(\n", " [\n", " html.H1(children='Wine Recommender', style={'textAlign':'center'}),\n", " dcc.Dropdown(wine_list, wine_list[0], id='dropdown-selection'),\n", " html.H1(id='wine-recommendation', style={'textAlign':'center'}),\n", " ], className='six columns',\n", " ),\n", " html.Div(\n", " [\n", " html.H1(children='something here', style={'textAlign':'center'}),\n", " ], className='six columns',\n", " )\n", " ], className='row'),\n", " \n", " \n", " html.H1(children=\"Wine Recommender based on users' feedback\", style={'textAlign':'center'}),\n", " html.Div(\n", " [\n", " html.Div(\n", " [\n", " dcc.Dropdown(user_ids, user_ids[0], id='dropdown-selection-user'),\n", " html.H4(id='wine-recommendation-from-user', style={'textAlign':'center'}),\n", " ], className='six columns',\n", " ),\n", " \n", " html.Div(\n", " [ \n", " html.H4(children='Data Example', style={'textAlign':'left'}),\n", " dash_table.DataTable(\n", " data=raw_ratings.to_dict('records'),\n", " columns=[{'id': c, 'name': c} for c in raw_ratings.columns]\n", " )\n", " ], className='six columns',\n", " ),\n", " ], className='row'),\n", " \n", " \n", " html.H1(children=\"Wine Preferences Form\", style={'textAlign':'center'}),\n", " html.Div(\n", " [\n", " html.Div(\n", " [\n", " #Dropdown for wine name\n", " dcc.Dropdown(wine_list, wine_list[0], id='dropdown-selection'),\n", " dcc.Input(id='input-wine-rating', type='number', placeholder='Enter wine rating', min=1, max=5),\n", " ], className='six columns',\n", " ),\n", " html.Div(\n", " [\n", " html.Button('Submit', id='submit-button', n_clicks=0), \n", " ], className='six columns',\n", " ),\n", " ], className='row'),\n", "\n", " html.Div(id='recommended-wine-rating-info', style={'textAlign':'center'}),\n", " html.Button('Reset', id='recommend-wine-from-form-reset', n_clicks=0),\n", " # Button to submit the form\n", " html.Button('Recommend Wine', id='recommend-wine-from-form', n_clicks=0),\n", " html.Div(id='recommended-wine-form-output', style={'textAlign':'center'}),\n", "], style={'background-color': '#333', 'font-family': 'Fantasy', 'color': '#999', 'padding': '10px'})\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", " print(n_clicks)\n", " if n_clicks > 0:\n", " TEMPORARY_WINE_RECOMMENDATION_FORM_INFO.clear()\n", " return 0\n", " \n", "\n", "@app.callback(\n", " Output('recommended-wine-rating-info', 'children'),\n", " Output('submit-button', 'n_clicks'),\n", " Input('submit-button', 'n_clicks'),\n", " Input('dropdown-selection', 'value'),\n", " Input('input-wine-rating', 'value'),\n", ")\n", "def update_output(n_clicks, wine_name, rating):\n", " if n_clicks > 0:\n", " TEMPORARY_WINE_RECOMMENDATION_FORM_INFO[wine_name] = rating\n", " return f'You rated {wine_name} with a score of {rating}', 0\n", " return '', 0\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", "\n", "\n", "\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", "\n", "@app.callback(\n", " Output('wine-recommendation', 'children'),\n", " Output('world-map-fig', 'figure'),\n", " Output('wine-recommendation-from-user', 'children'),\n", " Input('dropdown-selection', 'value'),\n", " Input('dropdown-wr', 'value'),\n", " Input('dropdown-wc', 'value'),\n", " Input('dropdown-selection-user', 'value')\n", ")\n", "def update_graph(value,wr,wc, user_value):\n", " ### Wine Recommendation ###\n", " recommended_wines = None\n", " if value:\n", " recommended_wines = core.get_top_5_similar_wines(value, wine_similarity_df)[1:]\n", " recommended_wines = f\"Based on ´{value}´, we recommend: \"+\"; \".join(recommended_wines)\n", "\n", "\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", "\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 recommended_wines, 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)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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 }