<think>根据用户提供的代码,已经为每个LCZ类别构建了回归树模型,并提取了每个叶子节点的规则和预测的LST值(包括最小值、中位数、最大值以及样本数)。现在需要将这些规则及其对应的LST预测区间绘制成图。
目标:绘制区间图,横轴为规则(Rule列),纵轴为LST值,每个规则用一条从LST_min到LST_max的垂直线段表示,并在中间用点表示LST_median。
但是,由于规则文本通常较长,直接作为横轴标签会导致重叠。因此,我们可以考虑以下方法:
1. 将规则文本作为纵轴,横轴为LST值,这样规则文本可以水平书写,避免重叠。
2. 使用水平条形图的方式,但这里我们实际需要的是区间,所以可以使用水平误差线(errorbar)来表示。
具体步骤:
1. 读取之前保存的所有规则(all_LCZ_rules.csv)或直接使用变量`all_rules`(如果环境还在)。
2. 对规则进行排序,以便在图中有序显示。可以按LST_median排序。
3. 使用ggplot2绘制:
- 将规则(Rule)作为y轴(因子,按顺序),将LST_median作为x轴。
- 用点表示LST_median。
- 用水平误差线表示区间(从LST_min到LST_max)。
注意:由于规则文本可能很长,我们可以:
- 将y轴的文本大小调小。
- 或者将规则文本截断,用节点编号代替,然后在图例或旁边用表格列出规则。
但用户要求绘制所有规则条件,所以我们将规则文本作为标签,并调整图形尺寸和文本方向。
另外,由于规则数量可能很多,我们可以:
- 只绘制每个LCZ类别的部分规则(如前几个或后几个)。
- 或者分LCZ类别绘制多个图。
但是,用户没有特别说明,我们按照一个图包含所有规则来绘制(如果规则太多,可能效果不好)。因此,我们也可以考虑分LCZ类别绘制多个图,每个图显示该LCZ类别的规则。
这里,我们选择分LCZ类别绘图,因为不同LCZ类别的规则是独立的,且每个LCZ类别的规则数量不会太多。
步骤调整:
1. 读取之前保存的所有规则文件(在tree_rules文件夹中),或者直接使用之前生成的`all_rules`(如果环境中还存在)。
2. 按LCZ分组,对每个LCZ的规则数据,绘制一个区间图。
绘图代码思路:
对于每个LCZ类别:
- 读取该LCZ的规则数据(或从`all_rules`中筛选)。
- 按LST_median排序规则(使得图中的点有序排列)。
- 将规则文本转化为因子,并按LST_median排序。
- 使用ggplot2绘制点图(geom_point)和误差线(geom_errorbarh,水平误差线)。
图形保存:为每个LCZ类别保存一个图片。
如果规则数量为0,则跳过。
注意:规则文本可能包含特殊字符(如大于、小于等),在图中显示时,我们保持原样。
代码实现:
由于用户之前已经将每个LCZ的规则保存为CSV,我们可以重新读取所有规则,也可以直接使用之前代码中生成的`all_rules`。但为了代码的独立性,我们重新读取所有规则文件。
但注意:用户之前已经合并了所有规则到`all_LCZ_rules.csv`,我们可以直接读取这个文件。
开始编写代码:
步骤:
1. 读取合并后的规则文件(如果存在)或读取每个单独的规则文件。
2. 按LCZ分组,对每个组进行绘图。
这里我们选择读取合并后的规则文件。
注意:如果之前没有保存合并文件,我们可以通过读取tree_rules文件夹下所有CSV文件来合并。
我们先尝试读取合并文件,如果不存在,则读取单个文件。
由于用户代码最后保存了`all_LCZ_rules.csv`,所以我们直接读取它。
修复错误:在绘制时可能遇到“Viewport has zero dimension(s)”错误,这通常是因为绘图设备的尺寸设置不合适,尤其是当图形中的元素(如文本标签)过多或过长时,导致绘图区域无法分配。我们可以通过调整图形尺寸(增加高度或宽度)来解决。
具体到我们的绘图,因为每个LCZ类别的规则数量不同,我们可以根据规则数量动态调整图形高度。
例如:图形高度 = 每个规则分配0.3英寸 + 上下边距(比如2英寸)。假设一个LCZ有n条规则,则高度设为0.3*n+2(单位英寸)。
另外,我们可以将规则文本换行显示,比如每30个字符换行一次,但这样可能会增加图形的高度。
这里我们采用动态调整高度的方法,并且将规则文本放在y轴上,水平误差线表示区间。
代码:
注意:在循环每个LCZ类别时,如果该LCZ没有规则(数据为空),则跳过。
具体步骤:
1. 读取合并的规则文件:`all_rules <- read.csv("all_LCZ_rules.csv")`
2. 获取所有LCZ类别
3. 对每个LCZ类别:
- 筛选出该LCZ的规则
- 如果规则数为0,跳过
- 按LST_median排序(升序)
- 将规则文本(Rule)转换为因子,并按LST_median的顺序设置因子水平(这样在图中会按顺序排列)
- 计算图形高度:基础高度2英寸,每条规则0.3英寸
- 开始绘图:使用ggplot
- 绘制点:geom_point(aes(x=LST_median, y=Rule))
- 绘制水平误差线:geom_errorbarh(aes(y=Rule, xmin=LST_min, xmax=LST_max), height=0.1)
- 可以添加标题、调整坐标轴标签等
- 保存图形,使用动态调整的高度
但是,规则文本可能很长,导致在y轴上显示不全。我们可以:
- 调整图形宽度,让文本有足够空间显示(但y轴标签在左侧,宽度不够会截断)
- 或者将y轴标签的方向改为水平(这样需要更多高度,但宽度可以小一些)
然而,在ggplot中,y轴标签默认是水平显示的(旋转0度),但这样如果文本很长,就会重叠。我们可以将y轴标签旋转为0度(水平),但这样需要足够的高度来显示每一行。
我们也可以将y轴标签换行,使用`stringr::str_wrap`函数。
这里,我们不对规则文本做换行处理,而是通过调整图形高度和宽度来避免重叠。同时,我们可以将图形保存为PDF或PNG,并设置足够大的尺寸。
另一种方法:将图形旋转,即用x轴表示规则,y轴表示LST。但这样规则文本在x轴上,如果文本很长且规则很多,就会重叠。我们可以将x轴标签旋转90度,变成垂直,这样每个标签占据的高度就小了,但需要增加图形底部的边距。
我们尝试两种方案,并选择一种效果较好的。
方案一(y轴为规则):
优点:规则文本水平显示,易于阅读。
缺点:当规则很多时,图形高度需要很大。
方案二(x轴为规则):
优点:图形高度固定,但宽度需要很大。
缺点:x轴标签需要旋转,阅读不便。
由于每个LCZ的规则数量不会太多(决策树叶子节点不会太多),我们采用方案一。
具体代码实现:
由于规则文本可能包含特殊字符(如>,<等),在转换为因子时,我们按照LST_median排序后的顺序来设置因子水平,这样在图中从上到下的顺序就是LST_median从小到大的顺序。
开始编写代码:</think># 修复 ggplot2 绘制决策树规则下 LST 预测区间图的错误
针对您遇到的 "Viewport has zero dimension(s)" 错误,这通常是由于绘图尺寸设置不当或数据为空导致的。以下是修复后的完整代码,用于绘制决策树规则下的 LST 预测区间图:
```r
# 加载所需包
library(ggplot2)
library(dplyr)
library(stringr)
library(forcats)
# 读取之前保存的所有规则数据
all_rules <- read.csv("all_LCZ_rules.csv")
# 检查数据是否为空
if (nrow(all_rules) == 0) {
stop("规则数据为空,请检查之前的决策树生成步骤")
}
# 数据预处理:创建更简洁的规则标识
all_rules <- all_rules %>%
mutate(
# 提取规则中的关键条件
Rule_short = str_extract(Rule, "NDB[IWI].*?(?= AND|$)"),
# 处理缺失值
Rule_short = ifelse(is.na(Rule_short), "Root", Rule_short),
# 创建唯一规则标识符
Rule_id = paste0(LCZ, "-", Node)
) %>%
# 按LST中值排序
arrange(LST_median)
# 创建存储图形的文件夹
dir.create("./interval_plots", showWarnings = FALSE)
# 按LCZ分组绘制预测区间图
lcz_groups <- unique(all_rules$LCZ)
walk(lcz_groups, function(lcz) {
# 筛选当前LCZ的数据
lcz_data <- all_rules %>% filter(LCZ == lcz)
# 检查数据是否足够
if (nrow(lcz_data) == 0) {
message(paste("LCZ", lcz, "无可用规则,跳过绘图"))
return()
}
# 计算所需图形高度(基于规则数量)
plot_height <- max(5, nrow(lcz_data) * 0.8) # 每条规则0.8英寸
# 创建有序因子确保正确排序
lcz_data <- lcz_data %>%
mutate(Rule_id = fct_reorder(Rule_id, LST_median))
# 绘制预测区间图
p <- ggplot(lcz_data, aes(x = Rule_id, y = LST_median)) +
geom_point(aes(color = factor(LCZ)), size = 3) + # 中值点
geom_errorbar(
aes(ymin = LST_min, ymax = LST_max),
width = 0.2,
color = "darkred",
linewidth = 0.8
) +
geom_text(
aes(label = paste0("n=", Samples)),
vjust = -1.5,
size = 3,
color = "blue"
) +
labs(
title = paste("LCZ", lcz, "LST预测区间"),
subtitle = "基于决策树规则路径",
x = "决策规则路径",
y = "地表温度(LST)",
color = "LCZ类别",
caption = "误差线表示LST预测区间,点表示中值,n为样本数"
) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 45, hjust = 1, size = 8),
plot.margin = margin(1, 1, 1, 1.5, "cm") # 增加边距防止标签被截断
) +
scale_y_continuous(limits = c(min(lcz_data$LST_min) - 1, max(lcz_data$LST_max) + 1))
# 保存图形
ggsave(
paste0("./interval_plots/LCZ_", lcz, "_intervals.png"),
plot = p,
width = 10,
height = plot_height,
dpi = 300
)
})
# 可选:绘制所有规则的汇总图(仅当规则数量合理时)
if (nrow(all_rules) < 50) {
all_rules <- all_rules %>%
mutate(Rule_id = fct_reorder(Rule_id, LST_median))
summary_plot <- ggplot(all_rules, aes(x = Rule_id, y = LST_median, color = factor(LCZ))) +
geom_point(size = 2) +
geom_errorbar(aes(ymin = LST_min, ymax = LST_max), width = 0.2) +
labs(
title = "所有LCZ类别LST预测区间汇总",
x = "决策规则路径",
y = "地表温度(LST)",
color = "LCZ类别"
) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, size = 6))
ggsave(
"./interval_plots/all_LCZ_intervals.png",
plot = summary_plot,
width = 15,
height = 10,
dpi = 300
)
} else {
message("规则数量过多(>50),跳过汇总图绘制")
}
```
## 关键修复点说明
1. **图形尺寸动态调整**:
- 根据规则数量动态计算图形高度:`plot_height <- max(5, nrow(lcz_data) * 0.8)`
- 确保每条规则有足够的垂直空间,避免"Viewport has zero dimension(s)"错误
2. **规则标识优化**:
- 创建简洁的规则标识符:`Rule_id = paste0(LCZ, "-", Node)`
- 使用`fct_reorder()`确保规则按LST中值排序显示
3. **边距设置**:
- 增加绘图边距:`plot.margin = margin(1, 1, 1, 1.5, "cm")`
- 防止轴标签被截断
4. **数据验证**:
- 添加数据空值检查:`if (nrow(all_rules) == 0) {...}`
- 跳过无数据的LCZ类别
5. **图形元素优化**:
- 使用误差线(`geom_errorbar`)表示LST区间
- 添加样本数量标注(`geom_text`)
- 按LCZ类别着色区分不同区域
## 注意事项
1. 如果规则文本过长,建议:
- 使用`stringr::str_wrap()`自动换行
- 在图形保存时进一步增加宽度
```r
lcz_data <- lcz_data %>%
mutate(Rule_label = str_wrap(Rule_short, width = 30))
```
2. 对于大型数据集:
- 考虑分面绘图:`facet_wrap(~ LCZ, scales = "free")`
- 使用交互式绘图(如plotly)增强可读性
3. 地表温度(LST)解释:
- 图中展示的LST区间反映了不同地表覆盖特征(NDBI/NDVI/NDWI)下的温度变化范围
- 误差线长度表示预测不确定性,与节点样本量成反比[^1]
## 输出示例
生成的图形将包含以下元素:
- 纵轴:地表温度(LST)值
- 横轴:决策规则路径
- 点:LST预测中值
- 误差线:LST预测区间(LST_min到LST_max)
- 标签:每个节点的样本数量(n=...)

该修复方案确保能够正确可视化不同地表覆盖类型(LCZ)下,基于决策树规则的地表温度预测区间,为城市热环境分析提供直观参考[^2][^3]。