{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":102335,"databundleVersionId":12518947,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"This notebook aims to visualize the connection between different time series data from sensors and their labels. I'll keeping it exploratory, so no statistical analysis will be done.\n\nJust a heads-up, this will probably be a lot of plots mostly for my own amusement.","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2025-06-10T15:54:28.677465Z","iopub.execute_input":"2025-06-10T15:54:28.677834Z","iopub.status.idle":"2025-06-10T15:54:28.683988Z","shell.execute_reply.started":"2025-06-10T15:54:28.677813Z","shell.execute_reply":"2025-06-10T15:54:28.682625Z"}}},{"cell_type":"code","source":"import os\nfrom pathlib import Path\nfrom typing import List\n\nimport cv2\nimport matplotlib.gridspec as gridspec\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nfrom scipy.spatial.transform import Rotation as R\nfrom tqdm import tqdm\n\nimport base64\nfrom IPython import display as dd","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# input\ninput_path = Path(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/\")\ntrain_df = pd.read_csv(input_path / \"train.csv\")\n\n\n# output directory\nsave_dir = Path(\"./mp4\")\nsave_fig = Path(\"./images\")\n# sample = train_df.loc[train_df[\"sequence_id\"] == \"SEQ_056304\"]\n# sample","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T15:53:55.782471Z","iopub.execute_input":"2025-06-10T15:53:55.783187Z","iopub.status.idle":"2025-06-10T15:54:21.303900Z","shell.execute_reply.started":"2025-06-10T15:53:55.783158Z","shell.execute_reply":"2025-06-10T15:54:21.303113Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df = pd.read_csv(input_path / \"test.csv\")\ntest_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:30:32.801126Z","iopub.execute_input":"2025-06-10T16:30:32.801831Z","iopub.status.idle":"2025-06-10T16:30:32.852596Z","shell.execute_reply.started":"2025-06-10T16:30:32.801805Z","shell.execute_reply":"2025-06-10T16:30:32.851591Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.sample(10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:32:55.102067Z","iopub.execute_input":"2025-06-10T16:32:55.102410Z","iopub.status.idle":"2025-06-10T16:32:55.150050Z","shell.execute_reply.started":"2025-06-10T16:32:55.102386Z","shell.execute_reply":"2025-06-10T16:32:55.148966Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df[[\"subject\",\"gesture\"]].value_counts().to_frame().reset_index().sort_values(by=\"subject\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:31:57.042414Z","iopub.execute_input":"2025-06-10T16:31:57.042716Z","iopub.status.idle":"2025-06-10T16:31:57.162621Z","shell.execute_reply.started":"2025-06-10T16:31:57.042697Z","shell.execute_reply":"2025-06-10T16:31:57.161663Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"os.makedirs(save_dir, exist_ok=True)\nos.makedirs(save_fig, exist_ok=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T15:54:30.511069Z","iopub.execute_input":"2025-06-10T15:54:30.511407Z","iopub.status.idle":"2025-06-10T15:54:30.516580Z","shell.execute_reply.started":"2025-06-10T15:54:30.511384Z","shell.execute_reply":"2025-06-10T15:54:30.515617Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df[\"gesture\"].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T15:47:40.305455Z","iopub.execute_input":"2025-06-10T15:47:40.305776Z","iopub.status.idle":"2025-06-10T15:47:40.364687Z","shell.execute_reply.started":"2025-06-10T15:47:40.305749Z","shell.execute_reply":"2025-06-10T15:47:40.363779Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gestures = train_df[\"gesture\"].value_counts().index.values\ngestures","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T15:47:40.365614Z","iopub.execute_input":"2025-06-10T15:47:40.365953Z","iopub.status.idle":"2025-06-10T15:47:40.424788Z","shell.execute_reply.started":"2025-06-10T15:47:40.365901Z","shell.execute_reply":"2025-06-10T15:47:40.424032Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.sample(10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T15:47:40.426622Z","iopub.execute_input":"2025-06-10T15:47:40.426986Z","iopub.status.idle":"2025-06-10T15:47:40.504329Z","shell.execute_reply.started":"2025-06-10T15:47:40.426956Z","shell.execute_reply":"2025-06-10T15:47:40.503382Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df[[\"sequence_id\",\"gesture\"]].value_counts().to_frame().reset_index().sort_values(by=\"sequence_id\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T15:47:40.505239Z","iopub.execute_input":"2025-06-10T15:47:40.505512Z","iopub.status.idle":"2025-06-10T15:47:40.639708Z","shell.execute_reply.started":"2025-06-10T15:47:40.505491Z","shell.execute_reply":"2025-06-10T15:47:40.638854Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def quaternion_to_euler(df: pd.DataFrame) -> pd.DataFrame:\n    \"\"\"\n    DataFrame内のクォータニオン（rot_w, rot_x, rot_y, rot_z）を\n    オイラー角（yaw, pitch, roll）に変換して新しいカラムに追加\n    \"\"\"\n    output = df.copy()\n    # scipyでは (x, y, z, w) の順番が必要なので並べ替える\n    quats = df[[\"rot_x\", \"rot_y\", \"rot_z\", \"rot_w\"]].values\n    r = R.from_quat(quats)\n\n    # ZYX順 → yaw(ヨー), pitch(ピッチ), roll(ロール)\n    eulers = r.as_euler(\"zyx\", degrees=True)\n\n    output.loc[:, \"yaw\"] = eulers[:, 0]\n    output.loc[:, \"pitch\"] = eulers[:, 1]\n    output.loc[:, \"roll\"] = eulers[:, 2]\n    return output\n\n\ndef plot_euler_angles(df: pd.DataFrame, sequence_id: str) -> pd.DataFrame:\n    seq = df[df[\"sequence_id\"] == sequence_id]\n\n    plt.figure(figsize=(12, 4))\n    for angle in [\"yaw\", \"pitch\", \"roll\"]:\n        plt.plot(seq[\"sequence_counter\"], seq[angle], label=angle)\n\n    plt.title(f\"Euler Angles from Quaternion (sequence_id = {sequence_id})\")\n    plt.xlabel(\"Time step\")\n    plt.ylabel(\"Angle (degrees)\")\n    plt.legend(bbox_to_anchor=(1, 1), loc=\"upper left\", fontsize=15)\n    plt.grid(True)\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T15:54:44.106906Z","iopub.execute_input":"2025-06-10T15:54:44.107862Z","iopub.status.idle":"2025-06-10T15:54:44.116051Z","shell.execute_reply.started":"2025-06-10T15:54:44.107830Z","shell.execute_reply":"2025-06-10T15:54:44.115183Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def make_plot(sample: pd.DataFrame, gesture: str, idx: int):\n    # Figure全体を作成\n    fig = plt.figure(figsize=(15, 15))  # 横長のFigureを指定\n\n    # GridSpecで行の高さ比を調整（上:中:下 = 1:1:2）\n    gs = gridspec.GridSpec(nrows=3, ncols=5, height_ratios=[1, 1, 2])\n\n    # 時系列プロット（上の1行5列全体を1つのAxesに）\n    ax_ts = fig.add_subplot(gs[0, :])  # 1行目すべてを使う\n    ax_ts.set_title(f\"Time Series Plot | Gesture is {gesture}\")\n\n    for angle in [\"yaw\", \"pitch\", \"roll\"]:\n        ax_ts.plot(sample[\"sequence_counter\"], sample[angle], label=angle)\n    ax_ts.axvspan(\n        sample.loc[idx][\"sequence_counter\"],\n        sample.loc[idx + 1][\"sequence_counter\"],\n        color=\"red\",\n        alpha=0.2,\n        # edgecolor=\"none\",\n        label=\"time\",\n    )\n    ax_ts.grid(True)\n    ax_ts.legend(bbox_to_anchor=(1, 1), loc=\"upper left\", fontsize=15)\n\n    #####################################\n    # 時系列プロット（上の2行5列全体を1つのAxesに）\n    ax_ts_2 = fig.add_subplot(gs[1, :])  # 1行目すべてを使う\n    # ax_ts_2.set_title(f\"Time Series gesture is {gesture}\")\n\n    for angle in [\"acc_x\", \"acc_y\", \"acc_z\"]:\n        ax_ts_2.plot(sample[\"sequence_counter\"], sample[angle], label=angle)\n    ax_ts_2.axvspan(\n        sample.loc[idx][\"sequence_counter\"],\n        sample.loc[idx + 1][\"sequence_counter\"],\n        color=\"red\",\n        alpha=0.2,\n        # edgecolor=\"none\",\n        # label=\"time\",\n    )\n    ax_ts_2.grid(True)\n    ax_ts_2.legend(bbox_to_anchor=(1, 1), loc=\"upper left\", fontsize=15)\n\n    #####################################\n    # ヒートマップ（2行目：5個並べる）\n    for i in range(5):\n        tof_features = [c for c in tof_columns if f\"tof_{i+1}\" in c]\n        ax_hm = fig.add_subplot(gs[2, i])\n        im = ax_hm.imshow(\n            sample[tof_features].values[idx].reshape(8, 8), cmap=\"Blues\", aspect=\"equal\"\n        )  # 正方形\n        ax_hm.set_title(f\"time of fright {idx}\")\n        ax_hm.axis(\"off\")  # 軸を消すと見やすくなる\n\n    return fig","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:11:33.696473Z","iopub.execute_input":"2025-06-10T16:11:33.696979Z","iopub.status.idle":"2025-06-10T16:11:33.710204Z","shell.execute_reply.started":"2025-06-10T16:11:33.696949Z","shell.execute_reply":"2025-06-10T16:11:33.709103Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def make_image_from_sequence(input_df: pd.DataFrame, sequence_id: str, save_fig=False) -> List[str]:\n    sample = input_df[input_df[\"sequence_id\"] == sequence_id].reset_index(drop=True)\n    sample = quaternion_to_euler(sample)\n    gesture = sample[\"gesture\"].unique()\n    gesture = \",\".join(gesture)\n\n    image_paths = []\n\n    for idx in range(len(sample)):\n        if idx == len(sample) - 1:\n            continue\n        fig = make_plot(sample, gesture, idx)\n        path = save_fig / f\"{sequence_id}_{idx:03}.png\"\n\n        if save_fig:\n            fig.savefig(path, bbox_inches=\"tight\")\n            image_paths.append(path)\n        plt.close(fig)\n    return image_paths","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:14:31.993240Z","iopub.execute_input":"2025-06-10T16:14:31.993625Z","iopub.status.idle":"2025-06-10T16:14:32.000956Z","shell.execute_reply.started":"2025-06-10T16:14:31.993599Z","shell.execute_reply":"2025-06-10T16:14:32.000073Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"target = [\"gesture\"]\ntrain_only_columns = [\"sequence_type\", \"orientation\"]\ntof_columns = [c for c in train_df.columns if \"tof\" in c]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T15:48:01.469979Z","iopub.execute_input":"2025-06-10T15:48:01.470275Z","iopub.status.idle":"2025-06-10T15:48:01.475606Z","shell.execute_reply.started":"2025-06-10T15:48:01.470255Z","shell.execute_reply":"2025-06-10T15:48:01.474557Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gesture_seq_id = {}\n\nfor gesture in gestures:\n    gesture_seq_id[gesture] = train_df[train_df[\"gesture\"]==gesture][\"sequence_id\"].sample(1, random_state=0).values","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T15:48:38.905182Z","iopub.execute_input":"2025-06-10T15:48:38.905472Z","iopub.status.idle":"2025-06-10T15:48:40.372675Z","shell.execute_reply.started":"2025-06-10T15:48:38.905453Z","shell.execute_reply":"2025-06-10T15:48:40.371644Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gesture_seq_id","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T15:48:41.975682Z","iopub.execute_input":"2025-06-10T15:48:41.975998Z","iopub.status.idle":"2025-06-10T15:48:41.983232Z","shell.execute_reply.started":"2025-06-10T15:48:41.975977Z","shell.execute_reply":"2025-06-10T15:48:41.982404Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df[\"sequence_id\"].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:02:54.943039Z","iopub.execute_input":"2025-06-10T16:02:54.943387Z","iopub.status.idle":"2025-06-10T16:02:54.989989Z","shell.execute_reply.started":"2025-06-10T16:02:54.943363Z","shell.execute_reply":"2025-06-10T16:02:54.988791Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df[train_df[\"sequence_id\"]==\"SEQ_039523\"][\"gesture\"].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:04:04.374243Z","iopub.execute_input":"2025-06-10T16:04:04.374634Z","iopub.status.idle":"2025-06-10T16:04:04.434151Z","shell.execute_reply.started":"2025-06-10T16:04:04.374614Z","shell.execute_reply":"2025-06-10T16:04:04.432782Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#!rm /kaggle/working/images/*.png","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:03:48.586873Z","iopub.execute_input":"2025-06-10T16:03:48.587356Z","iopub.status.idle":"2025-06-10T16:03:48.600025Z","shell.execute_reply.started":"2025-06-10T16:03:48.587295Z","shell.execute_reply":"2025-06-10T16:03:48.599001Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# for g, ID in gesture_seq_id.items():\n#     make_image_from_sequence(input_df=train_df, sequence_id=ID[0])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:07:02.097198Z","iopub.execute_input":"2025-06-10T16:07:02.098249Z","iopub.status.idle":"2025-06-10T16:07:02.101950Z","shell.execute_reply.started":"2025-06-10T16:07:02.098216Z","shell.execute_reply":"2025-06-10T16:07:02.101083Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"g='Text on phone'\ntime=0\nID = gesture_seq_id[g]\nsample = train_df[train_df[\"sequence_id\"] == ID[0]].reset_index(drop=True)\nsample = quaternion_to_euler(sample)\nfig = make_plot(sample=sample, gesture=g, idx=time)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:13:11.403792Z","iopub.execute_input":"2025-06-10T16:13:11.404171Z","iopub.status.idle":"2025-06-10T16:13:12.312069Z","shell.execute_reply.started":"2025-06-10T16:13:11.404146Z","shell.execute_reply":"2025-06-10T16:13:12.311010Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for time in range(60, 80, 1):\n    fig = make_plot(sample=sample, gesture=g, idx=time)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:14:49.102136Z","iopub.execute_input":"2025-06-10T16:14:49.102445Z","iopub.status.idle":"2025-06-10T16:15:06.421577Z","shell.execute_reply.started":"2025-06-10T16:14:49.102425Z","shell.execute_reply":"2025-06-10T16:15:06.420564Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gesture_seq_id","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:16:02.645177Z","iopub.execute_input":"2025-06-10T16:16:02.646175Z","iopub.status.idle":"2025-06-10T16:16:02.653430Z","shell.execute_reply.started":"2025-06-10T16:16:02.646143Z","shell.execute_reply":"2025-06-10T16:16:02.652579Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"g='Wave hello'\ntime=0\nID = train_df[train_df[\"gesture\"]==gesture][\"sequence_id\"].sample(1, random_state=0).values[0]\nsample = train_df[train_df[\"sequence_id\"] == ID].reset_index(drop=True)\nsample = quaternion_to_euler(sample)\n\nfig = make_plot(sample=sample, gesture=g, idx=time)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:25:14.129855Z","iopub.execute_input":"2025-06-10T16:25:14.130799Z","iopub.status.idle":"2025-06-10T16:25:15.070001Z","shell.execute_reply.started":"2025-06-10T16:25:14.130766Z","shell.execute_reply":"2025-06-10T16:25:15.069074Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"g='Wave hello'\ntime=0\nID = train_df[train_df[\"gesture\"]==gesture][\"sequence_id\"].sample(1, random_state=20).values[0]\nsample = train_df[train_df[\"sequence_id\"] == ID].reset_index(drop=True)\nsample = quaternion_to_euler(sample)\n\nfig = make_plot(sample=sample, gesture=g, idx=time)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:25:46.270646Z","iopub.execute_input":"2025-06-10T16:25:46.271052Z","iopub.status.idle":"2025-06-10T16:25:47.209491Z","shell.execute_reply.started":"2025-06-10T16:25:46.271006Z","shell.execute_reply":"2025-06-10T16:25:47.208563Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"g='Wave hello'\nID = train_df[train_df[\"gesture\"]==gesture][\"sequence_id\"].sample(1, random_state=20).values[0]\nsample = train_df[train_df[\"sequence_id\"] == ID].reset_index(drop=True)\nsample = quaternion_to_euler(sample)\n\nsample.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:27:46.714346Z","iopub.execute_input":"2025-06-10T16:27:46.714721Z","iopub.status.idle":"2025-06-10T16:27:46.826120Z","shell.execute_reply.started":"2025-06-10T16:27:46.714695Z","shell.execute_reply":"2025-06-10T16:27:46.825027Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for time in range(60,100,5):\n    fig = make_plot(sample=sample, gesture=g, idx=time)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:28:39.221341Z","iopub.execute_input":"2025-06-10T16:28:39.221647Z","iopub.status.idle":"2025-06-10T16:28:46.059385Z","shell.execute_reply.started":"2025-06-10T16:28:39.221627Z","shell.execute_reply":"2025-06-10T16:28:46.058285Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"agg_df = train_df.groupby([\"gesture\", \"sequence_counter\"], as_index=False)[[\"acc_x\", \"acc_y\", \"acc_z\"]].agg(\"mean\")\nagg_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:18:02.956805Z","iopub.execute_input":"2025-06-10T16:18:02.957195Z","iopub.status.idle":"2025-06-10T16:18:03.040741Z","shell.execute_reply.started":"2025-06-10T16:18:02.957170Z","shell.execute_reply":"2025-06-10T16:18:03.039785Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"g='Eyebrow - pull hair'\ntime=0\nID = train_df[train_df[\"gesture\"]==gesture][\"sequence_id\"].sample(1, random_state=0).values[0]\nsample = train_df[train_df[\"sequence_id\"] == ID].reset_index(drop=True)\nsample = quaternion_to_euler(sample)\n\nfig = make_plot(sample=sample, gesture=g, idx=time)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:44:39.727717Z","iopub.execute_input":"2025-06-10T16:44:39.728185Z","iopub.status.idle":"2025-06-10T16:44:40.714276Z","shell.execute_reply.started":"2025-06-10T16:44:39.728157Z","shell.execute_reply":"2025-06-10T16:44:40.713333Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"g='Eyebrow - pull hair'\ntime=0\nID = train_df[train_df[\"gesture\"]==gesture][\"sequence_id\"].sample(1, random_state=100).values[0]\nsample = train_df[train_df[\"sequence_id\"] == ID].reset_index(drop=True)\nsample = quaternion_to_euler(sample)\n\nfig = make_plot(sample=sample, gesture=g, idx=time)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:48:54.472536Z","iopub.execute_input":"2025-06-10T16:48:54.472900Z","iopub.status.idle":"2025-06-10T16:48:55.435825Z","shell.execute_reply.started":"2025-06-10T16:48:54.472876Z","shell.execute_reply":"2025-06-10T16:48:55.434693Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"g='Eyebrow - pull hair'\ntime=0\nID = train_df[train_df[\"gesture\"]==gesture][\"sequence_id\"].sample(1, random_state=101).values[0]\nsample = train_df[train_df[\"sequence_id\"] == ID].reset_index(drop=True)\nsample = quaternion_to_euler(sample)\n\nfig = make_plot(sample=sample, gesture=g, idx=time)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T16:49:10.747712Z","iopub.execute_input":"2025-06-10T16:49:10.748104Z","iopub.status.idle":"2025-06-10T16:49:11.769989Z","shell.execute_reply.started":"2025-06-10T16:49:10.748079Z","shell.execute_reply":"2025-06-10T16:49:11.768986Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"g='Eyebrow - pull hair'\ntime=0\nID = train_df[train_df[\"gesture\"]==gesture][\"sequence_id\"].sample(1, random_state=101).values[0]\nsample = train_df[train_df[\"sequence_id\"] == ID].reset_index(drop=True)\nsample = quaternion_to_euler(sample)\n\nos.makedirs(f\"/kaggle/working/images/{ID}/\", exist_ok=True)\n\nimage_paths = []\nfor time in tqdm(range(0,70)):\n    fig = make_plot(sample=sample, gesture=g, idx=time)\n    path=f\"/kaggle/working/images/{ID}/{g}_{time}.png\"\n    fig.savefig(path, bbox_inches=\"tight\")\n    image_paths.append(path)\n    plt.close(fig)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T17:08:00.043023Z","iopub.execute_input":"2025-06-10T17:08:00.043394Z","iopub.status.idle":"2025-06-10T17:08:54.008700Z","shell.execute_reply.started":"2025-06-10T17:08:00.043369Z","shell.execute_reply":"2025-06-10T17:08:54.007717Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"frames = [Image.open(p) for p in image_paths]\nframes[0].save(\n    \"output.gif\", save_all=True, append_images=frames[1:], duration=500, loop=0  # ms\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T17:09:09.027247Z","iopub.execute_input":"2025-06-10T17:09:09.027572Z","iopub.status.idle":"2025-06-10T17:09:16.799128Z","shell.execute_reply.started":"2025-06-10T17:09:09.027551Z","shell.execute_reply":"2025-06-10T17:09:16.798180Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T17:11:47.385056Z","iopub.execute_input":"2025-06-10T17:11:47.385397Z","iopub.status.idle":"2025-06-10T17:11:47.693179Z","shell.execute_reply.started":"2025-06-10T17:11:47.385376Z","shell.execute_reply":"2025-06-10T17:11:47.692127Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with open(\"output.gif\", \"rb\") as f:\n    b64 = base64.b64encode(f.read()).decode(\"ascii\")\n    \ndisplay(dd.HTML(f'<img src=\"data:image/gif;base64,{b64}\" />'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-10T17:10:46.073379Z","iopub.execute_input":"2025-06-10T17:10:46.073699Z","iopub.status.idle":"2025-06-10T17:10:46.119533Z","shell.execute_reply.started":"2025-06-10T17:10:46.073677Z","shell.execute_reply":"2025-06-10T17:10:46.117969Z"}},"outputs":[],"execution_count":null}]}