{"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":"IceCube Events Interactive Animation\n\n\nIf you want to visualize an IceCube event such that you can track sensor readings and how they change with time, look no further. \n\nPlease find below the code to visualize any IceCube event  ","metadata":{}},{"cell_type":"code","source":"%matplotlib inline\n\nimport os\nimport glob\nimport math\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport plotly.express as px\n\nPATH_DATASET = \"/kaggle/input/\"","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-04-19T07:49:57.555054Z","iopub.execute_input":"2023-04-19T07:49:57.555465Z","iopub.status.idle":"2023-04-19T07:49:57.563398Z","shell.execute_reply.started":"2023-04-19T07:49:57.555428Z","shell.execute_reply":"2023-04-19T07:49:57.562019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Make sure the \"num\" of both train_meta_{num}.parquet and batch_{num}.parquet match\ntrain = pd.read_parquet(os.path.join(PATH_DATASET, \"icecube-neutrinos-in-deep-ice/train/batch_1.parquet\"))\ngeometry = pd.read_csv(os.path.join(PATH_DATASET, \"icecube-neutrinos-in-deep-ice/sensor_geometry.csv\"))\nmeta_train = pd.read_parquet(os.path.join(PATH_DATASET, \"train-meta-parquet/train_meta_1.parquet\"))","metadata":{"execution":{"iopub.status.busy":"2023-04-19T07:50:00.368349Z","iopub.execute_input":"2023-04-19T07:50:00.369000Z","iopub.status.idle":"2023-04-19T07:50:01.768296Z","shell.execute_reply.started":"2023-04-19T07:50:00.368960Z","shell.execute_reply":"2023-04-19T07:50:01.767128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = px.scatter_3d(geometry, x='x', y='y', z='z', opacity=0.6, color=\"sensor_id\")\nfig.update_traces(marker_size=2)\nfig.update_layout(height=1000, width=1000)\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2023-04-19T07:50:04.787566Z","iopub.execute_input":"2023-04-19T07:50:04.787991Z","iopub.status.idle":"2023-04-19T07:50:06.156992Z","shell.execute_reply.started":"2023-04-19T07:50:04.787949Z","shell.execute_reply":"2023-04-19T07:50:06.155890Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def directions(meta):\n    azimuth = meta[\"azimuth\"]\n    zenith = meta[\"zenith\"]\n    dx = math.sin(zenith) * math.cos(azimuth)\n    dy = math.sin(zenith) * math.sin(azimuth)\n    dz = math.cos(zenith)\n    return dx, dy, dz\n\ndef animate_event(evt):\n    return px.scatter_3d(evt,\n                x=\"x\", y=\"y\", z=\"z\",\n                hover_name=\"sensor_id\",\n                opacity=0.6,\n                animation_frame=\"time\",\n                size=\"charge\",\n                size_max=55,\n                range_x=[min(evt['x']-100), max(evt['x']+100)],\n                range_y=[min(evt['y']-100), max(evt['y']+100)],\n                range_z=[min(evt['z']-100), max(evt['z']+100)],\n                color=\"update_at\",\n                range_color=[min(evt['time']), max(evt['time'])],\n            )\n\ndef create_vis_df(event):\n    list_t = sorted(list(set(list(event['time']))))\n    charge_per_sensor = [0]*5160 #state of charge detected at each sensor\n    update_per_sensor = [0]*5160 #time at which event was last detected at each sensor\n    vis_lod = []                 #vis_df list of dictionaries\n    for ts, t in enumerate(list_t):\n        evt_slice = event[event['time'] == t]\n        evt_slice.reset_index(inplace=True)\n        for s_id in range(0, 5160):\n            if s_id in list(evt_slice.sensor_id):\n                evt_charge = evt_slice.loc[evt_slice.sensor_id == s_id, \"charge\"].values[0]\n                charge_per_sensor[s_id] = evt_charge\n                update_per_sensor[s_id] = t               \n            new_row = {\"sensor_id\": s_id, \"charge\": charge_per_sensor[s_id], \"time\": t, \"time_step\": ts, \"update_at\": update_per_sensor[s_id]}\n            vis_lod.append(new_row)\n\n    vis_df = pd.DataFrame(vis_lod, columns=[\"sensor_id\", \"charge\", \"time\", \"time_step\", \"update_at\"])\n    return vis_df\n\ndef verify_correctness(train, vis_df):\n    train_l = [train['sensor_id'], train['time'], train['charge']]\n    train_lot = set(zip(*train_l))\n    vis_df_l = [vis_df['sensor_id'], vis_df['update_at'], vis_df['charge']]\n    vis_df_lot = set(zip(*vis_df_l))\n\n    diff = train_lot.difference(vis_df_lot)\n\n    assert diff == set()\n\n\ndef show_event(event_id=72, data=train, sensors=geometry, metadata=meta_train):\n    meta = dict(metadata[metadata[\"event_id\"] == event_id].iloc[0])\n    event = data[data.index == event_id]\n    event = event.merge(sensors, on=\"sensor_id\")\n    event.loc[:, 'charge'] /= event['charge'].max() #normalize\n    dx, dy, dz = directions(meta)\n\n    event.sort_values(by='time', axis='index', ascending=True, inplace=True, ignore_index=True)\n    vis_df = create_vis_df(event=event)\n    vis_df = vis_df.merge(sensors, on=\"sensor_id\")\n#     verify_correctness(event, vis_df) #uncomment to check for correctness \n    fig = animate_event(evt=vis_df)\n    fig.update_layout(\n        height=900, width=1000, showlegend=False, title_text=f\"Event #{event_id}\"\n        f\" / azimuth={meta['azimuth']:0.3}; zenith={meta['zenith']:0.3}\\n\"\n        f\"-> x={dx:0.2}; y={dy:0.2}; z={dz:0.2}\",\n    )\n    fig.show(\"notebook\")","metadata":{"execution":{"iopub.status.busy":"2023-04-19T07:52:18.208607Z","iopub.execute_input":"2023-04-19T07:52:18.209041Z","iopub.status.idle":"2023-04-19T07:52:18.230413Z","shell.execute_reply.started":"2023-04-19T07:52:18.209002Z","shell.execute_reply":"2023-04-19T07:52:18.228941Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* In the below visualization, I have taken all the *time* at which an event was detected in any sensor and saved the state of the IceCube detector sensors at that point as an animation frame.\n\n* The *update_at* parameter tells you when that sensor was last updated and is color coded\n\n* The size of the circle indicates the magnitude of charge picked up by sensors.\n \n* As you vary the animation frames you can see how the charge at a any given sensor changes.","metadata":{}},{"cell_type":"code","source":"show_event(event_id=24)","metadata":{"execution":{"iopub.status.busy":"2023-04-19T07:52:18.790781Z","iopub.execute_input":"2023-04-19T07:52:18.791963Z","iopub.status.idle":"2023-04-19T07:52:23.975504Z","shell.execute_reply.started":"2023-04-19T07:52:18.791903Z","shell.execute_reply":"2023-04-19T07:52:23.973304Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}