如何在 ggplot geom_tile 中正确使用刻面,同时保持纵横比不变?
How do I use facetting correctly in ggplot geom_tile, while keeping the aspect ratio intact?
我正在尝试创建一个 'likeliness plot' 旨在快速显示一个项目与 table 中其他项目的相似性。
一个简单的例子:
'property_data.csv' 要使用的文件:
"","Country","Town","Property","Property_value"
"1","UK","London","Road_quality","Bad"
"2","UK","London","Air_quality","Very bad"
"3","UK","London","House_quality","Average"
"4","UK","London","Library_quality","Good"
"5","UK","London","Pool_quality","Average"
"6","UK","London","Park_quality","Bad"
"7","UK","London","River_quality","Very good"
"8","UK","London","Water_quality","Decent"
"9","UK","London","School_quality","Bad"
"10","UK","Liverpool","Road_quality","Bad"
"11","UK","Liverpool","Air_quality","Very bad"
"12","UK","Liverpool","House_quality","Average"
"13","UK","Liverpool","Library_quality","Good"
"14","UK","Liverpool","Pool_quality","Average"
"15","UK","Liverpool","Park_quality","Bad"
"16","UK","Liverpool","River_quality","Very good"
"17","UK","Liverpool","Water_quality","Decent"
"18","UK","Liverpool","School_quality","Bad"
"19","USA","New York","Road_quality","Bad"
"20","USA","New York","Air_quality","Very bad"
"21","USA","New York","House_quality","Average"
"22","USA","New York","Library_quality","Good"
"23","USA","New York","Pool_quality","Average"
"24","USA","New York","Park_quality","Bad"
"25","USA","New York","River_quality","Very good"
"26","USA","New York","Water_quality","Decent"
"27","USA","New York","School_quality","Bad"
代码:
prop <- read.csv('property_data.csv')
Property_col_vector <- c("NA" = "#e6194b",
"Very bad" = "#e6194B",
"Bad" = "#ffe119",
"Average" = "#bfef45",
"Decent" = "#3cb44b",
"Good" = "#42d4f4",
"Very good" = "#4363d8")
plot_likeliness <- function(town_property_table){
g <- ggplot(town_property_table, aes(Property, Town)) +
geom_tile(aes(fill = Property_value, width=.9, height=.9)) +
theme_classic() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust=0.5),
strip.text.y = element_text(angle = 0)) +
scale_fill_manual(values = Property_col_vector) +
coord_fixed()
return(g)
}
summary_town_plot <- plot_likeliness(prop)
输出:
这看起来很棒!
现在我创建了一个看起来不错的图,因为我使用了 coord_fixed() 函数,但现在我想创建相同的图,由 Country.
分面
为此,我创建了以下函数:
plot_likeliness_facetted <- function(town_property_table){
g <- ggplot(town_property_table, aes(Property, Town)) +
geom_tile(aes(fill = Property_value, width=.9, height=.9)) +
theme_classic() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust=0.5),
strip.text.y = element_text(angle = 0)) +
scale_fill_manual(values = Property_col_vector) +
facet_grid(Country ~ .,
scale = 'free_y')
return(g)
}
facetted_town_plot <- plot_likeliness_facetted(prop)
facetted_town_plot
结果:
但是,现在我的图块被拉伸了,如果我尝试使用“+ coords_fixed()”,我会收到错误消息:
Error: coord_fixed doesn't support free scales
我怎样才能让情节多面化,但保持纵横比?请注意,我将这些绘制成一个系列,因此使用手动值对绘图的高度进行硬编码并不是我想要的解决方案,我需要一些可以根据 table 中的值数量动态缩放的东西。
非常感谢您的帮助!
编辑:虽然同一个问题在其他地方的上下文略有不同,但它有多个答案 none 标记为解决问题。
这可能不是一个完美的答案,但无论如何我都会试一试。基本上,使用基本 ggplot 很难做到这一点,因为 - 正如你提到的 - coord_fixed()
或 theme(aspect.ratio = ...)
不能很好地处理小平面。
我建议的第一个解决方案是使用 gtables 以编程方式设置面板的宽度以匹配 x-axis:
上的变量数量
plot_likeliness_gtable <- function(town_property_table){
g <- ggplot(town_property_table, aes(Property, Town)) +
geom_tile(aes(fill = Property_value, width=.9, height=.9)) +
theme_classic() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust=0.5),
strip.text.y = element_text(angle = 0)) +
scale_fill_manual(values = Property_col_vector) +
facet_grid(Country ~ .,
scale = 'free_y', space = "free_y")
# Here be the gtable bits
gt <- ggplotGrob(g)
# Find out where the panel is stored in the x-direction
panel_x <- unique(gt$layout$l[grepl("panel", gt$layout$name)])[1]
# Set that width based on the number of x-axis variables, plus 0.2 because
# of the expand arguments in the scales
gt$widths[panel_x] <- unit(nlevels(droplevels(town_property_table$Property)) + 0.2, "null")
# Respect needs to be true to have 'null' units match in x- and y-direction
gt$respect <- TRUE
return(gt)
}
这将按以下方式工作:
library(grid)
x <- plot_likeliness_gtable(prop)
grid.newpage(); grid.draw(x)
并给出了这个情节:
这一切都运行良好,但在这一点上,讨论使用 gtables 而不是 ggplot 对象的一些缺点可能会很好。首先,你不能再用 ggplot 编辑它,所以你不能添加另一个 + geom_myfavouriteshape()
或任何类似的东西。不过,您仍然可以在 gtable/grid 中编辑部分情节。其次,它有古怪的 grid.newpage(); grid.draw()
语法,需要网格库。第三,我们有点依赖 ggplot 分面来正确设置 y-direction 面板高度(在您的示例中为 2.2 和 1.2 null-units),但这可能并不适用于所有情况。从好的方面来说,您仍在灵活地定义维度 null-units,因此它可以很好地适应您使用的任何绘图设备。
我提出的第二个解决方案对很多人来说可能有点老套,但它会消除使用 gtables 的前两个缺点。前段时间,我在分面时遇到了奇怪的面板尺寸行为的类似问题,所以我写了 these functions 来设置面板尺寸。其本质是从您正在制作的任何绘图中复制面板绘图函数,并将其包装在一个新函数中,该函数将面板大小设置为一些 pre-defined 数字。它必须在任何分面函数之后调用。它会像这样工作:
plot_likeliness_forcedsizes <- function(town_property_table){
g <- ggplot(town_property_table, aes(Property, Town)) +
geom_tile(aes(fill = Property_value, width=.9, height=.9)) +
theme_classic() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust=0.5),
strip.text.y = element_text(angle = 0)) +
scale_fill_manual(values = Property_col_vector) +
facet_grid(Country ~ .,
scale = 'free_y', space = "free_y") +
force_panelsizes(cols = nlevels(droplevels(town_property_table$Property)) + 0.2,
respect = TRUE)
return(g)
}
myplot <- plot_likeliness_forcedsizes(prop)
myplot
虽然它仍然依赖于 ggplot 正确设置 y-direction 高度,但如果出现问题,您可以在 force_panelsizes()
内覆盖这些。
希望对您有所帮助,祝您好运!
theme(aspect.ratio = 1)
和 space = 'free'
似乎有效。
plot_likeliness_facetted <- function(town_property_table){
g <- ggplot(town_property_table, aes(Property, Town)) +
geom_tile(aes(fill = Property_value, width=.9, height=.9)) +
theme_classic() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust=0.5),
strip.text.y = element_text(angle = 0), aspect.ratio = 1) +
scale_fill_manual(values = Property_col_vector) +
facet_grid(Country ~ .,
scale = 'free_y', space = 'free')
return(g)
}
我正在尝试创建一个 'likeliness plot' 旨在快速显示一个项目与 table 中其他项目的相似性。
一个简单的例子:
'property_data.csv' 要使用的文件:
"","Country","Town","Property","Property_value"
"1","UK","London","Road_quality","Bad"
"2","UK","London","Air_quality","Very bad"
"3","UK","London","House_quality","Average"
"4","UK","London","Library_quality","Good"
"5","UK","London","Pool_quality","Average"
"6","UK","London","Park_quality","Bad"
"7","UK","London","River_quality","Very good"
"8","UK","London","Water_quality","Decent"
"9","UK","London","School_quality","Bad"
"10","UK","Liverpool","Road_quality","Bad"
"11","UK","Liverpool","Air_quality","Very bad"
"12","UK","Liverpool","House_quality","Average"
"13","UK","Liverpool","Library_quality","Good"
"14","UK","Liverpool","Pool_quality","Average"
"15","UK","Liverpool","Park_quality","Bad"
"16","UK","Liverpool","River_quality","Very good"
"17","UK","Liverpool","Water_quality","Decent"
"18","UK","Liverpool","School_quality","Bad"
"19","USA","New York","Road_quality","Bad"
"20","USA","New York","Air_quality","Very bad"
"21","USA","New York","House_quality","Average"
"22","USA","New York","Library_quality","Good"
"23","USA","New York","Pool_quality","Average"
"24","USA","New York","Park_quality","Bad"
"25","USA","New York","River_quality","Very good"
"26","USA","New York","Water_quality","Decent"
"27","USA","New York","School_quality","Bad"
代码:
prop <- read.csv('property_data.csv')
Property_col_vector <- c("NA" = "#e6194b",
"Very bad" = "#e6194B",
"Bad" = "#ffe119",
"Average" = "#bfef45",
"Decent" = "#3cb44b",
"Good" = "#42d4f4",
"Very good" = "#4363d8")
plot_likeliness <- function(town_property_table){
g <- ggplot(town_property_table, aes(Property, Town)) +
geom_tile(aes(fill = Property_value, width=.9, height=.9)) +
theme_classic() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust=0.5),
strip.text.y = element_text(angle = 0)) +
scale_fill_manual(values = Property_col_vector) +
coord_fixed()
return(g)
}
summary_town_plot <- plot_likeliness(prop)
输出:
这看起来很棒! 现在我创建了一个看起来不错的图,因为我使用了 coord_fixed() 函数,但现在我想创建相同的图,由 Country.
分面为此,我创建了以下函数:
plot_likeliness_facetted <- function(town_property_table){
g <- ggplot(town_property_table, aes(Property, Town)) +
geom_tile(aes(fill = Property_value, width=.9, height=.9)) +
theme_classic() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust=0.5),
strip.text.y = element_text(angle = 0)) +
scale_fill_manual(values = Property_col_vector) +
facet_grid(Country ~ .,
scale = 'free_y')
return(g)
}
facetted_town_plot <- plot_likeliness_facetted(prop)
facetted_town_plot
结果:
但是,现在我的图块被拉伸了,如果我尝试使用“+ coords_fixed()”,我会收到错误消息:
Error: coord_fixed doesn't support free scales
我怎样才能让情节多面化,但保持纵横比?请注意,我将这些绘制成一个系列,因此使用手动值对绘图的高度进行硬编码并不是我想要的解决方案,我需要一些可以根据 table 中的值数量动态缩放的东西。
非常感谢您的帮助!
编辑:虽然同一个问题在其他地方的上下文略有不同,但它有多个答案 none 标记为解决问题。
这可能不是一个完美的答案,但无论如何我都会试一试。基本上,使用基本 ggplot 很难做到这一点,因为 - 正如你提到的 - coord_fixed()
或 theme(aspect.ratio = ...)
不能很好地处理小平面。
我建议的第一个解决方案是使用 gtables 以编程方式设置面板的宽度以匹配 x-axis:
上的变量数量plot_likeliness_gtable <- function(town_property_table){
g <- ggplot(town_property_table, aes(Property, Town)) +
geom_tile(aes(fill = Property_value, width=.9, height=.9)) +
theme_classic() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust=0.5),
strip.text.y = element_text(angle = 0)) +
scale_fill_manual(values = Property_col_vector) +
facet_grid(Country ~ .,
scale = 'free_y', space = "free_y")
# Here be the gtable bits
gt <- ggplotGrob(g)
# Find out where the panel is stored in the x-direction
panel_x <- unique(gt$layout$l[grepl("panel", gt$layout$name)])[1]
# Set that width based on the number of x-axis variables, plus 0.2 because
# of the expand arguments in the scales
gt$widths[panel_x] <- unit(nlevels(droplevels(town_property_table$Property)) + 0.2, "null")
# Respect needs to be true to have 'null' units match in x- and y-direction
gt$respect <- TRUE
return(gt)
}
这将按以下方式工作:
library(grid)
x <- plot_likeliness_gtable(prop)
grid.newpage(); grid.draw(x)
并给出了这个情节:
这一切都运行良好,但在这一点上,讨论使用 gtables 而不是 ggplot 对象的一些缺点可能会很好。首先,你不能再用 ggplot 编辑它,所以你不能添加另一个 + geom_myfavouriteshape()
或任何类似的东西。不过,您仍然可以在 gtable/grid 中编辑部分情节。其次,它有古怪的 grid.newpage(); grid.draw()
语法,需要网格库。第三,我们有点依赖 ggplot 分面来正确设置 y-direction 面板高度(在您的示例中为 2.2 和 1.2 null-units),但这可能并不适用于所有情况。从好的方面来说,您仍在灵活地定义维度 null-units,因此它可以很好地适应您使用的任何绘图设备。
我提出的第二个解决方案对很多人来说可能有点老套,但它会消除使用 gtables 的前两个缺点。前段时间,我在分面时遇到了奇怪的面板尺寸行为的类似问题,所以我写了 these functions 来设置面板尺寸。其本质是从您正在制作的任何绘图中复制面板绘图函数,并将其包装在一个新函数中,该函数将面板大小设置为一些 pre-defined 数字。它必须在任何分面函数之后调用。它会像这样工作:
plot_likeliness_forcedsizes <- function(town_property_table){
g <- ggplot(town_property_table, aes(Property, Town)) +
geom_tile(aes(fill = Property_value, width=.9, height=.9)) +
theme_classic() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust=0.5),
strip.text.y = element_text(angle = 0)) +
scale_fill_manual(values = Property_col_vector) +
facet_grid(Country ~ .,
scale = 'free_y', space = "free_y") +
force_panelsizes(cols = nlevels(droplevels(town_property_table$Property)) + 0.2,
respect = TRUE)
return(g)
}
myplot <- plot_likeliness_forcedsizes(prop)
myplot
虽然它仍然依赖于 ggplot 正确设置 y-direction 高度,但如果出现问题,您可以在 force_panelsizes()
内覆盖这些。
希望对您有所帮助,祝您好运!
theme(aspect.ratio = 1)
和 space = 'free'
似乎有效。
plot_likeliness_facetted <- function(town_property_table){
g <- ggplot(town_property_table, aes(Property, Town)) +
geom_tile(aes(fill = Property_value, width=.9, height=.9)) +
theme_classic() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust=0.5),
strip.text.y = element_text(angle = 0), aspect.ratio = 1) +
scale_fill_manual(values = Property_col_vector) +
facet_grid(Country ~ .,
scale = 'free_y', space = 'free')
return(g)
}