{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"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":"2023-11-13T21:43:32.269495Z","iopub.execute_input":"2023-11-13T21:43:32.270382Z","iopub.status.idle":"2023-11-13T21:43:34.441290Z","shell.execute_reply.started":"2023-11-13T21:43:32.270343Z","shell.execute_reply":"2023-11-13T21:43:34.440232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"Read_data\"></a>\n## Read data","metadata":{}},{"cell_type":"code","source":"df_train = pd.read_csv('/kaggle/input/cool-quiet-city-competition/cozie_responses_and_physiological_data_training.csv', index_col=[0], keep_default_na=False, na_values=[''], parse_dates=['time', 'ws_timestamp_location', 'ws_timestamp_start'], 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], keep_default_na=False, na_values=[''], parse_dates=['time', 'ws_timestamp_location', 'ws_timestamp_start'], 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":"2023-11-13T21:43:34.443660Z","iopub.execute_input":"2023-11-13T21:43:34.444282Z","iopub.status.idle":"2023-11-13T21:46:31.014496Z","shell.execute_reply.started":"2023-11-13T21:43:34.444244Z","shell.execute_reply":"2023-11-13T21:46:31.012856Z"},"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":"print(df_train.index.max())\nprint(df_solution.index.max())\nprint(df_rain.index.max())","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:46:31.016689Z","iopub.execute_input":"2023-11-13T21:46:31.017336Z","iopub.status.idle":"2023-11-13T21:46:31.043458Z","shell.execute_reply.started":"2023-11-13T21:46:31.017288Z","shell.execute_reply":"2023-11-13T21:46:31.041831Z"},"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":"df_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":"2023-11-13T21:46:31.046652Z","iopub.execute_input":"2023-11-13T21:46:31.047051Z","iopub.status.idle":"2023-11-13T21:46:31.111299Z","shell.execute_reply.started":"2023-11-13T21:46:31.047019Z","shell.execute_reply":"2023-11-13T21:46:31.109892Z"},"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()","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:46:31.112934Z","iopub.execute_input":"2023-11-13T21:46:31.113326Z","iopub.status.idle":"2023-11-13T21:46:31.307710Z","shell.execute_reply.started":"2023-11-13T21:46:31.113293Z","shell.execute_reply":"2023-11-13T21:46:31.306290Z"},"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":"df_temperature = df_temperature.drop(columns=['S117'])","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:46:31.309532Z","iopub.execute_input":"2023-11-13T21:46:31.309994Z","iopub.status.idle":"2023-11-13T21:46:31.323988Z","shell.execute_reply.started":"2023-11-13T21:46:31.309951Z","shell.execute_reply":"2023-11-13T21:46:31.322717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get dimensions of the air temperature data\ndf_temperature.shape","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:46:31.325420Z","iopub.execute_input":"2023-11-13T21:46:31.326336Z","iopub.status.idle":"2023-11-13T21:46:31.340443Z","shell.execute_reply.started":"2023-11-13T21:46:31.326296Z","shell.execute_reply":"2023-11-13T21:46:31.339223Z"},"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":"# Resample weather data\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# Check size of resulting dataframe\ndf_temperature_average.shape","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:46:31.342539Z","iopub.execute_input":"2023-11-13T21:46:31.343130Z","iopub.status.idle":"2023-11-13T21:46:31.469525Z","shell.execute_reply.started":"2023-11-13T21:46:31.343055Z","shell.execute_reply":"2023-11-13T21:46:31.468281Z"},"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":"ws_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":"2023-11-13T21:46:31.471234Z","iopub.execute_input":"2023-11-13T21:46:31.471710Z","iopub.status.idle":"2023-11-13T21:46:31.478545Z","shell.execute_reply.started":"2023-11-13T21:46:31.471657Z","shell.execute_reply":"2023-11-13T21:46:31.477289Z"},"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":"cols_num = 1\nrows_num = len(df_temperature_average.columns)\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, col in enumerate(df_temperature_average.columns):\n    row_current = i\n    axs[row_current].plot(df_temperature_average.index, df_temperature_average[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('Air Temperature [°C]')","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:46:31.484935Z","iopub.execute_input":"2023-11-13T21:46:31.485507Z","iopub.status.idle":"2023-11-13T21:46:38.550107Z","shell.execute_reply.started":"2023-11-13T21:46:31.485460Z","shell.execute_reply":"2023-11-13T21:46:38.548449Z"},"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":"2023-11-13T21:46:38.552669Z","iopub.execute_input":"2023-11-13T21:46:38.553165Z","iopub.status.idle":"2023-11-13T21:46:38.564434Z","shell.execute_reply.started":"2023-11-13T21:46:38.553123Z","shell.execute_reply":"2023-11-13T21:46:38.562916Z"},"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]')","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:46:38.566472Z","iopub.execute_input":"2023-11-13T21:46:38.567594Z","iopub.status.idle":"2023-11-13T21:46:45.605370Z","shell.execute_reply.started":"2023-11-13T21:46:38.567531Z","shell.execute_reply":"2023-11-13T21:46:45.603851Z"},"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]')","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:46:45.607203Z","iopub.execute_input":"2023-11-13T21:46:45.607636Z","iopub.status.idle":"2023-11-13T21:47:14.060616Z","shell.execute_reply.started":"2023-11-13T21:46:45.607599Z","shell.execute_reply":"2023-11-13T21:47:14.058245Z"},"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 [%]')","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:47:14.064061Z","iopub.execute_input":"2023-11-13T21:47:14.064684Z","iopub.status.idle":"2023-11-13T21:47:20.839923Z","shell.execute_reply.started":"2023-11-13T21:47:14.064644Z","shell.execute_reply":"2023-11-13T21:47:20.838310Z"},"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]')","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:47:20.841624Z","iopub.execute_input":"2023-11-13T21:47:20.842061Z","iopub.status.idle":"2023-11-13T21:47:27.720017Z","shell.execute_reply.started":"2023-11-13T21:47:20.842022Z","shell.execute_reply":"2023-11-13T21:47:27.718131Z"},"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 [°]')","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:47:27.721964Z","iopub.execute_input":"2023-11-13T21:47:27.723042Z","iopub.status.idle":"2023-11-13T21:47:35.748874Z","shell.execute_reply.started":"2023-11-13T21:47:27.722997Z","shell.execute_reply":"2023-11-13T21:47:35.747291Z"},"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()","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:47:35.750795Z","iopub.execute_input":"2023-11-13T21:47:35.751912Z","iopub.status.idle":"2023-11-13T21:47:35.771734Z","shell.execute_reply.started":"2023-11-13T21:47:35.751861Z","shell.execute_reply":"2023-11-13T21:47:35.770113Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_stations.shape","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:47:35.773751Z","iopub.execute_input":"2023-11-13T21:47:35.774337Z","iopub.status.idle":"2023-11-13T21:47:35.785171Z","shell.execute_reply.started":"2023-11-13T21:47:35.774290Z","shell.execute_reply":"2023-11-13T21:47:35.783602Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Have a look at the air temperature data\ndf_temperature.columns","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:47:35.786935Z","iopub.execute_input":"2023-11-13T21:47:35.787476Z","iopub.status.idle":"2023-11-13T21:47:35.799379Z","shell.execute_reply.started":"2023-11-13T21:47:35.787385Z","shell.execute_reply":"2023-11-13T21:47:35.797497Z"},"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()","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:47:35.801627Z","iopub.execute_input":"2023-11-13T21:47:35.802133Z","iopub.status.idle":"2023-11-13T21:47:35.884429Z","shell.execute_reply.started":"2023-11-13T21:47:35.802086Z","shell.execute_reply":"2023-11-13T21:47:35.883215Z"},"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":"2023-11-13T21:47:35.886324Z","iopub.execute_input":"2023-11-13T21:47:35.886853Z","iopub.status.idle":"2023-11-13T21:47:36.433400Z","shell.execute_reply.started":"2023-11-13T21:47:35.886816Z","shell.execute_reply":"2023-11-13T21:47:36.432102Z"},"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":"2023-11-13T21:47:36.435205Z","iopub.execute_input":"2023-11-13T21:47:36.436671Z","iopub.status.idle":"2023-11-13T21:47:36.452915Z","shell.execute_reply.started":"2023-11-13T21:47:36.436622Z","shell.execute_reply":"2023-11-13T21:47:36.450951Z"},"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":"2023-11-13T21:47:36.454965Z","iopub.execute_input":"2023-11-13T21:47:36.455594Z","iopub.status.idle":"2023-11-13T21:47:36.534895Z","shell.execute_reply.started":"2023-11-13T21:47:36.455530Z","shell.execute_reply":"2023-11-13T21:47:36.533761Z"},"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":"2023-11-13T22:00:59.040749Z","iopub.execute_input":"2023-11-13T22:00:59.041342Z","iopub.status.idle":"2023-11-13T22:00:59.052744Z","shell.execute_reply.started":"2023-11-13T22:00:59.041295Z","shell.execute_reply":"2023-11-13T22:00:59.051362Z"},"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":"2023-11-13T22:01:44.358640Z","iopub.execute_input":"2023-11-13T22:01:44.359145Z","iopub.status.idle":"2023-11-13T22:01:45.176204Z","shell.execute_reply.started":"2023-11-13T22:01:44.359108Z","shell.execute_reply":"2023-11-13T22:01:45.171872Z"},"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":"2023-11-13T21:53:03.344552Z","iopub.execute_input":"2023-11-13T21:53:03.345190Z","iopub.status.idle":"2023-11-13T21:54:19.158584Z","shell.execute_reply.started":"2023-11-13T21:53:03.345147Z","shell.execute_reply":"2023-11-13T21:54:19.156175Z"},"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))\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')\n    axs[row_current].set_title(f'Participant ID: {id_participant_current}')\n    axs[row_current].set_ylabel(col)","metadata":{"execution":{"iopub.status.busy":"2023-11-13T21:54:34.199625Z","iopub.execute_input":"2023-11-13T21:54:34.200144Z","iopub.status.idle":"2023-11-13T21:54:37.554221Z","shell.execute_reply.started":"2023-11-13T21:54:34.200106Z","shell.execute_reply":"2023-11-13T21:54:37.552880Z"},"trusted":true},"execution_count":null,"outputs":[]}]}