{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":61145,"databundleVersionId":7047669,"sourceType":"competition"}],"dockerImageVersionId":30558,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Example Notebook 1 - Basic Visualizations\n\nThis notebook will show some visualizations that might come handy when working the data provided in the competition.\n\n## Table of Content\n* [Read data](#Read_data)\n* [Data pre-processing](#Data_pre-processing)\n  * [Check dates](#Check_dates)\n  * [Check weather data](#Check_weather_data)\n  * [Map watch survey questions to question ID](#Map_question_id)\n* [Plot weather data](#Plot_weather_data)\n  * [Plot weather station locations](#Plot_weather_station_locations)\n  * [Plot weather weather data time-series](#Plot_weather_data_time-series)\n  * [Map of all weather stations that measure air temperature](#Map_of_all_weather_stations_temperature)\n  * [Map of all weather stations that measure X](#Map_of_all_weather_stations_x)\n* [Plot Cozie data](#Plot_Cozie_data)\n  * [Plot locations of watch survey responses](#Plot_locations_watch_surveys)\n  * [Plot heart rate of all participants](#Plot_heart_rate_of_all_participants)\n  * [Plot all health kit data for one participant](#Plot_all_health_kit_data_for_one)","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport plotly.graph_objects as go\nimport math","metadata":{"executionInfo":{"elapsed":36755,"status":"ok","timestamp":1691039448204,"user":{"displayName":"BUDS Lab Team Member","userId":"04037643885455272587"},"user_tz":-480},"id":"IUuDaG7zh_Tv","outputId":"020ca595-e284-4ac4-83aa-b838bb0a46c3","execution":{"iopub.status.busy":"2024-03-14T23:08:38.843761Z","iopub.execute_input":"2024-03-14T23:08:38.844182Z","iopub.status.idle":"2024-03-14T23:08:38.849960Z","shell.execute_reply.started":"2024-03-14T23:08:38.844142Z","shell.execute_reply":"2024-03-14T23:08:38.848839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"Read_data\"></a>\n## Read data","metadata":{}},{"cell_type":"code","source":"#This code loads multiple CSV data sets into pandas DataFrames. Each line of code loads a CSV file into a specific DataFrame, performing operations such as setting the index, parsing dates, and removing unwanted columns. The resulting DataFrames contain data related to physiological responses, meteorological data, and weather statio\ndf_train = pd.read_csv('/kaggle/input/cool-quiet-city-competition/cozie_responses_and_physiological_data_training.csv', index_col=[0], \n                       keep_default_na=False, na_values=[''], parse_dates=['time', 'ws_timestamp_location', 'ws_timestamp_start'], \n                       date_format='%Y-%m-%d %H:%M:%S.%f%z')\ndf_solution = pd.read_csv('/kaggle/input/cool-quiet-city-competition/cozie_responses_and_physiological_data_test_public.csv', index_col=[0],\n                          keep_default_na=False, na_values=[''], parse_dates=['time', 'ws_timestamp_location', 'ws_timestamp_start'], \n                          date_format='%Y-%m-%d %H:%M:%S.%f%z')\ndf_rain = pd.read_csv('/kaggle/input/cool-quiet-city-competition/weather_rainfall.csv', parse_dates=True, index_col=[0])\ndf_temperature = pd.read_csv('/kaggle/input/cool-quiet-city-competition/weather_air-temperature.csv', parse_dates=True, index_col=[0])\ndf_humidity = pd.read_csv('/kaggle/input/cool-quiet-city-competition/weather_relative-humidity.csv', parse_dates=True, index_col=[0])\ndf_wind_speed = pd.read_csv('/kaggle/input/cool-quiet-city-competition/weather_wind-speed.csv', parse_dates=True, index_col=[0])\ndf_wind_direction = pd.read_csv('/kaggle/input/cool-quiet-city-competition/weather_wind-direction.csv', parse_dates=True, index_col=[0])\ndf_stations = pd.read_csv('/kaggle/input/cool-quiet-city-competition/weather_stations.csv').drop(columns=['Unnamed: 0'])","metadata":{"executionInfo":{"elapsed":10680,"status":"ok","timestamp":1691040022955,"user":{"displayName":"BUDS Lab Team Member","userId":"04037643885455272587"},"user_tz":-480},"id":"Xiq5v84MixpP","execution":{"iopub.status.busy":"2024-03-14T23:08:42.332280Z","iopub.execute_input":"2024-03-14T23:08:42.332719Z","iopub.status.idle":"2024-03-14T23:10:38.866964Z","shell.execute_reply.started":"2024-03-14T23:08:42.332684Z","shell.execute_reply":"2024-03-14T23:10:38.865622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_stations.info()\n\n\n#This summary provides information about the structure and content of a Pandas DataFrame. Here's a breakdown of what each part means:","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:14:24.560179Z","iopub.execute_input":"2024-03-14T23:14:24.560605Z","iopub.status.idle":"2024-03-14T23:14:24.573036Z","shell.execute_reply.started":"2024-03-14T23:14:24.560574Z","shell.execute_reply":"2024-03-14T23:14:24.571833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"Data_pre-processing\"></a>\n# Data pre-processing\n<a id=\"Check_dates\"></a>\n## Check dates\n\nWhen checking the last date of different kinds of dataframes it becomes clear that the watch survey responses only last until Jan 21, 2023, while the weather data lasts until July 3, 2023. ","metadata":{}},{"cell_type":"code","source":"#These three print commands display the maximum value of the indices in the DataFrames df_train, df_solution and df_rain, respectively. The maximum index is simply the highest value in the index of each DataFrame, which can be useful to know how many rows each DataFrame has or to perform some type of comparison or analysis.\nprint(\"Fecha máxima en df_train:\", df_train.index.max().strftime('%Y-%m-%d'))\nprint(\"Fecha máxima en df_solution:\", df_solution.index.max().strftime('%Y-%m-%d'))\nprint(\"Fecha máxima en df_rain:\", df_rain.index.max().strftime('%Y-%m-%d'))\n","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:15:17.911129Z","iopub.execute_input":"2024-03-14T23:15:17.911583Z","iopub.status.idle":"2024-03-14T23:15:17.921493Z","shell.execute_reply.started":"2024-03-14T23:15:17.911530Z","shell.execute_reply":"2024-03-14T23:15:17.920317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We don't really need the weather data after Jan 21, 2023, so we might just as well get rid of it.","metadata":{}},{"cell_type":"code","source":"# These commands delete all rows from the DataFrames df_rain, df_temperature, df_humidity, df_wind_speed and df_wind_direction whose indexes are after January 21, 2023. It is a way to filter the data to only keep the rows before that date.\ndf_rain = df_rain[df_rain.index<'2023-01-22']\ndf_temperature = df_temperature[df_temperature.index<'2023-01-22']\ndf_humidity = df_humidity[df_humidity.index<'2023-01-22']\ndf_wind_speed = df_wind_speed[df_wind_speed.index<'2023-01-22']\ndf_wind_direction = df_wind_direction[df_wind_direction.index<'2023-01-22']","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:15:22.852320Z","iopub.execute_input":"2024-03-14T23:15:22.852761Z","iopub.status.idle":"2024-03-14T23:15:22.904774Z","shell.execute_reply.started":"2024-03-14T23:15:22.852726Z","shell.execute_reply":"2024-03-14T23:15:22.903413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"Check_weather_data\"></a>\n## Check weather data","metadata":{}},{"cell_type":"code","source":"# Show new shortened air temperature dataframe\ndf_temperature.describe()\nstyled_df = df_temperature.describe().style.set_properties(**{'background-color': 'lightgreen', 'color': 'black'})\nstyled_df\n","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:16:25.523612Z","iopub.execute_input":"2024-03-14T23:16:25.524551Z","iopub.status.idle":"2024-03-14T23:16:25.806688Z","shell.execute_reply.started":"2024-03-14T23:16:25.524506Z","shell.execute_reply":"2024-03-14T23:16:25.805482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"It looks like there is no temperature data available in before Jan 21, 2023 for weather station S117. So, we might just as well remove that column","metadata":{}},{"cell_type":"code","source":"try:\n    df_temperature = df_temperature.drop(columns=['S117'])\nexcept KeyError:\n    print(\"The 'S117' column does not exist in the DataFrame.\")\n# This code demonstrates that the column S117 is not found in the DataFrame\n","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:16:30.328267Z","iopub.execute_input":"2024-03-14T23:16:30.328723Z","iopub.status.idle":"2024-03-14T23:16:30.340668Z","shell.execute_reply.started":"2024-03-14T23:16:30.328688Z","shell.execute_reply":"2024-03-14T23:16:30.339391Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_temperature = df_temperature.drop(columns=['S117'])","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:16:35.575223Z","iopub.execute_input":"2024-03-14T23:16:35.575648Z","iopub.status.idle":"2024-03-14T23:16:35.660195Z","shell.execute_reply.started":"2024-03-14T23:16:35.575618Z","shell.execute_reply":"2024-03-14T23:16:35.658125Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get dimensions of the air temperature data\nprint(f\"Shape of df_temperature: {df_temperature.shape}\")\n","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:17:02.402111Z","iopub.execute_input":"2024-03-14T23:17:02.402770Z","iopub.status.idle":"2024-03-14T23:17:02.409003Z","shell.execute_reply.started":"2024-03-14T23:17:02.402705Z","shell.execute_reply":"2024-03-14T23:17:02.407812Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The weather dataframes are rather large. This can make the plotting of the data slow and the output images large. To make it a bit lighter, we are going to resample the data hourly.","metadata":{}},{"cell_type":"code","source":"# This code resamples weather data in 60-minute intervals, calculating the average for temperature, humidity, wind speed and wind direction, and the sum for rainfall. The result is DataFrames with average data for temperature, humidity, wind speed and wind direction, and summed data for rainfall, all grouped into one-hour intervals.\ndf_temperature_average = df_temperature.resample('60min').mean()\ndf_rain_sum = df_rain.resample('60min').sum() # note: for rain the data is aggregated with a sum instead of the mean\ndf_humidity_average = df_humidity.resample('60min').mean()\ndf_wind_speed_average = df_wind_speed.resample('60min').mean()\ndf_wind_direction_average = df_wind_direction.resample('60min').mean()\n\n#df_temperature_average.shape returns the shape of the df_temperature_average DataFrame, indicating the number of rows and columns in that DataFrame\ndf_temperature_average.shape\nprint(f\"Shape of df_temperature_average: {df_temperature_average.shape}\")\n# This code regroups weather data into 60-minute intervals, calculating the average for temperature, humidity, and wind speed, and the sum for rainfall. The result is DataFrames with average or summed data for each hour.","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:20:25.794726Z","iopub.execute_input":"2024-03-14T23:20:25.795187Z","iopub.status.idle":"2024-03-14T23:20:25.877429Z","shell.execute_reply.started":"2024-03-14T23:20:25.795154Z","shell.execute_reply":"2024-03-14T23:20:25.876201Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"Map_question_id\"></a>\n## Map watch survey questions to question ID","metadata":{}},{"cell_type":"code","source":"#This code creates a dictionary called ws_questions that contains questions related to a person's environment and activity, along with descriptions of those questions.\nws_questions = {\"q_noise_nearby\": \"Noise distractions nearby? (without earphones)\",\n                \"q_noise_kind\": \"What kind of noise?\",\n                \"q_earphones\": \"Wearing earphones?\",\n                \"q_thermal_preference\": \"Thermally, what do you prefer now?\",\n                \"q_location\": \"Where are you?\",\n                \"q_location_office\": \"What kind of office?\",\n                \"q_location_transport\": \"What kind of transport?\",\n                \"q_alone_group\": \"Alone or in a group?\",\n                \"q_activity_category_alone\": \"Category of activity? (alone)\",\n                \"q_activity_category_group\": \"Category of activity? (group)\"}","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:20:33.550650Z","iopub.execute_input":"2024-03-14T23:20:33.551047Z","iopub.status.idle":"2024-03-14T23:20:33.557815Z","shell.execute_reply.started":"2024-03-14T23:20:33.551019Z","shell.execute_reply":"2024-03-14T23:20:33.556556Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"Plot_weather_data\"></a>\n# Plot weather data\n\n<a id=\"Plot_weather_data_time-series\"></a>\n## Plot weather weather data time-series","metadata":{}},{"cell_type":"markdown","source":"Below we are going to plot the air temperature data from all weather stations.\nI used the Matplotlib method plt.plot() instead of sns.lineplot(). The reason is that plt.plot() shows the gaps in the data, while sns.lineplot() draws straight lines accross the gaps.","metadata":{}},{"cell_type":"code","source":"#This code creates a set of line graphs to display air temperatures from various weather stations over time. It uses a for loop to iterate over the columns of the df_temperature_average DataFrame, plotting a graph for each station with its name and air temperature on the Y axis.\ncols_num = 1\nrows_num = len(df_temperature_average.columns)\nfig, axs = plt.subplots(rows_num, cols_num, figsize=(20, 3 * rows_num))\nplt.subplots_adjust(hspace=0.5)\n\nfor i, col in enumerate(df_temperature_average.columns):\n    axs[i].plot(df_temperature_average.index, df_temperature_average[col], color='green')\n    station_name = df_stations[df_stations['id'] == col]['name'].values[0]\n    axs[i].set_title(f'Weather Station {col}: {station_name}')\n    axs[i].set_ylabel('Air Temperature [°C]')\nfig.set_facecolor('lightblue')  # Change the background color to light blue\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:20:39.680984Z","iopub.execute_input":"2024-03-14T23:20:39.681410Z","iopub.status.idle":"2024-03-14T23:20:44.404311Z","shell.execute_reply.started":"2024-03-14T23:20:39.681376Z","shell.execute_reply":"2024-03-14T23:20:44.402999Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Since, we are going to plot more weather data, we might just as well wrap the above code for plotting in to a function.","metadata":{}},{"cell_type":"code","source":"# Function that plots weather data fromm all weather stations\ndef plot_weather(df, ylabel):\n    cols_num = 1\n    rows_num = len(df.columns)\n    col_current = 0\n    row_current = 0 \n    fig, axs = plt.subplots(rows_num, cols_num, figsize=(20,3*rows_num))\n    plt.subplots_adjust(hspace = 0.5)\n\n    for i, col in enumerate(df.columns):\n        row_current = i\n        axs[row_current].plot(df.index, df[col])\n        station_name = df_stations[df_stations['id']==col]['name'].values[0]\n        axs[row_current].set_title(f'Weather Station {col}: {station_name}')\n        axs[row_current].set_ylabel(ylabel)\n    \n    return fig, axs","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:21:00.504417Z","iopub.execute_input":"2024-03-14T23:21:00.504880Z","iopub.status.idle":"2024-03-14T23:21:00.513590Z","shell.execute_reply.started":"2024-03-14T23:21:00.504841Z","shell.execute_reply":"2024-03-14T23:21:00.512007Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Temperature","metadata":{}},{"cell_type":"code","source":"fig, axs = plot_weather(df_temperature_average, 'Temperature [°C]')\nfor ax in axs.flat:\n    ax.lines[0].set_color('red')  # Change the color of all lines to red\n    ax.lines[0].set_linestyle('dashed') # Change line type to points\nfig.set_facecolor('lightblue')  # Change the background color to light blue\nplt.show()\n#This code calls a plot_weather function with two arguments: df_temperature_average (a DataFrame of average temperature) and 'Temperature [°C]' (a label for the Y axis of the graph). Presumably the plot_weather function generates a plot of air temperature.","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:21:03.896459Z","iopub.execute_input":"2024-03-14T23:21:03.897000Z","iopub.status.idle":"2024-03-14T23:21:08.622809Z","shell.execute_reply.started":"2024-03-14T23:21:03.896957Z","shell.execute_reply":"2024-03-14T23:21:08.621077Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Rainfall","metadata":{}},{"cell_type":"code","source":"fig, axs = plot_weather(df_rain_sum, 'Rainfall [mm/h]')\nfor ax in axs.flat:\n    ax.lines[0].set_color('green')  # Change the color of all lines to green\n    ax.lines[0].set_linestyle('dashed') # Change line type to points\nfig.set_facecolor('lightblue')  # Change the background color to light blue\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:21:16.787025Z","iopub.execute_input":"2024-03-14T23:21:16.787429Z","iopub.status.idle":"2024-03-14T23:21:37.494867Z","shell.execute_reply.started":"2024-03-14T23:21:16.787398Z","shell.execute_reply":"2024-03-14T23:21:37.493641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Relative humdity","metadata":{}},{"cell_type":"code","source":"fig, axs = plot_weather(df_humidity_average, 'Relative humidity [%]')\nfor ax in axs.flat:\n    ax.lines[0].set_color('blue')  # Change the color of all lines to blue\n    ax.lines[0].set_linestyle('dashed') # Change line type to points\nfig.set_facecolor('lightblue')  # Change the background color to light blue\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:21:55.723578Z","iopub.execute_input":"2024-03-14T23:21:55.724752Z","iopub.status.idle":"2024-03-14T23:22:00.715493Z","shell.execute_reply.started":"2024-03-14T23:21:55.724701Z","shell.execute_reply":"2024-03-14T23:22:00.714176Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Wind speed","metadata":{}},{"cell_type":"code","source":"fig, axs = plot_weather(df_wind_speed_average, 'Wind speed [knots]')\nfor ax in axs.flat:\n    ax.lines[0].set_color('red')  # Change the color of all lines to red\n    ax.lines[0].set_linestyle('dashed')  # Change line type to dashed\nfig.set_facecolor('lightblue')  # Change the background color to light blue\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:22:10.448466Z","iopub.execute_input":"2024-03-14T23:22:10.448876Z","iopub.status.idle":"2024-03-14T23:22:15.295058Z","shell.execute_reply.started":"2024-03-14T23:22:10.448848Z","shell.execute_reply":"2024-03-14T23:22:15.293729Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Wind direction","metadata":{}},{"cell_type":"code","source":"fig, axs = plot_weather(df_wind_direction_average, 'Wind direction [°]')\nfor ax in axs.flat:\n    ax.lines[0].set_color('black')  # Change the color of all lines to black\n    ax.lines[0].set_linestyle('dashed')  # Change line type to dashed\nfig.set_facecolor('lavender')  # Change the background color to light purple\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:08:18.462543Z","iopub.status.idle":"2024-03-14T23:08:18.463030Z","shell.execute_reply.started":"2024-03-14T23:08:18.462816Z","shell.execute_reply":"2024-03-14T23:08:18.462837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Looking at the temperature data above, it is clear that there are some significant gaps in January, 2023.","metadata":{}},{"cell_type":"markdown","source":"<a id=\"Map_of_all_weather_stations_temperature\"></a>\n## Map of all weather stations that measure air temperature","metadata":{}},{"cell_type":"code","source":"# Have a look at the weather station meta data\ndf_stations.head()\nstyled_df = df_stations.head().style.apply(lambda x: ['background-color: lightgreen' for _ in x], axis=1)\nstyled_df","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:08:18.464236Z","iopub.status.idle":"2024-03-14T23:08:18.464651Z","shell.execute_reply.started":"2024-03-14T23:08:18.464434Z","shell.execute_reply":"2024-03-14T23:08:18.464451Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_stations.shape","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:08:18.466134Z","iopub.status.idle":"2024-03-14T23:08:18.466517Z","shell.execute_reply.started":"2024-03-14T23:08:18.466333Z","shell.execute_reply":"2024-03-14T23:08:18.466352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Have a look at the air temperature data\ndf_temperature.columns\nstyled_df = df_stations.head().style.apply(lambda x: ['background-color: lightblue' for _ in x], axis=1)\nstyled_df","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:08:18.468584Z","iopub.status.idle":"2024-03-14T23:08:18.469157Z","shell.execute_reply.started":"2024-03-14T23:08:18.468884Z","shell.execute_reply":"2024-03-14T23:08:18.468909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Note, the list of all weather stations is much longer then the list with weather stations that can measure air temperature. Hence, we need to pre-process the data a bit and only pick the weather stations that can measure temperature data.","metadata":{}},{"cell_type":"code","source":"# Initialize a new dataframe for creating the map\ndf_map = pd.DataFrame(columns=['latitude', 'longitude', 'text'])\n\n\n# Go through each column of the temperature dataframe\nfor col in df_temperature.columns:\n    # Get the weather station name based on the station id\n    station_name = df_stations.loc[df_stations.id==col].name.values[0]\n    \n    # Create a new row, with latitude, longitude, hover text, and marker color as columns\n    df_row = pd.DataFrame([{'latitude': df_stations.loc[df_stations.id==col].latitude.values[0], \n                            'longitude': df_stations.loc[df_stations.id==col].longitude.values[0], \n                            'text': f'Station ID: {col} <br>Station name: {station_name} <br>Measurement: Rain',\n                            'color': 'rgb(0, 128, 255)'}])\n    \n    # Append new row to map dataframe\n    df_map = pd.concat([df_map, df_row])\n    \ndf_map.head()\nstyled_df = df_stations.head().style.apply(lambda x: ['background-color: lightblue' for _ in x], axis=1)\nstyled_df","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:08:18.470734Z","iopub.status.idle":"2024-03-14T23:08:18.471302Z","shell.execute_reply.started":"2024-03-14T23:08:18.470997Z","shell.execute_reply":"2024-03-14T23:08:18.471023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The pre-processing for the maps is done. Now, we can go and actually create the map chart.","metadata":{}},{"cell_type":"code","source":"# Create trace and add markers to map\ntrace = go.Scattermapbox(lat=df_map.latitude, \n                         lon=df_map.longitude,\n                         mode='markers',\n                         marker=dict(size=10,\n                                     color=df_map['color'],\n                                     opacity=0.8),\n                         hovertemplate = \"\",\n                         text=df_map['text'])\n\n# Define the layout for the map\nlayout = go.Layout(\n    margin={\"l\": 0, \"r\": 0, \"t\": 0, \"b\": 0},\n    mapbox=dict(\n        style='carto-positron', # Alternative: 'open-street-map',\n        center=dict(lat=df_map.latitude.median(),\n                    lon=df_map.longitude.median()),\n        zoom=10,\n        ),\n    height=700, width=900)\n\n# Create figure\nfig = go.Figure(data=[trace], layout=layout)\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:08:18.472669Z","iopub.status.idle":"2024-03-14T23:08:18.473200Z","shell.execute_reply.started":"2024-03-14T23:08:18.472934Z","shell.execute_reply":"2024-03-14T23:08:18.472959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Note, you can hovering the cursor over the markers will reveal some meta information about the weather station.","metadata":{}},{"cell_type":"markdown","source":"<a id=\"Map_of_all_weather_stations_x\"></a>\n## Map of all weather stations that measure X\nAgain, we can wrap up the above code into a function for convenience.","metadata":{}},{"cell_type":"code","source":"def plot_map_stations(df_measurements, df_stations):\n    # Initialize a new dataframe for creating the map\n    df_map = pd.DataFrame(columns=['latitude', 'longitude', 'text'])\n\n\n    # Go through each column of the temperature dataframe\n    for col in df_measurements.columns:\n        # Get the weather station name based on the station id\n        station_name = df_stations.loc[df_stations.id==col].name.values[0]\n\n        # Create a new row, with latitude, longitude, hover text, and marker color as columns\n        df_row = pd.DataFrame([{'latitude': df_stations.loc[df_stations.id==col].latitude.values[0], \n                                'longitude': df_stations.loc[df_stations.id==col].longitude.values[0], \n                                'text': f'Station ID: {col} <br>Station name: {station_name} <br>Measurement: Rain',\n                                'color': 'rgb(0, 128, 255)'}])\n\n        # Append new row to map dataframe\n        df_map = pd.concat([df_map, df_row])\n\n    # Create trace and add markers to map\n    trace = go.Scattermapbox(lat=df_map.latitude, \n                             lon=df_map.longitude,\n                             mode='markers',\n                             marker=dict(size=10,\n                                         color=df_map['color'],\n                                         opacity=0.8),\n                             hovertemplate = \"\",\n                             text=df_map['text'])\n\n    # Define the layout for the map\n    layout = go.Layout(\n        margin={\"l\": 0, \"r\": 0, \"t\": 0, \"b\": 0},\n        mapbox=dict(\n            style='carto-positron',\n            center=dict(lat=df_map.latitude.median(),\n                        lon=df_map.longitude.median()),\n            zoom=10,\n            ),\n        height=700, width=900)\n\n    # Create figure\n    fig = go.Figure(data=[trace], layout=layout)\n    \n    # Return figure\n    return fig","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2024-03-14T23:08:18.475168Z","iopub.status.idle":"2024-03-14T23:08:18.475725Z","shell.execute_reply.started":"2024-03-14T23:08:18.475422Z","shell.execute_reply":"2024-03-14T23:08:18.475448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = plot_map_stations(df_wind_speed, df_stations)\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:08:18.477082Z","iopub.status.idle":"2024-03-14T23:08:18.477656Z","shell.execute_reply.started":"2024-03-14T23:08:18.477330Z","shell.execute_reply":"2024-03-14T23:08:18.477356Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Feel free to plot the maps for the other weather data. You could also try to modify the `plot_map_stations` function to show the station locations for all weather data. (Tip: Some of the weather stations measure more than one type of weather data. Hence, the will have the same coordinates. Adding a small offset to the weather station coordinate can help with the visualization ;-)).","metadata":{}},{"cell_type":"markdown","source":"<a id=\"Plot_Cozie_data\"></a>\n# Plot Cozie data\n\nUntil now, we've only seen weather data. It is time to look into the Cozie data.\n\n<a id=\"Plot_locations_watch_surveys\"></a>\n## Plot locations of watch survey responses\nWe can leverage the skill for map making and reuse most of the code above to show the location of the watch survey responses.","metadata":{}},{"cell_type":"code","source":"df_map.columns","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:08:18.478967Z","iopub.status.idle":"2024-03-14T23:08:18.479527Z","shell.execute_reply.started":"2024-03-14T23:08:18.479252Z","shell.execute_reply":"2024-03-14T23:08:18.479278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_map = df_train.copy()\n\n# Filter for micro-survey response data only\ndf_map = df_map[df_map.ws_survey_count.notna()]\n\n# Create text for hover\ndf_map[\"text\"] = df_map['id_participant'] + \", \"\ndf_map[\"text\"] = df_map[\"text\"] + df_map.index[0].strftime('%a, %d.%m.%Y, %H:%M') + \"<br>\"\nfor key in ws_questions:\n    question = ws_questions[key]\n    df_map[key] = df_map[key].fillna('-')\n    df_map[\"text\"] = df_map[\"text\"] + question + \"  \" + df_map[key] +\"<br>\"\n\n# Add markers to map\ntrace = go.Scattermapbox(lat=df_map.ws_latitude, \n                            lon=df_map.ws_longitude,\n                            mode='markers',\n                            marker=dict(\n                                size=10,\n                                color='rgb(0, 128, 255)',\n                                opacity=0.8),\n                            hovertemplate = \"\",\n                            text=df_map['text'])\n\n# Define the layout for the map\nlayout = go.Layout(\n    #title='Scatter Map using Plotly',\n    margin={\"l\": 0, \"r\": 0, \"t\": 0, \"b\": 0},\n    mapbox=dict(\n        style='carto-positron', #'open-street-map',\n        center=dict(lat=df_map.ws_latitude.median(),\n                    lon=df_map.ws_longitude.median()),\n        zoom=10,\n        ),\n    height=700, width=900)\n\nfig = go.Figure(data=[trace], layout=layout)\nfig.update_layout(title_text='')","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:08:18.481065Z","iopub.status.idle":"2024-03-14T23:08:18.481599Z","shell.execute_reply.started":"2024-03-14T23:08:18.481314Z","shell.execute_reply":"2024-03-14T23:08:18.481339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"Plot_heart_rate_of_all_participants\"></a>\n## Plot heart rate of all participants\n\nAgain Matplotlib was chosen over Seaborn because it takes much less time to create the charts. \nFurther, this time only the markers are plotted without connecting lines. This way only real data is shown and gaps in the data are preserved. Due to the irregular logging interval of the health data is much more difficult to determine when to draw a line between two markers and when to omit it.","metadata":{}},{"cell_type":"code","source":"list_participants = df_train.id_participant.unique()\nlist_participants.sort()\ncols_num = 1\nrows_num = len(list_participants)\ncol_current = 0\nrow_current = 0 \nfig, axs = plt.subplots(rows_num, cols_num, figsize=(20,3*rows_num))\nplt.subplots_adjust(hspace = 0.5)\n\nfor i, id_participant in enumerate(list_participants):\n    row_current = i\n    df_participant = df_train[df_train.id_participant == id_participant]\n    df_participant = df_participant[df_participant['ts_heart_rate'].notna()]\n    axs[row_current].scatter(df_participant.index, df_participant['ts_heart_rate'], marker='.')\n    axs[row_current].set_title(f'Participant ID: {id_participant}')\n    axs[row_current].set_ylabel('Heart Rate [bpm]')","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:08:18.483335Z","iopub.status.idle":"2024-03-14T23:08:18.483896Z","shell.execute_reply.started":"2024-03-14T23:08:18.483620Z","shell.execute_reply":"2024-03-14T23:08:18.483645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"Plot_all_health_kit_data_for_one\"></a>\n## Plot all health kit data for one participant","metadata":{}},{"cell_type":"code","source":"list_health_cols = ['ts_audio_exposure_environment', \n                    'ts_heart_rate',\n                    'ts_oxygen_saturation', \n                    'ts_resting_heart_rate', \n                    'ts_stand_time',\n                    'ts_step_count', \n                    'ts_walking_distance']\n\nid_participant_current = 'xesh001'\ndf_participant = df_train[df_train.id_participant == id_participant_current]\ndf_participant = df_participant.reset_index()\ncols_num = 1\nrows_num = len(list_health_cols)\ncol_current = 0\nrow_current = 0 \nfig, axs = plt.subplots(rows_num, cols_num, figsize=(20,3*rows_num))\nfig.set_facecolor('lightgreen')  # Cambiar el color de fondo de la figura a verde claro\nplt.subplots_adjust(hspace = 0.5)\n\nfor i, col in enumerate(list_health_cols):\n    row_current = i\n    axs[row_current].plot(df_participant['time'], df_participant[col], marker='.', linestyle='None', markersize=6, color='red')\n    axs[row_current].set_title(f'Participant ID: {id_participant_current}')\n    axs[row_current].set_ylabel(col)\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-14T23:08:18.485444Z","iopub.status.idle":"2024-03-14T23:08:18.486022Z","shell.execute_reply.started":"2024-03-14T23:08:18.485719Z","shell.execute_reply":"2024-03-14T23:08:18.485745Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}