corybrunson / ggalluvial

ggplot2 extension for alluvial plots
http://corybrunson.github.io/ggalluvial/
GNU General Public License v3.0
497 stars 34 forks source link

Inverting x axis in gglauvial #19

Closed DemaLM closed 6 years ago

DemaLM commented 6 years ago

Description of the issue

Hi, I'm trying to produce a ggaluvial plot with the x-axis increasing towards the left.

Ideally I'd like the following picture image

My code to produce a regular alluvial plot is:

Reproducible example (preferably using reprex::reprex())

trait<- rep("C", 4)
organ<- factor (c("ROOT", "STEM", "BRANCH", "LEAF"), levels= c("ROOT", "STEM", "BRANCH", "LEAF" ) )
conc <- runif(4, min=440, max=495)
subj<- rep(1,4)

aluv.org.df <- data.frame(  trait, organ, conc, subj) 

ggplot( aluv.org.df ,
        aes(x = organ, stratum = trait, alluvium = subj,
            weight = conc, fill = trait, label=trait), na.rm=T, colour="grey") +
  geom_flow(aes (colour=trait), alpha = .5,stat = "alluvium", lode.guidance = "rightleft", show.legend = T) +
  geom_stratum(aes( colour=trait), alpha = .5, na.rm=T, show.legend = T) +
   theme_classic(base_size = 36)+
  theme(legend.position = "top", legend.box = "horizontal") +
  coord_flip() +
  ylab ( expression(mg ~"* g"^ -1))+
  xlab ("Position")+
  scale_fill_discrete (name="Trait")+
  scale_colour_discrete (name="Trait")+
  guides(colour = guide_legend(nrow = 1, reverse = TRUE), 
         fill = guide_legend(nrow = 1, reverse = TRUE) ) +
 scale_x_discrete (position ="top")

Thanks!

corybrunson commented 6 years ago

Thanks a lot @DemaLM for raising this issue! The core problem, i think, is that my internal tricks for positioning the geoms (in particular, calculating y, ymin, and ymax in the stat_*() functions) have run afoul of ggplot2 internals that control the axes and their labels. Here's a minimal reproduction of the problem using your dataset (note the incorrect negative values on the vertical axis):

ggplot(aluv.org.df,
       aes(x = organ, stratum = trait, alluvium = subj)) +
  geom_stratum() +
  scale_y_reverse()

I'll get to work figuring this out and fixing it ASAP.

corybrunson commented 6 years ago

The problem here seems to arise from the following things:

Therefore, during the plot-building process, scale_y_continuous() has no effect on the data, which at the moment of encounter has fields named by the aesthetics fed directly to ggplot(), in this case x, stratum, and alluvium.

I imagine this could be resolved in one of the following ways:

  1. Rewrite the stat_*() functions to take a y aesthetic instead of stratum.
  2. Write a function scale_alluvium_discrete() to handle transformations of the stratum axis.
  3. Add a logical reverse.alluvium.axis parameter to the stat_*() functions that must be called consistently and in tandem with scale_y_reverse().

Option 3 would be too cumbersome, i think. I'm giving option 2 a try. Option 1 would require quite an overhaul and i don't want to start down that route until i've exhausted at least option 2. I'll update this issue as it develops. : )

Update: Option 2 is probably infeasible because only a discrete scale can be used to transform the stratum variable. Update 2: Option 1 may also be infeasible, for the same reason, since the variable passed to y is discrete. Option 3 might actually be simple (without the need for an additional parameter), since the scale transformations can be accessed from within the layers. So that'll be my next attempt.

DemaLM commented 6 years ago

Hi corybrunson, sounds great, thanks!

corybrunson commented 6 years ago

This was a valuable issue to raise, since it exposed problems with the dissimilarity between the geoms of this package and geom_bar(), which have troubled me off-and-on for a while.

This issue is being addressed in the experimental branch weight-y. @DemaLM please see if the new functionality suits you! You can install the experimental version using the devtools package:

devtools::install_github("corybrunson/ggalluvial", ref = "weight-y")

The basic idea is to replace the weight aesthetic parameter with y, so that it will be recognized by scale_y_continuous(). As with weight, y will not be required, and weight will be preserved but deprecated. An example using scale_y_reverse() is provided in the documentation for geom_alluvium().

The major limitation is that the y aesthetic must be assigned a column of data in order for scale_y_continuous() to correctly transform the scale. So, if every observation is assumed to have unit weight, the user might leave out y = weight_column and wonder why scale_y_reverse() doesn't work. I wasn't able to resolve this by, e.g., adding y = 1 to default_aes in the definitions of the Geom*s.

The *_*_form() functions for testing and converting alluvial data will continue to use a weight parameter, but the default character string used in output will be replaced with "y".

DemaLM commented 6 years ago

Hi @corybrunson,

this suits me very well, indeed!!! Many thanks for this great help! Cheers

corybrunson commented 6 years ago

Excellent! I'll release this as v0.8.0 (and close this issue) once i've done a couple more checks.