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