Call ggplot2 aesthetics in another function

35 views Asked by At

In base R, it is possible to automatically use the Freedman-Diaconis rule for setting bin width in a histogram:

hist(rnorm(100), breaks = "FD")

There does not appear to be this behavior in base ggplot. I have been trying to implement this method for easier use with geom_histogram.

I would like to be able to modify the function so that it can be called without specifying the original dataframe and column.

bin_number <- function(data_vector = NULL) {

    if (is.null(data_vector)) {
        data_vector <- # something
    }

    bin_width <-
        2 * stats::IQR(data_vector) / (length(data_vector) ^ (1 / 3))
    number_bins <- ceiling(diff(range(data_vector)) / bin_width)

    return(number_bins)
}


df <- data.frame(xval = rnorm(100))

ggplot(data = df) +
    geom_histogram(
        mapping = aes(
            x = xval,
            y = after_stat(density)
        ),
        bins = bin_number()
    )

I have looked through the ggplot documentation, but I haven't been able to find a way to get the aesthetics of the current dataframe easily.

My current method requires calling the data vector directly, which does work but can be clunky and makes the code for histograms harder to reproduce.

bin_number <- function(data_vector) {

    bin_width <-
        2 * stats::IQR(data_vector) / (length(data_vector) ^ (1 / 3))
    number_bins <- ceiling(diff(range(data_vector)) / bin_width)

    return(number_bins)
}


df <- data.frame(xval = rnorm(100))

ggplot(data = df) +
    geom_histogram(
        mapping = aes(
            x = xval,
            y = after_stat(density)
        ),
        bins = bin_number(df$xval)
    )

1

There are 1 answers

0
Patrick Coulombe On BEST ANSWER

If you create the plot in two steps, you can definitely retrieve the x aesthetic from the aesthetic object. One option is to create the aesthetic object first, then generate the plot and retrieve the x aesthetic from the aes object:

my_aes<-aes(
  x = xval,
  y = after_stat(density)
)
ggplot(data = df) +
  geom_histogram(mapping=my_aes, 
                 bins=bin_number(df[,as_label(my_aes$x)]))

Another option is to map the aesthetics inside ggplot(), and again retrieve the x aesthetic when adding the geom_histogram layer (you can also retrieve the data from the ggplot object):

p<-ggplot(data=df, aes(x=xval, y=after_stat(density)))
p+geom_histogram(bins=bin_number(p$data[,as_label(p$mapping$x)]))