Q: ggplot - facet wrap - adjusting scale to show apparent differences between values I have a dataframe like below:
text <- "
brand   a   b   c   d   e   f
nissan  99.21   99.78   6496    1.28    216 0.63
toyota  99.03   99.78   7652    1.39    205 0.60
"
df <- read.table(textConnection(text), sep="\t", header = T)

I'm trying to get all the variables for the two groups plotted in a single ggplot using face_wrapas below:
library(reshape2)
library(ggplot2)
library(ggthemes)
library(RColorBrewer)
ggplot(melt(df, id = "brand")) + 
  aes(brand, value, fill = brand) + 
  geom_bar(stat = "identity", position='dodge') +
  geom_text(data=melt(df, id = "brand"), angle = 0, 
               aes(brand, value,
                   label = ifelse(value > 100, round(value, 0), value) ) ) +
  facet_wrap(~ variable, scales = "free_y") + 
  scale_fill_brewer(palette = "Paired") + 
    theme(
      legend.position = "top",
      strip.text.y = element_text(angle = 0),
      axis.text.x = element_blank(),
      axis.text.y = element_blank(),
      axis.ticks = element_blank()
      )

It works well except for one thing. The apparent differences between the group for value of a variable is not coming out very well visually. For example for variable a I want the height of the bars to be such that it is clear which is the higher one in an easier fashion. How do I get the height difference between such close values to be larger? 


A: Edit
(I wasn't planning to return to this, since I think all the answers are really on the same side. But it kept popping up on my feed, until I finally thought of an angle that hasn't been mentioned yet.)
The only way I can think of that somewhat justifies using bars in this context is to make it very clear that the bar heights represent rank, not value:
df2 <- melt(df, id = "brand") %>%
  group_by(variable) %>%
  mutate(rank = rank(value))

> df2
# A tibble: 12 x 4
# Groups: variable [6]
   brand  variable    value  rank
   <fctr> <fctr>      <dbl> <dbl>
 1 nissan a          99.2    2.00
 2 toyota a          99.0    1.00
 3 nissan b          99.8    1.50
 4 toyota b          99.8    1.50
 5 nissan c        6496      1.00
 6 toyota c        7652      2.00
 7 nissan d           1.28   1.00
 8 toyota d           1.39   2.00
 9 nissan e         216      2.00
10 toyota e         205      1.00
11 nissan f           0.630  2.00
12 toyota f           0.600  1.00

Use rank for the y-values, and everything else can flow naturally without bringing in geom_rect() & so on:
ggplot(df2,
       aes(x = brand, y = rank, fill = brand,
           label = value)) +
  geom_col() +
  geom_text(vjust = 0) +
  facet_wrap(~variable) + 
  scale_fill_brewer(palette = "Paired") + 
  theme(
    legend.position="top",
    strip.text.y = element_text(angle = 0),
    axis.text=element_blank(),
    axis.ticks = element_blank()
  )

(Plot image not included. It's essentially the same chart as below, except for the y-axis title being "rank" now.)
Is the result still chart junk? I'd say yes, but if you absolutely have to show arbitrary bars to others, tell them the height is based on rank, and it should make a bit more sense.
Original answer below
If you really need to use a bar plot, you can use geom_rect & manually define a different ymin for each facet.
Modify dataframe:
library(dplyr)

df2 <- melt(df, id = "brand") %>%
  group_by(variable) %>%
  mutate(ymax = value, 
         ymin = ifelse(diff(value) == 0, 0,
                       min(value) - (max(value) - min(value)) / 2),
         yblank = ifelse(diff(value) == 0, value * 2,
                         max(value) + (max(value) - min(value)) / 2),
         x = as.integer(brand),
         xmin = x - 0.4,
         xmax = x + 0.4,
         label = ifelse(value > 100, round(value, 0), value)) %>%
  ungroup()

> df2
# A tibble: 12 x 10
   brand  variable    value     ymax     ymin   yblank     x  xmin  xmax    label
   <fctr> <fctr>      <dbl>    <dbl>    <dbl>    <dbl> <int> <dbl> <dbl>    <dbl>
 1 nissan a          99.2     99.2     98.9     99.3       1 0.600  1.40   99.2  
 2 toyota a          99.0     99.0     98.9     99.3       2 1.60   2.40   99.0  
 3 nissan b          99.8     99.8      0      200         1 0.600  1.40   99.8  
 4 toyota b          99.8     99.8      0      200         2 1.60   2.40   99.8  
 5 nissan c        6496     6496     5918     8230         1 0.600  1.40 6496    
 6 toyota c        7652     7652     5918     8230         2 1.60   2.40 7652    
 7 nissan d           1.28     1.28     1.23     1.44      1 0.600  1.40    1.28 
 8 toyota d           1.39     1.39     1.23     1.44      2 1.60   2.40    1.39 
 9 nissan e         216      216      200      222         1 0.600  1.40  216    
10 toyota e         205      205      200      222         2 1.60   2.40  205    
11 nissan f           0.630    0.630    0.585    0.645     1 0.600  1.40    0.630
12 toyota f           0.600    0.600    0.585    0.645     2 1.60   2.40    0.600

This creates bars such that the shorter bar in each facet occupies one quarter of the facet's height, while the taller bar occupies three quarters. If the two bars are exactly the same height, they both occupy half the facet's height. If you want to tweak the appearance, just change ymin / yblank.
Plot:
ggplot(df2,
       aes(x = x, y = ymax, fill = brand)) + 
  geom_rect(aes(xmin = xmin, xmax = xmax,
                ymin = ymin, ymax = ymax)) +
  geom_text(aes(label = label), 
            vjust = -1) + # position labels slightly above top of each bar
  geom_blank(aes(y = yblank)) +
  facet_wrap(~ variable, scales = "free_y") + 
  scale_fill_brewer(palette = "Paired") + 
  theme(
    legend.position="top",
    strip.text.y = element_text(angle = 0),
    axis.text=element_blank(),
    axis.ticks = element_blank()
  )



A: I agree with the answers and comments that it is not a good idea to manipulate the relative bar length. If you just want to show which bar is higher in current plot, you can use another aesthetic to highlight it, for example put the higher bar in a box like the plot below.

library(reshape2)
library(ggplot2)
library(ggthemes)
library(RColorBrewer)

library(data.table)
library(magrittr)


# add a winner column to mark the winner in red
aaa <- melt(df, id = "brand") %>%
    setDT() %>%
    .[, winner := ifelse(value > mean(value), "red", "NA"), by = variable]

# plot and show the higher bar in read box
ggplot(aaa, aes(brand, value, fill = brand)) + 
    geom_bar(aes(color = winner), stat = "identity", position='dodge') +
    geom_text(data=melt(df, id = "brand"), angle = 0, 
              aes(brand, value,
                  label = ifelse(value > 100, round(value, 0), value) ) ) +
    facet_wrap(~ variable, scales = "free_y") + 
    scale_fill_brewer(palette = "Paired") + 
    scale_color_identity() +
    theme(
        legend.position = "top",
        strip.text.y = element_text(angle = 0),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank()
    )


A: I'm sure people will happily tell you how to hack ggplot2 so you can have bars start at an arbitrary y value. However, you need to be aware that the result will be a meaningless junk chart, in particular if you strip the y axis of axis ticks. I would recommend reading this blog post on the principle of proportional ink.
One solution that you could pursue is to plot bars that represent the ratio of the two variables, like so:
text <- "
brand   a   b   c   d   e   f
nissan  99.21   99.78   6496    1.28    216 0.63
toyota  99.03   99.78   7652    1.39    205 0.60
"

df_wide <- read.table(textConnection(text), sep="\t", header = T)

library(ggplot2)
library(tidyr)
library(dplyr)

df_long <- gather(df_wide, variable, value, -brand) %>%
  spread(brand, value) %>%
  mutate(ratio = nissan/toyota,
         label = paste(signif(nissan, 3), signif(toyota, 3), sep = " / "),
         vjust = ifelse(ratio >= 1, -.5, 1.5)) %>%
  mutate(ratio = ifelse(ratio == 1, 1.001, ratio))

ggplot(df_long, aes(variable, ratio, fill = (ratio>=1))) + 
  geom_col() +
  geom_text(aes(label = label, vjust = vjust)) +
  scale_y_log10(name = "ratio Nissan / Toyota",
                breaks = c(.85, .9, .95, 1, 1.05, 1.1),
                expand = c(.15, 0)) +
  scale_fill_brewer(palette = "Paired", guide = "none")


The result is only a single bar per pairing, but the bar height accurately reflects the relative magnitude of the two variables. And you don't seem to be interested in the absolute magnitude anyways, since you're using free y axis scaling in your original facet_wrap() command.

A: It's misleading to start scales at arbitrary y values as many on this thread have pointed out.
One answer that hasn't been considered is to put the scales on an log scale with scale_y_log10(), and combine with geom_text labels to show differences between facetted groups.
data
df <- data_frame(
  pair = letters[1:6] %>% rep(2),
  brand = c("nissan", "toyota") %>% rep(each = 6),
  value = c(99.21, 99.78, 6496, 1.28, 216, 0.63, 
            99.03, 99.78, 7652, 1.39, 205, 0.60)
)

plot
df %>% 
  ggplot(aes(x = brand, y = value)) +
  geom_col(aes(fill = brand)) +
  geom_text(aes(label = value), vjust = -1) +
  scale_y_log10() +
  facet_wrap(~pair) +
  theme_bw()


