{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Analysing Montecarlo Packets" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "`RPacketPlotter` plots the `RPackets` that are generated by the [Montecarlo](https://tardis-sn.github.io/tardis/physics/montecarlo/index.html) method and creates an animated plot that contains the packet trajectories as they move away from the photosphere.\n", "The properties of individual RPackets are taken from the [rpacket_tracker](https://tardis-sn.github.io/tardis/io/output/rpacket_tracking.html).\n", "\n", "`RPacketPlotter` uses the properties (specifically, `mu` and `r`) present in the `rpacket_tracker` to calculate the coordinates of packets as they move through the ejecta. In the following section, the mathematical expression for getting the angle(θ) of packets with respect to the x-axis is shown, which can be used (along with radius `r`) to calculate the x and y coordinates of packets." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Getting packet coordinates\n", "\n", "`RPacketPlotter` uses the properties (specifically, `θ` and `r`) present in the `rpacket_tracker` to calculate the coordinates of packets as they move through the ejecta. In the following section, the mathematical expression for getting the angle(α) of packets with respect to the x-axis is shown, which can be used (along with radius `r`) to calculate the x and y coordinates of packets.\n", "

\n", "\n", "\n", "
The diagram above shows the packet trajectory as it starts from photosphere `P0` and continues to move along the subsequent points `P1`, `P2`, and so on.\n", "\n", "
\n", "\n", "Note\n", " \n", "Here `θ` represents the direction of packet propagation with respect to the radial line.\n", " \n", "
\n", "\n", "To determine the polar coordinates of any arbitrary point, say `P2`, we need `r2` and `α2`. `r2` is already present in the array obtained from the simulation. To determine `α2`, we use the sine rule and apply it to the triangle `OP1P2`, where `O` is the center.\n", "\n", "$$\n", "\\frac{r_2}{\\sin(\\pi - \\theta_1)} = \\frac{r_1}{\\sin(\\beta)}\n", "$$\n", "\n", "Now, writing `α` in terms of `μ1` and `θ2`\n", "\n", "$$ \n", "\\beta = \\theta_1 - \\alpha_2\n", "$$\n", "$$\n", "\\frac{r_2}{\\sin(\\pi - \\theta_1)} = \\frac{r_1}{\\sin(\\theta_1 - \\alpha_2)}\n", "$$\n", "\n", "Thus,\n", "\n", "$$ \n", "\\alpha_2 = -\\sin^{-1} \\left( \\frac{r_1}{r_2} \\sin(\\theta_1) \\right) + \\theta_1\n", "$$\n", "\n", "Hence, for `i-th` point, `θ` will be:\n", "\n", "$$ \n", "\\alpha_i = -\\sin^{-1} \\left( \\frac{r_{i-1}}{r_i} \\sin(\\theta_{i-1}) \\right) + \\theta_{i-1}\n", "$$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import copy\n", "import math\n", "\n", "import astropy.units as u\n", "import numpy as np\n", "import plotly.graph_objects as go\n", "\n", "from tardis.visualization import plot_util as pu\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Every simulation run requires [atomic data](io/configuration/components/atomic/atomic_data.rst) and a [configuration file](io/configuration/index.rst). \n", "\n", "## Atomic Data\n", "\n", "We recommend using the [kurucz_cd23_chianti_H_He.h5](https://github.com/tardis-sn/tardis-regression-data/raw/main/atom_data/kurucz_cd23_chianti_H_He.h5) dataset." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from tardis.io.atom_data import download_atom_data\n", "\n", "# We download the atomic data needed to run the simulation\n", "download_atom_data(\"kurucz_cd23_chianti_H_He\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example Configuration File" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!wget -q -nc https://raw.githubusercontent.com/tardis-sn/tardis/master/docs/tardis_example.yml" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!cat tardis_example.yml" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from tardis.io.configuration.config_reader import Configuration\n", "\n", "# Reading the Configuration stored in `tardis_example.yml` into config\n", "config = Configuration.from_yaml(\"tardis_example.yml\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# changing config file for enabling the rpacket_tracking\n", "config[\"montecarlo\"][\"tracking\"][\"track_rpacket\"] = True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loading Simulation Data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Running simulation\n", "\n", "To run the simulation, import the `run_tardis` function and create the `sim` object." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Note:**\n", "\n", "Get more information about the [progress bars](io/output/progress_bars.rst), [logging configuration](io/optional/tutorial_logging_configuration.ipynb), and [convergence plots](io/visualization/tutorial_convergence_plot.ipynb).\n", "\n", "
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "from tardis import run_tardis\n", "\n", "sim = run_tardis(config, show_progress_bars=False, log_level=\"ERROR\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### HDF" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "TARDIS can save simulation data to HDF files for later analysis. The code below shows how to load a simulation from an HDF file. This is useful when you want to analyze simulation results without re-running the simulation.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import astropy.units as u\n", "# import pandas as pd\n", "\n", "# hdf_fpath = \"add_file_path_here\"\n", "# with pd.HDFStore(hdf_fpath, \"r\") as hdf:\n", "# sim = u.Quantity(hdf[\"/simulation\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setting up Theme Colors" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "theme_colors = dict(\n", " light=dict(\n", " linecolor=\"#555\",\n", " gridcolor=\"#fafafa\",\n", " zerolinecolor=\"#fafafa\",\n", " color=\"#000\",\n", " photosphere_line_color=\"black\",\n", " photosphere_fillcolor=\"darkgrey\",\n", " shells_line_color=\"black\",\n", " packet_line_color=\"darkslategrey\",\n", " plot_bgcolor=\"#fafafa\",\n", " paper_bgcolor=\"#fafafa\",\n", " title_font_color=\"#444\",\n", " legendgrouptitle_color=\"#444\",\n", " button_bgcolor=\"#fafafa\",\n", " button_font_color=\"#2A3F5F\",\n", " slider_font_color=\"#2A3F5F\",\n", " bordercolor=\"#BEC8D9\",\n", " slider_bgcolor=\"#F8FAFC\",\n", " slider_activebgcolor=\"#DBDDE0\",\n", " slider_currentvalue_color=\"#2A3F5F\",\n", " font_color=\"#000\",\n", " )\n", ")\n", "\n", "interaction_from_num = [\n", " {\"text\": \"No Interaction\", \"color\": \"darkslategrey\", \"opacity\": 0},\n", " {\"text\": \"e-Scattering\", \"color\": \"#3366FF\", \"opacity\": 1},\n", " {\"text\": \"Line Interaction\", \"color\": \"#FF3300\", \"opacity\": 1},\n", "]\n", "theme = \"light\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Base templates and configurations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Button Controls\n", "\n", "Play/Pause animation control buttons for the figure." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "BUTTONS = [\n", " {\n", " \"args\": [\n", " None,\n", " {\n", " \"frame\": {\"duration\": 500, \"redraw\": False},\n", " \"fromcurrent\": True,\n", " \"transition\": {\n", " \"duration\": 300,\n", " \"easing\": \"quadratic-in-out\",\n", " },\n", " },\n", " ],\n", " \"label\": \"Play\",\n", " \"method\": \"animate\",\n", " },\n", " {\n", " \"args\": [\n", " [None],\n", " {\n", " \"frame\": {\"duration\": 0, \"redraw\": False},\n", " \"mode\": \"immediate\",\n", " \"transition\": {\"duration\": 0},\n", " },\n", " ],\n", " \"label\": \"Pause\",\n", " \"method\": \"animate\",\n", " },\n", "]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Shell Shape Template\n", "\n", "Base shape dict used to draw ejecta shell circles." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "SHELL_CIRCLE_TEMPLATE = {\n", " \"type\": \"circle\",\n", " \"xref\": \"x\",\n", " \"yref\": \"y\",\n", " \"x0\": None,\n", " \"y0\": None,\n", " \"x1\": None,\n", " \"y1\": None,\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Hover Tooltip\n", "\n", "Tooltip content shown on packet hover." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "HOVER_TEMPLATE = (\n", " \"X: %{x}
Y: %{y}
Last Interaction: %{text}\"\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Legend Config\n", "\n", "Base config for a legend entry." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "BASE_LEGEND_CONFIG = dict(\n", " x=[9999999],\n", " y=[0],\n", " legendgroup=\"a\",\n", " opacity=1,\n", " mode=\"lines+markers\",\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Slider Step\n", "\n", "Template for each step in the animation slider." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "SLIDER_STEP_TEMPLATE = {\n", " \"args\": [\n", " None,\n", " {\n", " \"frame\": {\"duration\": 300, \"redraw\": False},\n", " \"mode\": \"immediate\",\n", " \"transition\": {\"duration\": 300},\n", " },\n", " ],\n", " \"label\": None,\n", " \"method\": \"animate\",\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Slider Styling and Behavior\n", "\n", "Full slider configuration for animation steps." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "SLIDERS_TEMPLATE = {\n", " \"active\": 0,\n", " \"activebgcolor\": theme_colors[theme][\"slider_activebgcolor\"],\n", " \"bgcolor\": theme_colors[theme][\"slider_bgcolor\"],\n", " \"bordercolor\": theme_colors[theme][\"bordercolor\"],\n", " \"yanchor\": \"top\",\n", " \"xanchor\": \"left\",\n", " \"currentvalue\": {\n", " \"font\": {\n", " \"color\": theme_colors[theme][\"slider_currentvalue_color\"],\n", " },\n", " \"prefix\": \"Step:\",\n", " \"visible\": True,\n", " \"xanchor\": \"right\",\n", " },\n", " \"font\": {\"color\": theme_colors[theme][\"slider_font_color\"]},\n", " \"transition\": {\"duration\": 300, \"easing\": \"cubic-in-out\"},\n", " \"pad\": {\"b\": 10, \"t\": 50},\n", " \"len\": 0.9,\n", " \"x\": 0.1,\n", " \"y\": 0,\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Axis Styling\n", "\n", "Base styling for x and y axis." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "BASE_AXIS_CONFIG = {\n", " \"exponentformat\": \"none\",\n", " \"color\": theme_colors[theme][\"color\"],\n", " \"linecolor\": theme_colors[theme][\"linecolor\"],\n", " \"gridcolor\": theme_colors[theme][\"gridcolor\"],\n", " \"zerolinecolor\": theme_colors[theme][\"zerolinecolor\"],\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Calculating Packet Coordinates and Interactions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Setting up initial parameters for packet tracking" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "no_of_packets = 20\n", "# getting velocity of different shells\n", "v_shells = sim.simulation_state.velocity.to_value(u.km / u.s)\n", "r_packet_tracker = sim.transport.transport_state.rpacket_tracker_df.loc[\n", " 0:(no_of_packets)\n", "]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Calculating packet trajectories and interactions" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# for plotting packets at equal intervals throught the circle, we choose alphas distributed uniformly\n", "alphas = np.linspace(0, 2 * math.pi, no_of_packets + 1)\n", "rpackets_x = []\n", "rpackets_y = []\n", "rpackets_interactions = []\n", "# getting coordinates and interaction arrays for all packets\n", "for packet_no in range(no_of_packets):\n", " r_track = r_packet_tracker.loc[packet_no][\"r\"]\n", " mu_track = r_packet_tracker.loc[packet_no][\"mu\"]\n", " time = sim.simulation_state.time_explosion.value\n", " last_interaction_type = r_packet_tracker.loc[packet_no][\"interaction_type\"]\n", " alpha_initial = alphas[packet_no]\n", "\n", " (\n", " single_rpacket_x,\n", " single_rpacket_y,\n", " single_alpha,\n", " single_rpacket_interactions,\n", " ) = [], [], [], []\n", "\n", " # getting alphas at different steps of the packet movement\n", " for step_no in range(len(r_track)):\n", " # for the first step the packet is at photosphere, so alpha will be equal to the intial angle we are launching the packet from\n", " if step_no == 0:\n", " single_alpha.append(alpha_initial)\n", " # for further steps we calculate alphas with the formula derived in the documentation\n", " else:\n", " if r_track[step_no] < r_track[step_no - 1]:\n", " single_alpha.append(\n", " single_alpha[-1]\n", " - math.pi\n", " + math.asin(\n", " r_track[step_no - 1]\n", " * math.sin(math.acos(mu_track[step_no - 1]))\n", " / r_track[step_no]\n", " )\n", " + math.acos(mu_track[step_no - 1])\n", " )\n", " else:\n", " single_alpha.append(\n", " single_alpha[-1]\n", " + math.asin(\n", " -1\n", " * r_track[step_no - 1]\n", " * math.sin(math.acos(mu_track[step_no - 1]))\n", " / r_track[step_no]\n", " )\n", " + math.acos(mu_track[step_no - 1])\n", " )\n", "\n", " # converting the alphas into x and y coordinates using radius as radius*cos(alpha) and radius*sin(alpha) respectively\n", " single_rpacket_x = (\n", " (np.array(r_track)) * np.cos(np.array(single_alpha)) * 1e-5 / time\n", " )\n", " single_rpacket_y = (\n", " (np.array(r_track)) * np.sin(np.array(single_alpha)) * 1e-5 / time\n", " )\n", "\n", " # adding interactions at different steps\n", " # using the change of slope of the trajectory line at different steps, we determine if an interactions happened or not.\n", "\n", " for step_no in range(len(r_track)):\n", " # when packet is at its starting and ending point in its trajectory, we consider it as no interaction\n", " if step_no == 0 or step_no == len(r_track) - 1:\n", " single_rpacket_interactions.append(0)\n", " else:\n", " # current slope is the slope of line from previous position of the packet to the current position\n", " single_rpacket_interactions.append(last_interaction_type[step_no])\n", "\n", " rpackets_x.append(single_rpacket_x)\n", " rpackets_y.append(single_rpacket_y)\n", " rpackets_interactions.append(single_rpacket_interactions)\n", "\n", "np_rpackets_x = np.array(rpackets_x, dtype=\"object\")\n", "np_rpackets_y = np.array(rpackets_y, dtype=\"object\")\n", "np_rpackets_interactions = np.array(rpackets_interactions, dtype=\"object\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Padding Arrays to Uniform Length" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Get the maximum number of steps among all packets\n", "rpacket_step_no_array_max_size = max(list(map(len, np_rpackets_x)))\n", "\n", "for packet_no in range(len(np_rpackets_x)):\n", " # making all coordinate arrays of size `rpacket_step_no_array_max_size` by repeating the last element across the remaining length of array\n", " np_rpackets_x[packet_no] = np.append(\n", " np_rpackets_x[packet_no],\n", " np_rpackets_x[packet_no][-1]\n", " * np.ones(\n", " [rpacket_step_no_array_max_size - len(np_rpackets_x[packet_no])]\n", " ),\n", " )\n", " np_rpackets_y[packet_no] = np.append(\n", " np_rpackets_y[packet_no],\n", " np_rpackets_y[packet_no][-1]\n", " * np.ones(\n", " [rpacket_step_no_array_max_size - len(np_rpackets_y[packet_no])]\n", " ),\n", " )\n", " np_rpackets_interactions[packet_no] = np.append(\n", " np_rpackets_interactions[packet_no],\n", " np_rpackets_interactions[packet_no][-1]\n", " * np.ones(\n", " [\n", " rpacket_step_no_array_max_size\n", " - len(np_rpackets_interactions[packet_no])\n", " ]\n", " ),\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Visualizing Packet Trajectories" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Timeline slider" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "slider_steps = [\n", " {\n", " **SLIDER_STEP_TEMPLATE,\n", " \"args\": [[step_no], SLIDER_STEP_TEMPLATE[\"args\"][1]],\n", " \"label\": step_no,\n", " }\n", " for step_no in range(rpacket_step_no_array_max_size)\n", "]\n", "\n", "slider = {\n", " **SLIDERS_TEMPLATE,\n", " \"steps\": slider_steps,\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fig = go.Figure()\n", "# Set axes properties\n", "label = pu.axis_label_in_latex(\"Velocity\", u.Unit(\"km/s\"), only_text=True)\n", "\n", "fig.update_xaxes(\n", " scaleanchor=\"y\",\n", " scaleratio=1,\n", " range=[-1.1 * v_shells[-1], 1.1 * v_shells[-1]],\n", " title=label,\n", " **BASE_AXIS_CONFIG,\n", ")\n", "\n", "fig.update_yaxes(\n", " range=[-1.1 * v_shells[-1], 1.1 * v_shells[-1]],\n", " title=label,\n", " **BASE_AXIS_CONFIG,\n", ")\n", "\n", "\n", "# adding the shells and photosphere\n", "for shell_no in range(len(sim.simulation_state.radius.value)):\n", " shell_radius = v_shells[shell_no]\n", "\n", " # Update only the required attributes\n", " shape = copy.deepcopy(SHELL_CIRCLE_TEMPLATE)\n", " shape[\"x0\"] = -1 * shell_radius\n", " shape[\"y0\"] = -1 * shell_radius\n", " shape[\"x1\"] = shell_radius\n", " shape[\"y1\"] = shell_radius\n", " if shell_no == 0:\n", " # photosphere\n", " fig.add_shape(\n", " **shape,\n", " line_color=theme_colors[theme][\"photosphere_line_color\"],\n", " fillcolor=theme_colors[theme][\"photosphere_fillcolor\"],\n", " opacity=1,\n", " )\n", " elif shell_no == (len(sim.simulation_state.radius.value) - 1):\n", " # outermost shell\n", " fig.add_shape(\n", " **shape,\n", " line_color=theme_colors[theme][\"shells_line_color\"],\n", " opacity=1,\n", " )\n", " else:\n", " # remaining shells\n", " fig.add_shape(\n", " **shape,\n", " line_color=theme_colors[theme][\"shells_line_color\"],\n", " opacity=0.2,\n", " )\n", "\n", "\n", "for packet_no in range(len(np_rpackets_x)):\n", " fig.add_trace(\n", " go.Scatter(\n", " x=np_rpackets_x[packet_no],\n", " y=np_rpackets_y[packet_no],\n", " mode=\"markers+lines\",\n", " name=\"Packet \" + str(packet_no + 1),\n", " showlegend=False,\n", " hovertemplate=HOVER_TEMPLATE,\n", " text=[\n", " interaction_from_num[\n", " int(np_rpackets_interactions[packet_no][step_no])\n", " ][\"text\"]\n", " for step_no in range(len(np_rpackets_x[packet_no]))\n", " ],\n", " line=dict(color=theme_colors[theme][\"packet_line_color\"]),\n", " marker=dict(\n", " opacity=[\n", " interaction_from_num[\n", " int(np_rpackets_interactions[packet_no][step_no])\n", " ][\"opacity\"]\n", " for step_no in range(len(np_rpackets_x[packet_no]))\n", " ],\n", " color=[\n", " interaction_from_num[\n", " int(np_rpackets_interactions[packet_no][step_no])\n", " ][\"color\"]\n", " for step_no in range(len(np_rpackets_x[packet_no]))\n", " ],\n", " ),\n", " )\n", " )\n", "\n", "# adding legends\n", "fig.add_trace(\n", " go.Scatter(\n", " **BASE_LEGEND_CONFIG,\n", " name=\"e-scattering\",\n", " hoverlabel={\"font\": {\"color\": \"#222\"}},\n", " marker={\"color\": \"#3366FF\"},\n", " legendgrouptitle={\n", " \"font\": {\"color\": theme_colors[theme][\"legendgrouptitle_color\"]},\n", " \"text\": \"Interaction Type:\",\n", " },\n", " )\n", ")\n", "\n", "# Add line interaction trace\n", "fig.add_trace(\n", " go.Scatter(\n", " **BASE_LEGEND_CONFIG,\n", " name=\"Line Interaction\",\n", " marker={\"color\": \"#FF3300\"},\n", " )\n", ")\n", "\n", "# Set figure size\n", "fig.layout.plot_bgcolor = theme_colors[theme][\"plot_bgcolor\"]\n", "fig.layout.paper_bgcolor = theme_colors[theme][\"paper_bgcolor\"]\n", "\n", "fig.update_layout(\n", " width=820,\n", " height=680,\n", " title=\"Packet Trajectories\",\n", " title_font_color=theme_colors[theme][\"title_font_color\"],\n", " font_color=theme_colors[theme][\"font_color\"],\n", " updatemenus=[\n", " dict(\n", " type=\"buttons\",\n", " xanchor=\"right\",\n", " x=0.1,\n", " y=0,\n", " yanchor=\"top\",\n", " direction=\"left\",\n", " pad={\"r\": 10, \"t\": 87},\n", " showactive=False,\n", " bgcolor=theme_colors[theme][\"button_bgcolor\"],\n", " bordercolor=theme_colors[theme][\"bordercolor\"],\n", " font={\"color\": theme_colors[theme][\"button_font_color\"]},\n", " buttons=BUTTONS,\n", " )\n", " ],\n", ")\n", "\n", "# adding frames\n", "all_frames = []\n", "for frame in range(rpacket_step_no_array_max_size + 1):\n", " frame_data = []\n", " for packet_no in range(len(np_rpackets_x)):\n", " # adding a scatter object containing the trajectory of a packet upto a particular frame number\n", " frame_data.append(\n", " go.Scatter(\n", " x=np_rpackets_x[packet_no].tolist()[0:frame],\n", " y=np_rpackets_y[packet_no].tolist()[0:frame],\n", " mode=\"markers+lines\",\n", " name=\"Packet \" + str(packet_no + 1),\n", " showlegend=False,\n", " hovertemplate=HOVER_TEMPLATE,\n", " text=[\n", " interaction_from_num[\n", " int(np_rpackets_interactions[packet_no][step_no])\n", " ][\"text\"]\n", " for step_no in range(len(np_rpackets_x[packet_no]))\n", " ],\n", " line=dict(color=theme_colors[theme][\"packet_line_color\"]),\n", " marker=dict(\n", " opacity=[\n", " interaction_from_num[\n", " int(np_rpackets_interactions[packet_no][step_no])\n", " ][\"opacity\"]\n", " for step_no in range(len(np_rpackets_x[packet_no]))\n", " ],\n", " color=[\n", " interaction_from_num[\n", " int(np_rpackets_interactions[packet_no][step_no])\n", " ][\"color\"]\n", " for step_no in range(len(np_rpackets_x[packet_no]))\n", " ],\n", " ),\n", " )\n", " )\n", " all_frames.append(go.Frame(data=frame_data, name=frame))\n", "\n", "fig.frames = all_frames\n", "\n", "fig.layout.sliders = [slider]\n", "\n", "fig.show(renderer=\"notebook_connected\")" ] } ], "metadata": { "kernelspec": { "display_name": "tardis", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.2" } }, "nbformat": 4, "nbformat_minor": 4 }