ggplot with bty="n",或者如何将网格坐标添加到绘图坐标
ggplot with bty="n", or how to add grid coordinates to plot coordinates
我有一个关于 this one. Basically I want to add bty = "n"
to a ggplot2 graph in a proper way. Emphasis on proper here because the solution in the other question almost what I want, except for this detail: 的问题,我希望轴线能一直持续到刻度结束,而不是直到它的中间。首先,图表代码:
library(ggplot2)
library(grid)
graph = ggplot(faithful, aes(x=eruptions, y=waiting)) +
geom_point(shape=21) +
theme(
# tick width, a bit exaggerated as example
axis.ticks = element_line(size = 5, color = "gray")
)
graph # graph with no axis lines
# get axis limits
gb = ggplot_build(graph)
xLim = range(gb$layout$panel_ranges[[1]]$x.major_source)
yLim = range(gb$layout$panel_ranges[[1]]$y.major_source)
# add lines
graph +
geom_segment(y = -Inf, yend = -Inf, x = xLim[1], xend = xLim[2]) +
geom_segment(x = -Inf, xend = -Inf, y = yLim[1], yend = yLim[2])
所以问题是:我在 x 轴上绘制从 50 到 90。但是,刻度线以 50 和 90 为中心,因此它们每边延伸 size = 5
的一半。 ?element_line
告诉我线条/边框大小默认以毫米为单位。因此,我想画一条从 50 - 5mm / 2 到 90 + 5mm / 2 的线。我尝试了以下(许多变体):
xLim = range(gb$layout$panel_ranges[[1]]$x.major_source)
yLim = range(gb$layout$panel_ranges[[1]]$y.major_source)
uType = "npc"
uType2 = "mm"
# attempt conversion of units
xLim[1] = xLim[1] - convertWidth(unit(2.5, units = uType2),
unitTo = uType, valueOnly = TRUE)
xLim[2] = xLim[2] + convertWidth(unit(2.5, units = uType2),
unitTo = uType, valueOnly = TRUE)
yLim[1] = yLim[1] - convertHeight(unit(2.5, units = uType2),
unitTo = uType, valueOnly = TRUE)
yLim[2] = yLim[2] - convertHeight(unit(2.5, units = uType2),
unitTo = uType, valueOnly = TRUE)
# redraw graph
cairo_pdf("Rplot.pdf")
graph +
geom_segment(y = -Inf, yend = -Inf, x = xLim[1], xend = xLim[2]) +
geom_segment(x = -Inf, xend = -Inf, y = yLim[1], yend = yLim[2])
dev.off()
但没有任何运气。有什么想法吗?
我相信您必须编写一个 drawDetails 方法或类似方法来在绘图时进行单位计算,这样才能起作用。
或者(也许更容易),您可以编写一个自定义的刻度 grob,它可以延伸以覆盖轴线。
(请注意,由于其 z 顺序 IIRC,两个轴具有不同的线宽;我认为该错误已修复)。
library(ggplot2)
library(grid)
element_grob.element_custom_x <- function (element, x = 0:1, y = 0:1, colour = NULL, size = NULL,
linetype = NULL, lineend = "butt", default.units = "npc", id.lengths = NULL,
...)
{
gp <- gpar(lwd = ggplot2:::len0_null(size * .pt), col = colour, lty = linetype,
lineend = lineend)
element_gp <- gpar(lwd = ggplot2:::len0_null(element$size * .pt), col = element$colour,
lty = element$linetype, lineend = element$lineend)
arrow <- if (is.logical(element$arrow) && !element$arrow) {
NULL
}
else {
element$arrow
}
g1 <- polylineGrob(x, y, default.units = default.units,
gp = utils::modifyList(element_gp, gp),
id.lengths = id.lengths, arrow = arrow, ...)
vertical <- length(unique(element$x)) == 1 && length(unique(element$y)) >= 1
g2 <- grid::editGrob(g1, y=y + unit(1,"mm"), gp=utils::modifyList(gp, list(col="green")), name="new")
grid::grobTree(g2, g1)
}
element_grob.element_custom_y <- function (element, x = 0:1, y = 0:1, colour = NULL, size = NULL,
linetype = NULL, lineend = "butt", default.units = "npc", id.lengths = NULL,
...)
{
gp <- gpar(lwd = ggplot2:::len0_null(size * .pt), col = colour, lty = linetype,
lineend = lineend)
element_gp <- gpar(lwd = ggplot2:::len0_null(element$size * .pt), col = element$colour,
lty = element$linetype, lineend = element$lineend)
arrow <- if (is.logical(element$arrow) && !element$arrow) {
NULL
}
else {
element$arrow
}
g1 <- polylineGrob(x, y, default.units = default.units,
gp = utils::modifyList(element_gp, gp),
id.lengths = id.lengths, arrow = arrow, ...)
g2 <- grid::editGrob(g1, x=x + unit(1,"mm"), gp=utils::modifyList(gp, list(col="green")), name="new")
grid::grobTree(g2, g1)
}
## silly wrapper to fool ggplot2
x_custom <- function(...){
structure(
list(...), # this ... information is not used, btw
class = c("element_custom_x","element_blank", "element") # inheritance test workaround
)
}
y_custom <- function(...){
structure(
list(...), # this ... information is not used, btw
class = c("element_custom_y","element_blank", "element") # inheritance test workaround
)
}
graph = ggplot(faithful, aes(x=eruptions, y=waiting)) +
geom_point(shape=21) + theme_minimal() +
theme(
axis.ticks.x = x_custom(size = 5, colour = "red") ,
axis.ticks.y = y_custom(size = 5, colour = "red") ,
axis.ticks.length = unit(2,"mm")
)
graph # graph with no axis lines
gb <- ggplot_build(graph)
xLim = range(gb$layout$panel_ranges[[1]]$x.major_source)
yLim = range(gb$layout$panel_ranges[[1]]$y.major_source)
graph +
geom_segment(y = -Inf, yend = -Inf, x = xLim[1], xend = xLim[2],lwd=2) +
geom_segment(x = -Inf, xend = -Inf, y = yLim[1], yend = yLim[2],lwd=2)
现在简单多了:使用包 ggthemes()
中的 geom_rangeframe()
。我认为它完全符合您的要求。
我有一个关于 this one. Basically I want to add bty = "n"
to a ggplot2 graph in a proper way. Emphasis on proper here because the solution in the other question almost what I want, except for this detail:
library(ggplot2)
library(grid)
graph = ggplot(faithful, aes(x=eruptions, y=waiting)) +
geom_point(shape=21) +
theme(
# tick width, a bit exaggerated as example
axis.ticks = element_line(size = 5, color = "gray")
)
graph # graph with no axis lines
# get axis limits
gb = ggplot_build(graph)
xLim = range(gb$layout$panel_ranges[[1]]$x.major_source)
yLim = range(gb$layout$panel_ranges[[1]]$y.major_source)
# add lines
graph +
geom_segment(y = -Inf, yend = -Inf, x = xLim[1], xend = xLim[2]) +
geom_segment(x = -Inf, xend = -Inf, y = yLim[1], yend = yLim[2])
所以问题是:我在 x 轴上绘制从 50 到 90。但是,刻度线以 50 和 90 为中心,因此它们每边延伸 size = 5
的一半。 ?element_line
告诉我线条/边框大小默认以毫米为单位。因此,我想画一条从 50 - 5mm / 2 到 90 + 5mm / 2 的线。我尝试了以下(许多变体):
xLim = range(gb$layout$panel_ranges[[1]]$x.major_source)
yLim = range(gb$layout$panel_ranges[[1]]$y.major_source)
uType = "npc"
uType2 = "mm"
# attempt conversion of units
xLim[1] = xLim[1] - convertWidth(unit(2.5, units = uType2),
unitTo = uType, valueOnly = TRUE)
xLim[2] = xLim[2] + convertWidth(unit(2.5, units = uType2),
unitTo = uType, valueOnly = TRUE)
yLim[1] = yLim[1] - convertHeight(unit(2.5, units = uType2),
unitTo = uType, valueOnly = TRUE)
yLim[2] = yLim[2] - convertHeight(unit(2.5, units = uType2),
unitTo = uType, valueOnly = TRUE)
# redraw graph
cairo_pdf("Rplot.pdf")
graph +
geom_segment(y = -Inf, yend = -Inf, x = xLim[1], xend = xLim[2]) +
geom_segment(x = -Inf, xend = -Inf, y = yLim[1], yend = yLim[2])
dev.off()
但没有任何运气。有什么想法吗?
我相信您必须编写一个 drawDetails 方法或类似方法来在绘图时进行单位计算,这样才能起作用。
或者(也许更容易),您可以编写一个自定义的刻度 grob,它可以延伸以覆盖轴线。
(请注意,由于其 z 顺序 IIRC,两个轴具有不同的线宽;我认为该错误已修复)。
library(ggplot2)
library(grid)
element_grob.element_custom_x <- function (element, x = 0:1, y = 0:1, colour = NULL, size = NULL,
linetype = NULL, lineend = "butt", default.units = "npc", id.lengths = NULL,
...)
{
gp <- gpar(lwd = ggplot2:::len0_null(size * .pt), col = colour, lty = linetype,
lineend = lineend)
element_gp <- gpar(lwd = ggplot2:::len0_null(element$size * .pt), col = element$colour,
lty = element$linetype, lineend = element$lineend)
arrow <- if (is.logical(element$arrow) && !element$arrow) {
NULL
}
else {
element$arrow
}
g1 <- polylineGrob(x, y, default.units = default.units,
gp = utils::modifyList(element_gp, gp),
id.lengths = id.lengths, arrow = arrow, ...)
vertical <- length(unique(element$x)) == 1 && length(unique(element$y)) >= 1
g2 <- grid::editGrob(g1, y=y + unit(1,"mm"), gp=utils::modifyList(gp, list(col="green")), name="new")
grid::grobTree(g2, g1)
}
element_grob.element_custom_y <- function (element, x = 0:1, y = 0:1, colour = NULL, size = NULL,
linetype = NULL, lineend = "butt", default.units = "npc", id.lengths = NULL,
...)
{
gp <- gpar(lwd = ggplot2:::len0_null(size * .pt), col = colour, lty = linetype,
lineend = lineend)
element_gp <- gpar(lwd = ggplot2:::len0_null(element$size * .pt), col = element$colour,
lty = element$linetype, lineend = element$lineend)
arrow <- if (is.logical(element$arrow) && !element$arrow) {
NULL
}
else {
element$arrow
}
g1 <- polylineGrob(x, y, default.units = default.units,
gp = utils::modifyList(element_gp, gp),
id.lengths = id.lengths, arrow = arrow, ...)
g2 <- grid::editGrob(g1, x=x + unit(1,"mm"), gp=utils::modifyList(gp, list(col="green")), name="new")
grid::grobTree(g2, g1)
}
## silly wrapper to fool ggplot2
x_custom <- function(...){
structure(
list(...), # this ... information is not used, btw
class = c("element_custom_x","element_blank", "element") # inheritance test workaround
)
}
y_custom <- function(...){
structure(
list(...), # this ... information is not used, btw
class = c("element_custom_y","element_blank", "element") # inheritance test workaround
)
}
graph = ggplot(faithful, aes(x=eruptions, y=waiting)) +
geom_point(shape=21) + theme_minimal() +
theme(
axis.ticks.x = x_custom(size = 5, colour = "red") ,
axis.ticks.y = y_custom(size = 5, colour = "red") ,
axis.ticks.length = unit(2,"mm")
)
graph # graph with no axis lines
gb <- ggplot_build(graph)
xLim = range(gb$layout$panel_ranges[[1]]$x.major_source)
yLim = range(gb$layout$panel_ranges[[1]]$y.major_source)
graph +
geom_segment(y = -Inf, yend = -Inf, x = xLim[1], xend = xLim[2],lwd=2) +
geom_segment(x = -Inf, xend = -Inf, y = yLim[1], yend = yLim[2],lwd=2)
现在简单多了:使用包 ggthemes()
中的 geom_rangeframe()
。我认为它完全符合您的要求。