Setting x/y lim in facet_grid

Showing 1-9 of 9 messages
Setting x/y lim in facet_grid Stavros Macrakis 12/30/09 8:44 AM
If what I'm asking for below can't be done with facet_grid(scales="free"), is it possible to set  coord_cartesian-type limits independently in each row and column of a facet_grid?

On Thu, Dec 24, 2009 at 11:12 PM, Stavros Macrakis <macr...@post.harvard.edu> wrote:
I have some data which is inherently positive, and would like to ensure that all graphs in a facet-grid start with y=0, but scale appropriately on the high end.

For example, suppose I'm comparing the growth of hamburger and hot dog sales from year to year:

fr <-
  data.frame(
             year=rep(1:10,2),                                         # 2 runs of 10
             quant=(c(1:10,1:10*3)+rnorm(20,0,3))^2,     # some variation in dependent var
             type=rep(c('hamburgers','hot dogs'),each=10))     # first 10 and second 10 are separate series

and plot it with:

ggplot(fr,aes(x=year,y=quant)) +
  geom_point() +
  geom_smooth() +
  facet_grid(type~.,scales="free")

This is fine, except that the geom_smooth overflows into (meaningless) negative values.

So I'd like to do something like

   +  coord_cartesian(ylim=c(0,NA))    # causes internal error

to ensure that the lower y limit is always at 0 to make the graphs comparable.  I do, however, want to let the upper y limit be free.

How do I do this in ggplot?

              -s



Re: Setting x/y lim in facet_grid Hadley Wickham 1/2/10 2:10 PM
> If what I'm asking for below can't be done with facet_grid(scales="free"),
> is it possible to set  coord_cartesian-type limits independently in each row
> and column of a facet_grid?

Not currently, unfortunately.  If you could suggest some possible
syntaxes I can think about how to incorporate it into the back end.

Hadley

> --
> You received this message because you are subscribed to the ggplot2 mailing
> list.
> To post to this group, send email to ggp...@googlegroups.com
> To unsubscribe from this group, send email to
> ggplot2+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/ggplot2

--
http://had.co.nz/

Re: Setting x/y lim in facet_grid baptiste auguie 1/3/10 3:16 AM
Hi,

Lattice has the following approach: the default scales are calculated
automatically but the user can override this with custom limits in the
form of a list. The list elements are recycled if necessary. The
following example illustrates a possible syntax,

set.seed(123)
xx = stats::runif(10)
yy = stats::runif(10, min=-0.2, max=1.2)

library(grid)
grid.panel <- function(ii=1,
                       x = xx,
                       y = yy,
                       xscale = extendrange(x),
                       yscale = extendrange(y),
                       vp=viewport(layout.pos.row=ii, layout.pos.col=1)) {

## Inf means the full range
  yscale[yscale == Inf] <- max(yy)
  yscale[yscale == -Inf] <- min(yy)

  pushViewport(vp)

  plot.vp <- viewport(xscale=xscale, yscale=yscale, height=0.6, clip=T)
  pushViewport(plot.vp)
  grid.points(x, y, gp=gpar(col="blue"), pch="+")
  grid.rect()
  upViewport()

  surr.vp <- viewport(xscale=xscale, yscale=yscale, height=0.6, clip=F)
  pushViewport(surr.vp)
  grid.yaxis(name="y")
  grid.xaxis(name="x")
  upViewport()

  upViewport()
}

plot.multipanel <- function(ylim=NULL){
  if(is.null(ylim))
    ylim <- replicate(4, extendrange(yy), simplify=FALSE) else
  ylim <- rep(ylim, length=4)

  pushViewport(viewport(layout=grid.layout(4, 1), width=0.8, height=0.8))
  grid.panel(1, yscale=ylim[[1]])
  grid.panel(2, yscale=ylim[[2]])
  grid.panel(3, yscale=ylim[[3]])
  grid.panel(4, yscale=ylim[[4]])
  upViewport()

}

# set all scales to [0, 1]
grid.newpage()
plot.multipanel(ylim=list(c(0, 1)))

# set every odd/even scale
grid.newpage()
plot.multipanel(ylim=list(range(yy), c(0, 1)))

# set every scale
grid.newpage()
plot.multipanel(ylim=list(extendrange(yy), c(-Inf, Inf), c(0, 1), c(0, Inf)))


All the best,

baptiste

Re: Setting x/y lim in facet_grid Hadley Wickham 1/3/10 1:28 PM
Hi Baptiste,

I don't find that syntax at all appealing because it loses the
connection between the data and panels - the panels are not just a
meaningless list but have variables associated with them.

Hadley

--
http://had.co.nz/

Re: Setting x/y lim in facet_grid baptiste auguie 1/4/10 1:31 AM
Hi,

True, a list isn't very meaningful but it's the most straight-forward
way I could think of. If I follow you it would be better to provide a
data.frame with the same structure as the plot. To this aim, it would
be nice to have a way to extract a minimal data set from a ggplot2
object that reproduces the plot structure (with flattened layers).
Say, I have the following plot,

p = qplot(mpg, wt, data=mtcars) +
facet_grid(cyl ~ vs)  # + maybe other layers with different data

I would call,

s = extractStructure(p)

and get a result like,

s = subset(mtcars, select = c("mpg","wt","cyl","vs"))
s = s[ !duplicated(subset(s, select=c("cyl","vs"))) , ]

s[, c("mpg","wt") ] <- NA
# maybe these variables are not needed at all
# or perhaps they should be replaced with their range in each panel

str(s)
'data.frame':        5 obs. of  4 variables:
 $ mpg: logi  NA NA NA NA NA
 $ wt : logi  NA NA NA NA NA
 $ cyl: num  6 4 6 8 4
 $ vs : num  0 1 1 0 0

From this minimal data.frame the user can identify each combination of
factors that is present in the plot and override the default scales,

s$default.y.scale <- list(c(-Inf, Inf))
s$default.x.scale <- list(c(-Inf, Inf))

s$default.x.scale[with(s, cyl == 6 & vs == 0)] <- list(c(0, Inf))

(of course the syntax should be made easier)

                  mpg wt cyl vs default.y.scale default.x.scale
Mazda RX4          NA NA   6  0       -Inf, Inf          0, Inf
Datsun 710         NA NA   4  1       -Inf, Inf       -Inf, Inf
Hornet 4 Drive     NA NA   6  1       -Inf, Inf       -Inf, Inf
Hornet Sportabout  NA NA   8  0       -Inf, Inf       -Inf, Inf
Porsche 914-2      NA NA   4  0       -Inf, Inf       -Inf, Inf

At this point it is similar in spirit to the recent expand_range()
function, in fact one could imagine that several parameters could be
adjusted this way:

- limits
- axis breaks and axis labels
- panel and inter-panel sizes
- strip labels
- ... (maybe one day panel.background color, other crazy things)


Best,

baptiste


On Sun, Jan 3, 2010 at 10:28 PM, hadley wickham <h.wi...@gmail.com> wrote:
> Hi Baptiste,
>
> I don't find that syntax at all appealing because it loses the
> connection between the data and panels - the panels are not just a
> meaningless list but have variables associated with them.
>
> Hadley
>

Re: Setting x/y lim in facet_grid Hadley Wickham 1/4/10 7:40 AM
Hmmmm.  I think we're getting closer - thanks providing suggestions
that I keep objecting too - it really helps me think about the
problem!

I think development version of ggplot2, the facetting system now
creates a data frame that looks something like this:

  PANEL ROW COL SCALE_X SCALE_Y vs cyl
1     1   1   1       1       1  0   4
2     2   2   1       1       1  1   4
3     3   1   2       1       2  0   6
4     4   2   2       1       2  1   6
5     5   1   3       1       3  0   8
6     6   2   3       1       3  1   8

(from qplot(mpg, wt, data = mtcars) + facet_grid(vs ~ cyl, scales="free_y"))

this describes the relationship between the data and the panels, as
well as describing the constraints imposed on the scales (I think this
is the info you'd want from extractStructure - the complication is
that it's only generated just prior to plotting).  Any way of manually
specifying breaks and limits needs to keep these constraints in mind
by either telling the user what they're doing is impossible and
raising an error (you can't set different x limits in this case),
updating the scale specification (to force differences even though) or
automatically combining in some way.

I think specification of varying scale parameters must come in through
the facetter, because this is what coordinates the data, scales,
coordinate system and panelling specification to produce the final
plot.  I like the idea of using a data frame, but it makes it hard to
pass in vector valued variables, because you have to jump through
hoops to get them into a data frame.  I'm currently working on an
alternative to the data frame, the data list, which makes this easier,
but it's not ready yet and I'm not sure whether having yet another
function to learn is a good idea.

I could add scale.x.limits, scale.y.limits, scale.x.breaks,
scale.y.breaks, scale.x.labels, scale.y.labels as arguments to the
facetters.  This would be easy to do, but I don't like the explosion
of arguments, and it's not very maintainable if I add more parameters
to the scales.  I think scale_params = list(x = list(), y = list())
would be more maintainable, but I don't like breaking the connection
between the parameters and the data.

Hadley

PS.  Making it possible to change the background colour of individual
panels becomes fairly easy in this paradigm I just do something along
the lines of:

background <- rep(theme$panel.background, length = max(panels$PANEL)
background[panels$PANEL]

--
http://had.co.nz/

Re: Setting x/y lim in facet_grid baptiste auguie 1/5/10 4:01 AM
That sounds good! I'm not sure what you mean by "data list", is it
simply a list or a new class altogether?

Best,

baptiste

Re: Setting x/y lim in facet_grid Hadley Wickham 1/5/10 5:14 AM
It's a list with the constraint that all elements must have the same
"length" (i.e. length(x) = n or nrow(x) = n).  It's like a data frame
but without all the auto-coercions, and so is a bit faster, and is
also easier to use with m*ply.

Hadley

--
http://had.co.nz/

Re: Setting x/y lim in facet_grid ignacio 9/30/14 12:36 PM
Hi,

is this capability implemented?

Thanks,

Ignacio

On Wednesday, June 12, 2013 5:16:12 PM UTC-4, Malcolm Cook wrote:
Hi,

Am I correct that this capability has not been implemented?   That is what I understand from my reading of the docs (http://docs.ggplot2.org/current/facet_grid.html)

If it has not, are there any 'clever' workarounds/hacks?

Thanks,

Malcolm