---
title: "Custom Visualization with ggplot2 and plotly"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Custom Visualization with ggplot2 and plotly}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7,
  fig.height = 5
)
```

```{r}
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.

## The Raw Output

Here's what the simulation tibble looks like:

```{r}
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.

## Custom ggplot2 Visualizations

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:

```{r}
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:

```{r}
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()
```

## Custom plotly Visualizations

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:

```{r}
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.
