Possiamo creare un nuovo geom, geom_arrowbar
che possiamo usare come qualsiasi altro geom, quindi nel tuo caso darebbe la trama desiderata semplicemente facendo:
tibble(y = c(10, 20, 30), n = c(300, 100, 200), transparency = c(10, 2, 4)) %>%
ggplot() +
geom_arrowbar(aes(x = n, y = y, alpha = transparency), fill = "red") +
scale_y_continuous(limits = c(5, 35)) +
scale_x_continuous(limits = c(0, 350))
E contiene 3 parametri, column_width
, head_width
e head_length
che consentono di modificare la forma della freccia, se non lo fai come i valori di default. Possiamo anche specificare il colore di riempimento e altre estetiche secondo necessità:
tibble(y = c(10, 20, 30), n = c(300, 100, 200), transparency = c(10, 2, 4)) %>%
ggplot() +
geom_arrowbar(aes(x = n, y = y, alpha = transparency, fill = as.factor(n)),
column_width = 1.8, head_width = 1.8, colour = "black") +
scale_y_continuous(limits = c(5, 35)) +
scale_x_continuous(limits = c(0, 350))
L'unico inconveniente è che dobbiamo scriverlo prima!
Seguendo gli esempi nell'estensione della vignetta ggplot2 , possiamo definire i nostri geom_arrowbar
nello stesso modo in cui sono definiti altri geomi, tranne che vogliamo essere in grado di passare i nostri 3 parametri che controllano la forma della freccia. Questi vengono aggiunti params
all'elenco layer
dell'oggetto risultante , che verrà utilizzato per creare il nostro livello di frecce:
library(tidyverse)
geom_arrowbar <- function(mapping = NULL, data = NULL, stat = "identity",
position = "identity", na.rm = FALSE, show.legend = NA,
inherit.aes = TRUE, head_width = 1, column_width = 1,
head_length = 1, ...)
{
layer(geom = GeomArrowBar, mapping = mapping, data = data, stat = stat,
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
params = list(na.rm = na.rm, head_width = head_width,
column_width = column_width, head_length = head_length, ...))
}
Ora "tutto" ciò che resta è definire ciò che GeomArrowBar
è. Questa è effettivamente una ggproto
definizione di classe. La parte più importante di essa è la draw_panel
funzione membro, che prende ogni riga del nostro frame di dati e la converte in forme di freccia. Dopo alcuni calcoli matematici di base sulle coordinate xey, nonché sui nostri vari parametri di forma quale dovrebbe essere la forma della freccia, ne produce uno grid::polygonGrob
per ogni riga dei nostri dati e lo memorizza in a gTree
. Ciò costituisce il componente grafico del livello.
GeomArrowBar <- ggproto("GeomArrowBar", Geom,
required_aes = c("x", "y"),
default_aes = aes(colour = NA, fill = "grey20", size = 0.5, linetype = 1, alpha = 1),
extra_params = c("na.rm", "head_width", "column_width", "head_length"),
draw_key = draw_key_polygon,
draw_panel = function(data, panel_params, coord, head_width = 1,
column_width = 1, head_length = 1) {
hwidth <- head_width / 5
wid <- column_width / 10
len <- head_length / 10
data2 <- data
data2$x[1] <- data2$y[1] <- 0
zero <- coord$transform(data2, panel_params)$x[1]
coords <- coord$transform(data, panel_params)
make_arrow_y <- function(y, wid, hwidth) {
c(y - wid/2, y - wid/2, y - hwidth/2, y, y + hwidth/2, y + wid/2, y + wid/2)
}
make_arrow_x <- function(x, len){
if(x < zero) len <- -len
return(c(zero, x - len, x - len , x, x - len, x - len, zero))
}
my_tree <- grid::gTree()
for(i in seq(nrow(coords))){
my_tree <- grid::addGrob(my_tree, grid::polygonGrob(
make_arrow_x(coords$x[i], len),
make_arrow_y(coords$y[i], wid, hwidth),
default.units = "native",
gp = grid::gpar(
col = coords$colour[i],
fill = scales::alpha(coords$fill[i], coords$alpha[i]),
lwd = coords$size[i] * .pt,
lty = coords$linetype[i]))) }
my_tree}
)
Questa implementazione è tutt'altro che perfetta. Manca alcune importanti funzionalità, come i limiti degli assi predefiniti sensibili e la possibilità dicoord_flip
, e produrrà risultati antiestetici se le teste delle frecce sono più lunghe dell'intera colonna (anche se potresti non voler comunque utilizzare un tale diagramma in quella situazione) . Tuttavia, avrà ragionevolmente la freccia che punta a sinistra se si dispone di un valore negativo. Una migliore implementazione potrebbe anche aggiungere un'opzione per punte di freccia vuote.
In breve, occorrerebbero molte modifiche per appianare questi (e altri) bug e renderli pronti per la produzione, ma nel frattempo è abbastanza buono per produrre dei grafici carini senza troppi sforzi.
Creato il 2020-03-08 dal pacchetto reprex (v0.3.0)
tibble(y = c(10, 20, 30), n = c(300, 100, 200), transparency = c(10, 2, 4)) %>% ggplot() + geom_segment(aes(x = 0, xend = n-10, y = y, yend = y, alpha = transparency), colour = 'red', size = 10) + geom_segment(aes(x = n-0.1, xend = n, y = y, yend = y, alpha = transparency), colour = 'red', size = 1, arrow = arrow(length = unit(1.5, 'cm'), type = 'closed')) + scale_y_continuous(limits = c(5, 35))