Dual x-axis (analog to dual scale) with optional grating or similar

I want to make specific numbers that we need in oceanography. Unfortunately, double, triple, or more axes are not very well implemented in R. I don't need a double y-axis like I do in the double scale of the extra lattice. I need a double or triple x axis. I couldn't find a way to use doubleYScale to my advantage. Perhaps it is possible. Help would be greatly appreciated.

Here's what I've now based on the data:

stackoverflow_fluo.csv: http://pastebin.com/embed_js.php?i=7KNEiytF

animals_stackoverflow.csv: http://pastebin.com/embed_js.php?i=CnEJaq6b

Important update: I forgot to mention that the depth values ​​on the Y-axis of both datasets are different.

library(latticeExtra)
#dataset 1

    data1011 <- file.path('stackoverflow_fluo.csv')
    jdatax1 = read.csv(data1011)
    jdatax1$stat<-as.factor(jdatax1$Station)

    #dataset2

    data1012 <- file.path('animals_stackoverflow.csv')
    jdatax2 = read.csv(data1012)
    jdatax2$stat<-as.factor(jdatax2$stat)

    #attempt multi axes

    animals<-barchart( depth_good ~Mass | stat, data = jdatax2)
    fluo<-xyplot( depth~chl | stat, data = jdatax1, type = "l")
    doubleYScale(animals, fluo)

    #plot
    jpeg("double_y", width = 11, height = 8.5, units = 'in', res = 300)
    doubleYScale(animals, fluo)
    dev.off()

      

enter image description here

What I need is exactly the same except the pink data (fluo) needs its own axis. The histogram should look like this, but I would really like the y-axis to be reversed so that 0 is at the top. The actual data also contains more stations, so it will look like 8 data bars.

We look forward to seeing what you can do about it! Many thanks!


EDIT: Added example. See here:

enter image description here PS. I'm not saying I want something like this. Or too many axes. But two x would be nice -.-

+2


source to share


1 answer


As far as I know, there is no prepackaged solution to a more general issue.

The example below provides several approaches to adding an additional axis. The second and more general approach (which I would like to use even when adding an axis along the border of the graph) works by first clicking the viewport and then adding an axis along its edge. By clicking on the screen in inches high (for example), you can create an axis that floats an inch above the graph. Clicking the viewport with the supplied argument xlim=

also allows you to set your own coordinate system, which allows you to bypass some of the otherwise required coordinate transformations.

There is much more in the code below below, and I'll tell you about it myself.

library(lattice)
library(grid)

## Functions for converting units between axes
year2salinity <- function(year) {33 + (1/30)*(year-1900)}
salinity2year <- function(salinity) 1900 + 30*(salinity-33)
year2copepod <- function(year) {1000 + 100*(year-1900)}

## A better pretty(). (base::pretty() will often return limits that
## run beyond plot ends.)
prettyBetween <- function(x,...) {
    xx <- pretty(x,...)
    xx[xx >= min(x) & xx <= max(x)]
}

## Custom axis-drawing function to be invoked via xyplot(..., axis=customAxis)
customAxis <- function(side, ...) {
    if (side == "top") {
        xlim <- current.panel.limits()$xlim
        ## Method #1 (Only works for axis along side of plot)
        atSalinity <- prettyBetween(year2salinity(xlim))
        panel.axis(side = side, outside = TRUE, at=salinity2year(atSalinity),
                   labels = as.character(atSalinity),
                   rot=0)
        grid.text("Salinity", gp=gpar(cex=0.9),
                  y=unit(1, "npc") + unit(2.5, "lines"))
        ## Method #2 (Works for "floating" axis or -- with viewport height=0 --
        ##            for axis along side of plot.)
        atCopepod <- prettyBetween(year2copepod(xlim))
        pushViewport(viewport(height = unit(4, "lines"),
                              y = 1, just = "bottom",
                              xscale = year2copepod(xlim)))
        panel.axis(side = side, outside = TRUE, at=atCopepod,
                   labels = as.character(atCopepod),
                   line.col = "grey65", text.col = "grey35", rot=0)
        ## panel.axis doesn't draw the axis' "baseline", so we do it using grid.axis  
        grid.xaxis(at = atCopepod, label = FALSE,
                   main = FALSE, gp = gpar(col="grey65"))
        grid.text(expression("Copepods m"^{-3}), gp=gpar(cex=0.9, col="grey35"),
                  y=unit(1, "npc") + unit(2.5, "lines"))
        popViewport()
    }
    else {
        axis.default(side = side, ...)
    }
}

xyplot(nhtemp ~ time(nhtemp), aspect = "xy", type = "o",
       xlab = "Year", ylab = "Temperature",
       axis = customAxis,
       main = "Yearly temperature, salinity, and copepod abundance",
       scales = list(x=list(alternating=3)),
       ## Set up key.axis.padding (an element of each lattice plot layout) to
       ## understand values in terms of lines...
       lattice.options=list(layout.heights=list(key.axis.padding=list(x=1,units="lines"))),
       ## ... so that you can tell it you need 6 "lines" of space for axes
       par.settings = list(layout.heights=list(key.axis.padding=6)))

      

enter image description here




Additional note, mainly for me:

In the above code is required as the challenges panel.axis()

, and grid.xaxis()

that is not really ideal. The only reason we need to call grid.xaxis()

(and, for that matter, define a function prettyBetween()

) is to panel.axis()

draw ticks and labels, but not the baseline of the axis. If I panel.axis()

had the opportunity to do this, everything would be much easier. To see what this would look like, run trace()

to add some extra baseline code for each call panel.axis()

...

trace(panel.axis,
      exit=expression(
      grid.lines(x = unit(at[c(1,length(at))], "native"),
                    y = unit(c(1,1), "npc"),
                    gp = gp.line)))

      

.... after which calls to the pane axis (with side=="top"

) will display the baseline we would like.

+2


source







All Articles