eli*_*ing 15 r ggplot2 geom-bar geom-text ggproto
这实际上是两个问题中的一个(不确定是否违反SO规则,但无论如何).
第一个问题是我如何强迫一个geom_text适合geom_bar?(动态根据绘制的值)
环顾四周,我发现的解决方案正在改变标签的大小.这当然有效,但不适用于所有情况.您可以更改特定绘图的大小以使文本适合条形,但是当数据更改时,您可能需要再次手动更改文本的大小.我现实生活中的问题是,我需要为不断变化的数据(每日)生成相同的图,所以我无法真正手动调整每个图的大小.
我尝试将标签的大小设置为数据的函数.它有点工作,不完美,但适用于许多情况.
但这是另一个问题,即使标签适合栏内,重新调整情节会使一切变得混乱.调查一下,我也在ggplot文档中找到了
标签确实有高度和宽度,但它们是物理单位,而不是数据单位.它们在该绘图上占用的空间量在数据单位中不是恒定的:当您调整绘图大小时,标签保持相同的大小,但轴的大小会发生变化.
这让我想到了第二个问题:是否可以更改此默认行为并让/使图表调整大小?
还让我提炼我的第一个问题.是否可以强制a geom_text适合a geom_bar,使用物理单位和数据单元之间的聪明关系动态设置文本的大小?
所以,为了遵循良好的做法,这是我可重复的例子:
set.seed(1234567)
data_gd <- data.frame(x = letters[1:5],
y = runif(5, 100, 99999))
ggplot(data = data_gd,
mapping = aes(x = x, y = y, fill = x)) +
geom_bar(stat = "identity") +
geom_text(mapping = aes(label = y, y = y/2))
Run Code Online (Sandbox Code Playgroud)
此代码生成此图:
如果我只是简单地调整绘图大小," 标签保持相同的大小,但轴的大小会发生变化 ",从而使标签适合条形图(现在标签甚至可能太小).
所以,这是我的第二个问题.标签调整大小并保持纵横比相对于条形图会很好.任何想法如何实现这一点或是否有可能?
好的,但回到如何在条形图中标注标签,最简单的解决方案是设置标签的大小.
ggplot(data = data_gd,
mapping = aes(x = x, y = y, fill = x)) +
geom_bar(stat = "identity") +
geom_text(mapping = aes(label = y, y = y/2), size = 3)
Run Code Online (Sandbox Code Playgroud)
同样,这可以如下所示工作,但它对数据的变化不可维护/不稳健.
例如,生成具有不同数据的图的完全相同的代码会产生灾难性的结果.
data_gd <- data.frame(x = letters[1:30],
y = runif(30, 100, 99999))
ggplot(data = data_gd,
mapping = aes(x = x, y = y, fill = x)) +
geom_bar(stat = "identity") +
geom_text(mapping = aes(label = y, y = y/2), size = 3)
Run Code Online (Sandbox Code Playgroud)
我可以继续使用这些示例,将标签的大小设置为x轴上类别数量的函数,依此类推.但是你明白了,也许你们中的一位ggplot2专家可以给我一些想法.
bap*_*ste 11
一个选项可能是编写一个geom,它使用带有自定义drawDetails方法的textGrob来适应分配的空间,由条形宽度设置.
library(grid)
library(ggplot2)
fitGrob <- function(label, x=0.5, y=0.5, width=1){
grob(x=x, y=y, width=width, label=label, cl = "fit")
}
drawDetails.fit <- function(x, recording=FALSE){
tw <- sapply(x$label, function(l) convertWidth(grobWidth(textGrob(l)), "native", valueOnly = TRUE))
cex <- x$width / tw
grid.text(x$label, x$x, x$y, gp=gpar(cex=cex), default.units = "native")
}
`%||%` <- ggplot2:::`%||%`
GeomFit <- ggproto("GeomFit", GeomRect,
required_aes = c("x", "label"),
setup_data = function(data, params) {
data$width <- data$width %||%
params$width %||% (resolution(data$x, FALSE) * 0.9)
transform(data,
ymin = pmin(y, 0), ymax = pmax(y, 0),
xmin = x - width / 2, xmax = x + width / 2, width = NULL
)
},
draw_panel = function(self, data, panel_scales, coord, width = NULL) {
bars <- ggproto_parent(GeomRect, self)$draw_panel(data, panel_scales, coord)
coords <- coord$transform(data, panel_scales)
width <- abs(coords$xmax - coords$xmin)
tg <- fitGrob(label=coords$label, y = coords$y/2, x = coords$x, width = width)
grobTree(bars, tg)
}
)
geom_fit <- function(mapping = NULL, data = NULL,
stat = "count", position = "stack",
...,
width = NULL,
binwidth = NULL,
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE) {
layer(
data = data,
mapping = mapping,
stat = stat,
geom = GeomFit,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
width = width,
na.rm = na.rm,
...
)
)
}
set.seed(1234567)
data_gd <- data.frame(x = letters[1:5],
y = runif(5, 100, 99999))
ggplot(data = data_gd,
mapping = aes(x = x, y = y, fill = x, label=round(y))) +
geom_fit(stat = "identity") +
theme()
Run Code Online (Sandbox Code Playgroud)
如果水平条形图没问题,那么问题不在于标签的大小,而在于展示位置.我的解决方案是
由此代码创建:
library(ggplot2)
data_gd <- data.frame(x = letters[1:26],
y = runif(26, 100, 99999))
ymid <- mean(range(data_gd$y))
ggplot(data = data_gd,
mapping = aes(x = x, y = y, fill = x)) +
geom_bar(stat = "identity") +
geom_text(mapping = aes(label = y, y = y,
hjust = ifelse(y < ymid, -0.1, 1.1)), size = 3) +
coord_flip()
Run Code Online (Sandbox Code Playgroud)
诀窍分三步完成:
coord_flip 制作一个水平条形图.geom_text也取决于y的值.如果条形长度小于y范围的一半,则文本将打印在条形图外部(右侧为y值).如果条形长度超过y范围的一半,则文本将打印在条形内部(左侧为y值).这样可以确保文本始终打印在绘图区域内(如果不是太长).hjust = ifelse(y < ymid, 0, 1)).| 归档时间: |
|
| 查看次数: |
4285 次 |
| 最近记录: |