{"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":91249,"databundleVersionId":11294684,"sourceType":"competition"}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as patches","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-04T00:12:00.803345Z","iopub.execute_input":"2025-04-04T00:12:00.803789Z","iopub.status.idle":"2025-04-04T00:12:01.237563Z","shell.execute_reply.started":"2025-04-04T00:12:00.803745Z","shell.execute_reply":"2025-04-04T00:12:01.236295Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TRAIN_DIR = '/kaggle/input/byu-locating-bacterial-flagellar-motors-2025/train'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T00:12:01.238911Z","iopub.execute_input":"2025-04-04T00:12:01.239540Z","iopub.status.idle":"2025-04-04T00:12:01.244642Z","shell.execute_reply.started":"2025-04-04T00:12:01.239501Z","shell.execute_reply":"2025-04-04T00:12:01.243523Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(\"/kaggle/input/byu-locating-bacterial-flagellar-motors-2025/train_labels.csv\")\nprint(df.shape)\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T00:12:01.246123Z","iopub.execute_input":"2025-04-04T00:12:01.246502Z","iopub.status.idle":"2025-04-04T00:12:01.299955Z","shell.execute_reply.started":"2025-04-04T00:12:01.246468Z","shell.execute_reply":"2025-04-04T00:12:01.298760Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_motors = df[df['Number of motors'] > 0].copy()\ndf_motors = df_motors.sort_values(['tomo_id', 'Motor axis 0']).reset_index(drop=True)\nprint(df_motors.shape)\ndf_motors.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T00:12:01.301478Z","iopub.execute_input":"2025-04-04T00:12:01.301875Z","iopub.status.idle":"2025-04-04T00:12:01.328837Z","shell.execute_reply.started":"2025-04-04T00:12:01.301835Z","shell.execute_reply":"2025-04-04T00:12:01.327712Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('min(cy - 0):', df_motors['Motor axis 1'].min())\nprint('min(cx - 0):', df_motors['Motor axis 2'].min())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T00:12:01.329946Z","iopub.execute_input":"2025-04-04T00:12:01.330361Z","iopub.status.idle":"2025-04-04T00:12:01.337601Z","shell.execute_reply.started":"2025-04-04T00:12:01.330316Z","shell.execute_reply":"2025-04-04T00:12:01.336546Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('min(yshape - cy):', (df_motors['Array shape (axis 1)'] - df_motors['Motor axis 1']).min())\nprint('min(xshape - cx):', (df_motors['Array shape (axis 2)'] - df_motors['Motor axis 2']).min())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T00:12:01.338803Z","iopub.execute_input":"2025-04-04T00:12:01.339201Z","iopub.status.idle":"2025-04-04T00:12:01.356645Z","shell.execute_reply.started":"2025-04-04T00:12:01.339163Z","shell.execute_reply":"2025-04-04T00:12:01.355332Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Util Function","metadata":{}},{"cell_type":"code","source":"def plot_motor(index, bbox_size=60, z_offsets=range(0, 1)):\n    \"\"\"Plot a motor slice with a bounding box and its cropped region.\n\n    Parameters:\n    - index (int): Index of the motor data from `df_motors`.\n    - bbox_size (int, optional): Size of the bounding box (default is 60).\n    - z_offsets (iterable, optional): Range of z-axis offsets to plot (default is range(0, 1)).\n\n    Examples:\n    - range(0, 1) → [0]\n    - range(-3, 4) → [-3, -2, -1, 0, 1, 2, 3] (Plots 7 slices around z)\n    \"\"\"\n    for z_offset in z_offsets:\n        ser = df_motors.loc[index]\n        tomo_id = ser['tomo_id']\n        cz = int(ser['Motor axis 0'])\n        z = cz + z_offset        \n        cy = int(ser['Motor axis 1'])\n        cx = int(ser['Motor axis 2'])\n        zshape = int(ser['Array shape (axis 0)'])\n        yshape = int(ser['Array shape (axis 1)'])\n        xshape = int(ser['Array shape (axis 2)'])\n\n        if z < 0 or z >= zshape:\n            print(f'Warning! {tomo_id}. z({z}) is out of range')\n            continue;\n\n        slice_filename = f\"{TRAIN_DIR}/{tomo_id}/slice_{z:04d}.jpg\"\n\n        half_w = bbox_size / 2\n        half_h = bbox_size / 2\n\n        if cx - half_w < 0:\n            half_w = cx\n        elif cx + half_w >= xshape:\n            half_w = xshape - cx\n\n        if cy - half_h < 0:\n            half_h = cy\n        elif cy + half_h >= yshape:\n            half_h = yshape - cy\n        \n        x1 = cx - half_w\n        y1 = cy - half_h\n        x2 = cx + half_w        \n        y2 = cy + half_h\n        \n        fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(12, 6), )\n        img = plt.imread(slice_filename)\n        axes[0].imshow(img, cmap='gray')\n        axes[0].set_title(f'({index}) {tomo_id} ({cz}{z_offset:+d}, {cy}, {cx})')\n        \n        rect = patches.Rectangle(\n            xy=(x1, y1), width=(x2 - x1), height=(y2 - y1), \n            linewidth=1, edgecolor='lightgreen', facecolor='none',\n        )\n        axes[0].add_patch(rect)\n\n        cropped = img[int(y1):int(y2+1), int(x1):int(x2+1)]\n        axes[1].imshow(\n            cropped, cmap='bone',  # gray, bone, viridis, cividis, hot\n            interpolation='bicubic'  # none, bilinear(default), bicubic\n        )\n        \n        plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T00:12:01.357758Z","iopub.execute_input":"2025-04-04T00:12:01.358068Z","iopub.status.idle":"2025-04-04T00:12:01.382094Z","shell.execute_reply.started":"2025-04-04T00:12:01.358037Z","shell.execute_reply":"2025-04-04T00:12:01.380827Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## motor slices (index 0 ~ 19)","metadata":{}},{"cell_type":"code","source":"for i in range(20):\n    plot_motor(i, bbox_size=60)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T00:12:01.384581Z","iopub.execute_input":"2025-04-04T00:12:01.384945Z","iopub.status.idle":"2025-04-04T00:12:14.096331Z","shell.execute_reply.started":"2025-04-04T00:12:01.384909Z","shell.execute_reply":"2025-04-04T00:12:14.095037Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## box sizes","metadata":{}},{"cell_type":"code","source":"for box_size in [24, 48, 60, 100]:\n    plot_motor(13, bbox_size=box_size)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T00:12:14.097400Z","iopub.execute_input":"2025-04-04T00:12:14.097699Z","iopub.status.idle":"2025-04-04T00:12:16.424596Z","shell.execute_reply.started":"2025-04-04T00:12:14.097664Z","shell.execute_reply":"2025-04-04T00:12:16.423164Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## nearby slices","metadata":{}},{"cell_type":"code","source":"plot_motor(14, bbox_size=60, z_offsets=range(-4, 5))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T00:12:16.425640Z","iopub.execute_input":"2025-04-04T00:12:16.425928Z","iopub.status.idle":"2025-04-04T00:12:21.906361Z","shell.execute_reply.started":"2025-04-04T00:12:16.425903Z","shell.execute_reply":"2025-04-04T00:12:21.905228Z"}},"outputs":[],"execution_count":null}]}