R:如何将多边形和线段的直线与极坐标结合起来?
R: How to combine straight lines of polygon and line segments with polar coordinates?
假设我在 6 个方向上有一些长度的线性数据。我想制作 "wind rose".
风格的图表
###create sample data
a <- c(1,2,3,4,5,6) #directions
perc <- c(0.15,0.05,0.3,0.15,0.05,0.3) #percentual lengths
lab <- c("A", "B", "C", "D", "E", "F") #labels of directions
data <- data.frame(a,perc,lab)
我已经使用 ggplot2 尝试了两种变体,使用 coord_polar
和 coord_radar
(受 an article from Erwan Le Pennec: From Parallel Plot to Radar Plot 启发)。每一个都部分正确部分错误(以我的预期来看):
#similar parameters in both variants:
chart_stuff <- list(
geom_polygon(aes(x=a, y=perc, col = 1), fill=NA,show.legend = F),
geom_segment(aes(x=as.factor(a), yend=perc, xend=as.factor(a), y=0), size=2),
scale_x_discrete(labels=data$lab),
scale_y_continuous(labels = scales::percent, limits = c(0,0.31)),
theme_light(),
theme(axis.title = element_blank())
)
#chart1
ggplot(data) +
chart_stuff+
coord_polar(start=(-pi/6))+
ggtitle("coord_polar: wrong polygon, good segments")
#chart2
#coord_radar function with modified start parameter:
coord_radar <- function (theta = "x", start = -pi/6, direction = 1) {
theta <- match.arg(theta, c("x", "y"))
r <- if (theta == "x") "y" else "x"
ggproto("CordRadar", CoordPolar, theta = theta, r = r, start = start,
direction = sign(direction),
is_linear = function(coord) TRUE)
}
ggplot(data) +
chart_stuff+
coord_radar()+
ggtitle("coord_radar: good polygon, wrong segments")
输出:
所以我想要一张图片,其中包含直线的多边形边界和代表方向的线段(长度百分比)。我想错误可能是将离散比例与连续比例混合使用,但我无法解决。有什么想法吗?
说明
在GeomSegment的draw_panel
函数中,坐标系是否线性影响如何绘制面板:
> GeomSegment$draw_panel
<ggproto method>
<Wrapper function>
function (...)
f(...)
<Inner function (f)>
function (data, panel_params, coord, arrow = NULL, arrow.fill = NULL,
lineend = "butt", linejoin = "round", na.rm = FALSE)
{
data <- remove_missing(data, na.rm = na.rm, c("x", "y", "xend",
"yend", "linetype", "size", "shape"), name = "geom_segment")
if (empty(data))
return(zeroGrob())
if (coord$is_linear()) {
coord <- coord$transform(data, panel_params)
arrow.fill <- arrow.fill %||% coord$colour
return(segmentsGrob(coord$x, coord$y, coord$xend, coord$yend,
default.units = "native", gp = gpar(col = alpha(coord$colour,
coord$alpha), fill = alpha(arrow.fill, coord$alpha),
lwd = coord$size * .pt, lty = coord$linetype,
lineend = lineend, linejoin = linejoin), arrow = arrow))
}
data$group <- 1:nrow(data)
starts <- subset(data, select = c(-xend, -yend))
ends <- plyr::rename(subset(data, select = c(-x, -y)), c(xend = "x",
yend = "y"), warn_missing = FALSE)
pieces <- rbind(starts, ends)
pieces <- pieces[order(pieces$group), ]
GeomPath$draw_panel(pieces, panel_params, coord, arrow = arrow,
lineend = lineend)
}
coord_polar
不是线性的,因为默认情况下CoordPolar$is_linear()
求值为FALSE,所以geom_segment
是根据GeomPath$draw_panel(...)
.
绘制的
另一方面,coord_radar
是线性的,因为is_linear = function(coord) TRUE
包含在它的定义中,所以geom_segment
是使用segmentsGrob(...)
绘制的。
解决方法
我们可以定义自己的GeomSegment版本,无论坐标系是否为线性,它都使用前一个选项draw_panel
:
GeomSegment2 <- ggproto("GeomSegment2",
GeomSegment,
draw_panel = function (data, panel_params, coord, arrow = NULL,
arrow.fill = NULL, lineend = "butt",
linejoin = "round", na.rm = FALSE) {
data <- remove_missing(data, na.rm = na.rm,
c("x", "y", "xend", "yend", "linetype",
"size", "shape"),
name = "geom_segment")
if (ggplot2:::empty(data))
return(zeroGrob())
# remove option for linear coordinate system
data$group <- 1:nrow(data)
starts <- subset(data, select = c(-xend, -yend))
ends <- plyr::rename(subset(data, select = c(-x, -y)),
c(xend = "x", yend = "y"),
warn_missing = FALSE)
pieces <- rbind(starts, ends)
pieces <- pieces[order(pieces$group), ]
GeomPath$draw_panel(pieces, panel_params, coord, arrow = arrow,
lineend = lineend)
})
geom_segment2 <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity",
..., arrow = NULL, arrow.fill = NULL, lineend = "butt",
linejoin = "round", na.rm = FALSE, show.legend = NA,
inherit.aes = TRUE) {
layer(data = data, mapping = mapping, stat = stat, geom = GeomSegment2,
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
params = list(arrow = arrow, arrow.fill = arrow.fill,
lineend = lineend, linejoin = linejoin, na.rm = na.rm,
...))
}
试试看:
chart_stuff <- list(
geom_polygon(aes(x=a, y=perc, col = 1), fill=NA,show.legend = F),
# geom_segment2 instead of geom_segment
geom_segment2(aes(x=as.factor(a), yend=perc, xend=as.factor(a), y=0), size=2),
scale_x_discrete(labels=data$lab),
scale_y_continuous(labels = scales::percent, limits = c(0,0.31)),
theme_light(),
theme(axis.title = element_blank())
)
ggplot(data) +
chart_stuff+
coord_radar()+
ggtitle("coord_radar: good polygon, good segments")
假设我在 6 个方向上有一些长度的线性数据。我想制作 "wind rose".
风格的图表###create sample data
a <- c(1,2,3,4,5,6) #directions
perc <- c(0.15,0.05,0.3,0.15,0.05,0.3) #percentual lengths
lab <- c("A", "B", "C", "D", "E", "F") #labels of directions
data <- data.frame(a,perc,lab)
我已经使用 ggplot2 尝试了两种变体,使用 coord_polar
和 coord_radar
(受 an article from Erwan Le Pennec: From Parallel Plot to Radar Plot 启发)。每一个都部分正确部分错误(以我的预期来看):
#similar parameters in both variants:
chart_stuff <- list(
geom_polygon(aes(x=a, y=perc, col = 1), fill=NA,show.legend = F),
geom_segment(aes(x=as.factor(a), yend=perc, xend=as.factor(a), y=0), size=2),
scale_x_discrete(labels=data$lab),
scale_y_continuous(labels = scales::percent, limits = c(0,0.31)),
theme_light(),
theme(axis.title = element_blank())
)
#chart1
ggplot(data) +
chart_stuff+
coord_polar(start=(-pi/6))+
ggtitle("coord_polar: wrong polygon, good segments")
#chart2
#coord_radar function with modified start parameter:
coord_radar <- function (theta = "x", start = -pi/6, direction = 1) {
theta <- match.arg(theta, c("x", "y"))
r <- if (theta == "x") "y" else "x"
ggproto("CordRadar", CoordPolar, theta = theta, r = r, start = start,
direction = sign(direction),
is_linear = function(coord) TRUE)
}
ggplot(data) +
chart_stuff+
coord_radar()+
ggtitle("coord_radar: good polygon, wrong segments")
输出:
所以我想要一张图片,其中包含直线的多边形边界和代表方向的线段(长度百分比)。我想错误可能是将离散比例与连续比例混合使用,但我无法解决。有什么想法吗?
说明
在GeomSegment的draw_panel
函数中,坐标系是否线性影响如何绘制面板:
> GeomSegment$draw_panel
<ggproto method>
<Wrapper function>
function (...)
f(...)
<Inner function (f)>
function (data, panel_params, coord, arrow = NULL, arrow.fill = NULL,
lineend = "butt", linejoin = "round", na.rm = FALSE)
{
data <- remove_missing(data, na.rm = na.rm, c("x", "y", "xend",
"yend", "linetype", "size", "shape"), name = "geom_segment")
if (empty(data))
return(zeroGrob())
if (coord$is_linear()) {
coord <- coord$transform(data, panel_params)
arrow.fill <- arrow.fill %||% coord$colour
return(segmentsGrob(coord$x, coord$y, coord$xend, coord$yend,
default.units = "native", gp = gpar(col = alpha(coord$colour,
coord$alpha), fill = alpha(arrow.fill, coord$alpha),
lwd = coord$size * .pt, lty = coord$linetype,
lineend = lineend, linejoin = linejoin), arrow = arrow))
}
data$group <- 1:nrow(data)
starts <- subset(data, select = c(-xend, -yend))
ends <- plyr::rename(subset(data, select = c(-x, -y)), c(xend = "x",
yend = "y"), warn_missing = FALSE)
pieces <- rbind(starts, ends)
pieces <- pieces[order(pieces$group), ]
GeomPath$draw_panel(pieces, panel_params, coord, arrow = arrow,
lineend = lineend)
}
coord_polar
不是线性的,因为默认情况下CoordPolar$is_linear()
求值为FALSE,所以geom_segment
是根据GeomPath$draw_panel(...)
.
coord_radar
是线性的,因为is_linear = function(coord) TRUE
包含在它的定义中,所以geom_segment
是使用segmentsGrob(...)
绘制的。
解决方法
我们可以定义自己的GeomSegment版本,无论坐标系是否为线性,它都使用前一个选项draw_panel
:
GeomSegment2 <- ggproto("GeomSegment2",
GeomSegment,
draw_panel = function (data, panel_params, coord, arrow = NULL,
arrow.fill = NULL, lineend = "butt",
linejoin = "round", na.rm = FALSE) {
data <- remove_missing(data, na.rm = na.rm,
c("x", "y", "xend", "yend", "linetype",
"size", "shape"),
name = "geom_segment")
if (ggplot2:::empty(data))
return(zeroGrob())
# remove option for linear coordinate system
data$group <- 1:nrow(data)
starts <- subset(data, select = c(-xend, -yend))
ends <- plyr::rename(subset(data, select = c(-x, -y)),
c(xend = "x", yend = "y"),
warn_missing = FALSE)
pieces <- rbind(starts, ends)
pieces <- pieces[order(pieces$group), ]
GeomPath$draw_panel(pieces, panel_params, coord, arrow = arrow,
lineend = lineend)
})
geom_segment2 <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity",
..., arrow = NULL, arrow.fill = NULL, lineend = "butt",
linejoin = "round", na.rm = FALSE, show.legend = NA,
inherit.aes = TRUE) {
layer(data = data, mapping = mapping, stat = stat, geom = GeomSegment2,
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
params = list(arrow = arrow, arrow.fill = arrow.fill,
lineend = lineend, linejoin = linejoin, na.rm = na.rm,
...))
}
试试看:
chart_stuff <- list(
geom_polygon(aes(x=a, y=perc, col = 1), fill=NA,show.legend = F),
# geom_segment2 instead of geom_segment
geom_segment2(aes(x=as.factor(a), yend=perc, xend=as.factor(a), y=0), size=2),
scale_x_discrete(labels=data$lab),
scale_y_continuous(labels = scales::percent, limits = c(0,0.31)),
theme_light(),
theme(axis.title = element_blank())
)
ggplot(data) +
chart_stuff+
coord_radar()+
ggtitle("coord_radar: good polygon, good segments")