116

I have an object from ggplot2, say myPlot, how can I identify the ranges for the x and y axes?

It doesn't seem to be a simple multiple of the data values' range, because one can rescale plots, modify axes' ranges, and so on. findFn (from sos) and Google don't seem to be turning up relevant results, other than how to set the axes' ranges.

Iterator
  • 20,250
  • 12
  • 75
  • 111
  • 2
    I'm fairly sure that can't be extracted directly from the plot object itself, but you can infer it (in simple cases) from your data and the default values for `expand`. See [here](http://stackoverflow.com/questions/7611691/relative-positioning-of-geom-text-in-ggplot2/7617377#7617377). – joran Oct 09 '11 at 19:27
  • @joran Thanks - that looks interesting. Do you mean `expand_range`? I wasn't able to get `expand` to work as suggested in the link. – Iterator Oct 10 '11 at 00:47
  • 2
    I was referring to the `expand` argument to the `scale_*` functions in `ggplot`. For example, see the defaults listed [here](http://had.co.nz/ggplot2/scale_continuous.html). – joran Oct 10 '11 at 00:50
  • 8
    You will be able to extract it in the next version... – hadley Oct 10 '11 at 02:29
  • 1
    Could you please accept Alex Holcombe's answer instead? Paul Hiemstra's is only relevant for versions of ggplot2 from over three years ago. – Max Ghenis Sep 06 '15 at 17:02
  • 9
    **As of Aug 2018 you extract the x and y-axes ranges with the following . ** `ggplot_build(obj)$layout$panel_scales_x[[1]]$range$range` `ggplot_build(obj)$layout$panel_scales_y[[1]]$range$range` – Michael Sep 01 '18 at 20:27
  • 1
    This thread [access tick marks of ggplot2 object](https://stackoverflow.com/questions/31223818/accessing-vector-of-axis-ticks-for-an-existing-plot-in-ggplot2) helps to find the "limits" (if we can call them that) when they have not been set. – M-- Mar 15 '19 at 14:23

9 Answers9

54

I am using ggplot2 version 2, I am not sure if this is same is previous version, Suppose you have saved your plot on plt object. It is easy to extract the ranges,

# y-range
layer_scales(plt)$y$range$range

# x-range
layer_scales(plt)$x$range$range

In case of facet plot, you can access scales of individual facets using layer_scales(plot, row_idx, col_idx). For example to access the facet at first row and second column,

# y-range
layer_scales(plt, 1, 2)$y$range$range

# x-range
layer_scales(plt, 1, 2)$x$range$range
TheRimalaya
  • 4,232
  • 2
  • 31
  • 37
  • 3
    And **version 3.1.0** – r_alanb Dec 17 '18 at 23:59
  • 3
    Note this gives you the range of the data to be plotted - to get the full axis range you will need to allow for the scale expansion. Moreover, if limits have been set (e.g. via `ylim` or `coord_cartesian`) the scale expansion will be applied to these limits rather than those returned by the code given here. – Heather Turner May 01 '19 at 15:04
  • Note that the range does not include the `expand`. My default is to use an expand of `expansion = mult(c(0, 0.25))`, so a y scale of [0, 10] will practically/visibly become [0, 12], though `$y$range$range` returns [0, 10]. – MS Berends Dec 28 '21 at 16:37
46

In newer versions of ggplot2, you can find this information among the output of ggplot_build(p), where p is your ggplot object.

For older versions of ggplot (< 0.8.9), the following solution works:

And until Hadley releases the new version, this might be helpful. If you do not set the limits in the plot, there will be no info in the ggplot object. However, in that case you case you can use the defaults of ggplot2 and get the xlim and ylim from the data.

> ggobj = ggplot(aes(x = speed, y = dist), data = cars) + geom_line()
> ggobj$coordinates$limits

$x
NULL

$y
NULL

Once you set the limits, they become available in the object:

> bla = ggobj + coord_cartesian(xlim = c(5,10))
> bla$coordinates$limits
$x
[1]  5 10

$y
NULL
Paul Hiemstra
  • 59,984
  • 12
  • 142
  • 149
  • I got this info by calling the str function on a ggplot object. This is a real neat function when you need to find the structure of an R object. – Paul Hiemstra Nov 17 '11 at 13:02
  • My even-more-favorite command is ggplot :), or plyr :), or both! – Paul Hiemstra Nov 17 '11 at 13:17
  • By the way, welcome to SO - be sure to stop by the R chat room - http://chat.stackoverflow.com/rooms/106/r to say hello. :) – Iterator Nov 17 '11 at 13:40
  • 36
    Specifically, in the newer versions of ggplot2, you can get the yrange with ggplot_build(ggobj)$panel$ranges[[1]]$y.range and the xrange with ggplot_build(ggobj)$panel$ranges[[1]]$x.range – Alex Holcombe May 28 '13 at 04:03
  • As a head's up, giving the range as the limit argument in the subsequent plots will not have the expected effect. You can (i) add a `expand = c(0,0)` in your call to `scale_y_continuous()` or (ii) grab the minimum and maximum values of the data in the $data field of the `ggplot_build()` object, and give these as `limits=` (more hacky). – Antoine Lizée Oct 09 '14 at 01:15
  • @AlexHolcombe: I had exactly the same question and found your comment above to be the best answer. May i suggest you add it as an answer? – RHA Jul 26 '15 at 20:07
  • 11
    For `ggplot2` version 2.1.0.9001 use this `R` code: `ggplot_build(obj)$layout$panel_ranges[[1]]$x.range` `ggplot_build(obj)$layout$panel_ranges[[1]]$y.range` – GegznaV Oct 28 '16 at 12:15
  • 25
    For `ggplot2` **version 2.2.1.9000** and (most probably) newer use this `R` code: `ggplot_build(obj)$layout$panel_scales_x[[1]]$range$range` `ggplot_build(obj)$layout$panel_scales_y[[1]]$range$range` – GegznaV Apr 30 '17 at 14:59
  • 3
    Is there no way to do it dynamically within the original plot call? – jzadra May 03 '17 at 18:56
  • 6
    In 2.2.1 you can also use layer_scales(ggobj)$y$range$range – Alex Holcombe Feb 08 '18 at 04:09
  • 1
    Doesn't appear to work when limits are set via ``scale_x_continuous(limits = c(5, 10))``... – PatrickT Nov 20 '18 at 05:54
  • This approach is useful when a plot-generating function sets the limits. To get the full range (the equivalent of that extracted from the result of `ggplot_build`) you'll need to allow for the scale expansion, by default 5% at each end for continuous scales (https://ggplot2.tidyverse.org/reference/expand_scale.html) – Heather Turner May 01 '19 at 13:40
  • In 3.4.1, it can be done with `ggplot_build(obj)$layout$panel_params[[1]]$x.range` or `ggplot_build(obj)$layout$panel_params[[1]]$y.range` to get the full range of the axes. – dark-walrus Mar 06 '23 at 01:01
33

November 2018 UPDATE

As of ggplot2 version 3.1.0, the following works:

obj <- qplot(mtcars$disp, bins = 5)

# x range
ggplot_build(obj)$layout$panel_params[[1]]$x.range

# y range
ggplot_build(obj)$layout$panel_params[[1]]$y.range

A convenience function:

get_plot_limits <- function(plot) {
    gb = ggplot_build(plot)
    xmin = gb$layout$panel_params[[1]]$x.range[1]
    xmax = gb$layout$panel_params[[1]]$x.range[2]
    ymin = gb$layout$panel_params[[1]]$y.range[1]
    ymax = gb$layout$panel_params[[1]]$y.range[2]
    list(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax)
}
get_plot_limits(p)

Until the next update...

Community
  • 1
  • 1
GegznaV
  • 4,938
  • 4
  • 23
  • 43
  • 1
    Suggested an edit with a convenience function, roll-back if you don't like it. ;-) – PatrickT Nov 20 '18 at 06:01
  • 1
    @PatrickT your update is really convenient. I really appreciate it :) – GegznaV Nov 20 '18 at 17:39
  • To get the x and y axis limits as a data frame, you can use `purrr::map_df(.x=ggplot_build(obj)$layout$panel_params, .f=function(a) {setNames(object=c(a$x.range, a$y.range), nm=c("xMin", "xMax", "yMin", "yMax"))})` where obj is a ggplot object. This is especially useful for facet plots with scales="free". If someone knows how to add column(s) indicating the corresponding facet variable values, I'd love to see that code. – user3799203 May 10 '21 at 20:32
20

Get the yrange with

ggplot_build(myPlot)$panel$ranges[[1]]$y.range 

and the xrange with

ggplot_build(myPlot)$panel$ranges[[1]]$x.range
Alex Holcombe
  • 2,453
  • 4
  • 24
  • 34
  • 2
    These solutions work well for continuous numeric axes, but how can one handle axes with dates (continuous scale) or categorical values? When I use this method I get large numeric values that require some conversion to date format in order to add text using geom_text. – Joseph Kreke Mar 24 '16 at 23:29
  • What if I am not setting the axis limits but using what ggplot suggests by default? My use case is that I like the default values for plot 1 but I want plot 2 to have the same axis limits as plot 1. – NewNameStat Oct 31 '18 at 16:39
17

In version 2.2.0 this has to be done as follows:

# y-range
ggplot_build(plot.object)$layout$panel_ranges[[1]]$y.range
# x-range
ggplot_build(plot.object)$layout$panel_ranges[[1]]$x.range
pat-s
  • 5,992
  • 1
  • 32
  • 60
10

As of Aug 2018 you extract the x and y-axes ranges with the following.

ggplot_build(obj)$layout$panel_scales_x[[1]]$range$range ggplot_build(obj)$layout$panel_scales_y[[1]]$range$range

Tung
  • 26,371
  • 7
  • 91
  • 115
Michael
  • 1,537
  • 6
  • 20
  • 42
9

As mentioned here: https://gist.github.com/tomhopper/9076152#gistcomment-2624958 there is a difference between the two options:

#get ranges of the data
ggplot_build(obj)$layout$panel_scales_x[[1]]$range$range 
ggplot_build(obj)$layout$panel_scales_y[[1]]$range$range

#get ranges of the plot axis
ggplot_build(obj)$layout$panel_params[[1]]$x.range
ggplot_build(obj)$layout$panel_params[[1]]$y.range

Here is a set of convenience functions to take a list of plots, extract the common y-axis range and replace it. I needed it because I used different data sets within one graph arranged via ggarange :

require(ggplot2)
#get the visible scales from single plots
get_plot_view_ylimits <- function(plot) {
  gb = ggplot_build(plot)
  ymin = gb$layout$panel_params[[1]]$y.range[1]
  ymax = gb$layout$panel_params[[1]]$y.range[2]
  message(paste("limits are:",ymin,ymax))
  list(ymin = ymin, ymax = ymax)
}

#change the limit of single plot, using list of limits
change_plot_ylimits <- function(plot, nlimits){
  p <- plot + ggplot2:::limits(unlist(nlimits, use.names =FALSE),"y")
}

#adjust the scales of multiple plots
#take a list of plots, passes back adjusted list of plots
adjust_plots_shared_ylimits <- function(plotList) {
  #read limits
  first <- TRUE
  for (plot in plotList) {
    if (first) {
      nlimits <- get_plot_view_ylimits(plot)
      first <- FALSE
    } else {
      altLimits <- get_plot_view_ylimits(plot)
      nlimits$ymin <- min(nlimits$ymin,altLimits$ymin)
      nlimits$ymax <- max(nlimits$ymax,altLimits$ymax)
    }
  }
  message(paste("new limits are:",nlimits$ymin,nlimits$ymax))
  #adjust limits
  lapply(plotList,change_plot_ylimits,nlimits)
}

I thought this might also be useful for others.

Frederik
  • 355
  • 2
  • 8
  • There is one problem, perhaps someone knows how to deal with: The ranges reported are "big enough" to include all the ranges from the plots in the list, but they are a lot bigger than the actual maximum (say, in a list of plots using ```stat_smooth( method = "lm")``` – Frederik Aug 09 '19 at 12:44
0

This is a potential work around for you! This works unless you change the axis limits in the layout of the plot. It essentially takes the range from the data in the plot, so it work better when the axis is changed through filtering data rather than by using the layout function.

Here's the code!

# load ggplot2
library(ggplot2)

# A basic scatterplot
p <-ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width, color=Species)) + 
      geom_point(size=6)

# p$data returns the dataset used to create the plot (iris)
head(p$data)

# Choose plot variable you want range for 
range(p$data[,"Sepal.Length"]) # * c(0.95, 1.05)

Its not a perfect solution but is a great easy quick workaround, hope it helped!

Maximilian
  • 143
  • 1
  • 8
0

Update:

ggplot2 version 3.3.2 now uses this code:

xmin <- ggplot_build(myPlot)$layout$panel_params[[1]]$x_range[1]
xmax <- ggplot_build(myPlot)$layout$panel_params[[1]]$x_range[2]
needshelp
  • 595
  • 1
  • 6
  • 25