Specify xlim and ylim for each facet separately #187

Closed
kohske opened this Issue May 23, 2011 · 19 comments

Comments

Projects
None yet
Collaborator

kohske commented May 23, 2011

Maybe it is fine if xlim and ylim can be specified for each facet separately, at least, for facet_wrap.
Now, panel contains the information about ranges of each facet, so e.g.,

# lims like this:
  vs am xmin xmax ymin ymax
1  0  0    8    8 10.4 19.2
2  0  1    4    8 15.0 26.0
3  1  0    4    6 17.8 24.4
4  1  1    4    4 21.4 33.9

and specify by, e.g.,

+ facet_wrap(~vs+am, limits = lims)
Owner

hadley commented May 23, 2011

Yes, I like this idea, and I like that basic syntax. But how do limit and free scales interact? And what happens if you specify facet_wrap(~ vs, limits = lims).

Another related idea that I've been thinking about is giving layers the ability not to affect scale limits - this is useful when you are plotting spatial data and want to add a map on top. You don't want the map to affect the limits, because it may be much bigger than you data, and using coord to zoom in is a hassle. If that idea was implemented, modifying scales on a facet-by-facet basis would amount to using train_position = F for all layers, apart from a geom_blank which specified the dummy data to expand the scales as needed - which expand_limits already does.

Implementing scale limits in that way would also mean the behaviour of free scales etc could remain as is.

Collaborator

kohske commented May 23, 2011

Hi

Actually I meant the limits for coord, but yes, the limits for scale
also should be like that.

In the case of coord, probably we have nothing to worry about.
Just passing lims data drame to coord_* is sufficient, and there
is no problem about the interaction of free scale and limits.
I will try to implement it.

As for the limits for scales, as you say, things may be somewhat complicated.

But how do limit and free scales interact?

I think manual limits should have top-priority.

And what happens if you specify facet_wrap(~ vs, limits = lims).

Just an error, since the limits are indeterminable.
Or, with warning, use the first apparence of vs.

Another related idea that I've been thinking about is giving layers the ability not to affect scale limits - this is useful when you are plotting spatial data and want to add a map on top.  You don't want the map to affect the limits, because it may be much bigger than you data, and using coord to zoom in is a hassle.  If that idea was implemented, modifying scales on a facet-by-facet basis would amount to using train_position = F for all layers, apart from a geom_blank which specified the dummy data to expand the scales as needed - which expand_limits already does.

Totally the idea sounds good, although I'm not sure if explicit
null-geom is necessary.

Kohske Takahashi takahashi.kohske@gmail.com

Research Center for Advanced Science and Technology,
The University of  Tokyo, Japan.
http://www.fennel.rcast.u-tokyo.ac.jp/profilee_ktakahashi.html

On Mon, May 23, 2011 at 10:06 PM, hadley
reply@reply.github.com
wrote:

Yes, I like this idea, and I like that basic syntax.  But how do limit and free scales interact?  And what happens if you specify facet_wrap(~ vs, limits = lims).

Another related idea that I've been thinking about is giving layers the ability not to affect scale limits - this is useful when you are plotting spatial data and want to add a map on top.  You don't want the map to affect the limits, because it may be much bigger than you data, and using coord to zoom in is a hassle.  If that idea was implemented, modifying scales on a facet-by-facet basis would amount to using train_position = F for all layers, apart from a geom_blank which specified the dummy data to expand the scales as needed - which expand_limits already does.

Reply to this email directly or view it on GitHub:
hadley#187 (comment)

Collaborator

kohske commented May 23, 2011

Here is a testbed of manual limits for coord with facet_wrap.

kohske/ggplot2@bd71581

Owner

hadley commented May 24, 2011

Hmmmm, that code just looks too complicated to me. It's a lot of extra complexity for not a lot of extra gain. I think giving layers the ability to control whether or not they affect position scaling is simpler to implement, more elegant (in terms of playing nicely with existing code for free limits) and allows a number of other interesting techniques that were previously not possibly.

Collaborator

kohske commented May 24, 2011

Hmmmm, that code just looks too complicated to me.  It's a lot of extra complexity for not a lot of extra gain.  I think giving layers the ability to control whether or not they affect position scaling is simpler to implement, more elegant (in terms of playing nicely with existing code for free limits) and allows a number of other interesting techniques that were previously not possibly.

Yes, exactly, yes. It may be too complicated and hard to understand.
Probably the layers will do that, but thus far I could not entirely
figure out the power of the layers.
So, I will look into the code and consider a implementation.

thanks,

kohske

Contributor

baptiste commented May 24, 2011

I would like to add another, related request. Different panels with different limits may also require fine-tuning of the breaks on a per-panel basis (I do need this, often). Currently the only way I could achieve this was to mask grid.pretty() and play some ugly tricks to have it return different breaks for different data ranges.
It sure would be nice to be able to specify manual breaks for each facet, in those few special occasions. I don't expect there will ever be a properly grammatical syntax for this, though. Failing this, perhaps it should simply be part of opts()? I could imagine a new opts() for a ggplot being similar to the way lattice handles these cosmetic details,

  • specify the panel ordering
  • specify the panel widths, and interpanel spacings (allowing visual groupings, e.g. 2 by 2)
  • specify a list of panel limits, with optional recycling
  • specify the panel x and y breaks
    (- perhaps even more options, such as per-panel background colour, ...)
Owner

hadley commented May 25, 2011

That's actually possible in the devel version - you can take the output of ggplot_build and modify the per-panel labels there. I'm not sure if I want to commit to a formal API yet.

ggplot2 will never handle these details like lattice does, because I really dislike how that works - you should be describing things in terms of the underlying data, not by some arbitrary panel number.

Contributor

baptiste commented May 25, 2011

It should be possible to specify all these details in terms of the facetting variables as opposed to the panel number; admittedly the syntax becomes more cumbersome. There may be a way to define a new data structure between data.frame and list to handle these options. Below is an illustration of what I have in mind, storing the values in a long format matrix.

my.panel.details <- function(){

two facetting variables

row.var <- rep(letters[1:2], 2)
col.var <- rep(LETTERS[1:2], each=2)

corresponding specifications

cbind(row.var=row.var, col.var=col.var,
limits = c(list(c(0, 10)), # per panel limits
list(c(0, Inf)), # Inf means 'use the defaults from the data'
list(c(-Inf, Inf)),
list(c(-Inf, Inf))),
breaks = c(list(seq(0,10)),
list(seq(-10,10,by=5)),
list(seq(-10,10,by=2)),
list(seq(-10,10,by=1))),
vspacing = c(5, 5), # vertical spacing between the panels, repeated by technical necessity
hspacing = c(0, 0), # horizontal spacing between the panels
width = c(1, 2), # using null units?
height = c(1, 1), # using null units?
background.color = c("grey95"))

}

my.panel.details()

opts(panel.details = my.panel.details())

jonsedar commented Mar 1, 2013

It's two years on, but I'd really like to be able to specify ylims for each facet as described above. Any chance of getting this included?

Contributor

joey711 commented Apr 25, 2013

I second that last comment by @jonsedar. Any news on this?

gitspade commented May 7, 2013

+1

marrcl commented May 21, 2013

+1

A possible way to implement this feature is to add a attribute to layers on how they affect scale limits.
This attribute could have three values

  • Normal: The layer have the same behavior as in the current implementation of ggplot2
  • Ignore: The layer is ignored when computing the scale limits, as already proposed by @hadley above
  • Force: The layer force the scale limits based on his own data and the data on the other layers are not considered to compute the scales limits

Then we can easily set the scale limits by creating a layer, say geom_rect with the desired size. We can then control the visibility of the layer either by the aesthetic alpha, or a new attribute on layer controlling visibility. if we want to affect only on direction, say x, we can set the dimension of the geom to Inf and -Inf in this direction.

This is not a direct implementation of the feature requested, but it will do the job with a minimum of hacks. It will also enable the possibility of ignoring some layer. This is useful for maps as mentioned by @hadley but also, for example, to plot the prediction of a model together with data while only keeping the focus on the data.

Owner

hadley commented Feb 24, 2014

This sounds like a great feature, but unfortunately we don't currently have the development bandwidth to support it. If you'd like to submit a pull request that implements this feature, please follow the instructions in the development vignette.

@hadley hadley closed this Feb 24, 2014

pengchy commented May 8, 2015

I think the simple way is to modify the original data, remove the unwanted values

bshor commented May 21, 2015

+1

"I think the simple way is to modify the original data, remove the unwanted values". This doesn't work in many cases, such as the example Hadley mentioned earlier WRT maps. Sometimes you need the data to spool beyond the plot region (but be concealed/masked by the act of applying the limits), since by removing values, this may close and/or truncate paths and create ugly (and inaccurate) rendering of the data.

Frankly I think there should be a 'limiter' function (or rather the 'scales' argument to facet_wrap and/or facet_grid is able to accept a function), which is similar to the 'labeller' function. This limiter function could return 'fixed', 'free_x', 'free_y', 'free', or alternately return a list containing xlim, and ylim values for each facet given the input x and y indexes of the facet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment