ow to apply a panel function to each of several data series plotted on the same graph in lattice

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

ow to apply a panel function to each of several data series plotted on the same graph in lattice

David Wyllie
Hi

is it possible to fit a trend line (or some other panel function) through each of multiple data series plotted on the same graph?  Specifically, while one can do something like
xyplot(a+b+c~x)
which plots three series, a,b & c, but can one automatically fit lines through each of them?


I suppose one could generate three more variables afit, bfit, and cfit with a model & predict and then plot them, but wondered if there was an easier way.


Thank you for any advice. Here is an example:


# use an example panel function using smooth.spline; however, the issue relates to all panel functions
# a panel function to fit smoothed lines through data
panel.smooth.spline <- function(x, y,
            w=NULL, df, spar = NULL, cv = FALSE,
            lwd=plot.line$lwd, lty=plot.line$lty,col, col.line=plot.line$col,
            type, horizontal=FALSE,... )
{
  # Deepayan Sarkar code from: http://www.mail-archive.com/r-help@.../msg39654.html
    x <- as.numeric(x)
          y <- as.numeric(y)


          ok <- is.finite(x) & is.finite(y)


          if (sum(ok) < 1)
              return()
          if (!missing(col)) {
              if (missing(col.line))
                  col.line <- col
          }
          plot.line <- trellis.par.get("plot.line")
          if (horizontal) {
              spline <-
                  smooth.spline(y[ok], x[ok],
                                w=w, df=df, spar = spar, cv = cv, ...)
              panel.lines(x = spline$y, y = spline$x, col = col.line,
                  lty = lty, lwd = lwd, ...)
          }
          else {
              spline <-
                  smooth.spline(x[ok], y[ok],
                                w=w, df=df, spar = spar, cv = cv, ...)
              panel.lines(x = spline$x, y = spline$y, col = col.line,
                  lty = lty, lwd = lwd, ...)
          }
      }




# a composite function combining the xyplot and smooth.spline functions
panel.composite<-function(x,y,groups, subscripts, ...) {
panel.xyplot(x,y,...)
panel.smooth.spline(x,y,...)
}


# generate mock data; this comprises three data series, a,b,c with means of about 5,35, and 105.
test <- data.frame(
a = runif(100, min=0, max=10),
b = 30+runif(100, min=0, max=10),
c = 100+runif(100, min=0, max=10),
x = 1:100)


# illustrate data
xyplot(a + b + c ~ x, data = test, type = "p", auto.key=TRUE)


# plot with fits .. but actually only one fit
xyplot(
a + b + c ~ x,
panel=panel.composite,
data = test,
type = "p",
auto.key=TRUE)

______________________________________________
[hidden email] mailing list
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.
Reply | Threaded
Open this post in threaded view
|

Re: ow to apply a panel function to each of several data series plotted on the same graph in lattice

djmuseR
Hi:

Here's a simple example:

a <- rnorm(100)
b <- rnorm(100, 2)
c <- rnorm(100, 5)
x <- 1:100
library(lattice)
xyplot(a + b + c ~ x, type = 'l')

HTH,
Dennis

On Fri, Jun 18, 2010 at 12:45 AM, David Wyllie <[hidden email]>wrote:

> Hi
>
> is it possible to fit a trend line (or some other panel function) through
> each of multiple data series plotted on the same graph?  Specifically, while
> one can do something like
> xyplot(a+b+c~x)
> which plots three series, a,b & c, but can one automatically fit lines
> through each of them?
>
>
> I suppose one could generate three more variables afit, bfit, and cfit with
> a model & predict and then plot them, but wondered if there was an easier
> way.
>
>
> Thank you for any advice. Here is an example:
>
>
> # use an example panel function using smooth.spline; however, the issue
> relates to all panel functions
> # a panel function to fit smoothed lines through data
> panel.smooth.spline <- function(x, y,
>            w=NULL, df, spar = NULL, cv = FALSE,
>            lwd=plot.line$lwd, lty=plot.line$lty,col,
> col.line=plot.line$col,
>            type, horizontal=FALSE,... )
> {
>  # Deepayan Sarkar code from:
> http://www.mail-archive.com/r-help@.../msg39654.html
>    x <- as.numeric(x)
>          y <- as.numeric(y)
>
>
>          ok <- is.finite(x) & is.finite(y)
>
>
>          if (sum(ok) < 1)
>              return()
>          if (!missing(col)) {
>              if (missing(col.line))
>                  col.line <- col
>          }
>          plot.line <- trellis.par.get("plot.line")
>          if (horizontal) {
>              spline <-
>                  smooth.spline(y[ok], x[ok],
>                                w=w, df=df, spar = spar, cv = cv, ...)
>              panel.lines(x = spline$y, y = spline$x, col = col.line,
>                  lty = lty, lwd = lwd, ...)
>          }
>          else {
>              spline <-
>                  smooth.spline(x[ok], y[ok],
>                                w=w, df=df, spar = spar, cv = cv, ...)
>              panel.lines(x = spline$x, y = spline$y, col = col.line,
>                  lty = lty, lwd = lwd, ...)
>          }
>      }
>
>
>
>
> # a composite function combining the xyplot and smooth.spline functions
> panel.composite<-function(x,y,groups, subscripts, ...) {
> panel.xyplot(x,y,...)
> panel.smooth.spline(x,y,...)
> }
>
>
> # generate mock data; this comprises three data series, a,b,c with means of
> about 5,35, and 105.
> test <- data.frame(
> a = runif(100, min=0, max=10),
> b = 30+runif(100, min=0, max=10),
> c = 100+runif(100, min=0, max=10),
> x = 1:100)
>
>
> # illustrate data
> xyplot(a + b + c ~ x, data = test, type = "p", auto.key=TRUE)
>
>
> # plot with fits .. but actually only one fit
> xyplot(
> a + b + c ~ x,
> panel=panel.composite,
> data = test,
> type = "p",
> auto.key=TRUE)
>
> ______________________________________________
> [hidden email] mailing list
> 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.
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
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.
Reply | Threaded
Open this post in threaded view
|

Re: how to apply a panel function to each of several data series plotted on the same graph in lattice

David Wyllie
Hi
 
Thanks, but maybe I'm not making myself clear enough here.
I think I'm already doing what you suggest, below the line # plot with fits .. in the original mail.
 
I have made a little progress.  I wish to apply a panel function to each of a,b,and c.
When plotting
xyplot(a + b + c ~ x, type = 'l'),
in the below example the 'x' passed to the panel function is a numeric vector of 300 length, with no way of telling whether the data came from a,b, or c.
 
I have found a discussion here
http://www.mail-archive.com/r-help@.../msg94720.html 
which is helpful.
 
One can view the same data in a 'long format' where the property of being 'a' 'b' or 'c' is in a third column, 'grp'.
 
## code example starts here
 
# i.e instead of generate mock data; this comprises three data series, a,b,c with means of about 5,35, and 105.
test <- data.frame(
a = runif(100, min=0, max=10),
b = 30+runif(100, min=0, max=10),
c = 100+runif(100, min=0, max=10),
x = 1:100)
 
# we do  one can have the data in three columns,
# we arrange long so we can use groups and superpose
test2a<-data.frame (
y=runif(100, min=0, max=10), x=1:100, grp=rep('a',100))
test2b<-data.frame (
y=30+runif(100, min=0, max=10), x=1:100, grp=rep('b',100))
test2c<-data.frame (
y=100+runif(100, min=0, max=10), x=1:100, grp=rep('c',100))
test2<-rbind(test2a, test2b, test2c)
 
library(lattice)
# illustrate data the former way
xyplot(a + b + c ~ x, data = test, type = "p", auto.key=TRUE)

# or equivalently
xyplot(y~ x|grp, data = test2, type = "p", auto.key=TRUE)
## now the problem, which is to fit trends through the data
# the latter way, one can as described do http://www.mail-archive.com/r-help@.../msg94539.html 
xyplot(y~x, groups=grp,data=test2,
       type='l',
       panel = panel.superpose,
       panel.groups = function(x, y, ..., lty) {
               panel.xyplot(x, y, ..., lty = lty)
               panel.abline(h = mean(y), lty=3, ...)
 }
)
# and this succeeds.  however, when we then use the panel function
# Deepayan Sarkar code from: http://www.mail-archive.com/r-help@.../msg39654.html 
 panel.smooth.spline <- function(x, y,
            w=NULL, df, spar = NULL, cv = FALSE,
            lwd=plot.line$lwd, lty=plot.line$lty,col, col.line=plot.line$col,
            type, horizontal=FALSE,... )
{
       x <- as.numeric(x)
          y <- as.numeric(y)
 
          ok <- is.finite(x) & is.finite(y)

          if (sum(ok) < 1)
              return()
          if (!missing(col)) {
              if (missing(col.line))
                  col.line <- col
          }
          plot.line <- trellis.par.get("plot.line")
          if (horizontal) {
              spline <-
                  smooth.spline(y[ok], x[ok],
                                w=w, df=df, spar = spar, cv = cv, ...)
              panel.lines(x = spline$y, y = spline$x, col = col.line,
                  lty = lty, lwd = lwd, ...)
          }
          else {
              spline <-
                  smooth.spline(x[ok], y[ok],
                                w=w, df=df, spar = spar, cv = cv, ...)
              panel.lines(x = spline$x, y = spline$y, col = col.line,
                  lty = lty, lwd = lwd, ...)
          }
      }
 

# and try
xyplot(y~x, groups=grp,data=test2,
       type='l',
       panel = panel.superpose,
       panel.groups = function(x, y, ..., lty) {
               panel.xyplot(x, y, ..., lty = lty)
               panel.smooth.spline( ...)
 }
)
 
# then we generate an error 'error using packet 1', and I'm not sure why.
 
Thanks
David
 
David Wyllie, PhD
University Research Lecturer
The Jenner Institute
Oxford University
Old Road Campus Research Building
Roosevelt Drive
Oxford OX3 7DQ
UK
 
fax +44 (0)1865 617608
office +44 (0) 1865 617627
lab +44 (0) 1865 617649
mobile 07988 550815
 
>>> Dennis Murphy <[hidden email]> 6/18/2010 12:18 pm >>>
Hi:

Here's a simple example:

a <- rnorm(100)
b <- rnorm(100, 2)
c <- rnorm(100, 5)
x <- 1:100
library(lattice)
xyplot(a + b + c ~ x, type = 'l')

HTH,
Dennis


______________________________________________
[hidden email] mailing list
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.

David Wyllie.vcf (168 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: how to apply a panel function to each of several data series plotted on the same graph in lattice

Deepayan Sarkar
On Fri, Jun 18, 2010 at 5:19 PM, David Wyllie <[hidden email]> wrote:

> Hi
>
> Thanks, but maybe I'm not making myself clear enough here.
> I think I'm already doing what you suggest, below the line # plot with fits .. in the original mail.
>
> I have made a little progress.  I wish to apply a panel function to each of a,b,and c.
> When plotting
> xyplot(a + b + c ~ x, type = 'l'),
> in the below example the 'x' passed to the panel function is a numeric vector of 300 length, with no way of telling whether the data came from a,b, or c.
>
> I have found a discussion here
> http://www.mail-archive.com/r-help@.../msg94720.html
> which is helpful.
>
> One can view the same data in a 'long format' where the property of being 'a' 'b' or 'c' is in a third column, 'grp'.
>
> ## code example starts here
>
> # i.e instead of generate mock data; this comprises three data series, a,b,c with means of about 5,35, and 105.
> test <- data.frame(
> a = runif(100, min=0, max=10),
> b = 30+runif(100, min=0, max=10),
> c = 100+runif(100, min=0, max=10),
> x = 1:100)
>
> # we do  one can have the data in three columns,
> # we arrange long so we can use groups and superpose
> test2a<-data.frame (
> y=runif(100, min=0, max=10), x=1:100, grp=rep('a',100))
> test2b<-data.frame (
> y=30+runif(100, min=0, max=10), x=1:100, grp=rep('b',100))
> test2c<-data.frame (
> y=100+runif(100, min=0, max=10), x=1:100, grp=rep('c',100))
> test2<-rbind(test2a, test2b, test2c)
>
> library(lattice)
> # illustrate data the former way
> xyplot(a + b + c ~ x, data = test, type = "p", auto.key=TRUE)
>
> # or equivalently
> xyplot(y~ x|grp, data = test2, type = "p", auto.key=TRUE)
> ## now the problem, which is to fit trends through the data
> # the latter way, one can as described do http://www.mail-archive.com/r-help@.../msg94539.html
> xyplot(y~x, groups=grp,data=test2,
>       type='l',
>       panel = panel.superpose,
>       panel.groups = function(x, y, ..., lty) {
>               panel.xyplot(x, y, ..., lty = lty)
>               panel.abline(h = mean(y), lty=3, ...)
>  }
> )
> # and this succeeds.  however, when we then use the panel function
> # Deepayan Sarkar code from: http://www.mail-archive.com/r-help@.../msg39654.html
>  panel.smooth.spline <- function(x, y,
>            w=NULL, df, spar = NULL, cv = FALSE,
>            lwd=plot.line$lwd, lty=plot.line$lty,col, col.line=plot.line$col,
>            type, horizontal=FALSE,... )
> {
>       x <- as.numeric(x)
>          y <- as.numeric(y)
>
>          ok <- is.finite(x) & is.finite(y)
>
>          if (sum(ok) < 1)
>              return()
>          if (!missing(col)) {
>              if (missing(col.line))
>                  col.line <- col
>          }
>          plot.line <- trellis.par.get("plot.line")
>          if (horizontal) {
>              spline <-
>                  smooth.spline(y[ok], x[ok],
>                                w=w, df=df, spar = spar, cv = cv, ...)
>              panel.lines(x = spline$y, y = spline$x, col = col.line,
>                  lty = lty, lwd = lwd, ...)
>          }
>          else {
>              spline <-
>                  smooth.spline(x[ok], y[ok],
>                                w=w, df=df, spar = spar, cv = cv, ...)
>              panel.lines(x = spline$x, y = spline$y, col = col.line,
>                  lty = lty, lwd = lwd, ...)
>          }
>      }
>
>
> # and try
> xyplot(y~x, groups=grp,data=test2,
>       type='l',
>       panel = panel.superpose,
>       panel.groups = function(x, y, ..., lty) {
>               panel.xyplot(x, y, ..., lty = lty)
>               panel.smooth.spline( ...)
>  }
> )
>
> # then we generate an error 'error using packet 1', and I'm not sure why.

Actually, the complete error message is:

error using packet 1
'x' is missing

Look again carefully at your panel function. In the call to
panel.smooth.spline(...), are the 'x' and 'y' arguments supplied?

-Deepayan

______________________________________________
[hidden email] mailing list
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.