{"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":"# Overview\nI have seen notebooks that use scattered gitHub functions throughout this competition. In this nootebook, I have decided to demostrate how to use almost all the provided functions. I also explain the basic structure before using the gitHub.  \n\nEvery function in the GitHub does 1 of 3 things: generates feature(s), adjusts information, or creates visualizations.\n\nThe functions are separated into 4 primary files: io_f.py which reads in the data, main.py which creates the mwi dataset, visualize_f.py which allows you to see the building and features on the building, and compute_f.py which has a series of computations for feature generation and postprocessing.\n\nHere is a [begginer EDA notebook](https://www.kaggle.com/andradaolteanu/indoor-navigation-complete-data-understanding/notebook) and [postprocessing notebook](https://www.kaggle.com/saitodevel01/indoor-post-processing-by-cost-minimization) that are also great applications of the gitHub and I learned a lot from them.\n\n[This is a link to the gitHub](https://github.com/location-competition/indoor-location-competition-20/tree/75f05960cde0eb30ea62dd4dcc75cc0359cb9589)\n\nLeave a comment if you have any questions and upvote if this notebook helps you.","metadata":{}},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport glob\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib\nimport matplotlib.pyplot as plt\nimport plotly.graph_objs as go\nimport json\n\nfrom dataclasses import dataclass\nimport scipy.signal as signal\n\nfrom PIL import Image, ImageOps\nfrom skimage import io\nfrom skimage.color import rgba2rgb, rgb2xyz\nfrom tqdm import tqdm\nfrom dataclasses import dataclass\nfrom math import floor, ceil\nimport cv2\n\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Structure of the Data\n\nThe datasets are orginially in a txt file format.\n\nHere is the strucutre of the directory that includes all the original data:\n\n![image.png](attachment:image.png)","metadata":{},"attachments":{"image.png":{"image/png":"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"}}},{"cell_type":"markdown","source":"### Taking a Look at a Text File","metadata":{}},{"cell_type":"code","source":"f = open(\"../input/indoor-location-navigation/test/00ff0c9a71cc37a2ebdd0f05.txt\", \"r\")\nprint(\"Dataframe Info:\\n\")\nfor line in range(10):\n    print(f.readline())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Dataframe head in txt form:\\n\")\nfor line in range(5):\n    print(f.readline())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Understanding the Submission File and Output\n\nHere I am going to explore the sample_submission.csv in depth. This should clear up any confusion about the output file.","metadata":{}},{"cell_type":"code","source":"ss = pd.read_csv(\"../input/indoor-location-navigation/sample_submission.csv\")\nss.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Understanding The First Column: site_path_timestamp","metadata":{}},{"cell_type":"code","source":"spt = ss.site_path_timestamp.values\nspliter = lambda id_spt: id_spt.split('_')\nspt = np.array([spliter(id_spt) for id_spt in spt])\nspt = pd.DataFrame(spt, columns=[\"Site\", \"Path\", \"Timestamp\"])\nspt.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The site is the building id. The path is the id of a single walk that a person took. The timestamp is the time.","metadata":{}},{"cell_type":"code","source":"test_sites = spt[\"Site\"].unique()\nlen_sites = len(test_sites)\nprint(f\"There are {len_sites} sites in the test(submission) file:\") \nprint(test_sites)\nprint()\n\ntest_paths = spt[\"Path\"].unique()\nlen_paths = len(test_paths)\nprint(f\"There are {len_paths} paths in the test(submission) file\") ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"If the timestamp look confusing to you, putting them into datetime form should clear up what it means. The test datasets do not have a date or month, so I will only display the time.","metadata":{}},{"cell_type":"code","source":"spt['Datetime'] = pd.to_datetime(spt['Timestamp'].astype('int64'), unit='ms')\nspt['Datetime'] = spt['Datetime'].apply( lambda d : d.time() ) \nspt.head(10)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Floors","metadata":{}},{"cell_type":"markdown","source":"The floor map defined below can be used to convert between the train data floor labels and the numerical floor output you need in the test set.","metadata":{}},{"cell_type":"code","source":"FLOOR_MAP = {\"B2\": -2, \n             \"B1\": -1, \n             \"F1\": 0, \n             \"F2\": 1, \n             \"F3\": 2, \n             \"F4\": 3, \n             \"F5\": 4, \n             \"F6\": 5, \n             \"F7\": 6, \n             \"F8\": 7, \n             \"F9\": 8,\n             \"1F\": 0, \"2F\": 1, \"3F\": 2, \"4F\": 3, \"5F\": 4, \"6F\": 5, \"7F\": 6, \"8F\": 7, \"9F\": 8}","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Importing GitHub Scripts\n\nBy using this magical line of code you now are able to import classes and method from the preprocessing scripts on the GitHub Repo for this competition.\nI also have the indoor-locationnavigation-2021 dataset which includes all the github scripts","metadata":{"trusted":true}},{"cell_type":"code","source":"!git clone --depth 1 https://github.com/location-competition/indoor-location-competition-20 indoor_location_competition_20","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### All Individual Imports","metadata":{}},{"cell_type":"code","source":"from indoor_location_competition_20.io_f import read_data_file","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from indoor_location_competition_20.compute_f import split_ts_seq\nfrom indoor_location_competition_20.compute_f import correct_trajectory\nfrom indoor_location_competition_20.compute_f import correct_positions\nfrom indoor_location_competition_20.compute_f import init_parameters_filter\nfrom indoor_location_competition_20.compute_f import get_rotation_matrix_from_vector\nfrom indoor_location_competition_20.compute_f import get_orientation\nfrom indoor_location_competition_20.compute_f import compute_steps\nfrom indoor_location_competition_20.compute_f import compute_stride_length\nfrom indoor_location_competition_20.compute_f import compute_headings\nfrom indoor_location_competition_20.compute_f import compute_step_heading\nfrom indoor_location_competition_20.compute_f import compute_rel_positions\nfrom indoor_location_competition_20.compute_f import compute_step_positions","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"I like to use the main and visualize functions from the indoor-locationnavigation-2021 dataset (they are almost exactly the same as the gitHub)","metadata":{}},{"cell_type":"code","source":"!cp -r ../input/indoor-locationnavigation-2021/indoor-location-competition-20-master/indoor-location-competition-20-master/* ./\n\nfrom main import calibrate_magnetic_wifi_ibeacon_to_position\nfrom main import extract_magnetic_strength\nfrom main import extract_wifi_rssi\nfrom main import extract_ibeacon_rssi\nfrom main import extract_wifi_count","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# GitHub functions\nfrom visualize_f import visualize_trajectory\nfrom visualize_f import visualize_heatmap","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Reader with io_f.py\n\nLets start by just reading in the data. For this, we will use the read_data_file from the io_f script.","metadata":{}},{"cell_type":"code","source":"#ex_building = \"5cd56b6fe2acfd2d33b5a386\"\n#ex_floor = \"F1\"\n#ex_path = \"5cf4f05d14ddfa0008131970\"\n\nex_building = \"5a0546857ecc773753327266\"\nex_floor = \"F4\"\nex_path = \"5d11dc28ffe23f0008604f67\"\n\nex_file_path = f\"../input/indoor-location-navigation/train/{ex_building}/{ex_floor}/{ex_path}.txt\"\n\nex_file = open(ex_file_path, \"r\")\ncol_names = list()\nfor i in range(10):\n    ex_file.readline()\n    col_names.append(f\"col_{i}\")\nex_site = pd.read_csv(ex_file, names=col_names, delimiter='\\t')\nex_site.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This is a mess. So what can we do to read in the data in a clean and usable format? Well the competitions io_f.py script contains functions effective at reading in the data.","metadata":{}},{"cell_type":"code","source":"ex_db = read_data_file(ex_file_path) #create a sample database\n\nprint(\"Structure and Shape: \")\nprint(\"acce: {}\".format(ex_db.acce.shape), \"\\n\" +\n      \"acacce_uncalice: {}\".format(ex_db.acce_uncali.shape), \"\\n\" +\n      \"ahrs: {}\".format(ex_db.ahrs.shape), \"\\n\" +\n      \"gyro: {}\".format(ex_db.gyro.shape), \"\\n\" +\n      \"gyro_uncali: {}\".format(ex_db.gyro_uncali.shape), \"\\n\" +\n      \"ibeacon: {}\".format(ex_db.ibeacon.shape), \"\\n\" +\n      \"magn: {}\".format(ex_db.magn.shape), \"\\n\" +\n      \"magn_uncali: {}\".format(ex_db.magn_uncali.shape), \"\\n\" +\n      \"waypoint: {}\".format(ex_db.waypoint.shape), \"\\n\" +\n      \"wifi: {}\".format(ex_db.wifi.shape))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"I will be using these data frames throught this anaysis","metadata":{}},{"cell_type":"code","source":"ex_acce = pd.DataFrame(ex_db.acce, columns=['time','x','y','z'])\nex_gyro = pd.DataFrame(ex_db.gyro, columns=['time','x','y','z'])\nex_magn = pd.DataFrame(ex_db.magn, columns=['time','x','y','z'])\nex_ahrs = pd.DataFrame(ex_db.ahrs, columns=['time','x','y','z'])\n\nex_waypoints = pd.DataFrame(ex_db.waypoint, columns=['time','X','Y'])\n\nex_acce.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_sensor_info(df, name):    \n    cols = [\"x\", \"y\", \"z\"]\n    plt.subplots(3, 3, sharex='col', sharey='row', figsize=(16,10))\n    plt.suptitle(name, fontsize=22)\n    for i in range(3):\n        col=cols[i]\n        plt.subplot(3, 3, i+1)\n        sns.distplot(df[col], axlabel=col+\"_axis\")\n        \n        plt.subplot(3, 3, i+4)\n        sns.boxplot(df[col], color=\"#96bcfa\")\n        \n    plt.subplot(3, 1, 3)\n    plt.plot(df['z'], color='#69cf83', label='z_axis')\n    plt.plot(df['y'], color='#d6b258', label='y_axis')\n    plt.plot(df['x'], color='#96bcfa', label='x_axis')\n    plt.xlabel('Time')\n    plt.ylabel('Sensor Value')\n    plt.legend()\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sensor_info(ex_acce, \"ACCE\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sensor_info(ex_gyro, \"GYRO\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sensor_info(ex_magn, \"MAGN\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sensor_info(ex_ahrs, \"AHRS\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Magnetic, WiFi, iBeacon (mwi) Dataset with main.py\nThe function below in the main function of the github can create a \ngreat dataset with magnetic, WiFi, and iBeacon data","metadata":{}},{"cell_type":"code","source":"mwi = calibrate_magnetic_wifi_ibeacon_to_position([ex_file_path])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mwi_df = pd.DataFrame(mwi).T\nmwi_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Lets break this down and make it more understandable with the rest of the functions in main.py\n### Magnetic Strength","metadata":{}},{"cell_type":"code","source":"magnetic_strength = extract_magnetic_strength(mwi)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"magn_df = pd.DataFrame(magnetic_strength, index=[0]).T\nmagn_df.columns = [\"magn\"]\nmagn_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### WiFi","metadata":{}},{"cell_type":"code","source":"wifi_rssi = extract_wifi_rssi(mwi)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Example of a BSSID WiFi Feature","metadata":{}},{"cell_type":"code","source":"wifi_bssid = list(wifi_rssi.keys())\nwifi_rssi_df = pd.DataFrame(dict(wifi_rssi[wifi_bssid[0]])).T\nwifi_rssi_df.columns=[\"RSSI\", \"old_count\"]\nwifi_rssi_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"WiFi Couunts","metadata":{}},{"cell_type":"code","source":"wifi_counts = extract_wifi_count(mwi)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"wifi_counts_df = pd.DataFrame(wifi_counts, index=[0]).T\nwifi_counts_df.columns = [\"count\"]\nwifi_counts_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### iBeacon","metadata":{}},{"cell_type":"code","source":"ibeacon_rssi = extract_ibeacon_rssi(mwi)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Example of an iBeacon ummid","metadata":{}},{"cell_type":"code","source":"iBeacon_ummid = list(ibeacon_rssi.keys())\niBeacon_rssi_df = pd.DataFrame(dict(ibeacon_rssi[iBeacon_ummid[0]])).T\niBeacon_rssi_df.columns=[\"RSSI\", \"old_count\"]\niBeacon_rssi_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualizing with Visualize_f.py","metadata":{}},{"cell_type":"markdown","source":"### Visualize Floors of a Building","metadata":{}},{"cell_type":"code","source":"def show_site_png(site):\n    '''This functions outputs the visualization of the .png images available\n    in the metadata.\n    sites: the code coresponding to 1 site (or building)'''\n    \n    base = '../input/indoor-location-navigation'\n    site_path = f\"{base}/metadata/{site}/*/floor_image.png\"\n    floor_paths = glob.glob(site_path)\n    n = len(floor_paths)\n\n    # Create the custom number of rows & columns\n    ncols = [ceil(n / 3) if n > 4 else 4][0]\n    nrows = [ceil(n / ncols) if n > 4 else 1][0]\n\n    plt.figure(figsize=(20, 10))\n    plt.suptitle(f\"Site no. '{site}'\", fontsize=18)\n\n    # Plot image for each floor\n    for k, floor in enumerate(floor_paths):\n        plt.subplot(nrows, ncols, k+1)\n\n        image = Image.open(floor)\n\n        plt.imshow(image)\n        plt.axis(\"off\")\n        title = floor.split(\"/\")[5]\n        plt.title(title, fontsize=15)\n        ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#This site has a lot of floors so it is a good example\nshow_site_png(site='5cd56b64e2acfd2d33b592b3')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Visualize Waypoints","metadata":{}},{"cell_type":"code","source":"trajectory = ex_db.waypoint\ntrajectory = trajectory[:, 1:3]\n\nex_png_path = f\"../input/indoor-location-navigation/metadata/{ex_building}/{ex_floor}/floor_image.png\"\nex_json_path = f\"../input/indoor-location-navigation/metadata/{ex_building}/{ex_floor}/floor_info.json\"\n\nwith open(ex_json_path) as json_file:\n    json_data = json.load(json_file)\n    \nwidth_meter = json_data[\"map_info\"][\"width\"]\nheight_meter = json_data[\"map_info\"][\"height\"]\n\nvisualize_trajectory(trajectory = trajectory,\n                     floor_plan_filename = ex_png_path,\n                     width_meter=width_meter,\n                     height_meter=height_meter,\n                     title=\"Waypoint Path\",\n                     g_size=750,\n                     point_color='#76C1A0',\n                     start_color='#007B51',\n                     end_color='#9B0000')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Visualize Magnetic Strength","metadata":{}},{"cell_type":"code","source":"heat_positions = np.array(list(magnetic_strength.keys()))\nheat_values = np.array(list(magnetic_strength.values()))\n\nvisualize_heatmap(heat_positions, \n                  heat_values, \n                  ex_png_path,\n                  width_meter, \n                  height_meter, \n                  colorbar_title='strength', \n                  title='Magnetic Strength',\n                  g_size=750,\n                  colorscale='temps')\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Visualize WiFi","metadata":{}},{"cell_type":"code","source":"heat_positions = np.array(list(wifi_counts.keys()))\nheat_values = np.array(list(wifi_counts.values()))\n# filter out positions that no wifi detected\nmask = heat_values != 0\nheat_positions = heat_positions[mask]\nheat_values = heat_values[mask]\n\n# The heatmap\nvisualize_heatmap(heat_positions, \n                  heat_values, \n                  ex_png_path, \n                  width_meter, \n                  height_meter, \n                  colorbar_title=' WiFi Counts', \n                  title=f'WiFi Count',\n                  g_size=755,\n                  colorscale='temps')\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'This floor has {len(wifi_rssi.keys())} wifis.')\n\nwifi_bssid = list(wifi_rssi.keys())\ntarget_wifi = wifi_bssid[0]\nheat_positions = np.array(list(wifi_rssi[target_wifi].keys()))\nheat_values = np.array(list(wifi_rssi[target_wifi].values()))[:, 0]\n\n# The heatmap\nvisualize_heatmap(heat_positions, \n                  heat_values, \n                  ex_png_path, \n                  width_meter, \n                  height_meter, \n                  colorbar_title='dBm', \n                  title=f'WiFi RSSI ({target_wifi})',\n                  g_size=755,\n                  colorscale='temps')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Visualize iBeacon","metadata":{}},{"cell_type":"code","source":"print(f'This floor has {len(ibeacon_rssi.keys())} ibeacons.')\n\nibeacon_ummids = list(ibeacon_rssi.keys())\ntarget_ibeacon = ibeacon_ummids[0]\nheat_positions = np.array(list(ibeacon_rssi[target_ibeacon].keys()))\nheat_values = np.array(list(ibeacon_rssi[target_ibeacon].values()))[:, 0]\n\n# The heatmap\nvisualize_heatmap(heat_positions, \n                  heat_values, \n                  ex_png_path, \n                  width_meter, \n                  height_meter, \n                  colorbar_title='dBm', \n                  title=f'iBeacon RSSI ({target_ibeacon})',\n                  g_size=755,\n                  colorscale='temps')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Computing with compute_f.py","metadata":{"trusted":true}},{"cell_type":"code","source":"sensor_df = pd.DataFrame()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Compute Steps\nTakes in acce_datas from io_f.py. Computes the step_acce max, min, and std.","metadata":{}},{"cell_type":"code","source":"step_timestamps, step_indexs, step_acce_max_mins = compute_steps(ex_db.acce)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sensor_df = pd.DataFrame(step_acce_max_mins, index=step_indexs)\nsensor_df.columns = [\"timestamp\", \"acce_max\", \"acce_min\", \"acce_std\"]\nsensor_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Compute Stride Length\nTakes in step_acce_max_min from compute_steps. Computes stride length.","metadata":{}},{"cell_type":"code","source":"stride_lengths = compute_stride_length(step_acce_max_mins)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sensor_df[\"stride_length\"] = stride_lengths[:, 1]\nsensor_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Compute Headings and Compute Step Headings\nTakes in ahrs_datas from io_f.py. Computes headings.\n\nTakes in step_timestamps from compute_steps and headings from compute_headings. Computes step headings.","metadata":{}},{"cell_type":"code","source":"headings = compute_headings(ex_db.ahrs)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"headings.shape","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"step_headings = compute_step_heading(step_timestamps, headings)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sensor_df[\"step_heading\"] = step_headings[:, 1]\nsensor_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Compute Rel Positions\nTakes in stride_lengths from compute_stride_length and step_headings from compute_step_headings. Computes relative positions","metadata":{}},{"cell_type":"code","source":"rel_positions = compute_rel_positions(stride_lengths, step_headings)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sensor_df[\"rel_pos_x\"] = rel_positions[:, 1]\nsensor_df[\"rel_pos_y\"] = rel_positions[:, 2]\nsensor_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Compute Step Positions\nTakes in acce_datas, ahrs_datas, and posi_datas from io_f.py. Computes step positions.","metadata":{}},{"cell_type":"code","source":"step_positions = compute_step_positions(ex_db.acce, ex_db.ahrs, ex_db.waypoint)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sensor_df[\"step_pos_x\"] = step_positions[:, 1]\nsensor_df[\"step_pos_y\"] = step_positions[:, 2]\nsensor_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Examining our Computed Values","metadata":{}},{"cell_type":"code","source":"#Fix timestamp\ndef time_float_to_str(time):\n    return str(int(time))\n\nsensor_df[\"timestamp\"] = sensor_df[\"timestamp\"].apply(time_float_to_str)\nsensor_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_sensor_info(df, name='Computed Sensor Info'):\n    plt.subplots(6, 2, figsize=(18,24))\n    plt.suptitle(name, fontsize=22)\n    \n    plt.subplot(6, 1, 1)\n    plt.plot(df['acce_max'], color='#db5046', label='acce_max')\n    plt.plot(df['acce_min'], color='#96bcfa', label='acce_min')\n    plt.xlabel('Time')\n    plt.ylabel('Value')\n    plt.title('ACCE Max & Min Over Time')\n    plt.legend(loc='upper left')\n    \n    plt.subplot(6, 2, 3)\n    plt.title('ACCE Max Boxplot')\n    sns.boxplot(df['acce_min'], color=\"#db5046\").set(xlabel=None)\n    \n    plt.subplot(6, 2, 4)\n    plt.title('ACCE Min Boxplot')\n    sns.boxplot(df['acce_min'], color=\"#96bcfa\").set(xlabel=None)\n    \n    plt.subplot(6, 1, 3)\n    plt.plot(df['stride_length'], color='#69cf83')\n    plt.xlabel('Time')\n    plt.ylabel('Length')\n    plt.title('Stride Length Over Time')\n    \n    plt.subplot(6, 2 , 7)\n    sns.distplot(df['acce_std'], color='#eba834', axlabel='acce_std')\n    plt.title('acce_std')\n    \n    plt.subplot(6, 2, 8)\n    sns.distplot(df['step_heading'], color='#34c8ed', axlabel='step_heading')\n    plt.title('step_heading')\n    \n    plt.subplot(6, 1, 5)\n    plt.plot(df['rel_pos_x'], color='#96bcfa', label='rel_pos_x')\n    plt.plot(df['rel_pos_y'], color='#db5046', label='rel_pos_y')\n    plt.legend(loc='upper left')\n    plt.title('rel_pos')\n    \n    plt.subplot(6, 1, 6)\n    plt.plot(df['step_pos_x'], color='#96bcfa', label='step_pos_x')\n    plt.plot(df['step_pos_y'], color='#db5046', label='step_pos_y')\n    plt.legend(loc='upper left')\n    plt.title('step_pos')\n    \n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_sensor_info(sensor_df)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sensor_df.describe()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Final Thoughts","metadata":{}},{"cell_type":"markdown","source":"I did not include the split_ts_seq, correct_trajectory or correct_positions although I may add these in the future. I actually indirectly used them by calling other functions which called them. I also did not include init_parameters_filter, get_rotation_matrix_from_vector, and get_orientation as I am still figuring out how to properly use them. If you have any advice on how to use these functions comment below.\n\nLet me know if I used any function incorrectly or if I could improve in any way. \n\nI hope you find this notebook helpful in understanding the GitHub functions and comment how you plan to use these functions. Good luck!","metadata":{}}]}