ggplot2:如何用太少的图块强制多个方面?

时间:2016-04-01 14:05:47

标签: r ggplot2 facet

为了绘制每个ggplot图的9个直方图,我使用了以下数据:

                               id               variable      value
1                     Segment III | RIM BlackBerry Pearl | 5.600000
2                    Display size | RIM BlackBerry Pearl | 6.500000
3              Voice/call quality | RIM BlackBerry Pearl | 5.600000
4  Instant messaging availability | RIM BlackBerry Pearl | 7.200000
5                   Media quality | RIM BlackBerry Pearl | 6.100000
6          Ease of use for typing | RIM BlackBerry Pearl | 5.700000
7        Speed in accessing email | RIM BlackBerry Pearl | 6.400000
8                      Segment II | RIM BlackBerry Pearl | 5.545455
9                 Value for money | RIM BlackBerry Pearl | 6.000000
10                    Segment III |       Palm Treo 700p | 4.320000
11                   Display size |       Palm Treo 700p | 6.500000
12             Voice/call quality |       Palm Treo 700p | 8.000000
13 Instant messaging availability |       Palm Treo 700p | 5.100000
14                  Media quality |       Palm Treo 700p | 7.000000
15         Ease of use for typing |       Palm Treo 700p | 6.200000
16       Speed in accessing email |       Palm Treo 700p | 6.500000
17                     Segment II |       Palm Treo 700p | 4.454545
18                Value for money |       Palm Treo 700p | 5.400000
19                    Segment III |           Motorola Q | 4.680000
20                   Display size |           Motorola Q | 7.400000
21             Voice/call quality |           Motorola Q | 4.800000
22 Instant messaging availability |           Motorola Q | 5.300000
23                  Media quality |           Motorola Q | 6.900000
24         Ease of use for typing |           Motorola Q | 7.400000
25       Speed in accessing email |           Motorola Q | 8.000000
26                     Segment II |           Motorola Q | 3.121212
27                Value for money |           Motorola Q | 4.200000
28                    Segment III |           Nokia 9300 | 4.360000
29                   Display size |           Nokia 9300 | 6.400000
30             Voice/call quality |           Nokia 9300 | 7.800000
31 Instant messaging availability |           Nokia 9300 | 6.700000
32                  Media quality |           Nokia 9300 | 5.900000
33         Ease of use for typing |           Nokia 9300 | 4.500000
34       Speed in accessing email |           Nokia 9300 | 6.300000
35                     Segment II |           Nokia 9300 | 7.181818
36                Value for money |           Nokia 9300 | 4.600000
37                    Segment III |  Sony Ericsson M600i | 4.360000
38                   Display size |  Sony Ericsson M600i | 7.300000
39             Voice/call quality |  Sony Ericsson M600i | 8.000000
40 Instant messaging availability |  Sony Ericsson M600i | 1.500000
41                  Media quality |  Sony Ericsson M600i | 7.800000
42         Ease of use for typing |  Sony Ericsson M600i | 5.000000
43       Speed in accessing email |  Sony Ericsson M600i | 8.100000
44                     Segment II |  Sony Ericsson M600i | 3.606061
45                Value for money |  Sony Ericsson M600i | 4.000000
46                    Segment III |            Sidekick3 | 7.040000
47                   Display size |            Sidekick3 | 7.200000
48             Voice/call quality |            Sidekick3 | 6.300000
49 Instant messaging availability |            Sidekick3 | 7.200000
50                  Media quality |            Sidekick3 | 6.400000
51         Ease of use for typing |            Sidekick3 | 6.800000
52       Speed in accessing email |            Sidekick3 | 6.200000
53                     Segment II |            Sidekick3 | 3.424242
54                Value for money |            Sidekick3 | 5.300000

然后我使用了以下代码:

ggplot(data = data_sub, aes(x = variable, y = value)) +
  geom_bar(stat = "identity") +
  facet_wrap(~id, ncol = 3) +
  coord_flip() +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        panel.grid   = element_blank(),
        legend.position = "none")

得到了:

我的问题:

当我的图表较少时,例如只有一个,我想保持这种格式化。但是我只得到如下的大图(不介意传说)。

我怎样才能获得以下内容? enter image description here

3 个答案:

答案 0 :(得分:3)

一种方法是为每个非空因子级别创建一个图表,并为每个空因子级别创建一个空白占位符:

首先,使用内置的mtcars数据框,我们将faceting变量设置为9个级别的因子,但只有5个级别包含任何数据:

library(ggplot2)
library(grid)
library(gridExtra)

d = mtcars
set.seed(4193)
d$cyl = sample(1:9, nrow(d), replace=TRUE)
d$cyl <- factor(d$cyl, levels=sort(unique(d$cyl)))
d <- subset(d, cyl %in% c(1,5,7:9))

# Identify factor levels without any data
blanks = which(table(d$cyl)==0)

# Initialize a list
pl = list()

下面的for循环遍历faceting变量的每个级别,并创建一个级别有数据或nullGrob的图(也就是说,如果有该因子的数据,则为一个空占位符。级别)并将其添加到列表pl

for (i in 1:length(levels(d$cyl))) {

  if(i %in% blanks) {

    pl[[i]] = nullGrob()

  } else {

    pl[[i]] = ggplot(d[d$cyl %in% levels(d$cyl)[i], ], aes(x=am, y=wt) ) +
      geom_point() +
      facet_grid(.~ cyl)

  }
}

现在,布置图并在它们周围添加边框:

do.call(grid.arrange, c(pl, ncol=3))
grid.rect(.5, .5, gp=gpar(lwd=2, fill=NA, col="black"))

enter image description here

更新:我想添加到我的答案中的一项功能是删除不在最左侧列或最下行的图表的轴标签(更像是格式在OP)。以下是我不太成功的尝试。

从某些绘图中删除轴刻度和/或标签时出现的问题是绘图区域在不同的绘图中最终会有不同的大小。原因是所有的图都占据了相同的物理区域,但是带有轴标签的图使用了一些区域用于轴标签,使得它们的绘图区域相对于没有轴标签的图更小。

我曾希望我可以使用plot_grid包中的cowplot来解决此问题(由@ClausWilke撰写),但plot_grid不适用于nullGrob。然后@baptiste在这个问题上添加了另一个答案,这个问题已被删除,但对于声誉至少为10,000的SO用户仍然可以看到。该答案让我了解了他的egg包和set_panel_size函数,用于在不同的ggplots中设置通用面板大小。

以下是我尝试使用set_panel_size来解决情节区域问题。这不太成功,我将在展示代码和情节后更详细地讨论。

# devtools::install_github("baptiste/egg")
library(egg)

# Fake data for making a barplot. Once again we have 9 facet levels, 
# but with data for only 5 of the levels.
set.seed(4193)
d = data.frame(facet=rep(LETTERS[1:9],each=100), 
               group=sample(paste("Group",1:5),900,replace=TRUE))
d <- subset(d, facet %in% LETTERS[c(1,5,7:9)])

# Identify factor levels without any data
blanks = which(table(d$facet)==0)

# Initialize a list
pl = list()

for (i in 1:length(levels(d$facet))) {

  if(i %in% blanks) {

    pl[[i]] = nullGrob()

  } else {

    # Create the plot, including a common y-range across all plots
    # (though this becomes the x-range due to coord_flip)
    pl[[i]] = ggplot(d[d$facet %in% levels(d$facet)[i], ], aes(x=group) ) +
      geom_bar() +
      facet_grid(. ~ facet) +
      coord_flip() +
      labs(x="", y="") +
      scale_y_continuous(limits=c(0, max(table(d$group, d$facet)))) 

    # If the panel isn't on the left edge, remove y-axis labels
    if(!(i %in% seq(1,9,3))) {
      pl[[i]] = pl[[i]] + theme(axis.text.y=element_blank(),
                                axis.ticks.y=element_blank())
    }

    # If the panel isn't on the bottom, remove x-axis labels
    if(i %in% 1:6) {
      pl[[i]] = pl[[i]] + theme(axis.text.x=element_blank(),
                                axis.ticks.x=element_blank())
    }
  }

  # If the panel is a plot (rather than a nullGrob), 
  # remove margins and set to common panel size
  if(any(class(pl[[i]]) %in% c("ggplot","gtable"))) {
    pl[[i]] = pl[[i]] + theme(plot.margin=unit(rep(-1,4), "lines"))
    pl[[i]] = set_panel_size(pl[[i]], width=unit(4,"cm"), height=unit(3,"cm"))
  }

}

现在列出情节:

do.call(grid.arrange, c(pl, ncol=3))
grid.rect(.5, .5, gp=gpar(lwd=2, fill=NA, col="black"))

正如您在下图中看到的那样,即使这些图都具有相同的面板大小,它们之间的边距也不是恒定的,可能是由于grid.arrange处理空凹凸的间距的方式,具体取决于哪个职位有实际情节。此外,由于set_panel_size设置了绝对大小,我不得不手动调整最终绘图的大小,以使面板尽可能靠近在一起,同时仍然避免重叠。我希望SO的常驻grid专家中的一位能够顺便提出并提出更有效的方法。

(另请注意,使用此方法,您最终可能会在给定的行或列中没有标记的绘图。在下面的示例中,绘图“E”没有y轴标签,并且缺少“D”图,所以你必须查看不同的行以查看标签是什么。如果只有“B”,“C”,“E”和“F”的图表,则不会有任何标记的图在布局中。我不知道OP如何处理这种情况(一种选择是添加逻辑以在“内部”图上保留标签,如果给定行或列没有“外部”图),但我认为值得指出。)

enter image description here

答案 1 :(得分:1)

试试这个

d <- subset(mtcars, cyl==4)
d$cyl <- factor(d$cyl, levels=unique(mtcars$cyl))
ggplot(d, aes(x=am, y=wt) ) +
  geom_point() +
  facet_grid(.~cyl, drop = FALSE)

答案 2 :(得分:0)

一个可能的解决方案是生成一个ggplots列表,并用虚拟占位符替换其中一些。

/*Custom BBPress admin links menu*/
function wpmudev_bbp_admin_links_in_menu($retval, $r, $args) {
   if ( is_user_logged_in() ) {
   $menulinks = '<ul id="bbp_custom_links_menu-' . $r["id"] . '" class="bbp_custom_links_menu">';
    $menulinks .= '<li class="parent"><a href="#bbp_custom_links_menu-' . $r["id"] . '">Options</a>';
    $menulinks .= '<ul class="bbp_custom_links_submenu">';
    foreach($r['links'] as $key => $val) {
        $menulinks .= "<li>{$val}</li>";
    }
    $menulinks .= '</ul></li></ul>';

    echo $r['before'] . $menulinks . $r['after'];
    }
}
add_filter('bbp_get_topic_admin_links', 'wpmudev_bbp_admin_links_in_menu', 10, 3);
add_filter('bbp_get_reply_admin_links', 'wpmudev_bbp_admin_links_in_menu', 10, 3);

add_action( 'wp_footer', 'overflow_overriding' );
function overflow_overriding() {
    if ( !is_user_logged_in() ) {
    }else{
    ?>
<script type="text/javascript">
jQuery( document ).ready(function() {
jQuery('.bbp-admin-links:even').css({"position": "absolute", "right": "380px"});
jQuery('.bbp-admin-links:even').click(function(e) {
e.preventDefault();
$('ul:first',$(this)).toggleClass('hidden active');
});
});
</script>

     <?php
    }
}

enter image description here