Идеально вписывается в ggplot2 сюжет
Я хочу построить ограниченный кубический сплайн в качестве основного графика и добавить график типа "квадрат и усы", чтобы показать изменение переменной X. Однако нижний шарнир (х =42), медиана (х =51) и верхний шарнир (х =61) не полностью соответствовали соответствующей линии сетки основного графика.
library(Hmisc)
library(rms)
library(ggplot2)
library(gridExtra)
data(pbc)
d <- pbc
rm(pbc)
d$status <- ifelse(d$status != 0, 1, 0)
dd = datadist(d)
options(datadist='dd')
f <- cph(Surv(time, status) ~ rcs(age, 4), data=d)
p <- Predict(f, fun=exp)
df <- data.frame(age=p$age, yhat=p$yhat, lower=p$lower, upper=p$upper)
### 1st PLOT: main plot
(g <- ggplot(data=df, aes(x=age, y=yhat)) + geom_line(size=1))
# CI
(g <- g + geom_ribbon(data=df, aes(ymin=lower, ymax=upper), alpha=0.5, linetype=0, fill='#FFC000'))
# white background
(g <- g + theme_bw())
# X-axis
(breaks <- round(boxplot.stats(p[,"age"])$stats))
(g <- g + scale_x_continuous(breaks=breaks, limits=range(p[,"age"]), labels=round(breaks)))
(g <- g + xlab("Age"))
# Y-Achse
(g <- g + ylab("Hazard Ratio"))
# size and color of axis
(g <- g + theme(axis.line = element_line(color='black', size=1)))
(g <- g + theme(axis.ticks = element_line(color='black', size=1)))
(g <- g + theme( plot.background = element_blank() ))
#(g <- g + theme( panel.grid.major = element_blank() ))
(g <- g + theme( panel.grid.minor = element_blank() ))
(g <- g + theme( panel.border = element_blank() ))
### 2nd PLOT: box whisker plot
describe(df$age, digits=0)
round(range(df$age))
(gg <- ggplot(data=df, aes(x=1, y=age)) + geom_boxplot(outlier.shape=NA, size=1) + coord_flip())
(gg <- gg + theme( axis.line=element_blank() )) #
(gg <- gg + theme( axis.text.x=element_blank() ))
(gg <- gg + theme( axis.text.y=element_blank() ))
(gg <- gg + theme( axis.ticks=element_blank() ))
(gg <- gg + theme( axis.title.x=element_blank() ))
(gg <- gg + theme( axis.title.y=element_blank() ))
(gg <- gg + theme( panel.background=element_blank() ))
(gg <- gg + theme( panel.border=element_blank() )) #
(gg <- gg + theme( legend.position="none" )) #
(gg <- gg + theme( panel.grid.major=element_blank() )) #
(gg <- gg + theme( panel.grid.minor=element_blank() ))
(gg <- gg + theme( plot.background=element_blank() ))
(gg <- gg + theme( plot.margin = unit( c(0,0,0,0), "in" ) ))
(gg <- gg + scale_x_continuous(breaks=c(70,77,84), expand=c(0,0)) )
### FINAL PLOT: put box whisker plot in main plot
(final.gg <- g + annotation_custom(ggplotGrob(gg), ymin=2.4, ymax=2.6))
- Что я должен изменить для идеальной подгонки?
- Есть ли лучшее для автоматизированного выравнивания y-положения коробки и усика?
ОБНОВЛЕНИЕ #1 Спасибо за ваш ответ! Ниже вы можете увидеть мой пример с вашим кодом. Однако, как видите, нижний шарнир, медиана и верхний шарнир по-прежнему не подходят. Что не так?
library(Hmisc)
library(rms)
library(ggplot2)
library(gridExtra)
data(pbc)
d <- pbc
rm(pbc, pbcseq)
d$status <- ifelse(d$status != 0, 1, 0)
dd = datadist(d)
options(datadist='dd')
f <- cph(Surv(time, status) ~ rcs(age, 4), data=d)
p <- Predict(f, fun=exp)
df <- data.frame(age=p$age, yhat=p$yhat, lower=p$lower, upper=p$upper)
### 1st PLOT: main plot
(breaks <- boxplot.stats(p[,"age"])$stats)
g <- ggplot(data=df, aes(x=age, y=yhat)) + geom_line(size=1) +
geom_ribbon(data=df, aes(ymin=lower, ymax=upper), alpha=0.5, linetype=0, fill='#FFC000') +
theme_bw() +
scale_x_continuous(breaks=breaks) +
xlab("Age") +
ylab("Hazard Ratio") +
theme(axis.line = element_line(color='black', size=1),
axis.ticks = element_line(color='black', size=1),
plot.background = element_blank(),
# panel.border = element_blank(),
panel.grid.minor = element_blank())
### 2nd PLOT: box whisker plot
gg <- ggplot(data=df, aes(x=1, y=age)) +
geom_boxplot(outlier.shape=NA, size=1) +
scale_y_continuous(breaks=breaks) +
ylab(NULL) +
coord_flip() +
# theme_bw() +
theme(axis.line=element_blank(),
# axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
axis.title=element_blank(),
# panel.background=element_blank(),
panel.border=element_blank(),
# panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
# plot.background=element_blank(),
plot.margin = unit( c(0,0,0,0), "in" ),
axis.ticks.margin = unit(0, "lines"),
axis.ticks.length = unit(0, "cm"))
### FINAL PLOT: put box whisker plot in main plot
(final.gg <- g + annotation_custom(ggplotGrob(gg), ymin=2.4, ymax=2.6))
2 ответа
Небольшое редактирование: обновление до ggplot2 2.0.0axis.ticks.margin
устарела
На поле, даже если вы установили различные элементы element_blank
и поля равны нулю, пробелы по умолчанию остаются, что приводит к смещению. Эти места принадлежат:
- axis.ticks.length
- xlab
В приведенном ниже коде я несколько перестроил ваш код (надеюсь, что все в порядке) и прокомментировал некоторые строки кода, чтобы было видно, что эти два графика действительно совпадают. Я также установил разрывы в двух сюжете, чтобы не округлил breaks
(минимальное и максимальное значения, петли и медиана).
# X-axis
(breaks <- boxplot.stats(p[,"age"])$stats)
### 1st PLOT: main plot
g <- ggplot(data=df, aes(x=age, y=yhat)) + geom_line(size=1) +
geom_ribbon(data=df, aes(ymin=lower, ymax=upper), alpha=0.5, linetype=0, fill='#FFC000') +
theme_bw() +
scale_x_continuous(breaks=breaks) +
xlab("Age") +
ylab("Hazard Ratio") +
theme(axis.line = element_line(color='black', size=1),
axis.ticks = element_line(color='black', size=1),
plot.background = element_blank(),
# panel.border = element_blank(),
panel.grid.minor = element_blank())
### 2nd PLOT: box whisker plot
gg <- ggplot(data=df, aes(x=1, y=age)) +
geom_boxplot(outlier.shape=NA, size=1) +
scale_y_continuous(breaks=breaks) +
xlab(NULL) +
coord_flip() +
# theme_bw() +
theme(axis.line=element_blank(),
# axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
axis.title=element_blank(),
# panel.background=element_blank(),
panel.border=element_blank(),
# panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
# plot.background=element_blank(),
plot.margin = unit( c(0,0,0,0), "in" ),
# axis.ticks.margin = unit(0, "lines"),
axis.ticks.length = unit(0, "cm"))
### FINAL PLOT: put box whisker plot in main plot
(final.gg <- g + annotation_custom(ggplotGrob(gg), ymin=2.4, ymax=2.6))
Вы должны заметить, что метод ggplot для расчета петель немного отличается от метода, используемого boxplot.stats
,
# ggplot's hinges
bp = ggplot(data=df, aes(x=1, y=age)) +
geom_boxplot(outlier.shape=NA, size=1)
bpData = ggplot_build(bp)
bpData$data[[1]][1:5]
Альтернативный ответ с использованием gtable
функции для позиционирования бокса за пределами основного сюжета. Высота прямоугольника может быть скорректирована с помощью параметра "h"
library(rms)
# Data
data(pbc)
d <- pbc
rm(pbc)
d$status <- ifelse(d$status != 0, 1, 0)
dd = datadist(d)
options(datadist='dd')
f <- cph(Surv(time, status) ~ rcs(age, 4), data=d)
p <- Predict(f, fun=exp)
df <- data.frame(age=p$age, yhat=p$yhat, lower=p$lower, upper=p$upper)
# X-axis
breaks <- boxplot.stats(p[,"age"])$stats
# Main plot
MP <- ggplot(data=df, aes(x=age, y=yhat)) + geom_line(size=1) +
geom_ribbon(data=df, aes(ymin=lower, ymax=upper), alpha=0.5, linetype=0, fill='#FFC000') +
theme_bw() +
scale_x_continuous(breaks=breaks) +
xlab("Age") +
ylab("Hazard Ratio") +
theme(axis.line = element_line(color='black', size=1),
axis.ticks = element_line(color='black', size=1),
panel.grid.minor = element_blank())
# Boxplot
BP <- ggplot(data=df, aes(x=factor(1), y=age)) +
geom_boxplot(width = 1, outlier.shape=NA, size=1) +
geom_jitter(position = position_jitter(width = .3), size = 1) +
scale_y_continuous(breaks=breaks) +
coord_flip() +
theme_bw() +
theme(panel.border=element_blank(),
panel.grid=element_blank())
#### Set up the grobs and gtables here
library(gtable)
library(grid)
h = 1/15 # height of boxplot panel relative to main plot panel
# Get ggplot grobs
gMP = ggplotGrob(MP)
BPg = ggplotGrob(BP)
BPg = gtable_filter(BPg, "panel") # from the boxplot, extract the panel only
# In the main plot, get position of panel in the layout
pos = gMP$layout[gMP$layout$name == "panel", c('t', 'l')]
# In main plot, set height for boxplot
gMP$heights[pos$t-2] = unit(h, "null")
# Add boxplot to main plot
gMP = gtable_add_grob(gMP, BPg, t=pos$t-2, l=pos$l)
# Add small space
gMP$heights[pos$t-1] = unit(5, "pt")
# Draw it
grid.newpage()
grid.draw(gMP)