Wir können ein neues Geom erstellen geom_arrowbar
, das wir wie jedes andere Geom verwenden können. In Ihrem Fall würde es also den gewünschten Plot ergeben, indem Sie einfach Folgendes tun:
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))
Und es enthält drei Parameter column_width
, head_width
und head_length
dass können Sie die Form des Pfeils ändern , wenn Sie nicht wie die Standardwerte. Bei Bedarf können wir auch die Füllfarbe und andere Ästhetik festlegen:
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))
Der einzige Haken ist, dass wir es zuerst schreiben müssen!
Anhand der Beispiele in der erweiterten ggplot2-Vignette können wir unsere geom_arrowbar
auf dieselbe Weise definieren wie andere Geome, außer dass wir unsere 3 Parameter übergeben möchten, die die Form des Pfeils steuern. Diese werden der params
Liste des resultierenden layer
Objekts hinzugefügt, das zum Erstellen unserer Pfeilebene verwendet wird:
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, ...))
}
Jetzt bleibt nur noch zu definieren, was a GeomArrowBar
ist. Dies ist effektiv eine ggproto
Klassendefinition. Der wichtigste Teil davon ist die draw_panel
Elementfunktion, die jede Zeile unseres Datenrahmens in Pfeilformen konvertiert. Nach einigen grundlegenden Berechnungen aus den x- und y-Koordinaten sowie unseren verschiedenen Formparametern, wie die Form des Pfeils aussehen soll, wird grid::polygonGrob
für jede Zeile unserer Daten eine erstellt und in a gespeichert gTree
. Dies bildet die grafische Komponente der Ebene.
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}
)
Diese Implementierung ist alles andere als perfekt. Es fehlen einige wichtige Funktionen, wie z. B. sinnvolle Standardachsenbeschränkungen und die Fähigkeit dazu coord_flip
, und es werden unästhetische Ergebnisse erzielt, wenn die Pfeilspitzen länger als die gesamte Spalte sind (obwohl Sie in dieser Situation möglicherweise ohnehin kein solches Diagramm verwenden möchten). . Es wird jedoch sinnvoll sein, dass der Pfeil nach links zeigt, wenn Sie einen negativen Wert haben. Eine bessere Implementierung könnte auch eine Option für leere Pfeilspitzen hinzufügen.
Kurz gesagt, es würde eine Menge Verbesserungen erfordern, um diese (und andere) Fehler auszubügeln und produktionsbereit zu machen, aber es ist gut genug, um in der Zwischenzeit ohne allzu großen Aufwand einige schöne Charts zu erstellen.
Erstellt am 08.03.2020 durch das reprex-Paket (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))