Intro, a lyrics-melody data frame

library(tidyverse)


beluga_song <- ggdoremi:::join_phrases_drm_lyrics()

beluga_song %>% head()
## # A tibble: 6 × 6
## # Groups:   id_phrase [1]
##   id_phrase id_in_phrase drm   doremi  freq lyric
##       <int>        <int> <fct> <fct>  <dbl> <chr>
## 1         1            1 m     mi      557. Ba   
## 2         1            2 m     mi      557. by   
## 3         1            3 r     re      495  Be   
## 4         1            4 d     do      440  lu   
## 5         1            5 S     sol     330  ga   
## 6         1            6 d     do      440  in

Dandalion song w/o extension

compute_panel_dandalion <- function(data, scales, start_angle =  -90){
  
  spacer_df <- tibble(spacer = 1)
  
  data <- bind_rows(spacer_df, data, spacer_df)
  
  data$id <- 1:nrow(data)
  # nrow(data)
  
  single_wedge_angle <- 1/nrow(data)*360
  half_wedged_angle <- single_wedge_angle/2
  
  data$around <- (nrow(data)):1/nrow(data) 

  data$circ_angle <- data$around*2*pi + 
    (start_angle -half_wedged_angle)*2*pi/360 
  data$x <- data$radius * cos(data$circ_angle)
  data$xend <- 0
  data$yend <- 0
  data$y <- data$radius * sin(data$circ_angle)
  data$angle <- data$around*360 + 180 + 90 + 
    start_angle - half_wedged_angle
  
  data %>% 
    slice(-1) %>% 
    slice(-nrow(.))
  
}

beluga_song %>% head(4) %>% 
  # head(30) %>% 
  mutate(radius = as.numeric(drm) + 10) %>% 
  compute_panel_dandalion() %>% 
  ggplot() + 
  ggstamp::stamp_circle(radius = 8+10, alpha = 0, size = .25, linetype = "dotted") +
  ggstamp::stamp_circle(radius = 8+12, alpha = 0, size = .25, linetype = "dotted") +
  ggstamp::stamp_circle(radius = 8+14, alpha = 0, size = .25, linetype = "dotted") +
  aes(x = x, radius = radius, y = y, label = lyric, angle = angle) + 
  geom_segment(xend = 0, yend = 0, color = "black", linewidth = .5) +
  geom_point(shape = 21, size = 16, fill = "white") +
  # aes(color = doremi) +
  geom_text() +
  coord_equal()  + 
  theme_void()

statexpress enabled extension

write extension

stat_dandalion <- function(geom = "segment", ...){
  statexpress::stat_panel(compute_panel_dandalion, geom, ...)
}

geom_dandalion_segment <- stat_dandalion
geom_dandalion_text <- function(...){stat_dandalion(geom =  "text", ...)}
geom_dandalion_point <- function(...){stat_dandalion(geom =  "point", ...)}
stamp_staff_dms <- function(radius_addition = 10 ){
  
  list(
  ggstamp::stamp_circle(radius = 8+0+radius_addition, alpha = 0, size = .25, linetype = "dotted"),
  ggstamp::stamp_circle(radius = 8+2+radius_addition, alpha = 0, size = .25, linetype = "dotted"),
  ggstamp::stamp_circle(radius = 8+4+radius_addition, alpha = 0, size = .25, linetype = "dotted")
  )
  
  
}


stamp_staff_dmst <- function(radius_addition = 10 ){
  
  list(stamp_staff_dms(radius_addition = radius_addition), 
      ggstamp::stamp_circle(radius = 8+6+radius_addition, 
                            alpha = 0, size = .25, 
                            linetype = "dotted")
  )
  
  
}

stamp_staff_dmstr <- function(radius_addition = 10 ){
  
  list(stamp_staff_dmst(radius_addition = radius_addition), 
      ggstamp::stamp_circle(radius = 8+8+radius_addition, 
                            alpha = 0, size = .25, 
                            linetype = "dotted")
  )
  
  
}

Use extension

Beluga

ggdoremi:::join_phrases_drm_lyrics() ->
beluga_song

head(beluga_song) 
## # A tibble: 6 × 6
## # Groups:   id_phrase [1]
##   id_phrase id_in_phrase drm   doremi  freq lyric
##       <int>        <int> <fct> <fct>  <dbl> <chr>
## 1         1            1 m     mi      557. Ba   
## 2         1            2 m     mi      557. by   
## 3         1            3 r     re      495  Be   
## 4         1            4 d     do      440  lu   
## 5         1            5 S     sol     330  ga   
## 6         1            6 d     do      440  in
beluga_song %>% 
  ggplot() + 
  stamp_staff_dms(3) +
  aes(radius = as.numeric(drm)+3) +
  geom_dandalion_segment() +
  geom_dandalion_point(size = 21,
                       shape = 21) +
  aes(label = lyric) +
  geom_dandalion_text(size = 5) +
  coord_equal() + 
  theme_void() + 
  aes(fill = doremi) + 
  scale_fill_brewer("blues")
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_segment()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_text()`).

ABCs

To allow some melodic plotting, first of all thinks about dataframes. Here we see lyrics and tones (drmfslt) are entered independently as text. Then a function is used to pair up lyrics with the associated note.

Tones are positioned in three octaves. DRM, drm, 123 so single character represents relative position.

Looking at twinkle twinkle - Mozart-Salzburg connection!

lyrics_abc <- "A B C D E F G
H I J K L M N O P
Q R S T U V
W X Y Z
Now I know my A B Cs
Next time won't you sing with me"


drm_abc <- "ddsslls
ffmmrrrrd
ssfmmr
sfmr
ddsslls
ffmmrrd"
abc_df <- ggdoremi:::join_phrases_drm_lyrics(drm_phrases = drm_abc, 
                                   lyrics_phrases = lyrics_abc)  

abc_df %>% 
  ggplot() + 
  aes(radius = as.numeric(drm) - 2) +
  stamp_staff_dms(-2) +
  geom_dandalion_segment(color = "black", 
                         size = .5) +
  geom_dandalion_point(size = 13, 
                       fill = "white",
                       shape = 21) +
  aes(label = lyric) +
  geom_dandalion_text() +
  coord_equal() + 
  theme_void() + 
  aes(size = 5) + 
  scale_size(range = c(3,5))
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

last_plot() %+%
  (ggdoremi:::join_phrases_drm_lyrics(drm_abc, 
                                   lyrics_abc)[1:26,]) + 
  aes(size = 8) + 
  theme(legend.position = "none")

twinkle twinkle

lyrics_abcd <- '一 闪 一 闪 亮 晶 晶'

drm_abcd <- 'ddsslls'


ggdoremi:::join_phrases_drm_lyrics(drm_abcd, 
                                   lyrics_abcd) %>% 
  ggplot() + 
  aes(radius = as.numeric(drm) - 2) +
  stamp_staff_dms(-2) +
  geom_dandalion_segment(color = "black", 
                         size = .5) +
  geom_dandalion_point(size = 13, 
                       fill = "white",
                       shape = 21) +
  aes(label = lyric) +
  geom_dandalion_text(angle = 0) +
  coord_equal() + 
  theme_void() + 
  aes(size = 5)

  theme(legend.position = "none")
## List of 1
##  $ legend.position: chr "none"
##  - attr(*, "class")= chr [1:2] "theme" "gg"
##  - attr(*, "complete")= logi FALSE
##  - attr(*, "validate")= logi TRUE
lyrics_hb <- 
'Hap-py birth-day to you
Hap-py birth-day to you
Hap-py birth-day dear X-X
Hap-py birth-day to you'

drm_hb <- 
'SSLSdT
SSLSrd
SSsmdTL
ffmdrd'


hb_df <- ggdoremi:::join_phrases_drm_lyrics(drm_hb, lyrics_hb) 



hb_df %>%
  # head(30) %>%
  ggplot() +
  stamp_staff_dms(10) +
  aes(radius = as.numeric(drm) +10 ) +
  geom_dandalion_segment(xend = 0, yend = 0) +
  geom_dandalion_point(shape = 21, size = 20, fill = "white") +
  # aes(color = doremi) +
  aes(label = lyric) +
  geom_dandalion_text(size = 5) +
  coord_equal() + 
  theme_void() + 
  guides(color = "none", 
         label = "none")

lyrics_doe_a_deer <-
'Doe a deer a fe-male deer
ray a drop of gol-den sun
me a name I call my-self
far a long long way to run
sew a need-le pull-ing thread
la a note to fol-low sol
tea a drink with jam and bread
that will bring us back to do o o o'

drm_doe_a_deer <-
'drmdmdm
rmffmrf
mfsmsms
fsllsfl
sdrmfsl
lrmfslt
tmfslt1
1tlsts1smr'


ggdoremi:::join_phrases_drm_lyrics(drm_doe_a_deer, lyrics_phrases = lyrics_doe_a_deer) %>%
  # head(30) %>%
  ggplot() +
  stamp_staff_dmst(0) +
  aes(radius = as.numeric(drm) ) +
  geom_dandalion_segment(xend = 0, yend = 0) +
  geom_dandalion_point(shape = 21, size = 19, fill = "white") +
  aes(color = doremi, label = lyric) +
  geom_dandalion_text(size = 7) +
  coord_equal() + 
  theme_void() + 
  guides(color = "none", label = "none")

last_plot() + 
  aes(label = doremi)

ggdoremi:::join_phrases_drm_lyrics(drm_doe_a_deer, lyrics_phrases = lyrics_doe_a_deer) %>%
  head(30) %>%
  ggplot() + 
  aes(label = lyric, y = id_in_phrase, x = drm) +
  geom_label(size = 8) + 
  # geom_path(aes(x = as.numeric(drm))) +
  # geom_label(size = 8)
  facet_grid(-id_phrase ~ . ) +
  theme_void()

Closing remarks, Other Relevant Work, Caveats