Using Coord_Flip() with Facet_Wrap(Scales = "Free_Y") in Ggplot2 Seems to Give Unexpected Facet Axis Tick Marks and Tick Labels

Using coord_flip() with facet_wrap(scales = free_y ) in ggplot2 seems to give unexpected facet axis tick marks and tick labels

This is the second or third time I have run into this problem myself. I have found that I can hack my own solution by defining a custom geom.

geom_bar_horz <- function (mapping = NULL, data = NULL, stat = "bin", position = "stack", ...) {
GeomBar_horz$new(mapping = mapping, data = data, stat = stat, position = position, ...)
}

GeomBar_horz <- proto(ggplot2:::Geom, {
objname <- "bar_horz"

default_stat <- function(.) StatBin
default_pos <- function(.) PositionStack
default_aes <- function(.) aes(colour=NA, fill="grey20", size=0.5, linetype=1, weight = 1, alpha = NA)

required_aes <- c("y")

reparameterise <- function(., df, params) {
df$width <- df$width %||%
params$width %||% (resolution(df$x, FALSE) * 0.9)
OUT <- transform(df,
xmin = pmin(x, 0), xmax = pmax(x, 0),
ymin = y - .45, ymax = y + .45, width = NULL
)
return(OUT)
}

draw_groups <- function(., data, scales, coordinates, ...) {
GeomRect$draw_groups(data, scales, coordinates, ...)
}
guide_geom <- function(.) "polygon"
})

This is just copying the geom_bar code from the ggplot2 github and then switching the x and y references to make a horizontal barplot in the standard Cartesian coordinators.

Note that you must use position='identity' and possibly also stat='identity' for this to work. If you need to use a position other than identity then you will have to eddit the collide function for it to work properly.

R: ggplot reorder x-axis with facet_wrap and coord_flip

You need to convert your x into a factor and manually enter the values. In this case, since your axis is flipped you need to put the list in...flipped.

library(tidyverse)

d = data.frame(
f = rep(c("f1", "f2"), each = 4),
x = rep(c("a", "b", "c", "d"), 2),
y = c(0, 2, 3, 3, 2, 1, 0, 6))

d$x <- factor(d$x, levels= c('b','d','c','a'))

# plot ggplot
ggplot(d, aes(x, y)) +
geom_col() +
facet_wrap(~ f) +
coord_flip()

Sample Image

Remove inner labels in ggplot with nested facets and free y-axis (facet_wrap2 - ggh4x)

If you flip the x and y-aesthetic (making coord_flip() unnessary), you can use ggh4x::facetted_pos_scales() to explicitly remove the axis guide for the second column.

library(ggplot2)
library(ggh4x)
library(tibble)
library(dplyr)

set.seed(32123)
test <- tibble(
trial = rep(c("Trial_A", "Trial_B", "Trial_C"), each = 3, times = 8),
group = rep(c("A", "B"), each = 36),
result = rep(c("Fail", "Pass"), times = 36),
item = rep(c("item 1", "item 2", "item 3", "item 4"), each = 6, times = 3),
tries = round(runif(n = 72, min = 0, max = 20))) %>%
mutate(item = case_when(item == "item 4" & group == "B" & trial == "Trial_C" ~ "item 3",
item == "item 3" & group == "B" & trial == "Trial_C" ~ "item 2",
item == "item 3" & group == "B" & trial == "Trial_A" ~ "item 2",
item == "item 2" & group == "B" & trial == "Trial_A" ~ "item 1",
TRUE ~ item))

ggplot(test, aes(x = tries, y = item, fill = result)) +
geom_bar(position = "fill", stat = "identity") +
facet_wrap2(dplyr::vars(trial, group), # ggh4x package for nested facets
strip = strip_nested(), # sub facets normal
scales = "free_y", nrow = 3, axes = "margins",
remove_labels = "all") +
facetted_pos_scales(
y = list(COL == 2 ~ scale_y_discrete(guide = 'none'))
) +
theme(axis.title.x = element_blank())

Sample Image

Created on 2022-08-17 by the reprex package (v2.0.1)

Perhaps the documentation of facet_wrap2() should be clearer on when these arguments work.

How to make a a horizontal, faceted bar chart with free scales and space in ggplot2?

The problem here, as often with facetting, is the combination of coord_flip with anything more than the most basic facets. And as usual, the problem can be solved using the ggstance package on github. This package has horizontal versions of common geoms, such as geom_barh, which make coord_flip unnecessary.

library(ggstance)
ggplot(chartSet, aes(y = Item,
x = value,
alpha = factor(variable))) +
geom_barh(stat = "identity", position = "dodgev", fill = "red") +
scale_alpha_manual(values = c(0.1, 0.4, 1)) +
labs(alpha = "") +
theme_bw() + ylab("") + xlab("% Contribution to VaR") +
facet_grid(AssetClass ~ ., scales = "free_y", space = "free_y") +
theme(strip.text.y = element_text(angle = 0)) +
theme(legend.position = "bottom",
axis.text = element_text(size = 5))

Sample Image

ggplot2 facet_wrap with two nested variables: use different strip.position/switch for each variable?

I don't know a way to accomplish that within ggplot itself, but another approach would be to combine two plots using patchwork:

library(patchwork)
myplot <- function(section = "A") {
ggplot(subset(df, df$dim_1 == section), aes(x,y)) +
geom_point() +
# coord_cartesian(xlim = c(min(df$x), max(df$x))) + # To get single x scale between all plots
facet_grid(dim_2~dim_1, switch = "y")
}
myplot("A") / myplot("B")

Sample Image

R and ggplot2: scale_x_continuous(trans = log ) with tick labels that are not in logs

Still a bit confused at what you're really after. Perhaps this will help you see what's going on underneath the covers in ggplot2. Also, log(), trans="log" !== log10(), trans="log10":

library(ggplot2)
library(tibble)
library(gridExtra)

set.seed(1492)
df <- data_frame(x=abs(rnorm(10) * 100) + 1,
y=seq(0, 1, length.out=10))

gg <- ggplot(df, aes(x, y)) + geom_point()
gg <- gg + geom_vline(xintercept=10)

gg1 <- gg + scale_x_continuous()
gg2 <- gg + scale_x_continuous(breaks=c(10, 50, 100, 150))
gg3 <- gg + scale_x_continuous(trans="log")
gg4 <- gg + scale_x_continuous(trans="log", breaks=c(10, 50, 100, 150))

grid.arrange(
gg1,
gg2,
gg3,
gg4,
ncol=1
)

Sample Image

Avoid wasting space when placing multiple aligned plots onto one page

Here is a slight modification of the general plot you show, assuming that the y and x axis labels pertain to all plots. It uses an outer margin to contain the axis labelling, which we add with title() using argument outer = TRUE. The effect is somewhat like the labelling in ggplot2 or lattice plots.

The key line here is:

op <- par(mfrow = c(2,2),
oma = c(5,4,0,0) + 0.1,
mar = c(0,0,1,1) + 0.1)

which sets plot parameters (the values in place prior to the call are stored in op). We use 5 and 4 lines on sides 1 and 2 for the outer margin, which is the usual number for the mar parameter. Plot region margins (mar) of 1 line each are added to the top and right sides, to give a little room between plots.

The axis labels are added after the for() loop with

title(xlab = "Some Categories",
ylab = "Some Values",
outer = TRUE, line = 3)

The entire script is:

set.seed(42)
catA <- factor(c("m100", "m500", "m1000", "m2000", "m3000", "m5000"))
catB <- factor(20:28)
samples <- 100
rsample <- function(v) v[ceiling(runif(samples, max=length(v)))]
Tab <- data.frame(catA = rsample(catA),
catB = rsample(catB),
valA = rnorm(samples, 150, 8),
valB = pmin(1,pmax(0,rnorm(samples, 0.5, 0.3))))
op <- par(mfrow = c(2,2),
oma = c(5,4,0,0) + 0.1,
mar = c(0,0,1,1) + 0.1)
for (i in 0:3) {
x <- Tab[[1 + i %% 2]]
plot(x, Tab[[3 + i %/% 2]], axes = FALSE)
axis(side = 1,
at=1:nlevels(x),
labels = if (i %/% 2 == 1) levels(x) else FALSE)
axis(side = 2, labels = (i %% 2 == 0))
box(which = "plot", bty = "l")
}
title(xlab = "Some Categories",
ylab = "Some Values",
outer = TRUE, line = 3)
par(op)

which produces

Sample Image



Related Topics



Leave a reply



Submit