Thanks to the lattice gurus on this list, and having reference to the excellent open-access Sarkar 2008 ISBN 978-0-387-75968-5 e-ISBN 978-0-387-75969-2 http://dx.doi.org/10.1007/978-0-387-75969-2 I now know how to label lattice panels by variable value: see thread starting @ https://stat.ethz.ch/pipermail/r-help/2012-November/329450.html (and demonstrated below). This allows me to use lattice::levelplot() to display atmospheric data (gas concentrations) over a 3D space with dimensions longitude, latitude, and (vertical) level ... but I would like to fix a few things. Hopefully the following is a sufficiently "small, self-contained example" (though it has 2 side questions injected--answers to those are appreciated also): # start example library(reshape2) library(lattice) lon=11 lat=7 lev=5 len=lon*lat*lev array.3d <- array(data=c(1:len), dim=c(lat, lon, lev)) # Rewrite the array values "more spatially," i.e., row-wise from # bottom left. If there's a more-R-ish way to fill this array # as specified, please let me know: I know 'for' loops are deprecated # in R. i=1 for (z in 1:lev) { for (x in lat:1) { for (y in 1:lon) { array.3d[x,y,z]=i ; i=i+1 } } } # produces (with rows=latitudes and cols=longitudes) array.3d[,,1] array.3d[,,lev] # convert data=array.3d to dataframe with reshape2::melt array.3d.df <- melt(array.3d, varnames=c("lat","lon","lev"), value.name="conc") head(array.3d.df) tail(array.3d.df) # make level values {longer, "more realistic"} array.3d.df$lev <- array.3d.df$lev + 0.12345 head(array.3d.df) tail(array.3d.df) # plot "appropriately" for atmospheric data where lev=pressure: use # * lattice::levelplot # * one column, since atmospheric levels stack vertically # * rev(lev), since layers closer to ground level have higher pressure levelplot( conc ~ lon * lat | rev(lev), data=array.3d.df, layout=c(1,lev), # show levels stacked in 1 vertical column strip=FALSE, # this suppresses printing strips atop packets strip.left=strip.custom( strip.levels=TRUE, # print level values strip.names=FALSE # don't print name of level variable="rev(lev)" ) ) # end example Note that the (colored) 'strip' for each panel in the lattice has - the corresponding layer value printed inside curly brackets, e.g., '{1.12345}' - the layer value printed in full - the layer value rotated 90? CCW (like the y-axis label) I would prefer to have + the layer value *not* printed inside curly brackets + the layer value *not* rotated 90? CCW (i.e., to print the layer value like the x-axis label) + the layer value truncated or rounded to some significant digits, e.g., '1.1' I suspect this can be done with strip.custom, but am not seeing how; please enlighten! Your assistance is appreciated, Tom Roche <Tom_Roche at pobox.com>
On Nov 18, 2012, at 12:42 PM, Tom Roche wrote:> > Thanks to the lattice gurus on this list, and having reference to the > excellent open-access Sarkar 2008 > > ISBN 978-0-387-75968-5 > e-ISBN 978-0-387-75969-2 > http://dx.doi.org/10.1007/978-0-387-75969-2 > > I now know how to label lattice panels by variable value: see thread > starting @ > > https://stat.ethz.ch/pipermail/r-help/2012-November/329450.html > > (and demonstrated below). This allows me to use lattice::levelplot() > to > display atmospheric data (gas concentrations) over a 3D space with > dimensions longitude, latitude, and (vertical) level ... but I would > like to fix a few things. Hopefully the following is a sufficiently > "small, self-contained example" (though it has 2 side questions > injected--answers to those are appreciated also): > > # start example > library(reshape2) > library(lattice) > > lon=11 > lat=7 > lev=5 > len=lon*lat*lev > array.3d <- array(data=c(1:len), dim=c(lat, lon, lev)) > > # Rewrite the array values "more spatially," i.e., row-wise from > # bottom left. If there's a more-R-ish way to fill this array > # as specified, please let me know: I know 'for' loops are deprecated > # in R. > > i=1 > for (z in 1:lev) { > for (x in lat:1) { > for (y in 1:lon) { > array.3d[x,y,z]=i ; i=i+1 > } > } > } > > # produces (with rows=latitudes and cols=longitudes) > array.3d[,,1] > array.3d[,,lev] > > # convert data=array.3d to dataframe with reshape2::melt > array.3d.df <- melt(array.3d, varnames=c("lat","lon","lev"), > value.name="conc") > head(array.3d.df) > tail(array.3d.df) > > # make level values {longer, "more realistic"} > > array.3d.df$lev <- array.3d.df$lev + 0.12345 > head(array.3d.df) > tail(array.3d.df) > > # plot "appropriately" for atmospheric data where lev=pressure: use > # * lattice::levelplot > # * one column, since atmospheric levels stack vertically > # * rev(lev), since layers closer to ground level have higher pressure > levelplot( > conc ~ lon * lat | rev(lev), data=array.3d.df, > layout=c(1,lev), # show levels stacked in 1 vertical column > strip=FALSE, # this suppresses printing strips atop packets > strip.left=strip.custom( > strip.levels=TRUE, # print level values > strip.names=FALSE # don't print name of level variable="rev(lev)" > ) > ) > # end example > > Note that the (colored) 'strip' for each panel in the lattice has > > - the corresponding layer value printed inside curly brackets, e.g., > '{1.12345}' > > - the layer value printed in full > > - the layer value rotated 90? CCW (like the y-axis label) > > I would prefer to have > > + the layer value *not* printed inside curly brackets > > + the layer value *not* rotated 90? CCW (i.e., to print the layer > value > like the x-axis label) > > + the layer value truncated or rounded to some significant digits, > e.g., '1.1'levelplot( conc ~ lon * lat | rev(lev), data=array.3d.df, layout=c(1,lev), levs=as.character(round(array.3d.df[['lev']], 1)), strip=FALSE, strip.left=strip.custom( factor.levels=as.character(round(array.3d.df[['lev']], 3)), strip.levels=TRUE, horizontal=TRUE, strip.names=FALSE , par.strip.text=list( cex=0.5) ) )> > I suspect this can be done with strip.custom, but am not seeing how; > please enlighten!Your example does not do a very good job of testing the levels assignments since they are all the same. -- David Winsemius, MD Alameda, CA, USA
https://stat.ethz.ch/pipermail/r-help/2012-November/329479.html>> Hopefully [sufficiently] "small, self-contained example":mailquotes omitted from "start example" to "end example" to ease rerunning the following code: # start example library(reshape2) library(lattice) lon=11 lat=7 lev=5 len=lon*lat*lev array.3d <- array(data=c(1:len), dim=c(lat, lon, lev)) # Rewrite the array values "more spatially," i.e., row-wise from # bottom left. If there's a more-R-ish way to fill this array as # desired, please let me know: I know 'for' loops are deprecated # in R. i=1 for (z in 1:lev) { for (x in lat:1) { for (y in 1:lon) { array.3d[x,y,z]=i ; i=i+1 } } } # produces (with rows=latitudes and cols=longitudes) array.3d[,,1] array.3d[,,lev] # convert data=array.3d to dataframe with reshape2::melt array.3d.df <- melt(array.3d, varnames=c("lat","lon","lev"), value.name="conc") head(array.3d.df) tail(array.3d.df) # make level values {longer, "more realistic"} array.3d.df$lev <- array.3d.df$lev + 0.12345 # truncated below, and ... # ... below note output from these head(array.3d.df) tail(array.3d.df) # plot "appropriately" for atmospheric data where lev=pressure: use # * lattice::levelplot # * one column, since atmospheric levels stack vertically # * rev(lev), since layers closer to ground level have higher pressure levelplot( conc ~ lon * lat | rev(lev), data=array.3d.df, layout=c(1,lev), # show levels stacked in 1 vertical column strip=FALSE, # this suppresses printing strips atop packets strip.left=strip.custom( strip.levels=TRUE, # print level values strip.names=FALSE # don't print name of level variable="rev(lev)" ) ) # end example>> Note that the (colored) 'strip' for each panel in the lattice has>> - the corresponding layer value printed inside curly brackets, e.g., >> '{1.12345}'>> - the layer value printed in full>> - the layer value rotated 90? CCW (like the y-axis label)>> I would prefer to have>> + the layer value *not* printed inside curly brackets>> + the layer value *not* rotated 90? CCW (i.e., to print the layer >> value like the x-axis label)>> + the layer value truncated or rounded to some significant digits, >> e.g., '1.1'https://stat.ethz.ch/pipermail/r-help/2012-November/329505.html> levelplot( > conc ~ lon * lat | rev(lev), data=array.3d.df, > layout=c(1,lev), levs=as.character(round(array.3d.df[['lev']], 1)), > strip=FALSE, > strip.left=strip.custom( > factor.levels=as.character(round(array.3d.df[['lev']], 3)), > strip.levels=TRUE, > horizontal=TRUE, > strip.names=FALSE , > par.strip.text=list( cex=0.5) > ) > )...> Your example does not do a very good job of testing the levels > assignments since they are all the same.Actually, that claim is false, as can be demonstrated in 2 ways: 1. (simple) Note column=lev in output from head(array.3d.df) tail(array.3d.df) The levels are not "all the same." 2. (more complex, but clearly demonstrates a flaw in the suggestion) Shorten the level values, then comment out the 'factor.levels' argument to strip.custom (above), and plot: # shorten level values by 2 digits, for bug demonstration array.3d.df$lev <- array.3d.df$lev - 0.00045 # note different output from these in column=lev head(array.3d.df) tail(array.3d.df) # comment out for debugging levelplot( conc ~ lon * lat | rev(lev), data=array.3d.df, layout=c(1,lev), levs=as.character(round(array.3d.df[['lev']], 1)), strip=FALSE, strip.left=strip.custom( # factor.levels=as.character(round(array.3d.df[['lev']], 3)), strip.levels=TRUE, horizontal=TRUE, strip.names=FALSE , par.strip.text=list(cex=0.5) ) ) Note that, - without the line above commented out, strip values are (correctly) all 1.123 + with the line above commented out, strip values are (correctly) 1.123 .. 5.123 Am I missing something? If not, how to round() or signif() the values obtained from array.3d.df$lev and displayed in the strips? Your assistance is appreciated, Tom Roche <Tom_Roche at pobox.com>