user32147
user32147

Reputation: 1073

ggplot geom_bar with position_dodge is NOT adjusting the distance between bars

I am trying to decrease distance between bars narrower, however, position_dodge does not seem to work in adjusting the distance between bars.

Below is my code sample with two outputs with different widths one with 0.7 and one with 5, but the widths between bars are unaffected...:

library(ggplot2)
library(grid)
library(ggthemes)
library(scales)
library(gridExtra)

variables = c('a','b','c','d','e')
values = c(0.2,0.4,0.6,0.8,1.0)
std = c(0.05,0.06,0.03,0.08,0.09)

Data = data.frame(variables, values, std)

f3 = ggplot(data = Data, aes(x = variables, y = values, group = variables) ) + 
  geom_bar(stat='identity',width=0.6,position=position_dodge(width = 0.7),fill=c('#FF7F0E','#2CA02C','#D62728', '#00008B', '#B23AEE')) +
  coord_flip() +
  geom_errorbar(aes(ymin=values-std, ymax=values+std),
                width=.2,size=0.3) +
  scale_y_continuous("Variable Importance", expand = c(0,0),limits = c(0, 1.1), breaks=seq(0, 1.1, by = 0.1)) + # rescale Y axis slightly
  scale_x_discrete("Variables", limits = c('a','b',"c","d","e" )) +
  theme_bw() + # make the theme black-and-white rather than grey (do this before font changes, or it overrides them)
  theme(
    line = element_line(size=0.3),
    plot.title = element_blank(), # use theme_get() to see available options
    axis.title.x = element_text(family='sans',size=13),
    axis.title.y = element_text(family='sans',size=13, angle=90),
    axis.text.x = element_text(family='sans',vjust=0.4,size=11),
    axis.text.y = element_text(family='sans',size=11),
    panel.grid.major = element_blank(), # switch off major gridlines
    panel.grid.minor = element_blank(), # switch off minor gridlines
    legend.position = 'none', # manually position the legend (numbers being from 0,0 at bottom left of whole plot to 1,1 at top right)
    legend.title = element_blank(), # switch off the legend title
    legend.text = element_blank(),
    legend.key.size = unit(1.5, "lines"),
    legend.key = element_blank(), # switch off the rectangle around symbols in the legend
    panel.border=element_blank(),
    axis.line=element_line(size=0.3)
  )

plot(f3)

sample plot generated with position_dodge(witdt = 0.7)

sample plot generated with position_dodge(witdt = 5), these two plots are exactly identical..

Any help will be greatly appreciated! Thanks,

Upvotes: 1

Views: 1064

Answers (1)

Gregor Thomas
Gregor Thomas

Reputation: 145775

position_dodge is used when you have multiple bars at one position, like if you had several bars plotted at "a" on your "Variables" axis. See, e.g., an example from ?position_dodge:

ggplot(mtcars, aes(x=factor(cyl), fill=factor(vs))) +
  geom_bar(position="dodge")

Here, the x-axis is defined by cyl, but the fill color is defined by vs, so we'll have multiple bars distinguished by fill color at each x position. The position dodge says to put the bars next to each other (as opposed to on top of each other position = "identity" or stacked position = "stack").

You only have single bars at each position so position_dodge doesn't do anything. Get rid of your position_dodge entirely and use the width argument of geom_bar (which you've already set to 0.6).

This was a nice reproducible example, but I'd encourage you to make your Stack Overflow questions more minimal in the future. All of the theme calls you have are irrelevant to the question, and despite loading 5 packages, the only one you're actually using is ggplot2. Somewhat stripped-down code is below. I removed the position_dodge as discussed, got rid of you scale_x_continuous as it wasn't changing anything away from the defaults, I moved the fill inside aes() and added scale_fill_manual---which is just the style I prefer, and I got rid of the theme customization as its 16 lines of code that don't matter for the clarity of the question.

f3 = ggplot(data = Data,
            aes(x = variables, y = values,
                group = variables, fill = variables)) + 
    geom_bar(stat = 'identity',
             width = 0.6) +       ## adjust this width
    coord_flip() +
    geom_errorbar(aes(ymin = values - std, ymax = values + std),
                  width = .2, size = 0.3) +
    scale_y_continuous("Variable Importance",
                       expand = c(0,0),
                       limits = c(0, 1.1),
                       breaks = seq(0, 1.1, by = 0.1)) +
    scale_fill_manual(values = c('#FF7F0E','#2CA02C','#D62728', '#00008B', '#B23AEE'),
                      guide = FALSE) +
    theme_bw()

f3

As an example of adjusting width (though this is overplotting not replacing, so if you want to make the width smaller edit the original f3 definition).

f3 + geom_bar(stat = "identity", width = 0.9)

Two other notes:

  1. Most of your theme modifications seem to be duplicating theme_classic()---which is also built in to ggplot2. Using theme_classic() instead of theme_bw() may let you start much closer to your target.

    f3 + theme_classic()
    
  2. As Roman pointed out in comments, geom_pointrange might be better suited for this data. Confidence intervals on top of bars are often hard to see and compare. Here's an example:

    ggplot(data = Data,
           aes(x = variables, y = values, color = variables)) + 
      geom_pointrange(aes(ymin = values - std, ymax = values + std), size = 1) +
      scale_y_continuous("Variable Importance",
                         expand = c(0,0),
                         limits = c(0, 1.1),
                         breaks = seq(0, 1.1, by = 0.1)) +
      scale_color_manual(values = c('#FF7F0E','#2CA02C','#D62728', '#00008B', '#B23AEE'),
                         guide = FALSE) +
      coord_flip() +
      theme_classic()
    

    enter image description here

Upvotes: 2

Related Questions