Gggibbous: Moon charts

Gggibbous: Gráficos lunares

Sophia C. Delgado Astacio, University of Puerto Rico at Humacao
Amirah N. Nieves Medina, University of Puerto Rico at Humacao

I- Función del paquete

Brinda una perspectiva nueva a las visualizaciones de pie charts siguiendo una proporción similar a las fases de la luna. Es un paquete dinámico que busca añadir toques estéticos a los trabajos de R. Este paquete fue publicado por Michael Bramson en el 2021. Bramson compara el uso de los moon charts con los pie charts, sin embargo el autor explica que un gráfico circular o un pie chart divide un círculo en múltiples secciones en las que las longitudes de arco (y, por tanto, también las áreas) de las secciones representan proporciones de un todo. Los gráficos circulares no muestran los cambios en el comportamiento de las variables a través del tiempo, debido a esto, los pie charts deben ser usados de manera limitada en los procesos de publicación científica.

Moon Chart vs. pie chart
Moon Chart vs. pie chart

II- Objetivos del paquete

Presentar la relación de dos variables de manera estética sin necesitar un sistema de coordenadas cuadrados.

Nombres de las fases de la luna


III- Ejemplos de varios usos del paquete

a. Las propociones o “ratios” para hacer un moon chart. Estos son personalizables, en donde podemos delimitar cada “fase” de la luna con el valor que desemos graficar. Esto depende de cuan grande sean las unidades que tengamos en nuestro data frame. Nota: Antes de comenzar a usar este paquete debe de identificar si sus datos siguen una distribución normal o no. “geom_moon()” es la función geom desiganda para este paquete. “Ratio” establece los valores de la proporción de estas gráficas en donde los valores deben estar entre 0 y 1.

Ejemplo del autor:

#Ejemplo de como colocar las proporciones de cada fase de la "luna". 
library(ggplot2)
library(gggibbous)
library(gt)
#Primero creamos el data frame con los datos, y en esta misma función de aes() colocamos el ratio 
ggplot(data.frame(x = 1:5, y = 0, ratio = 0:4 * 0.25), aes(x = x, y = y)) +
  geom_moon(aes(ratio = ratio), size = 20, fill = "black") +
  geom_text(aes(y = y + 1, label = ratio)) +
  lims(x = c(0.5, 5.5), y = c(-1, 1.4)) +
  theme_void()

Ejemplo nuestro: En este ejemplo se alteró el ratio, size, fill y colour.

library(gggibbous)

ggplot(data.frame(x = 1:5, y = 0, ratio = 1:5 * 0.20), aes(x = x, y = y)) +
  geom_moon(aes(ratio = ratio), size = 18, fill = "darkgreen", colour= "pink") +
  geom_text(aes(y = y + 1, label = ratio)) +
  lims(x = c(0.5, 5.5), y = c(-1, 1.4)) +
  theme_void()

b. Manera alterna en la que se puede usar la proporción de estas gráficas circulares. En este caso no estamos delimitando un “ratio” debido a que nos enfocamos en el uso de las “lunas llenas” para demostrar la relación de las variables en el tiempo, manipulando directamente el tamaño de estos círculos. En la función de “size” se establece que los círculos aumentarán el tamaño de dos en dos siguiendo la proporción de 0:4 la cual es default en los moon charts.

Nota: Se intentó aplicar las funciones de “fill”, “colour” y “color”, sin embargo, las figurasno cambian de color.

Ejemplo usando “full moon”

#Primero creo el data frame y con "geom_point()" especifico que la fase de la luna que deseo usar es "full moon". 
ggplot(data.frame(x = 1:5, y = 1, size = 2^(0:4)), aes(x, y, size = size)) +
  geom_point(y = 2) +
  lims(x = c(0.5, 5.5), y = c(0.5, 2.5)) +
  scale_size(range = c(5, 10))

Ejemplo usando “Waxing Crescent”

#Primero creo el data frame y con "geom_moon()" especifico que la fase de la luna que deseo usar es la "waxing crescent". 
ggplot(data.frame(x = 1:5, y = 1, size = 2^(0:4)), aes(x, y, size = size)) +
  geom_moon(y = 2) +
  lims(x = c(0.5, 5.5), y = c(0.5, 2.5)) +
  scale_size(range = c(5, 10))

Ejemplo usando “Waxing Crescent” y “Full Moon”.

#En esta versión de los ejemplos anteriores, añado ambos: "geom_moon()" y "geom_point()".En este ejemplo también ajustamos el tamaño de las lunas. 
ggplot(data.frame(x = 1:5, y = 1, size = 3^(1:5)), aes(x, y, size = size)) +
  geom_moon() +
  geom_point(y = 2) +
  lims(x = c(0.5, 5.5), y = c(0.5, 2.5)) 

  scale_size(range = c(5, 10))
## <ScaleContinuous>
##  Range:  
##  Limits:    0 --    1

c. Ejemplo en donde tenemos un set de datos el cual posee valores 1>. El paquete de gggibous facilita la conversión de números enteros en proporciones mediante el uso de ” ratio=” y “Score=”. Además, en este ejemplo estaremos viendo como podemos aplicarle colores al lado derecho o izquierdo de la luna. Esto se aplica con “right=”. Para añadirle color al lado derechode la luna primero usamos “fill=” y separado de una coma especificamos “right=FALSE”. En el caso del lado izquierdo el proceso es igual solo se que se usa “right=TRUE”.

Este método de hacer comparaciones cualitativas se llama “Harvey Balls”.

#Primero creamos el data set. Este contiene distintas marcas cosméticas y sus valores de satisfacción a varios criterios. 

 Makeup_brand_names<- c(
  "Rare Beauty", "Fenty", "Kosas",
  "Laneige", "Summer Friday"
)
Brands <- data.frame(
  Brand = factor(Makeup_brand_names, levels = Makeup_brand_names),
  Quality = c(5, 3, 4, 4, 1),
  Online_Reviews = c(2, 5, 3, 1, 5),
  Customer_Service = c(4, 2, 3, 3, 5),
  Price = c(4, 5, 2, 5, 2)
)

Brands
##           Brand Quality Online_Reviews Customer_Service Price
## 1   Rare Beauty       5              2                4     4
## 2         Fenty       3              5                2     5
## 3         Kosas       4              3                3     2
## 4       Laneige       4              1                3     5
## 5 Summer Friday       1              5                5     2
#Luego de que hayamos definido nuestras variables y conjunto a la función de reshape() para acomodar los datos de manera longitudinal en donde usamos v.names para señalar el nombre de las variables en un formato hacia lo largo. 
#Usamos "direction" para especificar si la gráfica será ancha "wide" o longitudinal "long".

Brands_catg <- c("Quality", "Online_Reviews", "Customer_Service", "Price")
tidybrands <- reshape(
  Brands,
  varying = Brands_catg,
  v.names = "Score",
  timevar = "Category",
  times = factor(Brands_catg, levels = Brands_catg),
  idvar = "Brand",
  direction = "long"
)

Brands_catg 
## [1] "Quality"          "Online_Reviews"   "Customer_Service" "Price"
#Graficamos los datos anteriores usando geom_moon, sin embargo usamos ratio= para indicarle al paquete de gggibous que debe de calcular la proporción que exhibirán las lunas. 

#En este caso, el ratio se estará calculando al restar el valor asignado en el set de datos con la fracción 1/4. 

#La función de "right" se le aplica "TRUE" O "FALSE" para diferenciar entre los lados que tendrán color. Para que R le asigne color a cada lado, debe usar "fill=right".
ggplot(tidybrands, aes(0, 0)) +
  geom_moon(aes(ratio = (Score - 1) / 4), fill = "black") +
  geom_moon(aes(ratio = 1 - (Score - 1) / 4), right = FALSE) +
  facet_grid(Brand ~ Category, switch = "y") +
  theme_minimal() +
  theme(
    panel.grid = element_blank(),
    strip.text.y.left = element_text(angle = 0, hjust = 1),
    axis.text = element_blank(),
    axis.title = element_blank()
  )

#Para hacer que la gráfica aparezca en un fondo blanco usamos "theme_minimal()" en donde especificamos "element_blank()" dentro de "panel.grid =".
ggplot(tidybrands, aes(0, 0)) +
  geom_moon(aes(ratio = (Score - 1) / 4), fill = "pink", right= TRUE) +
  geom_moon(aes(ratio = 1 - (Score - 1) / 4), fill="purple", right = FALSE) +
  facet_grid(Brand ~ Category, switch = "y") +
  theme_minimal() +
  theme(
    panel.grid = element_blank(),
    strip.text.y.left = element_text(angle = 0, hjust = 1),
    axis.text = element_blank(),
    axis.title = element_blank()
  )

d. Grafica usando los moon charts aplicando repeticiones de los valores en ambos ejes mediante “rep()” y la aplicación de “draw_key_moon_left”.

#Primero creo el data frame en donde delimito los valores de x y y usando "rep()" la cual no es única de gggibbous.
Sophia_Amirahs_moons <- data.frame(
  x = rep(2:4, 6),
  y = rep(rep(4:2, each = 3), 2),
  ratio = c(1:9 / 10, 9:1 / 10),
  right = rep(c(TRUE, FALSE), each = 9)
)

gt(Sophia_Amirahs_moons)
x y ratio right
2 4 0.1 TRUE
3 4 0.2 TRUE
4 4 0.3 TRUE
2 3 0.4 TRUE
3 3 0.5 TRUE
4 3 0.6 TRUE
2 2 0.7 TRUE
3 2 0.8 TRUE
4 2 0.9 TRUE
2 4 0.9 FALSE
3 4 0.8 FALSE
4 4 0.7 FALSE
2 3 0.6 FALSE
3 3 0.5 FALSE
4 3 0.4 FALSE
2 2 0.3 FALSE
3 2 0.2 FALSE
4 2 0.1 FALSE

Creo la gráfica usando el data frame anterior, comienzo a definir las características que estarán presentes en el lado derecho de la luna. Para esto uso “data=” en donde el “subset=” usado sin las condiciones de “right”. Sin embargo, para poder definir las características que estarán presentes en el lado izquierdo de la luna necesito luego usar “draw_key_moon_left”. Esto es debido a que el paquete de gggibbous tiene como default graficar los valores del lado derecho solamente. Para esto copio un código similar, solo que coloco “!” en “right”. Esto es igual que decir %in%, me aseguro que los valores del primer argumento esten incluidos en el segundo argumento. “draw_key_moon_left” se encarga de incluir los datos del lado izquierdo.

ggplot(Sophia_Amirahs_moons, aes(x, y, ratio = ratio, right = right, size = 2^x)) +
  geom_moon(data = subset(Sophia_Amirahs_moons, right), fill = "#994C00") +
  geom_moon(
    data = subset(Sophia_Amirahs_moons, !right), fill = "#663300",
    key_glyph = draw_key_moon_left
  ) +
  lims(x = c(0.5, 3.5), y = c(0.5, 3.5)) +
  scale_size("size", range = c(5, 10), breaks = 2^(1:3))
## Warning: Removed 5 rows containing missing values (geom_moon).
## Warning: Removed 5 rows containing missing values.

e. Aplicación de moon charts como herramienta en el proceso de creación de mapas.

Ejemplo y descripción del autor:

Un uso habitual de los gráficos circulares múltiples es representar proporciones en diferentes coordenadas de un mapa. Las dimensiones x e y ya están comprometidas con las coordenadas del mapa, por lo que las visualizaciones proporcionales como los gráficos de barras son más difíciles. Esta es una oportunidad perfecta para probar los gráficos lunares.

Los mapas circulares son populares en genética de poblaciones, así que veamos un ejemplo de ese campo. Los datos dmeladh contienen las frecuencias de dos variantes del gen Adh en poblaciones de mosca de la fruta de Australia y Papúa Nueva Guinea. Muchas de estas poblaciones están muy próximas entre sí, por lo que tenemos que hacer frente al sobretrazado, que realizamos manualmente a continuación.

#Accedemos al set de datos que provee el autor.
head(dmeladh)
##       Locality Latitude Longitude  N AdhF AdhS
## 1  Sogeri (NG)     -8.8     148.3 88    9   91
## 2    Snake Bay    -11.4     130.7 48    8   92
## 3       Darwin    -12.5     130.8 48    9   91
## 4 Mount Molloy    -16.7     145.6 96    8   92
## 5        Derby    -17.3     123.6 16   71   29
## 6    Innisfail    -17.5     146.0 24    0  100
#Se ajustaron las condiciones de lat y long.
dmeladh_adj <- dmeladh
dmeladh_adj$long <- dmeladh$Longitude + c(
  -2, 0, -2, 2, -3, 3, 3, 2, 3, 4, -2.5, -2.5, -1, -2, -2.5, -4, 2.5,
  5, 6, 7, 2, -7, -5.5, -3, 0, -7, -2, 3, 5.5, 0.5, -1, -1.5, -3, 2)
dmeladh_adj$lat <- dmeladh$Latitude + c(
  -2, 2, 0, 1, 0, 0, 0, 2, 0.5, -1, 1, -1.5, 2, 4, 1.5, 0, 2,
  1, -1, -3, -2, 1, -1, -2, -3, -2, -4, -3, -1, 1.5, 2, 2, -2, 0)

#Tomando estos parámetros ajustados el autor delimitó las características de geolocalización y añadieron los valores nuevos de latitud y longitud. Luego se pasó a personalizar los moon charts con scripts similares a los que vimos anteriormente. 

moonmap <- ggplot(dmeladh_adj, aes(long, lat)) +
  geom_polygon(
    data = map_data(
      "world", region = "(Australia)|(Indonesia)|(Papua New Guinea)"),
    aes(group = group),
    fill = "gray80"
  ) +
  geom_segment(aes(xend = Longitude, yend = Latitude), color = "gray20") +
  geom_point(aes(Longitude, Latitude), size = 0.75, color = "gray20") +
  scale_size(range = c(4, 10)) +
  coord_map(xlim = c(110, 160), ylim = c(-45, -5)) +
  theme_void() +
  theme(
    legend.position = c(0.05, 0.05),
    legend.direction = "horizontal",
    legend.justification = c(0, 0)
  )

moonmap +
  geom_moon(
    aes(ratio = AdhS / 100, size = N),
    right = FALSE, fill = "gold", color = "gold",
    key_glyph = draw_key_moon_left
  ) +
  geom_moon(
    aes(ratio = AdhF / 100, size = N),
    fill = "forestgreen", color = "forestgreen"
  )

f. Graficando data lunar.

Ejemplo y descripción del autor:

A veces sólo quieres trazar representaciones literales de la Luna. Los datos lunardist, adaptados de la NASA, contienen la distancia de la Tierra a la Luna para cada día de 2019, así como las fechas (en UTC) de cada aparición de las cuatro fases principales de la Luna. Podemos trazar esas fases principales utilizando gráficos lunares (que en este caso son idénticos a los gráficos circulares).

moonphase <- subset(lunardist, !is.na(phase))
moonphase$percent <- ifelse(
  moonphase$phase == "new", 0, ifelse(moonphase$phase == "full", 1, 0.5))

ggplot(lunardist, aes(date, distance)) +
  geom_line() +
  # Plotting the lower layer as a full circle also works in most cases
  geom_moon(data = moonphase, ratio = 1, size = 5, fill = "black") +
  geom_moon(
    data = moonphase, aes(ratio = percent),
    size = 5, fill = "yellow", right = moonphase$phase == "first quarter"
  )


IV- Limitaciones y ventajas del paquete

Limitaciones:

  1. Solo se pueden usar dos variables por moon chart.
  2. Dependiendo del script que se pretenda usar, se tendrán que colocar los valores del pie chart como un data frame creado en el mismo script. Este paquete presenta limitaciones al momento de usar data frames externos.
  3. Si se usa un data frame externo, este debe contener una cantidad de información limitada y ajustada a las necesidades del paquete. Este debe de contener datos para la función de “right=”
  4. Si se usan valores mayores de 1, se limitan las visualizaciones que se puedan hacer con el paquete pero, si se ajustan las condiciones de size se pueden usar los moon charts para observar el crecimiento de los valores mediante las condiciones de las variables.

Ventajas:

  1. Aporta un toque estético a las publicaciones científicas lo cual las haría más dinámicas para su audiencia.
  2. Este paquete se puede usar para datos que tengan una distribución normal como una distribución no normal.
  3. En el caso de que una persona tenga datos con una distribución normal, se puede usar la forma de luna llena (x >1), en donde el incremento en el tamaño de esta actúa como la frecuencia (Vea: limitación 4).
  4. En el caso de que sus datos no cuenten con un ratio entre 0 y 1, la función geom_moon( ) tiene herramientas para calcular el ratio, así usted se evita hacer este paso de manera manual.
  5. En el caso de que sus valores no tengan una distribución normal, este paquete permite la graficación de valores como: frecuencias, promedios y porcentajes.
  6. Este paquete es una buena herramienta para especialistas en el campo de la astronomía los cuales quieran demostrar la frecuencia de cambio de las fases de la luna por un tiempo determinado.
  7. En R, los gráficos lunares en gggibbous no requieren ningún sistema de coordenadas especial. Se dibujan de forma muy similar a los puntos en ggplot2: su posición se define por una coordenada x y una coordenada y y su tamaño se define independientemente del sistema de coordenadas, por lo que siempre permanecen circulares.

V- Referencias:

  1. Bramson, M.

    1. gggibbous: Moon charts, a pie chart alternative for two groups, GGGIBBOUS: Moon Charts, a pie chart alternative for two groups. Available at: https://cran.r-project.org/web/packages/gggibbous/vignettes/gggibbous.html (Accessed: April 25, 2023).
  2. Cummings, D.

    1. Moon phases names - an easy way to remember, Star In A Star. Available at: https://starinastar.com/moon-phases-names-an-easy-way-to-remember/ (Accessed: April 25, 2023).
  3. Kosara, R.

    1. Circular Part-to-Whole Charts Using the Area Visual Cue. EuroVis 2019 - Short Papers. https://doi.org/10.2312/evs.20191163↩︎
  4. Oakeshott, J.G., et al. 1982. Alcohol dehydrogenase and glycerol-3-phosphate dehydrogenase clines in Drosophila melanogaster on different continents. Evolution, 36(1): 86-96.↩︎

  5. Rep: Replicate elements of vectors and lists (no date) RDocumentation. Available at: https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/rep (Accessed: April 25, 2023).