Double x axis (analog to doubleYScale) with lattice extra or similar

泄露秘密 提交于 2020-01-23 09:29:38

问题


I want to make specific figures that we need in oceanography. Unfortunately double, triple or more axes are not very good implemented in R. I don't need a double y axis as in doubleYScale of lattice extra. I need double or triple x axis. I could not find a way to use doubleYScale to my advantage. Maybe that's possible. Help would be appreciated a lot.

This is what I have 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 differently spaced.

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()

What I need is exactly like that except that the pink data (fluo) needs it's own axis. The bar chart has to be like this but in fact I would like to have the y axis reversed so that 0 is at the top. The actual data has also more stations, so it would be like 8 panels of data.

Looking forward to see what can be done with this! Thanks a lot!


EDIT: Added example. See here:

PS. I am not saying that I want something looking like that-.- or with too many axes. But two x would be nice -.-


回答1:


As far as I know, there's no prepackaged solution to the more general question here.

The example below presents a couple of approaches to adding an additional axis. The second and more general approach (which I'd be inclined to use even when adding an axis along the plot's boundary) works by first pushing a viewport and then adding an axis along its edge. By pushing a viewport an inch high (for example) it allows you to produce an axis that floats an inch above the plot. Pushing a viewport with a supplied xlim= argument also allows you to set its native coordinate system, which allows you to sidestep some otherwise-required coordinate-system conversions.

There's much more in the moderately-commented code below, which I'll let you explore on your own!

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's 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's 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)))


Additional note, mostly for myself:

The code above requires calls to both panel.axis() and grid.xaxis(), which is not really ideal. The only reason we need to call grid.xaxis() (and, for that matter, to define the function prettyBetween()) is that panel.axis() draws ticks and labels but not the axis baseline. If panel.axis() had an option to do so, things here would be a lot simpler. To see what that would be like, run trace() to append a bit of extra baseline-drawing code to each panel.axis() call...

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 panel axis (with side=="top") will plot the baseline we'd like.



来源:https://stackoverflow.com/questions/33578103/double-x-axis-analog-to-doubleyscale-with-lattice-extra-or-similar

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!