Я ищу способ добавить незначительные отметки в ggplots без использования coord_cartesian(clip = "off")
. Или способ воспроизведения можно применить отсечение к оси X, но не к оси Y, или наоборот.
До сих пор я использовал функцию annotation_ticks()
и геом GeomTicks
, определенные в этом превосходном ответе здесь (с некоторыми незначительными изменениями, чтобы он работал с ggplot2 v3.3.0
) , К сожалению, для того, чтобы аннотации в виде отметок появлялись снаружи графика, необходимо использовать coord_cartesian(clip = "off")
, что означает, что все остальное, что находится за пределами области построения, также выставлено (см. Представленный ниже).
В качестве альтернативы, возможно, есть это способ использовать любую из новых возможностей ggplot2 v3.3.0
для рисования второстепенных тиков не как аннотации, а как фактическая часть оси / графика, так что их можно рисовать вне области построения.
Я не разработчик программного обеспечения, но, возможно, можно определить новый элемент темы, используя register_theme_elements
с именем axis.minor.ticks
, который ведет себя как axis.ticks
, но получает соответствующее расположение второстепенных тиков из panel_params$y$break_positions_minor
вместо panel_params$y$break_positions
. Или как-то использовать новые функции guide_x()
S3.
Любая помощь будет принята с благодарностью!
Функция аннотации и объект ggproto
Функция annotation_ticks()
(включает * 1028) * это исправление для огранки):
annotation_ticks <- function(sides = "b",
scale = "identity",
scaled = TRUE,
ticklength = unit(0.1, "cm"),
colour = "black",
size = 0.5,
linetype = 1,
alpha = 1,
color = NULL,
ticks_per_base = NULL,
data = data.frame(x = NA),
...) {
if (!is.null(color)) {
colour <- color
}
# check for invalid side
if (grepl("[^btlr]", sides)) {
stop(gsub("[btlr]", "", sides), " is not a valid side: b,t,l,r are valid")
}
# split sides to character vector
sides <- strsplit(sides, "")[[1]]
if (length(sides) != length(scale)) {
if (length(scale) == 1) {
scale <- rep(scale, length(sides))
} else {
stop("Number of scales does not match the number of sides")
}
}
base <- sapply(scale, function(x) switch(x, "identity" = 10, "log10" = 10, "log" = exp(1)), USE.NAMES = FALSE)
if (missing(ticks_per_base)) {
ticks_per_base <- base - 1
} else {
if ((length(sides) != length(ticks_per_base))) {
if (length(ticks_per_base) == 1) {
ticks_per_base <- rep(ticks_per_base, length(sides))
} else {
stop("Number of ticks_per_base does not match the number of sides")
}
}
}
delog <- scale %in% "identity"
layer(
data = data,
mapping = NULL,
stat = StatIdentity,
geom = GeomTicks,
position = PositionIdentity,
show.legend = FALSE,
inherit.aes = FALSE,
params = list(
base = base,
sides = sides,
scaled = scaled,
ticklength = ticklength,
colour = colour,
size = size,
linetype = linetype,
alpha = alpha,
ticks_per_base = ticks_per_base,
delog = delog,
...
)
)
}
Объект ggproto (теперь работает с ggplot2 v3.3.0
):
GeomTicks <- ggproto(
"GeomTicks", Geom,
extra_params = "",
handle_na = function(data, params) {
data
},
draw_panel = function(data,
panel_scales,
coord,
base = c(10, 10),
sides = c("b", "l"),
scaled = TRUE,
ticklength = unit(0.1, "cm"),
ticks_per_base = base - 1,
delog = c(x = TRUE, y = TRUE)) {
ticks <- list()
for (s in 1:length(sides)) {
if (grepl("[b|t]", sides[s])) {
# for ggplot2 < 3.3.0 use: xticks <- panel_params$x.minor
if (utils::packageVersion("ggplot2") >= "3.2.1.9000") {
x_minor_breaks <- panel_scales$x$break_positions_minor()
x_major_breaks <- panel_scales$x$break_positions()
} else {
x_minor_breaks <- panel_scales$x.minor
x_major_breaks <- panel_scales$x.major
}
xticks <- setdiff(x_minor_breaks, x_major_breaks)
# Make the grobs
if (grepl("b", sides[s])) {
ticks$x_b <- with(
data,
segmentsGrob(
x0 = unit(xticks, "npc"),
x1 = unit(xticks, "npc"),
y0 = unit(0, "npc"),
y1 = ticklength,
gp = gpar(
col = alpha(colour, alpha),
lty = linetype,
lwd = size * .pt
)
)
)
}
if (grepl("t", sides[s])) {
ticks$x_t <- with(
data,
segmentsGrob(
x0 = unit(xticks, "npc"),
x1 = unit(xticks, "npc"),
y0 = unit(1, "npc"),
y1 = unit(1, "npc") - ticklength,
gp = gpar(
col = alpha(colour, alpha),
lty = linetype,
lwd = size * .pt
)
)
)
}
}
if (grepl("[l|r]", sides[s])) {
# for ggplot2 < 3.3.0 use: yticks <- panel_params$y.minor
if (utils::packageVersion("ggplot2") >= "3.2.1.9000") {
y_minor_breaks <- panel_scales$y$break_positions_minor()
y_major_breaks <- panel_scales$y$break_positions()
} else {
y_minor_breaks <- panel_scales$y.minor
y_major_breaks <- panel_scales$y.major
}
yticks <- setdiff(y_minor_breaks, y_major_breaks)
# Make the grobs
if (grepl("l", sides[s])) {
ticks$y_l <- with(
data,
segmentsGrob(
y0 = unit(yticks, "npc"),
y1 = unit(yticks, "npc"),
x0 = unit(0, "npc"),
x1 = ticklength,
gp = gpar(
col = alpha(colour, alpha),
lty = linetype, lwd = size * .pt
)
)
)
}
if (grepl("r", sides[s])) {
ticks$y_r <- with(
data,
segmentsGrob(
y0 = unit(yticks, "npc"),
y1 = unit(yticks, "npc"),
x0 = unit(1, "npc"),
x1 = unit(1, "npc") - ticklength,
gp = gpar(
col = alpha(colour, alpha),
lty = linetype,
lwd = size * .pt
)
)
)
}
}
}
gTree(children = do.call("gList", ticks))
},
default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = 1)
)
График с coord_cartesian(clip = "on")
Столбец с очень толстой шириной линии выглядит нормально, но не может видеть пометки тиков.
library(ggplot2)
library(grid)
ggplot(mpg, aes(x = class, y = displ, fill = class)) +
stat_summary(fun = mean, geom = "col", colour = "black", size = 1) +
theme_classic(base_size = 8) +
scale_y_continuous(limits = c(0, 8), expand = c(0, 0)) +
annotation_ticks(sides = "l", ticklength = -1 * unit(0.2, "cm")) +
coord_cartesian(clip = "on")
ggsave("clip_on.png", device = "png", width = 4, height = 3)
график столбца с клипом = on
График с coord_cartesian(clip = "off")
Примечания к тикам видны, но столбцы с очень толстой шириной линии отображаются за пределами области построения.
ggplot(mpg, aes(x = class, y = displ, fill = class)) +
stat_summary(fun = mean, geom = "col", colour = "black", size = 1) +
theme_classic(base_size = 8) +
scale_y_continuous(limits = c(0, 8), expand = c(0, 0)) +
annotation_ticks(sides = "l", ticklength = -1 * unit(0.2, "cm")) +
coord_cartesian(clip = "off")
ggsave("clip_off.png", device = "png", width = 4, height = 3)
график столбца с клипом = off