knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5 )
library(orbitr)
plot_orbits() and plot_orbits_3d() are convenience functions for quick trajectory plots — they're designed to get you a useful visualization in one line so you can focus on setting up the physics. But the real power of orbitr is that simulate_system() returns a standard tidy tibble. You can use ggplot2, plotly, or any other visualization tool directly on the output.
Here's what the simulation tibble looks like:
sim <- create_system() |> add_body("Earth", mass = mass_earth) |> add_body("Moon", mass = mass_moon, x = distance_earth_moon, vy = speed_moon) |> simulate_system(time_step = seconds_per_hour, duration = seconds_per_day * 28) sim
Each row is one body at one point in time. Every column is available for plotting, filtering, or analysis. Since this is just a tibble, you have the full power of dplyr and ggplot2 at your disposal.
For example, in the Earth-Moon system, plot_orbits() shows overlapping circles because both bodies orbit their shared barycenter at roughly the same scale. A more useful visualization might plot each body's distance from the barycenter over time:
library(ggplot2) sim |> dplyr::mutate(r = sqrt(x^2 + y^2)) |> ggplot(aes(x = time / seconds_per_day, y = r, color = id)) + geom_line(linewidth = 1) + labs( title = "Distance from Barycenter Over Time", x = "Time (days)", y = "Distance (m)", color = "Body" ) + theme_minimal()
Or plot the Moon's path relative to Earth with a color gradient showing the passage of time:
sim |> shift_reference_frame("Earth", keep_center = FALSE) |> ggplot(aes(x = x, y = y, color = time / seconds_per_day)) + geom_path(linewidth = 1.2) + scale_color_viridis_c(name = "Day") + coord_equal() + labs(title = "Lunar Orbit (Earth-Centered)", x = "X (m)", y = "Y (m)") + theme_minimal()
Just as plot_orbits() is a quick convenience for 2D work, plot_orbits_3d() is a quick convenience for 3D. Both are intentionally simple — they get you a useful plot in one line so you can focus on the physics, not the formatting. When you need more control, the simulation tibble works just as well with plotly as it does with ggplot2.
For example, you could color trajectories by speed rather than by body:
library(plotly) sim <- create_system() |> add_body("Earth", mass = mass_earth) |> add_body("Moon", mass = mass_moon, x = distance_earth_moon, vy = speed_moon * cos(5 * pi / 180), vz = speed_moon * sin(5 * pi / 180)) |> simulate_system(time_step = seconds_per_hour, duration = seconds_per_day * 28) sim <- sim |> dplyr::mutate(speed = sqrt(vx^2 + vy^2 + vz^2)) plot_ly() |> add_trace( data = dplyr::filter(sim, id == "Moon"), x = ~x, y = ~y, z = ~z, type = 'scatter3d', mode = 'lines', line = list( width = 5, color = ~speed, colorscale = 'Viridis', showscale = TRUE, colorbar = list(title = "Speed (m/s)") ), name = "Moon" ) |> add_trace( data = dplyr::filter(sim, id == "Earth"), x = ~x, y = ~y, z = ~z, type = 'scatter3d', mode = 'lines', line = list(width = 3, color = 'gray'), name = "Earth" ) |> layout( title = "Lunar Orbit Around Earth", showlegend = FALSE, scene = list( xaxis = list(title = 'X (m)'), yaxis = list(title = 'Y (m)'), zaxis = list(title = 'Z (m)'), aspectmode = "data" ) )
The point is the same as with ggplot2: simulate_system() returns a standard tibble, so you have full access to plotly's API for anything the built-in plotting functions don't cover.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.