RStudio中统一直方图坐标轴刻度的技术问询
问题
在RStudio中绘制了对应type为x、y、z、-x、-y、-z的6个直方图,按3列2行排列。当前每个图的坐标轴刻度独立适配,部分图最大柱高为30,部分仅为5,无法直观对比。
需求:
- 将type为x、y、-x、-y的直方图的y轴(count)和x轴(load)刻度统一
- 将z和-z的刻度也统一
- 也可接受6个图刻度全部统一
思路:先获取每种type的最大柱高,取最大值设置y轴;x轴取每种type的value最大值的全局最大值设置。
当前可用代码:
library(tidyverse) library(dplyr) library(ggplot2) #Sample data set max_values <- data.frame( type = c("x","x","x","x","y","y","y","y","z","z","z","z","z","-x","-x","-x","-x","-y","-y","-y","-y","-z","-z","-z","-z","-z"), values = c(0.5,1,2,0.3,1,2,3,4,0.5,0.4,0.3,0.2,2,5,5.1,6,4.9,3,10,9.5,9.1,9,9.7,8) ) # create a list of type values type_list <- c("x", "y", "z", "-x", "-y", "-z") # create an empty list to store the plots plot_list <- list() # loop through the type values and create a plot for each type for (i in type_list) { plot_data <- max_values %>% filter(type == i) # 原代码中scenario列不存在,此处移除该过滤条件 if(nrow(plot_data) > 0) { plot <- ggplot(plot_data, aes(values)) + # 修正数据列名为values geom_histogram(colour= 1, fill = "white", binwidth=0.5) + ggtitle(paste("Histogram |", toupper(i), "Max values | Scenario 1")) + xlab("Load (N) [Bin top 0.5]") + ylab("Count (@500 samples per sec)") # add the plot to the plot_list plot_list[[i]] <- plot } } # display the plots gridExtra::grid.arrange( plot_list[["x"]], plot_list[["y"]], plot_list[["z"]], plot_list[["-x"]], plot_list[["-y"]], plot_list[["-z"]], ncol = 3 )
尝试过的近似代码:
# loop through the type values and create a plot for each type for (i in type_list) { plot_data <- max_values %>% filter(type == i) # 移除不存在的scenario过滤条件 if(nrow(plot_data) > 0 && !all(is.na(plot_data$values))) { # 修正列名 # create bins of width 0.5 based on the values in the `value` column plot_data$binwidth <- cut(plot_data$values, breaks = seq(0, max(plot_data$values), by = 0.5), include.lowest = TRUE) # add a group column based on the bin width plot_data$group <- as.factor(match(plot_data$binwidth, unique(plot_data$binwidth))) # get the max bin width max_binwidth <- max(as.numeric(plot_data$binwidth)) # create the plot plot <- ggplot(plot_data, aes(values)) + # 修正列名 geom_histogram(colour=1, fill="white", binwidth=0.5) + ggtitle(paste("Histogram |", toupper(i), "Max values | Scenario 1")) + xlab("Load (N) [Bin top 0.5]") + ylab("Count (@500 samples per sec)") + facet_wrap(~ group, scales = "free_y") + # group the histograms by the bin width scale_x_continuous(limits = c(0, max_binwidth), expand = c(0,0)) + # set the x axis limits scale_y_continuous(limits = c(0, NA), expand = c(0,0)) # set the y axis limits # add the plot to the plot_list plot_list[[i]] <- plot } }
解决方案
方案1:分组统一刻度(x/y/-x/-y一组,z/-z一组)
提前计算两组的x轴最大值和y轴最大计数,绘图时按组统一设置坐标轴范围:
library(tidyverse) library(ggplot2) library(gridExtra) # 修正后的样本数据 max_values <- data.frame( type = c("x","x","x","x","y","y","y","y","z","z","z","z","z","-x","-x","-x","-x","-y","-y","-y","-y","-z","-z","-z","-z","-z"), values = c(0.5,1,2,0.3,1,2,3,4,0.5,0.4,0.3,0.2,2,5,5.1,6,4.9,3,10,9.5,9.1,9,9.7,8) ) # 定义分组 group1 <- c("x", "y", "-x", "-y") group2 <- c("z", "-z") # 计算group1的x轴最大值和y轴最大计数 group1_x_max <- max(max_values$values[max_values$type %in% group1]) group1_y_max <- max( max_values %>% filter(type %in% group1) %>% group_by(type) %>% summarise(count_max = table(cut(values, breaks = seq(0, group1_x_max, by = 0.5), include.lowest = TRUE)) %>% max()) %>% pull(count_max) ) # 计算group2的x轴最大值和y轴最大计数 group2_x_max <- max(max_values$values[max_values$type %in% group2]) group2_y_max <- max( max_values %>% filter(type %in% group2) %>% group_by(type) %>% summarise(count_max = table(cut(values, breaks = seq(0, group2_x_max, by = 0.5), include.lowest = TRUE)) %>% max()) %>% pull(count_max) ) type_list <- c("x", "y", "z", "-x", "-y", "-z") plot_list <- list() for (i in type_list) { plot_data <- max_values %>% filter(type == i) if(nrow(plot_data) > 0) { # 根据所属分组设置坐标轴范围 if(i %in% group1) { x_limits <- c(0, group1_x_max) y_limits <- c(0, group1_y_max) } else { x_limits <- c(0, group2_x_max) y_limits <- c(0, group2_y_max) } plot <- ggplot(plot_data, aes(values)) + geom_histogram(colour= 1, fill = "white", binwidth=0.5) + ggtitle(paste("Histogram |", toupper(i), "Max values | Scenario 1")) + xlab("Load (N) [Bin top 0.5]") + ylab("Count (@500 samples per sec)") + scale_x_continuous(limits = x_limits, expand = c(0, 0)) + scale_y_continuous(limits = y_limits, expand = c(0, 0)) plot_list[[i]] <- plot } } # 排列展示 grid.arrange( plot_list[["x"]], plot_list[["y"]], plot_list[["z"]], plot_list[["-x"]], plot_list[["-y"]], plot_list[["-z"]], ncol = 3 )
方案2:全部6个图统一刻度
计算全局x轴最大值和全局y轴最大计数,所有图共用同一坐标轴范围:
library(tidyverse) library(ggplot2) library(gridExtra) max_values <- data.frame( type = c("x","x","x","x","y","y","y","y","z","z","z","z","z","-x","-x","-x","-x","-y","-y","-y","-y","-z","-z","-z","-z","-z"), values = c(0.5,1,2,0.3,1,2,3,4,0.5,0.4,0.3,0.2,2,5,5.1,6,4.9,3,10,9.5,9.1,9,9.7,8) ) # 计算全局x轴最大值 global_x_max <- max(max_values$values) # 计算每个type的直方图计数最大值,再取全局最大 global_y_max <- max( max_values %>% group_by(type) %>% summarise(count_max = table(cut(values, breaks = seq(0, global_x_max, by = 0.5), include.lowest = TRUE)) %>% max()) %>% pull(count_max) ) type_list <- c("x", "y", "z", "-x", "-y", "-z") plot_list <- list() for (i in type_list) { plot_data <- max_values %>% filter(type == i) if(nrow(plot_data) > 0) { plot <- ggplot(plot_data, aes(values)) + geom_histogram(colour= 1, fill = "white", binwidth=0.5) + ggtitle(paste("Histogram |", toupper(i), "Max values | Scenario 1")) + xlab("Load (N) [Bin top 0.5]") + ylab("Count (@500 samples per sec)") + scale_x_continuous(limits = c(0, global_x_max), expand = c(0, 0)) + scale_y_continuous(limits = c(0, global_y_max), expand = c(0, 0)) plot_list[[i]] <- plot } } grid.arrange( plot_list[["x"]], plot_list[["y"]], plot_list[["z"]], plot_list[["-x"]], plot_list[["-y"]], plot_list[["-z"]], ncol = 3 )
关键说明
- 修正了原代码中的两个问题:数据列名应为
values而非value,移除了不存在的scenario过滤条件。 - 计算直方图最大计数时,采用和绘图一致的0.5宽度分箱逻辑,确保统计结果与实际绘图的柱高匹配。
- 使用
expand = c(0,0)去除坐标轴两端的空白,让图表布局更紧凑。
内容的提问来源于stack exchange,提问作者Chris Topher
相关产品推荐
相关产品推荐

