获得具有不同方面数的地块的高度相同,并且coord_fixed? [英] Get same height for plots having different facet numbers, and coord_fixed?

查看:232
本文介绍了获得具有不同方面数的地块的高度相同,并且coord_fixed?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


$ b

  set.seed(1)## dummy data.frame:
df < - data.frame(value1 = sample(5:15,20,replace = T),value2 = sample(5:15,20,replace = T),
var1 = c(rep ('type1',10),rep('type2',10)),var2 = c('a','b','c','d'))

##图1

ggplot()+
geom_point(data = df,aes(value1,value2))+
facet_grid(〜var1)+
coord_fixed()

ggsave(plot_2facet.pdf,height = 5,units ='in')
#Saving 10.3 x 5 in image

##我想要的情节2保存在单独的文件中(!)

ggplot()+
geom_point(data = df,aes(value1,value2))+
facet_grid(〜var2)+
coord_fixed()

ggsave(plot_4facet.pdf,height = 5,units ='in')
#Saving 10.3 x 5图像



但我想用 coord_fixed()

是否有解决方案,或者是否需要猜测设备的宽度尺寸以获得正确的绘图高度?



理想情况下,应该在独立的设备/文件中创建绘图。

解决方案

这对于ggplot来说有点棘手,所以请原谅冗长,错综复杂,基本问题是,使用 coord_fixed 时,y轴的高度与x轴的长度密不可分。



有两种方法可以打破这种依赖关系:


  1. 通过 scale_y_continuous 展开参数。这允许我们将y轴延伸超出数据范围的给定量。棘手的一点是知道要扩展它多少,因为这取决于难以预测的情节的所有元素,包括有多少面,以及轴标题和标签的大小等。

    / li>

  2. ,方法是允许两个图的宽度不同。这里棘手的是,如上所述,如何找到正确的宽度,因为这取决于图的各个方面。


首先我展示我们如何解决第一个版本(多少展开y轴)。然后使用类似的方法和一些额外的诡计,我们也可以解决不同宽度的版本。



解决方案找到多少展开y轴



考虑到预测绘图区域有多大的困难(它依赖于绘图所有元素的相对大小),我们可以做的是保存一个虚拟绘图,其中我们用黑色阴影阴影区域,将图像文件重新读入,然后测量黑色区域的大小以确定阴谋区域的大小:

1)让我们开始将您的图分配给变量

pre $ ggplot(df1)+
geom_point(aes(value1,value2) )+
facet_grid(〜var1)+
coord_fixed()

p2 = ggplot(df1)+
geom_point(aes(value1,value2))+
facet_grid(〜var2)+
coord_fixed()

2)现在我们可以保存这些绘图的一些虚拟版本只显示绘图区域i的黑色矩形s:

  t_blank =主题(strip.background = element_rect(fill = NA),
strip.text = element_text (color = NA),
axis.title = element_text(color = NA),
axis.text = element_text(color = NA),
axis.ticks = element_line(color = NA) )

p1 + geom_rect(aes(xmin = -Inf,xmax = Inf,ymin = -Inf,ymax = Inf),fill ='black')+
t_blank
ggsave(fn1 < - tempfile(fileext ='.png'),height = 5,units ='in')

p2 + geom_rect(aes(xmin = -Inf,xmax = Inf,ymin = -Inf,ymax = Inf),fill ='black')+
t_blank
ggsave(fn2 < - tempfile(fileext ='.png'),height = 5,units ='in' )



3)然后我们将它们读入一个数组中(只要第一个颜色带足够了) p>

  library(png)
p1.saved = readPNG(fn1)[,, 1]
p2.saved = readPNG(fn2)[,, 1]



<4>计算每个绘图区域的高度黑色阴影区域有一个值=零)

  p1.height = diff(row(p1.saved)[range(which(p1.saved == 0))])
p2.height = diff(row(p2.saved)[range(which(p2.saved == 0))]])

5)根据这些数据找出我们需要展开多少绘图区域。请注意,我们从1.1中减去高度的比例,以说明原始图在每个方向上已经扩展了0.05的默认值。 免责声明 - 此公式适用于您的示例。我没有时间更广泛地检查它,它可能还需要适应以确保其他地块的一般性

  height.expand = 1.1  -  p2.height / p1.height 

6)现在我们可以保存使用这个扩展因子的图

  ggsave(plot_2facet.pdf,p1,height = 5,units ='in') 
ggsave(plot_4facet.pdf,p2 + scale_y_continuous(expand = c(height.expand,0)),
height = 5,units ='in')




解决方案很大程度上改变了宽度



首先,让我们将第一个图的宽度设置为我们想要的宽度

  p1.width = 10 

现在,使用与上一节我们发现绘图区有多高。

  p1 + geom_rect(aes(xmin = -Inf,xmax = Inf,ymin = -Inf,ymax = Inf),fill ='black')+ 
t_blank
ggsave(fn1 < - tempfile(fileext ='.png'),height = 5,width = p1.width,units ='in')
p1.saved = readPNG(fn1,info = T) [,, 1]
p1.height = diff(row(p1.saved)[range(which(p1.saved == 0))]])

接下来,我们发现第二个图必须具有相同高度的最小宽度(注意 - 我们在这里寻找最小值,因为任何更大的宽度都不会增加这个高度已经填满了垂直空间,但是会简单地向左侧和右侧添加空白)

我们将使用函数<$ c $解决宽度问题c> uniroot ,它可以找到一个函数在零点的位置。要使用 uniroot ,我们首先定义一个函数,它将计算宽度作为参数的图的高度。然后它返回高度和我们想要的高度之间的差异。这个函数中的 if(x == 0)x = -1e-8 是一个肮脏的技巧,它允许uniroot解决一个达到零的函数,但不会交叉它 - 请参阅此处

 <$ c $ (a)(xmin = -Inf,xmax = Inf,ymin = fn2 < -  tempfile(fileext ='.png')
find.p2 = function(w){
p = p2 + geom_rect -Inf,ymax = Inf),fill ='black')+
t_blank
ggsave(fn2,p,height = 5,width = w,units ='in')
p2。 saved = readPNG(fn2,info = T)[,, 1]
p2.height = diff(row(p2.saved)[range(which(p2.saved == 0))])
x = abs(p1.height - p2.height)
if(x == 0)x = -1e-8
x
}

N1 =长度(df $ var1))
N2 =长度(唯一(df $ var2))
p2.width = uniroot(find.p2,c(p1.width,p1.width * N2 / N1))

现在我们准备将正确宽度的图保存下来,以确保它们具有相同的高度。 / p>

  p1 
ggsave( plot_2facet.pdf,height = 5,width = p1.width,units ='in')
p2
ggsave(plot_4facet.pdf,height = 5,width = p2.width $ root ,units ='in')


Let me explain in pictures what I mean:

set.seed(1)  ## dummy data.frame:
df <- data.frame( value1 = sample(5:15, 20, replace = T), value2 = sample(5:15, 20, replace = T),
                  var1 = c(rep('type1',10), rep('type2',10)), var2 = c('a','b','c','d'))

## Plot 1 

ggplot() +
  geom_point(data = df, aes(value1, value2)) +
  facet_grid(~var1) +
  coord_fixed()

ggsave("plot_2facet.pdf", height=5, units = 'in')
    #Saving 10.3 x 5 in image

## Plot 2  which I want to save in a separate file (!)

ggplot() +
  geom_point(data = df, aes(value1, value2)) +
  facet_grid(~var2) +
  coord_fixed()

ggsave("plot_4facet.pdf", height=5, units = 'in')
    #Saving 10.3 x 5 in image

Now what happens here, that the devices have the same height, but the plots have different heights. But I would like to get the same height for the plots.

In the code above, I tried to only specify the height, but ggsave then just takes a fixed width dimension for the device.

I tried theme(plot.margin = margin(t=1,b=1)), but this did not change anything.

Taking out coord_fixed() gives plots with the same height:

But I would like to use coord_fixed().

Is there a solution for this, or do I need to "guess" the width dimensions of the device to get the correct plot height?

Cheers


Edit

The plots should ideally be created in separate devices/ files.

解决方案

This is somewhat tricky with ggplot, so please forgive the long, convoluted, and admittedly a bit hacky answer. The basic problem is that with coord_fixed, the height of the y-axis becomes inextricably linked to the length of the x-axis.

There are two ways we can break this dependency:

  1. by using the expand argument of scale_y_continuous. This allows us to extend the y axis by a given amount beyond the range of the data. The tricky bit is knowing how much to expand it, because this depends in a hard-to-predict way on all elements of the plot, including how many facets there are and the size of axis titles and labels etc.

  2. by allowing the width of the two plots to differ. The tricky thing here is, as above, how to find the correct width as this depends on the various other aspects of the plots.

First I show how we can solve the first version (how much to expand the y-axis). Then using a similar approach and a little extra trickery we can also solve the varying width version.

Solution to finding how much to expand the y-axis

Given the difficulties of predicting how large the plotting area will be (which depnds on the relative sizes of all the elements of the plot), what we can do is to save a dummy plot in which we shade the plot area in black, read the image file back in, then measure the size of the black area to determine how large the plot area is:

1) let's start by assigning your plots to variables

p1 = ggplot(df1) +
  geom_point(aes(value1, value2)) +
  facet_grid(~var1) +
  coord_fixed()

p2 = ggplot(df1) +
  geom_point(aes(value1, value2)) +
  facet_grid(~var2) +
  coord_fixed() 

2) now we can save some dummy versions of these plots that only show a black rectangle where the plotting region is:

t_blank = theme(strip.background = element_rect(fill = NA),
      strip.text = element_text(color=NA),
      axis.title = element_text(color = NA),
      axis.text = element_text(color = NA),
      axis.ticks = element_line(color = NA))

p1 + geom_rect(aes(xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf), fill='black') + 
     t_blank
ggsave(fn1 <- tempfile(fileext = '.png'), height=5, units = 'in')

p2 + geom_rect(aes(xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf), fill='black') + 
     t_blank
ggsave(fn2 <- tempfile(fileext = '.png'), height=5, units = 'in')

3) then we read these into an array (just the first color band is enough)

library(png)
p1.saved = readPNG(fn1)[,,1]
p2.saved = readPNG(fn2)[,,1]

4) calculate the height of each plotting area (the black-shaded areas which have a value=zero)

p1.height = diff(row(p1.saved)[range(which(p1.saved==0))])
p2.height = diff(row(p2.saved)[range(which(p2.saved==0))])

5) Find how much we need to expand the plotting area based on these. Note that we subtract the ratio of heights from 1.1 to account for the fact that the original plots were already expanded by the default amount of 0.05 in each direction. Disclaimer -- this formula works on your example. I haven't had time to check it more broadly, and it may yet need adapting to ensure generality for other plots

height.expand = 1.1 - p2.height / p1.height

6) Now we can save the plots using this expansion factor

ggsave("plot_2facet.pdf", p1, height=5, units = 'in')
ggsave("plot_4facet.pdf", p2 + scale_y_continuous(expand=c(height.expand, 0)), 
        height=5, units = 'in')

Solution to finding how much to alter the width

first, lets set the width of the first plot to what we want

p1.width = 10

Now, using the same approach as in the previous section we find how tall the plotting area is in this plot.

p1 + geom_rect(aes(xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf), fill='black') + 
     t_blank
ggsave(fn1 <- tempfile(fileext = '.png'), height=5, width = p1.width, units = 'in')
p1.saved = readPNG(fn1, info = T)[,,1]
p1.height = diff(row(p1.saved)[range(which(p1.saved==0))])

Next, we find the mimimum width the second plot must have to get the same height (note - we look for a minimum here because any greater width than this will not increase the height, which already fiulls the vertical space, but will simply add white space to the left and right)

We will solve for the width using the function uniroot which finds where a function crosses zero. To use uniroot we first define a function that will calculate the height of a plot given its width as an argument. It then returns the difference between that height and the height we want. The line if (x==0) x = -1e-8 in this function is a dirty trick to allow uniroot solve a function that reaches zero, but does not cross it - see here.

fn2 <- tempfile(fileext = '.png')
find.p2 = function(w){
  p = p2 + geom_rect(aes(xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf), fill='black') + 
           t_blank
  ggsave(fn2, p, height=5, width = w, units = 'in')
  p2.saved = readPNG(fn2, info = T)[,,1]
  p2.height = diff(row(p2.saved)[range(which(p2.saved==0))])
  x = abs(p1.height - p2.height)
  if (x==0) x = -1e-8
  x
}

N1 = length(unique(df$var1)) 
N2 = length(unique(df$var2)) 
p2.width = uniroot(find.p2, c(p1.width, p1.width*N2/N1))

Now we are ready to save the plots with the correct widths to ensure they have the same height.

p1
ggsave("plot_2facet.pdf", height=5, width = p1.width, units = 'in')
p2
ggsave("plot_4facet.pdf", height=5, width = p2.width$root, units = 'in')

这篇关于获得具有不同方面数的地块的高度相同,并且coord_fixed?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆