如何缩小 sjPlot 预测图中成对数据的间距并保留横轴标签?
先看空白出现在哪里:同一组内两个预测值的距离用 dodge 调整;不同组之间的实际显示距离主要通过调整图形宽度改变;横轴两端的留白则由 expand 控制。单独设置 expand = c(0, 0) 无法消除组与组之间的空白。
横轴标签消失可能与刻度类型有关:plot_model(type = "pred") 使用的预测绘图流程可能把分类变量放在连续横轴上。此时应使用 scale_x_continuous(),并在替换刻度时保留原来的 breaks 和 labels。
为什么修改 expand 没有效果?
示例中,terms = c("Demonstrator", "Shelter") 将 Demonstrator 放在横轴上,用 Shelter 区分预测值。图中涉及三种距离:
| 空白位置 | 调整方式 |
|---|---|
| 同一个 Demonstrator 下两个 Shelter 预测值之间 | 调整 dodge |
| 相邻 Demonstrator 组之间 | 调整绘图宽度或面板宽高比 |
| 最左、最右数据与面板边缘之间 | 调整坐标轴 expand |
expand 只控制坐标范围两端的扩展量,不改变各组中心的相对位置。缩小两端留白后,数据可能占据更大的面板宽度,组间距离反而看起来更宽。ggplot2 坐标轴文档
如果使用 scale_x_discrete() 后标签和网格线消失,也不能由此判断留白已经消除。ggeffects 的绘图文档说明,其分类预测变量也使用连续横轴;直接换成离散刻度会破坏原有的刻度设置。添加新的连续刻度也可能覆盖原来用于显示分类名称的标签配置。ggeffects 横轴自定义说明
先修正示例,再调整组内间距
模拟数据代码的最后一个参数后面多了一个逗号,删除即可:
Group = factor(rep(group, times = 3))
)
模型拟合成功后,使用示例中的模型对象 mm 绘图。dodge = 0.15 是一个用来尝试较小组内间距的示例值,可以根据点和误差条是否重叠再调整:
library(ggplot2)
library(sjPlot)
library(lme4)
p <- plot_model(
mm,
type = "pred",
terms = c("Demonstrator", "Shelter"),
title = "Predicted Time in Shelters",
axis.title = c("", "Time Spent In Shelter"),
dodge = 0.15
) +
scale_color_manual(
name = "Shelter Type",
labels = c("Demonstrated", "Non Demonstrated"),
values = c("blue", "red")
) +
theme(
legend.position = "bottom",
axis.text.x = element_text(size = 14),
axis.title.y = element_text(size = 14),
legend.text = element_text(size = 14)
)
p
plot_model() 支持将 dodge 传给边际效应绘图函数,用来错开同一横轴位置上的预测值和误差条。减小该值会让同组数据更靠近;设为零时可能造成重叠。sjPlot 参数说明
如果想缩小不同组之间的空白,继续减小 dodge 可能让空白更明显,因为每组本身会变窄。
缩小不同组之间的显示距离
如果海报上的图显得过宽,可以先减小导出宽度,并在海报排版中保留调整后的宽高比例:
ggsave(
filename = "predicted_shelter_time.png",
plot = p,
width = 5.5,
height = 5,
units = "in",
dpi = 300
)
这些尺寸可以作为排版起点。保持高度不变,逐步减小宽度,可以缩短各组之间的物理距离。如果横轴文字开始重叠,就需要停止缩窄或调整标签排版。ggsave() 的 width、height 和 units 控制输出尺寸。ggsave 文档
如果希望在显示窗口内约束面板形状,也可以尝试:
p + theme(aspect.ratio = 1)
这里的 1 表示面板高度与宽度之比为 1。调整后的效果仍需结合导出尺寸检查。
调整两端留白,同时保留横轴标签
替换横轴刻度之前,先从原图读取刻度位置和标签。下面的代码适用于示例中的单面板图,并根据实际横轴类型选择刻度函数:
sx <- ggplot_build(p)$layout$panel_scales_x[[1]]
if (sx$is_discrete()) {
p_edges <- p +
scale_x_discrete(
expand = expansion(add = 0.4)
)
} else {
x_breaks <- sx$get_breaks()
x_labels <- sx$get_labels(x_breaks)
p_edges <- p +
scale_x_continuous(
breaks = x_breaks,
labels = x_labels,
expand = expansion(mult = 0, add = 0.2)
)
}
p_edges
读取原图标签,可以避免假定分类名称一定对应 1:3,也能保留原图设置好的显示顺序。这里的 0.2 和 0.4 是可调整的边缘余量,并非适用于所有图的固定值。
如果要尝试完全取消连续横轴的额外扩展,可以把 expand 改成 expansion(mult = 0, add = 0),但需要检查最外侧经过 dodge 偏移的点和误差条是否仍完整显示。
示例中的其他注意事项
- 初始绘图使用
model27,模拟数据拟合的是mm。复现时要使用对应的模型对象。 - 示例使用
lmer(),拟合的是线性混合模型;不能仅凭这段代码称其为 GLMM。 - 模拟数据没有设置随机种子,每次生成的缺失位置和拟合结果可能不同。如果出现拟合警告,应先检查模型,再判断绘图问题。
- 由于没有提供实际图像,无法确认最显眼的空白属于哪一种。可以先只调整一个参数,分别观察组内距离、组间距离和边缘留白的变化。
备注:内容仅供参考。
