Spencer Graves
2023-May-31 15:45 UTC
[R] plot level, velocity, acceleration with one x axis
On 5/31/23 9:20 AM, Eric Berger wrote:> I sent you an updated response to deal with the redundant copies of the x-axis. > Re-sending. >par(mfrow=c(3,1)) plot(DAX.[, 1], log='y', ylab='DAX', xaxt="n") plot(DAX.[, 2], ylab='vel (%)', xaxt="n") plot(DAX.[, 3], ylab='accel (%)') I got that. The primary problem with that is that most of the vertical space is reserved for axis labels, whether they are printed or not. If I squeeze the vertical dimension of the plot, I get, "figure margins too large". To control that, I need to set "mar" separately for each panel, and then the plot regions for each are not the same size. Using the "layout" function instead of "mfrow" is better, but I don't see now to make that work consistently without fixing the aspect ratio. There may be a way in the tidyverse, but I haven't found it yet. The only solution I've found so far that makes sense to me is to modify the code for plot.ts to accept a vector for the log argument, with the constraint that length(lot) = either 1 or ncol(x) and returning invisibly an object that would make it feasible for a user to call axis(2, ...) once for each vertical axis to handle cases where someone wanted to a vertical scale different from linear and log. I'd want to make sure that lines.ts also works with this, because I want to add fits and predictions. Comments? Thanks, Spencer Graves ** With either of the following plots, if I adjust the aspect ratio by enlarging or reducing the vertical dimension of the plot, the relative sizes of the plot regions change. DAX <- EuStockMarkets[, 'DAX'] DAX. <- cbind(DAX, diff(log(DAX)), diff(diff(log(DAX)))) colnames(DAX.) <- c("DAX", 'vel (%)', 'accel (%)') head(DAX.) plot(DAX., log='xy') op <- par(mfrow=c(3,1), mar=c(0, 4.1, 4.1, 2.1)) plot(DAX.[, 1], log='y', ylab='DAX', axes=FALSE) axis(2) box(col='grey') par(mar=c(0, 4.1, 0, 2.1)) plot(DAX.[, 2], ylab='vel (%)', axes=FALSE) axis(2) box(col='grey') par(mar=c(5.1, 4.1, 0, 2.1)) plot(DAX.[, 3], ylab='accel (%)', axes=FALSE) axis(2) box(col='grey') axis(1) par(op) > sessionInfo() R version 4.3.0 (2023-04-21) Platform: x86_64-apple-darwin20 (64-bit) Running under: macOS Big Sur 11.7.7 Matrix products: default BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib LAPACK: /Library/Frameworks/R.framework/Versions/4.3-x86_64/Resources/lib/libRlapack.dylib; LAPACK version 3.11.0 locale: [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 time zone: America/Chicago tzcode source: internal attached base packages: [1] stats graphics grDevices utils datasets methods base loaded via a namespace (and not attached): [1] compiler_4.3.0 tools_4.3.0 rstudioapi_0.14> > > On Wed, May 31, 2023 at 4:27?PM Spencer Graves > <spencer.graves at effectivedefense.org> wrote: >> >> >> >> On 5/30/23 10:23 AM, Eric Berger wrote: >>> What if you just precede these commands as follows: >>> >>> par(mfrow=c(3,1)) >>> plot(DAX.[, 1], log='y', ylab='DAX') >>> plot(DAX.[, 2], ylab='vel (%)') >>> plot(DAX.[, 3], ylab='accel (%)') >> >> Most of the space is consumed with two extraneous copies of the axis. >> We can get around that with three calls to par: >> >> >> op <- par(mfrow=c(3,1), mar=c(0, 4.1, 4.1, 2.1)) >> plot(DAX.[, 1], log='y', ylab='DAX') >> par(mar=c(0, 4.1, 0, 2.1)) >> plot(DAX.[, 2], ylab='vel (%)') >> par(mar=c(5.1, 4.1, 0, 2.1)) >> plot(DAX.[, 3], ylab='accel (%)') >> par(op) >> >> >> However, the three panels are NOT equal in size: roughly 30% vs. 44% >> vs. 26%. I can get closer using layout, but if I change the aspect >> ratio, it changes the relationship between the heights of the three >> panels. >> >> >> That's the problem I'm trying to solve. It's also why it makes sense >> to me to modify plot.ts to accept a vector for the log argument, with >> the constraint that length(lot) = either 1 or ncol(x). >> >> >> There may be a way to do it using gglot2 / the tidyverse, but I'm not >> facile with that, and my web searches have so far failed to produce >> anything better than modifying plot.ts.R (and then submitting such with >> compatible changes to plot.ts.Rd), as I suggested earlier. >> >> >> ??? >> Thanks, >> Spencer >> >>> >>> On Tue, May 30, 2023 at 5:45?PM Spencer Graves >>> <spencer.graves at effectivedefense.org> wrote: >>>> >>>> >>>> >>>> On 5/30/23 8:48 AM, Eric Berger wrote: >>>>> I am a bit confused as to what you are trying to achieve - and even >>>>> if I could guess it is not clear what the interpretation would be. >>>>>> head(DAX) >>>>> 1628.75 1613.63 1606.51 1621.04 1618.16 1610.61 >>>>> >>>>> Including the leading NA's, what would be the 6 leading terms of the 3 >>>>> series that you want to plot, >>>>> and what would be the Y labels that you want to appear at those levels >>>>> (assuming that there was a >>>>> Y label for each of them - just to understand the units you are talking about) >>>> >>>> >>>> DAX <- EuStockMarkets[, 'DAX'] >>>> DAX. <- cbind(DAX, diff(log(DAX)), diff(diff(log(DAX)))) >>>> colnames(DAX.) <- c("DAX", 'vel (%)', 'accel (%)') >>>> head(DAX.) >>>> >>>> >>>> DAX exhibits growth that is roughly exponential, so I want to plot it >>>> on a log scale: >>>> >>>> >>>> plot(DAX.[, 1], log='y', ylab='DAX') >>>> plot(DAX.[, 2], ylab='vel (%)') >>>> plot(DAX.[, 3], ylab='accel (%)') >>>> >>>> >>>> This is what I want as three panels of a single plot. >>>> >>>> >>>> I think I could get it by modifying the code for plot.ts so it >>>> accepted ylab as a vector, etc., as I previously mentioned. >>>> >>>> >>>> What do you think? >>>> Thanks, >>>> Spencer Graves >>>>> >>>>> >>>>> On Tue, May 30, 2023 at 4:06?PM Spencer Graves >>>>> <spencer.graves at effectivedefense.org> wrote: >>>>>> >>>>>> >>>>>> >>>>>> On 5/30/23 6:16 AM, Eric Berger wrote: >>>>>>> My code assumes that DAX is a ts object, as in your original post. >>>>>>> >>>>>>> On Tue, May 30, 2023 at 2:06?PM Eric Berger <ericjberger at gmail.com> wrote: >>>>>>>> >>>>>>>> Untested but why not >>>>>>>> >>>>>>>> a <- cbind(log(DAX), exp(diff(log(DAX))), exp(diff(diff(log(DAX))))) >>>>>>>> colnames(a) <- c("logDAX", "vel", "accel") >>>>>>>> plot(a) >>>>>> >>>>>> >>>>>> Progress, but we're not there yet. >>>>>> >>>>>> >>>>>> a <- cbind(DAX, exp(diff(log(DAX))), exp(diff(diff(log(DAX))))) >>>>>> colnames(a) <- c("logDAX", "vel", "accel") >>>>>> plot(a) >>>>>> plot(a, axes=FALSE, log='y') >>>>>> axis(1) >>>>>> axis(2) >>>>>> >>>>>> >>>>>> How do I get each y axis labeled in its original units? I can use >>>>>> pretty to get where I want tick marks, but I don't know where to place >>>>>> them "at" in calling axis(2, at= ___)? >>>>>> >>>>>> >>>>>> (axlb1 <- pretty(range(a[, 1]))) >>>>>> (axlb2 <- pretty(range(log(a[, 2]), na.rm=TRUE))) >>>>>> (axlb3 <- pretty(range(log(a[, 3]), na.rm=TRUE))) >>>>>> >>>>>> >>>>>> This suggests I write my own modification of plot.ts that accepts log >>>>>> as a character vector of length = ncol of the ts being plotted and >>>>>> returns invisibly a list with the default "at" and "label" arguments >>>>>> required to produce the default labeling. Then a user who wants a log >>>>>> scale for some but not all variables can get that easily and can further >>>>>> modify any of those scales further if they don't like the default. >>>>>> >>>>>> >>>>>> ??? >>>>>> Thanks very much. >>>>>> Spencer Graves >>>>>>>> >>>>>>>> >>>>>>>> On Tue, May 30, 2023 at 1:46?PM Spencer Graves >>>>>>>> <spencer.graves at effectivedefense.org> wrote: >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> On 5/29/23 2:37 AM, Eric Berger wrote: >>>>>>>>>> How about this: >>>>>>>>>> >>>>>>>>>> a <- cbind(AirPassengers, diff(log(AirPassengers)), >>>>>>>>>> diff(diff(log(AirPassengers)))) >>>>>>>>>> colnames(a)[2:3] <- c("percent increase", "acceleration") >>>>>>>>>> plot(a, xlab="year", main="AirPassengers") >>>>>>>>> >>>>>>>>> >>>>>>>>> My real problem is more difficult: I'm analyzing CO2 data from Our >>>>>>>>> World in Data (https://ourworldindata.org/co2-emissions), and I need to >>>>>>>>> plot the CO2 data on a log scale but velocity and acceleration on linear >>>>>>>>> scales. The following is comparable: >>>>>>>>> >>>>>>>>> >>>>>>>>> str(DAX <- EuStockMarkets[, 'DAX']) >>>>>>>>> str(DAX. <- cbind(DAX, diff(log(DAX)), >>>>>>>>> diff(diff(log(DAX))))) >>>>>>>>> colnames(DAX.)[2:3] <- c('vel', 'accel') >>>>>>>>> plot(DAX.) >>>>>>>>> >>>>>>>>> >>>>>>>>> I want the first of the three panels to plot on the log scale, but >>>>>>>>> the other two on linear scales. The obvious attempt does not work: >>>>>>>>> >>>>>>>>> >>>>>>>>> plot(DAX., log=c('y', '', '')) >>>>>>>>> #Error in length(log) && log != "" : >>>>>>>>> # 'length = 3' in coercion to 'logical(1)' >>>>>>>>> >>>>>>>>> >>>>>>>>> Trying to construct my own axes isn't easy, either: >>>>>>>>> >>>>>>>>> >>>>>>>>> str(logDAX <- cbind(log(DAX), diff(log(DAX)), >>>>>>>>> diff(diff(log(DAX))))) >>>>>>>>> colnames(logDAX) <- c('logDAX', 'vel', 'accel') >>>>>>>>> plot(logDAX, axes=FALSE) >>>>>>>>> axis(1) >>>>>>>>> axis(2) >>>>>>>>> >>>>>>>>> >>>>>>>>> I'm thinking of creating my own copy of "plot.ts", and changing it so >>>>>>>>> it accepts the "log" argument as a vector of length equal to ncol of the >>>>>>>>> ts object to be plotted AND returning an object that would allow a user >>>>>>>>> to call "axis" ncol times. >>>>>>>>> >>>>>>>>> >>>>>>>>> Suggestions? >>>>>>>>> >>>>>>>>> >>>>>>>>> Thanks, >>>>>>>>> Spencer Graves >>>>>>>>> >>>>>>>>>> >>>>>>>>>> HTH, >>>>>>>>>> Eric >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> On Mon, May 29, 2023 at 7:57?AM Spencer Graves >>>>>>>>>> <spencer.graves at effectivedefense.org> wrote: >>>>>>>>>>> >>>>>>>>>>> Hello, All: >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> I want to plot level, velocity, and acceleration in three panels with >>>>>>>>>>> only one x axis. The code below does this using "layout". However, I >>>>>>>>>>> want the three plot areas to be of equal size, and this won't do that: >>>>>>>>>>> If I stretch the plot vertically, the relative sizes of the three panels >>>>>>>>>>> changes. There's probably a way to do this with ggplot2, but I have yet >>>>>>>>>>> to find it. >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> Suggestions? >>>>>>>>>>> Thanks, >>>>>>>>>>> Spencer Graves >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> str(AirTime <- as.numeric(time(AirPassengers))) >>>>>>>>>>> str(AP <- as.numeric(AirPassengers)) >>>>>>>>>>> >>>>>>>>>>> def.par <- par(no.readonly = TRUE) # save default, for resetting... >>>>>>>>>>> (mat3x1 <- matrix(1:3, 3)) >>>>>>>>>>> plot3x1 <- layout(mat3x1, heights=c(1.4, 1, 1.5)) >>>>>>>>>>> layout.show(plot3x1) >>>>>>>>>>> >>>>>>>>>>> par(mar=c(0, 4.1, 4.1, 2.1)) >>>>>>>>>>> plot(AirTime, AP, log='y', type='l', axes=FALSE, >>>>>>>>>>> main='AirPassengers', ylab='AirPassengers') >>>>>>>>>>> box(col='grey') >>>>>>>>>>> axis(2, las=1) >>>>>>>>>>> >>>>>>>>>>> par(mar=c(0, 4.1, 0, 2.1)) >>>>>>>>>>> vAP <- diff(log(AP)) >>>>>>>>>>> plot(tail(AirTime, -1), vAP, type='l', >>>>>>>>>>> ylab='percent increase', axes=FALSE) >>>>>>>>>>> box(col='grey') >>>>>>>>>>> axis(2, las=1) >>>>>>>>>>> >>>>>>>>>>> par(mar=c(5.1, 4.1, 0, 2.1)) >>>>>>>>>>> plot(tail(AirTime, -2), diff(vAP), type='l', >>>>>>>>>>> ylab='acceleration', xlab='year', >>>>>>>>>>> las=1) >>>>>>>>>>> box(col='grey') >>>>>>>>>>> >>>>>>>>>>> par(def.par) >>>>>>>>>>> >>>>>>>>>>> ______________________________________________ >>>>>>>>>>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see >>>>>>>>>>> https://stat.ethz.ch/mailman/listinfo/r-help >>>>>>>>>>> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html >>>>>>>>>>> and provide commented, minimal, self-contained, reproducible code.
Viechtbauer, Wolfgang (NP)
2023-May-31 19:12 UTC
[R] plot level, velocity, acceleration with one x axis
How about using the same 'mar' for all plots, but adding an outer margin? DAX <- EuStockMarkets[, 'DAX'] DAX. <- cbind(DAX, diff(log(DAX)), diff(diff(log(DAX)))) colnames(DAX.) <- c("DAX", 'vel (%)', 'accel (%)') head(DAX.) par(mfrow=c(3,1), mar=c(1,4.5,0,2), oma=c(3,0,1,0)) plot(DAX.[, 1], log='y', ylab='DAX', axes=FALSE) axis(2) box(col='grey') plot(DAX.[, 2], ylab='vel (%)', axes=FALSE) axis(2) box(col='grey') plot(DAX.[, 3], ylab='accel (%)', axes=FALSE) axis(2) box(col='grey') axis(1) Best, Wolfgang>-----Original Message----- >From: R-help [mailto:r-help-bounces at r-project.org] On Behalf Of Spencer Graves >Sent: Wednesday, 31 May, 2023 17:45 >To: Eric Berger >Cc: r-help >Subject: Re: [R] plot level, velocity, acceleration with one x axis > >On 5/31/23 9:20 AM, Eric Berger wrote: >> I sent you an updated response to deal with the redundant copies of the x-axis. >> Re-sending. >> >par(mfrow=c(3,1)) >plot(DAX.[, 1], log='y', ylab='DAX', xaxt="n") >plot(DAX.[, 2], ylab='vel (%)', xaxt="n") >plot(DAX.[, 3], ylab='accel (%)') > > I got that. The primary problem with that is that most of the >vertical space is reserved for axis labels, whether they are printed or >not. If I squeeze the vertical dimension of the plot, I get, "figure >margins too large". To control that, I need to set "mar" separately for >each panel, and then the plot regions for each are not the same size. >Using the "layout" function instead of "mfrow" is better, but I don't >see now to make that work consistently without fixing the aspect ratio. >There may be a way in the tidyverse, but I haven't found it yet. The >only solution I've found so far that makes sense to me is to modify the >code for plot.ts to accept a vector for the log argument, with the >constraint that length(lot) = either 1 or ncol(x) and returning >invisibly an object that would make it feasible for a user to call >axis(2, ...) once for each vertical axis to handle cases where someone >wanted to a vertical scale different from linear and log. I'd want to >make sure that lines.ts also works with this, because I want to add fits >and predictions. > > Comments? > Thanks, > Spencer Graves > >** With either of the following plots, if I adjust the aspect ratio by >enlarging or reducing the vertical dimension of the plot, the relative >sizes of the plot regions change. > >DAX <- EuStockMarkets[, 'DAX'] >DAX. <- cbind(DAX, diff(log(DAX)), diff(diff(log(DAX)))) >colnames(DAX.) <- c("DAX", 'vel (%)', 'accel (%)') >head(DAX.) > >plot(DAX., log='xy') > >op <- par(mfrow=c(3,1), mar=c(0, 4.1, 4.1, 2.1)) >plot(DAX.[, 1], log='y', ylab='DAX', axes=FALSE) >axis(2) >box(col='grey') >par(mar=c(0, 4.1, 0, 2.1)) >plot(DAX.[, 2], ylab='vel (%)', axes=FALSE) >axis(2) >box(col='grey') >par(mar=c(5.1, 4.1, 0, 2.1)) >plot(DAX.[, 3], ylab='accel (%)', axes=FALSE) >axis(2) >box(col='grey') >axis(1) >par(op)