library(tidyverse)
places <- tribble(~cities, ~hour, 
        "Melbourne/\nSydney", 6,
        "Auckland", 8,
        "San\nFrancisco", 13,
        "Denver/\nSalt Lake",   14,
        "Chicago/\nDallas", 15,
        "New York/\nAtlanta", 16,
        "Sao Paolo", 17,
        "London/\nEdinburgh", 21,
        "Amsterdam/\nBerlin", 22,
        "Kampala", 23)
lag_around <- function(x, n){
  
  c(x[(n+1):length(x)], x[1:n])
  
}


1:10 |> lag_around(5)
##  [1]  6  7  8  9 10  1  2  3  4  5
{ggplot(data = summer_times_places) + 
  aes(x = hour_pretty |> fct_inorder()) + 
  aes(y = 1.15) + 
  coord_polar(start = 0, clip = F) + 
  theme_void(ink = "darkgrey") + 
  aes(label = hour_pretty) + 
  geom_label(linewidth = 0) + 
  aes(hjust = 1) +
  aes(yend = 0, xend = hour) +
  geom_segment(aes(y = 1.2)) + 
  aes(angle = -((hour-.5)/24)*360+90) + 
  aes(linetype = hour %% 3 |> 
        as.logical()) + 
  aes(vjust = 1) + 
  theme(legend.position = "none") + 
  aes(linewidth = I(.3)) +
  geom_label(fill = "white", 
             linewidth = 0,
            aes(x = hour, y = 1.22,
                label = cities, 
                hjust = 0,
                vjust = .5,
                lineheight = .8,
                xend = NULL,
                linetype = NULL)) + 
  geom_hline(yintercept = 1.2) +
  labs(title = "Virtual meetup coordinators' wheel, Summer 2026") +
  aes(label = lag_around(hour_pretty, 1)) + 
  aes(label = lag_around(hour_pretty, 2)) + 
  aes(label = lag_around(hour_pretty, 3)) +  
  aes(label = lag_around(hour_pretty, 4)) +  
  aes(label = lag_around(hour_pretty, 5)) +  
  aes(label = lag_around(hour_pretty, 6)) +
  aes(label = lag_around(hour_pretty, 7)) + 
  aes(label = lag_around(hour_pretty, 8)) + 
  aes(label = lag_around(hour_pretty, 9)) +  
  aes(label = lag_around(hour_pretty, 10)) +  
  aes(label = lag_around(hour_pretty, 11)) +  
  aes(label = lag_around(hour_pretty, 12)) + 
  aes(label = lag_around(hour_pretty, 13)) + 
  aes(label = lag_around(hour_pretty, 14)) +  
  aes(label = lag_around(hour_pretty, 15)) +  
  aes(label = lag_around(hour_pretty, 16)) +  
  aes(label = lag_around(hour_pretty, 17)) +
  aes(label = lag_around(hour_pretty, 18)) + 
  aes(label = lag_around(hour_pretty, 19)) + 
  aes(label = lag_around(hour_pretty, 20)) +  
  aes(label = lag_around(hour_pretty, 21)) +  
  aes(label = lag_around(hour_pretty, 22)) +  
  aes(label = lag_around(hour_pretty, 23))
    } |> 
  codehover::ch_hover()
ggplot(data = summer_times_places) +
aes(x = fct_inorder(hour_pretty)) +
aes(y = 1.15) +
coord_polar(start = 0, clip = F) +
theme_void(ink = "darkgrey") +
aes(label = hour_pretty) +
geom_label(linewidth = 0) +
aes(hjust = 1) +
aes(yend = 0, xend = hour) +
geom_segment(aes(y = 1.2)) +
aes(angle = -((hour - 0.5)/24) * 360 + 90) +
aes(linetype = as.logical(hour%%3)) +
aes(vjust = 1) +
theme(legend.position = "none") +
aes(linewidth = I(0.3)) +
geom_label(fill = "white", linewidth = 0, aes(x = hour, y = 1.22,
label = cities, hjust = 0, vjust = 0.5, lineheight = 0.8,
xend = NULL, linetype = NULL)) +
geom_hline(yintercept = 1.2) +
labs(title = "Virtual meetup coordinators' wheel, Summer 2026") +
aes(label = lag_around(hour_pretty, 1)) +
aes(label = lag_around(hour_pretty, 2)) +
aes(label = lag_around(hour_pretty, 3)) +
aes(label = lag_around(hour_pretty, 4)) +
aes(label = lag_around(hour_pretty, 5)) +
aes(label = lag_around(hour_pretty, 6)) +
aes(label = lag_around(hour_pretty, 7)) +
aes(label = lag_around(hour_pretty, 8)) +
aes(label = lag_around(hour_pretty, 9)) +
aes(label = lag_around(hour_pretty, 10)) +
aes(label = lag_around(hour_pretty, 11)) +
aes(label = lag_around(hour_pretty, 12)) +
aes(label = lag_around(hour_pretty, 13)) +
aes(label = lag_around(hour_pretty, 14)) +
aes(label = lag_around(hour_pretty, 15)) +
aes(label = lag_around(hour_pretty, 16)) +
aes(label = lag_around(hour_pretty, 17)) +
aes(label = lag_around(hour_pretty, 18)) +
aes(label = lag_around(hour_pretty, 19)) +
aes(label = lag_around(hour_pretty, 20)) +
aes(label = lag_around(hour_pretty, 21)) +
aes(label = lag_around(hour_pretty, 22)) +
aes(label = lag_around(hour_pretty, 23))
ggplyr::layers_wipe(i = 3) +
  aes(label = cities) + 
    geom_label(fill = "white", 
             linewidth = 0,
            aes(x = hour, y = 1.22,
                label = hour_pretty, 
                hjust = 0,
                vjust = .5,
                lineheight = .8,
                xend = NULL,
                linetype = NULL))
## NULL
compute_panel_around <- function(data, scales, around_start = 0, radius = 1){
  
  data |> 
    mutate(row_id = row_number()) |> 
    mutate(around = around_start* 2*pi/360 + 2 * pi * row_id/n(),
           x = radius*cos(around), 
           y = radius*sin(around),
           angle = 360*around/(2*pi),
           end = 0)

  
}

StatAround <- ggproto("StatAround", Stat, 
                      compute_panel = compute_panel_around,
                      default_aes = aes(hjust = after_stat(1), 
                                        xend = after_stat(end),
                                        yend = after_stat(end)))


summer_times_places |> 
  ggplot() +
  aes(label = cities) +
  coord_equal(ylim = c(-1.2,1.2), xlim = c(-1.2,1.2)) +
  geom_text(stat = StatAround, radius = .975) + 
  geom_text(stat = StatAround, 
            radius = 1.025, around_start = 90,
            aes(label = hour_pretty),
            hjust = 0) + 
  geom_segment(stat = StatAround, 
               around_start = pi/24 + 1, 
               linetype = "dashed") +
  geom_polygon(stat = StatAround, color = "darkgray", fill = NA,
               data = data.frame(x = 1:80), inherit.aes = F) + 
  labs(title = "Virtual meetup coordinators' wheel, Summer 2026",
       subtitle = "From the ggplot2 extenders ❤️") + 
  theme_void(base_size = 9, ink = "darkgray")

geom_text_inner <- make_constructor(GeomText, stat = StatAround, radius = .975)
geom_text_outer <- make_constructor(GeomText, stat = StatAround, radius = 1.025, hjust = 0)
stamp_segment_pie_cuts <- make_constructor(GeomSegment, stat = StatAround, around_start = pi/24 + 1, 
               linetype = "dotted", inherit.aes = FALSE)

GeomPolygonHollow <- ggproto("GeomPolygonHollow", GeomPolygon,
                             default_aes = GeomPolygon$default_aes |> 
                               modifyList(aes(color = from_theme(ink), fill = NA)))

stamp_polygon_circle <- make_constructor(GeomPolygonHollow, stat = StatAround, data = data.frame(x = 1:200), inherit.aes = FALSE)

theme_timezone_wheel <- function(...){
  
  theme_void(base_size = 9, ink = "darkgray", ...)
  
}

chart_timezone_wheel <- function(
  mapping.geom.text.outer = NULL,
  mapping.geom.text.inner = NULL,
  coord.equal.padded = coord_equal(ylim = c(-1.2,1.2), xlim = c(-1.2,1.2)),
  geom.text.inner = geom_text_inner(mapping = mapping.geom.text.inner), 
  geom.text.outer = geom_text_outer(mapping = mapping.geom.text.outer),
  stamp.segment.pie.cuts = stamp_segment_pie_cuts(),
  stamp.polygon.circle = stamp_polygon_circle()){
  
  
  list(
  coord.equal.padded,
  geom.text.inner, 
  geom.text.outer,
  stamp.segment.pie.cuts,
  stamp.polygon.circle)
  
}

theme_timezone_wheel() |> theme_set()

summer_times_places |> 
  ggplot() + 
  aes(label = cities) + 
  chart_timezone_wheel(aes(label = hour_pretty)) + 
  labs(title = "Virtual meetup coordinators' wheel, Summer 2026",
       subtitle = "From the ggplot2 extenders ❤️")