Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coord calendar #1

Open
cynthiahqy opened this issue Mar 29, 2024 · 5 comments
Open

coord calendar #1

cynthiahqy opened this issue Mar 29, 2024 · 5 comments

Comments

@cynthiahqy
Copy link

cynthiahqy commented Mar 29, 2024

Use a wrapped cartesian coordinate system to plot temporal data in calendar like layouts instead of calculated variables (e.g. https://github.com/cynthiahqy/ggtilecal)

Should support:

  • week in year layout with month line breaks;
  • faceted months, years
  • position after each wrap point -- 0 for over plot, 1, -1 for direction
  • ragged layout
  • split rendering of geometries across rows (maybe not possible in ggplot2)
  • most other geoms out of the box (e.g. moon phases which calendR has options for)

Needs:

  • Wrap point helpers similar to lubridate::floor_date() Gregorian calendar
  • hack grouping to fix rendering limitations (for portals!)

Stretch goal -- wrapping non-gregorian calendar layouts:

  • needs different datetime rounding system:
    • helpers for specifying "floor" functions e.g. floor_date_lunar()
    • return the nearest wrapping points
    • wrapping points via sequence generator OR lookup table
@mitchelloharawild
Copy link
Member

mitchelloharawild commented Mar 29, 2024

Possibly needs two 'limits' - one for limits applied to continuous time (what the associated scale expects), and another on wrapped time (what the x-axis is after mapping from cartesian to the calendar coordinate space). This nuance could prove tricky to implement.

@cynthiahqy
Copy link
Author

cynthiahqy commented Apr 9, 2024

There might be some utility in having a time aesthetic, which defaults to x if unavailable. It frees up the x & y channels for things pie charts for daily data, or side by side columns like:

image

If we can use the "y"-axis to nest both data & time labels, then why not also the "x"-axis ?

Maybe also some utility in exploring calendar layouts using nested facet for similar reasons (freeing up the x/y channels). Personal data/storytelling scale lends itself to facet solutions, while big data/analytics/modelling lends itself more to coordinate solutions?

@mitchelloharawild
Copy link
Member

Pie charts are a bit trickier than bar charts since there is a conflict in coordinate systems. The layout of pie charts respects a cartesian/calendar coordinate layout in time while the layout of x/y is in polar coordinates. Typical calendars are built on a cartesian coordinate system, and I'm not sure what a calendar built on a polar coordinate system would look like.

An idea for a calendar in polar coordinates could be:

  • Each 'wrapped' breakpoint needs to cover a complete rotation of the polar coordinate system (justified length/duration)
  • The calendar row is no longer a discrete jump to the next series, but instead perhaps a gradual increase over the wrapped time period.

Perhaps this is what a calendar looks like when built upon a polar coordinate system. The y-axis on the coordinate system is comprised within the black bands shown below.

library(ggplot2)
data.frame(
  y = 1:120,
  x = rep(1:12, 10),
  year = rep(2015:2024, each = 12)
) |> 
  ggplot(aes(x = x, y = y, group = year)) + 
  geom_line(linewidth = 5) + 
  coord_polar()

Or altenatively you can transform the calendar y-axis spacing to de-emphasise older observations in time.

data.frame(
  y = 1:120,
  x = rep(1:12, 10),
  year = rep(2015:2024, each = 12)
) |> 
  ggplot(aes(x = x, y = y, group = year, linewidth = y)) + 
  geom_line() + 
  coord_polar() + 
  scale_linewidth(range = c(1, 10)) +
  scale_y_continuous(transform = scales::transform_boxcox(2))

For example…

data.frame(
  y = 1:120 + runif(120, -6, 6),
  x = rep(1:12, 10),
  year = rep(2015:2024, each = 12)
) |> 
  ggplot(aes(x = x, y = y, group = year)) + 
  geom_line() + 
  coord_polar()

data.frame(
  y = 11:130 + runif(120, -6, 6),
  x = rep(1:12, 10),
  year = rep(2015:2024, each = 12)
) |> 
  ggplot(aes(x = x, y = y, group = year)) + 
  geom_line() + 
  coord_polar() + 
  scale_y_continuous(transform = scales::transform_boxcox(2))

Created on 2024-04-10 with reprex v2.0.2

@mitchelloharawild
Copy link
Member

The 'rendering' style issue with lines between wrap points for these coordinate systems could have some solutions in {sf}.

library(ggplot2)
library(sf)
#> Linking to GEOS 3.12.1, GDAL 3.8.4, PROJ 9.4.0; sf_use_s2() is TRUE
library(maps)
library(geosphere)

# Convert the world map to an sf object
world1 <- sf::st_as_sf(map('world', plot = FALSE, fill = TRUE))

# Define the coordinates for Melbourne and San Francisco
melbourne <- c(144.9631, -37.8136) # Longitude, Latitude
san_francisco <- c(-122.4194, 37.7749) # Longitude, Latitude

# Calculate the great circle route
gc_path <- gcIntermediate(
  melbourne, 
  san_francisco, 
  n = 100, 
  addStartEnd = TRUE, 
  breakAtDateLine = TRUE,
  sp = TRUE # Return as a SpatialLines object
)

# Convert the great circle route to an sf object
gc_path_sf <- st_as_sf(gc_path)

# Plot the map with the flight path
ggplot() +
  geom_sf(data = world1, fill = "lightgray", color = "white") +
  geom_sf(data = gc_path_sf, color = "blue", size = 1.2) +
  theme_minimal() +
  labs(
    title = "Flight Path from Melbourne to San Francisco",
    subtitle = "Great Circle Route"
  )

Created on 2025-01-22 with reprex v2.1.1

@mitchelloharawild
Copy link
Member

Although without breakAtDateLine enabled, we get the dreaded horizontal line - I suppose in this case it is handled by data pre-processing and not the coordinate system.

library(ggplot2)
library(sf)
#> Linking to GEOS 3.12.1, GDAL 3.8.4, PROJ 9.4.0; sf_use_s2() is TRUE
library(maps)
library(geosphere)

# Convert the world map to an sf object
world1 <- sf::st_as_sf(map('world', plot = FALSE, fill = TRUE))

# Define the coordinates for Melbourne and San Francisco
melbourne <- c(144.9631, -37.8136) # Longitude, Latitude
san_francisco <- c(-122.4194, 37.7749) # Longitude, Latitude

# Calculate the great circle route
gc_path <- gcIntermediate(
  melbourne, 
  san_francisco, 
  n = 100, 
  addStartEnd = TRUE, 
  breakAtDateLine = FALSE,
  sp = TRUE # Return as a SpatialLines object
)

# Convert the great circle route to an sf object
gc_path_sf <- st_as_sf(gc_path)

# Plot the map with the flight path
ggplot() +
  geom_sf(data = world1, fill = "lightgray", color = "white") +
  geom_sf(data = gc_path_sf, color = "blue", size = 1.2) +
  theme_minimal() +
  labs(
    title = "Flight Path from Melbourne to San Francisco",
    subtitle = "Great Circle Route"
  )

Created on 2025-01-22 with reprex v2.1.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants