Showing posts with label R Graphs. Show all posts
Showing posts with label R Graphs. Show all posts
Sunday, September 20, 2015
An Image Crossfader Function
Some project offspin, the jpgfader-function (the jpgfader-function in funny use can be viewed HERE):
# purpose: crossfade 2 jpeg images
# packages: jpeg
# arguments: img1 (path.to.img1), img2 (path.to.img2),
# outpath(defaults to current directory), outname,
# frames
# output: png
require(jpeg)
jpgfader <- function(img1 = NA, img2 = NA, outpath = NA, frames = NA, outname = NA){
if(is.na(outpath)) {outpath <- path.expand("~")}
# stop if images are missing
if(is.na(img1)|is.na(img2)) stop(cat("\nAt least one image is missing!\n"))
if(is.na(outname)) {outname = "img.1.2"}
if(is.na(frames)) {frames = 10}
# read 2 jpegs, assuming same size!
pic.1 <- readJPEG(img1)
pic.2 <- readJPEG(img2)
# warn if images dont have same size:
if(sum(dim(pic.1) != dim(pic.2))>1) warning(cat("\nImages do not have same dimensions!"))
# create new array with 4 dimensions, the new dimension
# representing alpha:
by = 1/(frames-1)
alpha = seq(0, 1, by)
n = length(alpha)
for(j in n:1){
pic.2.a <- array(data = c(as.vector(pic.2),
rep(alpha[j], dim(pic.1)[1]*dim(pic.1)[2])),
dim = c(dim(pic.1)[1], dim(pic.1)[2], 4))
# assign output file name:
pic.out <- paste(outpath, "\\", outname, ".", j ,".png", sep = "")
# and open device:
png(pic.out, width = dim(pic.1)[2], height = dim(pic.1)[1])
# plot-parameters:
par(mar = rep(0, 4), oma = rep(0, 4), new = F)
# print img.a to plot region:
plot(1:2,
xlim = c(0, dim(pic.1)[2]), ylim = c(0, dim(pic.1)[1]),
xlab="", ylab="", type = "n",
yaxs ="i", xaxs = "i")
rasterImage(pic.1, 0, 0, dim(pic.1)[2], dim(pic.1)[1])
# overplotting with new alpha-pic,
# starting with full transparency, decreasing in steps, showing pic.2
# finally:
rasterImage(pic.2.a, 0, 0, dim(pic.1)[2], dim(pic.1)[1])
dev.off()
}
}
# Example, with 2 images, one system.file and one altered
# version of it:
# make black jpg and save to default system folder
Rlogo <- readJPEG(system.file("img", "Rlogo.jpg", package="jpeg"))
Rlogo[] <- 0
jpeg(path.expand("~\\Rlogo_Black.jpg"), dim(Rlogo)[2], dim(Rlogo)[1])
par(mar = rep(0, 4), oma = rep(0, 4))
# save black image:
plot(1:2,
xlim = c(0, 1), ylim = c(0, 1),
xlab="", ylab="", type = "n",
yaxs ="i", xaxs = "i")
rasterImage(Rlogo, 0, 0, 1, 1)
dev.off()
# function call:
jpgfader(img1 = system.file("img", "Rlogo.jpg", package="jpeg"),
img2 = path.expand("~/Rlogo_black.jpg"),
outname = "img12",
outpath = path.expand("~"),
frames = 10)
# see the images:
browseURL(path.expand("~"))
# remove files:
# files <- dir(path.expand("~"), full.names = T)
# file.remove(c(files[grep("img12.", files)],
path.expand("~/Rlogo_black.jpg")))
Labels:
jpeg,
jpgfader(),
R,
R Graphs,
rasterImage(),
Transparency
Fit Sigmoid Curve with Confidence Intervals
Sigmoid curve fitting for transpiration measurements from porometer at different water potentials (pressure):
por<-data.frame(list(structure(list(run = structure(c(1L, 1L, 1L, 1L, 2L, 2L,
2L, 2L, 3L, 3L, 3L, 3L), .Label = c("1", "3", "4"), class = "factor"),
press = c(15, 21, 24, 29.5, 15, 21, 24, 29.5, 15, 21, 24,
29.5), tr_rel = c(1, 0.459454191, 0.234697856, 0.135282651,
1, 0.853283066, 0.306314797, 0.186302231, 1, 0.42980063,
0.103882476, 0.086463799), tr = c(513, 235.7, 120.4, 69.4,
318.3, 271.6, 97.5, 59.3, 476.5, 204.8, 49.5, 41.2)), .Names = c("run",
"press", "tr_rel", "tr"), row.names = c(NA, -12L), class = "data.frame")))
summary(mod1<-nls(tr ~ SSlogis( log(press), Asym, xmid, scal),data=por))
press_x <- seq(10, 40, length = 100)
predict(mod1, data.frame(press = press_x))
with(por, plot(press,tr,xlim=c(10,35),ylim=c(0,500)))
lines(press_x, predict(mod1, data.frame(press = press_x)))
## note that the variable in SSlogis is named "press"
## and the same name should appear on the left-hand side
## of "=" in the data frame
###http://finzi.psych.upenn.edu/R/Rhelp02/archive/42932.html
###calc. of conf. intervalls, by linear approximation
se.fit <- sqrt(apply(attr(predict(mod1, data.frame(press = press_x)),"gradient"),1,
function(x) sum(vcov(mod1)*outer(x,x))))
###plot points and curve plus ci's
matplot(press_x, predict(mod1, data.frame(press = press_x))+outer(se.fit,qnorm(c(.5, .025,.975))),
type="l",lty=c(1,3,3),ylab="transp",xlab="waterpot")
with(por, matpoints(press,tr,pch=1))
###hhbio.wasser.tu-dresden.de/projects/modlim/doc/modlim.pdf
###R squared for non-linear Regression
Rsquared <- 1 - var(residuals(mod1))/var(por$tr)
###add r^2 to plot:
text(35,550,bquote(R^2==.(round(Rsquared, 3))))
asym<-coef(mod1)[1]
y_tenth<-asym*0.1
abline(h=asym)
abline(h=y_tenth,lty=5)
text(10,65,"10% of max. transpiration",adj=0)
###finding y by x
x<-15
y<-SSlogis(log(x), coef(mod1)[1], coef(mod1)[2] ,coef(mod1)[3])
y
###alternative way
###y = Asym/(1+exp((xmid-log(x))/scal))
y<-coef(mod1)[1]/(1+exp((coef(mod1)[2]-log(x))/coef(mod1)[3]))
###finding x by y
Asym=coef(mod1)[1]
xmid=coef(mod1)[2]
scal=coef(mod1)[3]
y_tenth<-asym*0.1
x_tenth<-exp((xmid-log(Asym/y_tenth-1)*scal));names(x_tenth)<-"x"
x_tenth
abline(v=x_tenth)
text(10,25,paste("at waterpot.:",
round(x_tenth,2)),adj=0)
Add Transparency to JPEG - Yes, We Can!
...Just read in your JPEG and add an alpha channel manually, then assign values for transparency. Of course for printing you need to use a device that accepts alpha.
See how it's done HERE.
Labels:
arrays,
as.raster(),
jpeg,
R,
R Graphs,
Transparency
Apprentice Piece with Lattice Graphs
Lattice graphs can be quite tedious to learn. I don't use them too often and when I need them I usually have to dig deep into the archives for details on the parameter details.
The here presented example may serve as a welcome template for the usage of panel functions, panel ordering, for drawing of lattice keys, etc.
You can download the example data HERE.
(Also, check this resource with examples by the lattice-author).
Read more »
The here presented example may serve as a welcome template for the usage of panel functions, panel ordering, for drawing of lattice keys, etc.
You can download the example data HERE.
(Also, check this resource with examples by the lattice-author).
library(lattice)
df <- read.csv("PATH/TO/Downloads/lattice_data.csv",
header = T, sep = ";")
mypch <- rep(21, 3)
mycol <- c(rgb(0.2, 0.8, 0.9), rgb(0.8, 0.2, 0.9), rgb(0.9, 0.2, 0.2))
stripplot(mean ~ group1 | item_parc, groups = group2, data = df,
type = c("a", "p"), strip = strip.custom(strip.names = c(F, T)),
ylab = "Score-Mittelwert", layout = c(2, 4),
scales = list(y = list(cex = 0.9),
x = list(cex = 1.1, labels = c("männl.", "weibl."),
tck = c(1, 0))),
par.strip.text = list(cex = 0.9),
panel = function(...) {
panel.stripplot(..., col = mycol, pch = mypch, fill = mycol)
},
index.cond = list(c(7,8,5,6,3,4,1,2)),
key = list(space = "bottom", text = list(c("Alter < 35 J.",
"Alter 35-50 J.",
"Alter > 50 J.")),
points = list(col = mycol, cex = 0.8, pch = mypch, fill = mycol),
rep = F))
Import dbf to R, Manipulate Strings with grep & sub Function
Here's a set of historical species presence records of a certain geographical region (data-link). I wanted to manipulate / simplify strings (species names) and get an overview of the data.
...The tasks were to split genera and epitheta, to exclude species with specific strings included and to get rid of unwanted text (author names). For graphical presentation of the species record history I did a plot with segments indicating the first and last year of a species record: # for dbf import you'll need:
require(foreign)
# change to your directory: TLMFB_IL <- read.dbf("D:\\Downloads\\TLMFB_IL.dbf")
str(TLMFB_IL)
# get rid of hybrids:
dat_sub1 <- TLMFB_IL[-grep(" x ", TLMFB_IL$NAME),]
# check how many were dismissed:
length(TLMFB_IL$NAME) - length(dat_sub1$NAME)
# get genera and epitheta:
Gen <- sub(" .*", "", dat_sub1$NAME)
Epi <- sub(" .*", "", substring(dat_sub1$NAME, nchar(Gen)+2))
# get rid of species with unsure determination:
dat_sub2 <- dat_sub1[Epi != "spec." &
Epi != "sp." &
Epi != "cf." &
Epi != "" &
Epi != "?", ]
length(TLMFB_IL$NAME) - length(dat_sub2$NAME)
# check:
dat_sub2$NAME
TLMFB_IL$NAME
table(Epi != "spec." &
Epi != "sp." &
Epi != "cf." &
Epi != "" &
Epi != "?")
length(grep(" x ", TLMFB_IL$NAME))
length(dat_sub2$NAME)
# get genera and epitheta:
Gen <- sub(" .*", "", dat_sub2$NAME)
Epi <- sub(" .*", "", substring(dat_sub2$NAME, nchar(Gen)+2))
# get rid of authors:
sp <- paste(Gen, Epi)
length(sp)
# check arbitrary sample of 100 rows, window should be large
# enough to show columns next to each other:
id <- sample(1:3175, 100)
data.frame(sp = sp, orig = dat_sub2$NAME)[id,]
# add species names without authors to dataframe
dat_sub2$Sp <- sp
# there are some erronous values that should be discarded:
dat_sub3 <- dat_sub2[dat_sub2$date_long < 2010,]
str(dat_sub3)
# get max and min year at which species were recorded
y_min <- aggregate(. ~ Sp, min, data = dat_sub3[,c("Sp","date_long")])
y_max <- aggregate(. ~ Sp, max, data = dat_sub3[,c("Sp","date_long")])
# plot each species first and last record in line plot, data:
head(pldat <- data.frame(Sp = y_min[,1], y_min = y_min[,2],
y_max = y_max[,2], span = y_max[,2] - y_min[,2]))
# plot:
# example("segments")
# new ordering for plot:
pldat <- pldat[order(pldat$y_min, pldat$span),]
plot(x = c(min(pldat$y_min), max(pldat$y_max)), y = c(1, nrow(pldat)),
type = 'n', xlab = "Year", ylab ="", axes = F, frame.plot=FALSE)
segments(x0 = pldat$y_min, x1 = pldat$y_max, y0 = 1:nrow(pldat),
y1 = 1:nrow(pldat), col = "gray60")
axis(1, pretty(1800:2000), cex.axis = 0.75)
mtext(paste("Species Records Innsbruck\n", " (Sp - N = ", nrow(pldat), ")",
sep = ""), side = 2, line = -2)
# especially inbetween the 60's and 80's many species were
# re-recorded and newly added by only a few authors:
sixt_eight <- dat_sub3[dat_sub3$date_long > 1960 & dat_sub3$date_long < 1980, c("AUTOR", "Sp")]
data.frame(table(as.character(sixt_eight$AUTOR)))
To cite package ‘foreign’ in publications use:
R-core members, Saikat DebRoy , Roger Bivand and
others: see COPYRIGHTS file in the sources. (2011). foreign: Read Data Stored by Minitab, S,
SAS, SPSS, Stata, Systat, dBase, .... R package version 0.8-44.
http://CRAN.R-project.org/package=foreign
R-Function GScholarScraper to Webscrape Google Scholar Search Result
NOTE: You'll find the update HERE and HERE.
NOTE: The script is currently not working because the code of the Google-Scholar site has changed...
I'll see for this as soon as I find some spare time for it!
NOTE: If you try to access GoogleScholar programatically consider this words of caution:
http://stackoverflow.com/questions/7523961/google-scholar-with-matlab/7587994#7587994
...
Based on my previous post on Web Scraping I coded and uploaded the Function "GScholarScraper" HERE for testing!
The function will pull all (!) results, processing pages in chunks of 100 results/titles, and return a file with all titles, links, etc. It will also produce a word cloud using the words in the publication titles.
Please try your own search strings and report errors, etc.!
Build and run properly under:
R version 2.13.0 (2011-04-13) and R version R-2.13.2 (2011-09-30)
Platform: i386-pc-mingw32/i386 (32-bit) locale:
[1] LC_COLLATE=English_United States.1252
[2] LC_CTYPE=English_United States.1252
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] stringr_0.5 tm_0.5-6 wordcloud_1.2 Rcpp_0.9.7
loaded via a namespace (and not attached):
[1] plyr_1.5.1 slam_0.1-23
PS: Errors reported lately (see comments) were resolved, the source code was updated..
Read more »
NOTE: The script is currently not working because the code of the Google-Scholar site has changed...
I'll see for this as soon as I find some spare time for it!
NOTE: If you try to access GoogleScholar programatically consider this words of caution:
http://stackoverflow.com/questions/7523961/google-scholar-with-matlab/7587994#7587994
...
Based on my previous post on Web Scraping I coded and uploaded the Function "GScholarScraper" HERE for testing!
The function will pull all (!) results, processing pages in chunks of 100 results/titles, and return a file with all titles, links, etc. It will also produce a word cloud using the words in the publication titles.
Please try your own search strings and report errors, etc.!
Build and run properly under:
R version 2.13.0 (2011-04-13) and R version R-2.13.2 (2011-09-30)
Platform: i386-pc-mingw32/i386 (32-bit) locale:
[1] LC_COLLATE=English_United States.1252
[2] LC_CTYPE=English_United States.1252
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] stringr_0.5 tm_0.5-6 wordcloud_1.2 Rcpp_0.9.7
loaded via a namespace (and not attached):
[1] plyr_1.5.1 slam_0.1-23
PS: Errors reported lately (see comments) were resolved, the source code was updated..
Comparing Two Distributions
Here I compare two distributions, flowering duration of indigenous and allochtonous plant species. The hypothesis is that alien compared to indigenous plant species exhibit longer flowering periods.
download data*
*Data is courtesy of BiolFlor:
Klotz, S., Kühn, I. & Durka, W. [Hrsg.] (2002): BIOLFLOR - Eine Datenbank zu biologisch-ökologischen Merkmalen der Gefäßpflanzen in Deutschland. - Schriftenreihe für Vegetationskunde 38. Bonn: Bundesamt für Naturschutz.
Read more »
download data*
*Data is courtesy of BiolFlor:
Klotz, S., Kühn, I. & Durka, W. [Hrsg.] (2002): BIOLFLOR - Eine Datenbank zu biologisch-ökologischen Merkmalen der Gefäßpflanzen in Deutschland. - Schriftenreihe für Vegetationskunde 38. Bonn: Bundesamt für Naturschutz.
## comparing flowering time in indigenous and alien species by
## usage of a quantile-quantile plot (qqplot), the ks-test, by
## testing shifts in medians (wilcox test) and by testing
## difference of means (t-test, as we deal with integer and
## not a continous variable it is not the most appropiate choice)
## as well as by a chi-square test:
dat <- read.csv("E:\\R\\Data\\flowering_alien_vs_indigen.csv",
sep = ";")
library(lattice)
histogram(~ Flowering|Status, data = dat, col = "gray60", layout = c(1, 2),
xlab = list("Months of flowering"),
ylab = list("Percentage of total"),
scales = list(y = list(alternating = F)),
strip = strip.custom(factor.levels = c("alien", "indigenous")))
qqplot(dat$Flowering[dat$Status == "indigen"],
dat$Flowering[dat$Status == "Neophyt"])
abline(a = 0, b = 1, lty = 3)
ks.test(dat$Flowering[dat$Status == "indigen"],
dat$Flowering[dat$Status == "Neophyt"])
wilcox.test(Flowering ~ Status, data = dat)
t.test(Flowering ~ Status, data = dat)
## Note that in the two-sample case the estimator for the
## difference in location parameters does not estimate
## the difference in medians (a common misconception) but
## rather the median of the difference between a sample
## from x and a sample from y.
## as we deal with a limited number of classes (1-12 months)
## and sample size is big enough my favourite would be a
## chi-square test:
m <- table(dat$Status, dat$Flowering)
(Xsq <- chisq.test(m)) # Prints test summary
Xsq$observed # observed counts (same as M)
Xsq$expected # expected counts under the null
Xsq$residuals # Pearson residuals
Xsq$stdres # standardized residuals
Lattice Plots - Usage of Panel Functions - Different Axes For Panel-Rows - Alternating Axis Titles
I present code for a stacked graph with common axes only for panels of the same row and with axis titles at different sides. This admittedly took me days (because i had not much of a clue how to use lattice), but eventually I did it and maybe someone can use this for his/her own purpose:
library(lattice)
y1 <- rnorm(120,100,10)
y2 <- rnorm(120,10,1)
facs <- expand.grid(Sites=rep(c("Site I","Site II",
"Site III"),20),Treatment = c("A","B"))
trellis.par.set(clip = list(panel = "off",strip = "off"),
layout.widths = list(right.padding = 10,
left.padding = 8))
PanFun<-function(...){
panel.dotplot(...)
if(is.element(panel.number(),1:2))
{at<-pretty(c(min(y1),max(y1)))
panel.axis("right",at = at,outside = T,
labels = F,half = F)}
if(panel.number() == 3)
{at<-pretty(c(min(y1),max(y1)))
panel.axis("right",at = at,outside = T,
labels = T,half = F)}
if(panel.number() == 4)
{at<-pretty(c(min(y2),max(y2)))
panel.axis("left",at = at,outside = T,
labels = T,half = F)}
if(is.element(panel.number(),5:6))
{at<-pretty(c(min(y2),max(y2)))
panel.axis("left",at = at,outside = T,
labels = F,half = F)}}
dotplot(y1+y2 ~ Treatment|Sites,
outer = TRUE,data = facs,
scales = list(
x = list(rot = 0, tck=c(1,0)),
y = list(draw=F,relation="free",
limits = list(range(y1),range(y1),range(y1),
range(y2),range(y2),range(y2)))),
ylab = list("response one (y1)", y = 0.75, x = -4),
ylab.right = list("response two (y2)", y = 0.25,
rot = 270, x = 4),
xlab = c("Site 1", "Site 2","Site 3"),
strip = FALSE, panel=PanFun)
R package citation:
Sarkar, Deepayan (2008) Lattice: Multivariate Data Visualization with
R. Springer, New York. ISBN 978-0-387-75968-5
See also the thread:
http://www.mail-archive.com/r-help@r-project.org/msg107565.html
..and examples from:
http://lmdvr.r-forge.r-project.org/figures/figures.html
Function for Adding Transparency to JPEG (Output = PNG)
..see the function-code HERE.
Read more »
Multiple Comparisons for GLMMs using glmer() & glht()
...here's an example of how to apply multiple comparisons to a generalised linear mixed model (GLMM) using the function glmer from package lme4 & glht() from package multcomp. Also, I present a nice example for visualizing data from a nested sampling design with lattice-plots!
The comparisons: I have a 4-level (stage A, B, C, D) and a 2-level (center vs. periphery) fixed factor and I want to know whether there are differences between center vs. periphery within each stage-level, and whether this effect differs across stage-levels (interactions). For the case being I simulated an effect only for center vs. periphery and this effect was simulated to be the same across all stages, so there should not be any sign. interactions.
This method was used in Cichini et al. (2011).
This method was used in Cichini et al. (2011).
library(lme4)
library(mvtnorm)
library(multcomp)
library(lattice)
########################################################################
# setting up fake data, for details on sampling design see: #
# cichini et al. (2011) #
# http://www.springerlink.com/content/t4u305045t214882 #
########################################################################
# 3 successional stages with 44 units and 1 succ. stage wit 10 units:
N = 44*3+10
cen <- per <- cbind(n = rep(NA, N), X = rep(NA, N))
# i simulate an effect between factor-levels cen and per
# all other fixed and random factors and interactions will have
# no effect.
# X = incidents, n = no. of observations:
for(i in 1:N){cen[i,"X"]<-sum(rbinom(5, 1, 0.35)); cen[i, "n"] <- 5}
for(i in 1:N){per[i,"X"]<-sum(rbinom(8, 1, 0.65)); per[i, "n"] <- 8}
dat <- data.frame(rbind(cen, per))
# probabilities:
dat$p <- dat$X/dat$n
stage <- as.factor(rep(c(rep("A",44), rep("B",44), rep("C",44), rep("D",10)),2))
plotA <- paste("A",rep(1:11,c(4,4,4,4,4,4,4,4,4,4,4)),sep="")
plotB <- paste("B",rep(1:13,c(3,4,2,4,4,4,4,4,3,4,4,2,2)),sep="")
plotC <- paste("C",rep(1:12,c(3,4,4,4,4,4,4,4,3,4,4,2)),sep="")
plotD <- paste("D",rep(1:3,c(2,4,4)),sep="")
plot <- as.factor(rep(c(plotA, plotB, plotC, plotD),2))
subplot <- as.factor(rep(1:142,2))
pos <- as.factor(c(rep("cen", N),rep("per", N)))
df <- data.frame(cbind(dat, pos = pos, stage = stage, plot = plot, subplot = subplot))
str(df)
### visualize data:
stripplot(jitter(p,10) ~ pos | plot, data = df, groups = subplot,
strip = strip.custom(strip.names = c(F,T)),
ylab="p",
layout=c(12,4),
type = c("p", "a"),col=1,cex=0.5,
scales = list(y = list(cex=0.5),
x = list(rot=90,cex=0.6,labels=c("Centers","Periphery"))),
par.strip.text=list(cex=0.7),
page = function(...) {
ltext(x = 0.39,
y = 0.835,
lab = c("CENTERS vs. PERIPHERY\npanels = plots;\nrows = successional stages:\nA: pioneer, B: early, C: late, D: alpine gr.land; \nlines = paired samples (= subplots) "),
cex = 1,adj=0)
})
gmod <- glmer(cbind(dat$X, dat$n - dat$X) ~ stage * pos + (1|plot/subplot), family = binomial)
# comparisons -
# i want to know whether there are differences between center vs. periphery
# within each stage, and whether this effect differs across
# stages (interactions).
# as i simulated an effect only for centre vs. periphery and this
# effect was simulated
# to be the same across all stages, there should not be any sign.
# interactions:
c1 <- rbind("A: Center vs. Peri. Effect" = c(0,0,0,0,1,0,0,0),
"B: Center vs. Peri. Effect" = c(0,0,0,0,1,1,0,0),
"C: Center vs. Peri. Effect" = c(0,0,0,0,1,0,1,0),
"D: Center vs. Peri. Effect" = c(0,0,0,0,1,0,0,1),
"Center vs. Peri. Effect, A vs. B" = c(0,0,0,0,0,1,0,0),
"Center vs. Peri. Effect, A vs. C" = c(0,0,0,0,0,0,1,0),
"Center vs. Peri. Effect, A vs. D" = c(0,0,0,0,0,0,0,1),
"Center vs. Peri. Effect, B vs. C" = c(0,0,0,0,0,-1,1,0),
"Center vs. Peri. Effect, B vs. D" = c(0,0,0,0,0,-1,0,1),
"Center vs. Peri. Effect, C vs. D" = c(0,0,0,0,0,0,-1,1))
summary(glht(gmod, c1))
###########################################################################
# EDIT:
# for investigation of contrasts you can use this functions, i.e.:
stage <- relevel(stage, "B")
model.matrix(~ stage * pos, contrasts = list(stage = "contr.treatment", pos = "contr.treatment"))
To cite package ‘lme4’ in publications use:
Douglas Bates, Martin Maechler and Ben Bolker (2011). lme4: Linear mixed-effects models using S4 classes. R package version 0.999375-39. http://CRAN.R-project.org/package=lme4
Please cite the multcomp package by the following reference:
Torsten Hothorn, Frank Bretz and Peter Westfall (2008). Simultaneous Inference in General Parametric Models. Biometrical Journal 50(3), 346--363.
To cite the lattice package in publications use:
Sarkar, Deepayan (2008) Lattice: Multivariate Data Visualization with R. Springer, New York. ISBN 978-0-387-75968-5
Drawing Grids in R
Here's an example of how to draw a grid in R and how to fill it.
I did use the grid-package and its functions for displaying species cover values at squares of a recording frame...
library(grid)
dat <- data.frame(x = rep(seq(0, 0.8, 1/5), 5),
y = rep(seq(0, 0.8, 1/5), each = 5),
val = rnorm(25, 20, 5))
# making relative values (%) to be used for color-gradiation in plot
dat$rel <- 100 * dat$val / max(dat$val)
# creating grey-tones relative to val -
# maximum greytone is relative to the val-maximum
# i use the reciprocal to get darker tones for higher values:
dat$col<-paste("grey", 100 - round(dat$rel, 0), sep = "")
# opening the graphic device and
# setting up a viewport with borders:
grid.newpage()
vp1 <- viewport(x = 0.1, y = 0.1, w = 0.8, h = 0.8,
just = c("left", "bottom"), name = "vp1")
# plotting rectangles using x/y positions
grid.rect(x=dat$x,y=dat$y,height=1/5,width=1/5,hjust=0,vjust=0,vp=vp1,
gp=gpar(col=1, fill=as.character(dat$col)))
Read more »
I did use the grid-package and its functions for displaying species cover values at squares of a recording frame...
library(grid)
dat <- data.frame(x = rep(seq(0, 0.8, 1/5), 5),
y = rep(seq(0, 0.8, 1/5), each = 5),
val = rnorm(25, 20, 5))
# making relative values (%) to be used for color-gradiation in plot
dat$rel <- 100 * dat$val / max(dat$val)
# creating grey-tones relative to val -
# maximum greytone is relative to the val-maximum
# i use the reciprocal to get darker tones for higher values:
dat$col<-paste("grey", 100 - round(dat$rel, 0), sep = "")
# opening the graphic device and
# setting up a viewport with borders:
grid.newpage()
vp1 <- viewport(x = 0.1, y = 0.1, w = 0.8, h = 0.8,
just = c("left", "bottom"), name = "vp1")
# plotting rectangles using x/y positions
grid.rect(x=dat$x,y=dat$y,height=1/5,width=1/5,hjust=0,vjust=0,vp=vp1,
gp=gpar(col=1, fill=as.character(dat$col)))
Test Difference between Two Proportions & Plot Confidence Intervals
..an illustrative example for testing proportions and presenting the results.
the data: number of indigenous and alien plant species with and without vegetative reproduction (N = 3399, mid-european species, data-courtesy: BiolFlor) . Hypothesis: The proportion of species with vegetative reproduction is different between alien and indigenuos plant species.
result: the prop. of plants with veg. reproduction is sign. lower for alien compared to indigenous plant species. this is simply due to the large number of agricultural weeds and contaminants within alien species - these species almost always reproduce by seeds.
Read more »
the data: number of indigenous and alien plant species with and without vegetative reproduction (N = 3399, mid-european species, data-courtesy: BiolFlor) . Hypothesis: The proportion of species with vegetative reproduction is different between alien and indigenuos plant species.
result: the prop. of plants with veg. reproduction is sign. lower for alien compared to indigenous plant species. this is simply due to the large number of agricultural weeds and contaminants within alien species - these species almost always reproduce by seeds.
## data:
dat <- data.frame(list(structure(list(flstat = structure(c(2L, 1L, 2L, 1L),
.Label = c("allo", "auto"), class = "factor"),
reprod = structure(c(1L, 1L, 2L, 2L),
.Label = c("non-veg", "veg"), class = "factor"),
X = c(872L, 423L, 1872L, 232L)),
.Names = c("flstat", "reprod", "X"),
class = "data.frame", row.names = c(NA, -4L))))
## proportion of species with vegetative reproduction
p_allo <- dat$X[4] / (dat$X[2] + dat$X[4])
p_auto <- dat$X[3] / (dat$X[1] + dat$X[3])
p_allo
p_auto
## restructure data for glm:
dat1 <- dat[rep(1:4, dat$X), 1:2]
head(dat1)
dat1$inc <- ifelse(dat1$reprod == "non-veg", 0, 1)
## glm:
summary(gmod <- glm(inc ~ flstat, data = dat1, family = binomial))
## intercept = logit(p_allo):
print(est_p_allo <- plogis(gmod$coef[1]))
## intercept + b = logit(p_allo+p_auto):
print(est_p_auto <- plogis(gmod$coef[1] + gmod$coef[2]))
## alternatively test difference in two proportions with prop.test():
ptest_diff <- prop.test(x = c(dat$X[1], dat$X[2]),
n = c(dat$X[1] + dat$X[3], dat$X[2] + dat$X[4]))
## only for one proportion prop.test gives you the confidence
## intervals of p.
## (you could also extract the glm-standard errors and calculate
## the conf.int. for this purpose..):
ptest_auto <- prop.test(x = dat$X[3], n = dat$X[1] + dat$X[3])
ptest_allo <- prop.test(x = dat$X[4], n = dat$X[2] + dat$X[4])
## plot with confidence intervals from prop.test
## (see methods in ?prop.test):
## coordinates for plotting confidence interval bars:
y0_al <- ptest_allo$conf[1]
y1_al <- ptest_allo$conf[2]
y0_au <- ptest_auto$conf[1]
y1_au <- ptest_auto$conf[2]
library(grid)
library(lattice)
## panel function for suppressing tck at top and right side,
## drawing bar with confidence interval,
## plotting glm-estimates (the crosses)
mpanel = function(...) {grid.segments(x0 = c(0.2725, 1 - 0.2725),
x1 = c(0.2725, 1 - 0.2725),
y0 = c(y0_al, y0_au),
y1 = c(y1_al, y1_au))
panel.points(x = c(0.8, 2.2),
y = c(est_p_allo, est_p_auto), pch = 4)
panel.abline(h = c(p_allo, p_auto), lty = 15,
col = "grey70")
panel.text(x = 1.5, y = 0.9, cex = 1.2,
"Species With\nVegetative Reproduction");
panel.xyplot(...)}
xyplot(c(p_allo, p_auto) ~ as.factor(c("Alien", "Indigenous")), type = "b",
ylab = "Prop. +/- CIs\nX = GLM-Estimates",
xlab = "", ylim = c(0, 1),
panel = mpanel, pch = 16,
scales = list(alternating = 1, tck = c(1, 0)))
Custom Labels for Ordination Diagram
Here is how you do custom labels, hull, spider in a vegan ordination diagram:
library(vegan)
### data on 35 species of Oribatid mites
### data description at: http://cc.oulu.fi/~jarioksa/softhelp/vegan/html/mite.html
data(mite)
### ...and environmental variables
data(mite.env)
### the factor which you wish to use for labeling the displayed sites
### in the ordination diagramm:
fac<-mite.env$Topo
sol<-metaMDS(mite)
windows(9,5)
par(mfrow=c(1,2))
### graph with "spider":
plot(sol,type="n")
points(sol, display = "sites", cex=0.65, select=which(fac=="Hummock"),
pch = 21,col="black", bg="black")
points(sol, display = "sites", cex=0.65, select=which(fac=="Blanket"),
pch = 21,col="black", bg="white")
ordihull(sol,group=fac,show.groups="Hummock")
ordihull(sol,group=fac,show.groups="Blanket",lty=3)
orditorp(sol, dis = "sp", pcex=0,air=0.85,col="grey35",cex=0.8 ,font=3)
### graph with "hull":
plot(sol,type="n")
points(sol, display = "sites", cex=0.65, select=which(fac=="Hummock"),
pch = 21,col="black", bg="black")
points(sol, display = "sites", cex=0.65, select=which(fac=="Blanket"),
pch = 21,col="black", bg="white")
ordispider(sol,group=fac,show.groups="Hummock")
ordispider(sol,group=fac,show.groups="Blanket",lty=3)
orditorp(sol, dis = "sp", pcex=0,air=0.85,col="grey35",cex=0.8 ,font=3)
R package ‘vegan’ citation: Jari Oksanen, F. Guillaume Blanchet, Roeland Kindt, Pierre Legendre,
R. B. O'Hara, Gavin L. Simpson, Peter Solymos, M. Henry H. Stevens
and Helene Wagner (2011). vegan: Community Ecology Package. R package
version 1.17-9. http://CRAN.R-project.org/package=vegan
See also:
Use of Classification Trees to Investigate Traits of Invasive Species
Which traits make an alien species invasive?
Due to what traits an alien species becomes established in a foreign flora?
This kind of questions could be analysed by the use of recursive partitioning and classification trees..
(the below example also includes some useful data manipulation techniques)...
data-download*
*data is courtesy of BiolFlor:
Klotz, S., Kühn, I. & Durka, W. [Hrsg.] (2002): BIOLFLOR - Eine Datenbank zu biologisch-ökologischen Merkmalen der Gefäßpflanzen in Deutschland. - Schriftenreihe für Vegetationskunde 38. Bonn: Bundesamt für Naturschutz.
To cite package ‘partykit’ in publications use:
Torsten Hothorn and Achim Zeileis (2011). partykit: A Toolkit for Recursive
Partytioning. R package version 0.1-0/r179.
http://R-Forge.R-project.org/projects/partykit/
Read more »
Due to what traits an alien species becomes established in a foreign flora?
This kind of questions could be analysed by the use of recursive partitioning and classification trees..
(the below example also includes some useful data manipulation techniques)...
data-download*
*data is courtesy of BiolFlor:
Klotz, S., Kühn, I. & Durka, W. [Hrsg.] (2002): BIOLFLOR - Eine Datenbank zu biologisch-ökologischen Merkmalen der Gefäßpflanzen in Deutschland. - Schriftenreihe für Vegetationskunde 38. Bonn: Bundesamt für Naturschutz.
library(coin)
library(zoo)
library(modeltools)
library(sandwich)
library(strucchange)
library(vcd)
library(colorspace)
library(Formula)
library(partykit)
## (!)note: package party should not be loaded at the same time as partykit
## read data, mind to change the path:
dat <- read.csv("E:\\R\\Data\\Alien_Plant_Traits.csv",
sep = ";")
## delete unneeded variable:
dat$Repr_Literatur <- NULL
dat$Diasporen..bzw..Germinulentyp <- NULL
dat$Heteromorphietyp <- NULL
dat$Ausprägung <- NULL
dat$Status <- NULL
## source data uses "," as decimal seperator, as R uses
## "." we will change this appropriately:
dat$Länge_MW_mm <- as.numeric(sub(",", ".", dat$Länge_MW_mm))
## explore dataset:
head(dat[,1:10])
str(dat)
# Name : species names
# Status : floristic status; "Neophyt" = alien species, which is the whole set
# Einführung : mode of introduction
# Einbürg_grad_Max : level of naturalization
# Lebensform : lifeform
# Ausprägung : manifestation of lifeform, "immmer" = always, "manchmal" = sometimes
# Blattanatomie : leaf anatomy
# Blühdauer_Mon : flowering duration
# N_Blühphasen : number of flowering phases
# Länge_MW_mm : length of diaspore / germinule, "MW_mm" = mean value in milimeters
# Länge_Bezug : "Germinule" = length given is that of germinule,
# "Diaspore" = that of diaspore
# Länge_Bezug_Einschr : restricted knowledge, maybe erroneus data, "_FALSCH" = false, "_WAHR" = true
# Reproduktionstyp : reproduction type, "Samen" = seed, "vegetative" = clonal proliferation,
# "Samen/Sporen" = both
## ad diaspores / germinules:
## there are 2 cases - (1) a diaspore (= unit of propagation)
## is at the same time the germinule (= unit of seedling germination).
## this is the case when single seeds are propagated.
## (2) the diaspores disintegrates into many germinules.
## this is the cases when fruits or parts of them
## which contain many seeds are propagated.
## length measurments ("Länge_MW_mm") were taken for either
## germinules or diaspores or both (see "Länge_Bezug") and sometimes
## data may be erronous as indicated by the variable "Länge_Bezug_Einschr"
## what i want is the surely correct length-values of each germinules and
## diaspores for each species. therefore i create new variables:
dat1 <-
reshape(direction = "wide", idvar = "Name",
timevar = "Länge_Bezug_Einschr",
v.names = "Länge_MW_mm",
drop = "Länge_Bezug",
data = dat)
## there's a warning that tells me i aggregated several variables that
## actually were varying - i solve this by pasting those variables
## into one character string per each species
## (beforehand i have to convert them to character vectors)
dat$Einführung <- as.character(dat$Einführung)
dat$Lebensform <- as.character(dat$Lebensform)
dat$Blattanatomie <- as.character(dat$Blattanatomie)
str(dat)
## make function for pasting multiple character strings of each species
## i want only unique values to be pasted, seperated by a comma:
my.paste <- function(x) {paste(unique(x), collapse = ", ")}
test.vector <- c("a", "a", "b", "c")
my.paste(test.vector)
print(dat2 <-
aggregate(cbind(dat$Einführung, dat$Lebensform, dat$Blattanatomie) ~
dat$Name, FUN = my.paste))
## reset column names:
colnames(dat2) <- c("Name", "Einführung", "Lebensform", "Blattanatomie")
head(dat2)
## re-bind dataframes, variables with varying entries per species
## falsely aggregated in dat1 will be discarded and instead the
## pasted character strings of dat2, containing all info will be used.
## also variables present in both sub-datasets will be discarded:
head(dat2)
dat3 <- data.frame(dat1[, - which(names(dat1)%in%
c("Einführung", "Lebensform", "Blattanatomie"))],
dat2)
head(dat3)
## check for consistency (should be 340 species):
## Name-variables of the two sub-datasets should match
head(dat3)
dim(dat3)
dat3$Name == dat3$Name.1
## now i will choose one of the length measurements in the
## dataset - actually i'm interested in propagation (shorter/lighter propagules
## will be distributed easierly than larger/heavy ones) - that said i want
## diaspore weights but i don't have the data for each species.
## as an escape i will use the largest value within the different variables.
## the logic behind this would be that if diaspore = germinule
## the lengths will be the same and a germinule as a part of a diaspore
## will never be longer.
## by choosing the largest value i thus only use the germinule's value
## if the diaspore's value does not exist. this is seldomly the case and the
## length class will very likely still be the same as it would be for the
## diaspore of that plant, if i had the data
## (subsequently i will classify lengths):
dat3$Length_Diasp_new <- rep(NA, nrow(dat3))
dat3[is.na(dat3)] <- 0
for(i in 1:nrow(dat3)) {dat3$Length_Diasp_new[i] <- max(dat3[i, c(6:9)])}
## classify by cut-function:
dat3$Length_Class <- as.ordered(cut(dat3$Length_Diasp_new, c(0, 2, 5, Inf), labels = FALSE))
## i have to convert some character strings to factors
str(dat3)
dat3$Einführung <- as.factor(dat3$Einführung)
dat3$Lebensform <- as.factor(dat3$Lebensform)
dat3$Blattanatomie <- as.factor(dat3$Blattanatomie)
str(dat3)
## number if factor levels is too high for some variables -
## good results will rather be yielded
## if there are not too many levels:
levels(dat3$Lebensform)
## (1) makrophanerophytes will be "Tree"
## (2) chamaephyts, hemiphanerophyts, nanophanerophyts &
## pseudophanerophyts will be "Shrub"
## (3) therophytes will be "Terr_Herbs_ann" (annual herbs)
## (4) geophytes and hemikryptophytes will be "Terr_Herb_per" (perennial herbs)
## (5) hydrophyts will be "Hydr_Herb"
## sometimes the classification in the original data is unclear -
## i will assign distinct lifeforms following the subsequent rules:
## "Chamaephyt, Therophyt" --> "Terr_Herb_ann"
## "Hemikryptophyt, Therophyt" --> "Terr_Herb_ann"
## "Geophyt, Hemikryptophyt" --> "Terr_Herb_per"
## "Hydrophyt, Geophyt" --> "Hydr_Herb"
## "Hydrophyt, Hemikryptophyt" --> "Hydr_Herb"
## "Makrophanerophyt, Nanophanerophyt" --> "Tree"
dat3$Lifeform <- rep(NA, nrow(dat3))
dat3$Lifeform[dat3$Lebensform == "Makrophanerophyt"] <- "Tree"
dat3$Lifeform[dat3$Lebensform == "Pseudophanerophyt"|
dat3$Lebensform == "Nanophanerophyt"|
dat3$Lebensform == "Hemiphanerophyt"|
dat3$Lebensform == "Chamaephyt"] <- "Scrub"
dat3$Lifeform[dat3$Lebensform == "Therophyt"] <- "Terr_Herb_ann"
dat3$Lifeform[dat3$Lebensform == "Geophyt"|
dat3$Lebensform == "Hemikryptophyt"] <- "Terr_Herb_per"
dat3$Lifeform[dat3$Lebensform == "Hydrophyt"] <- "Hydr_Herb"
dat3$Lifeform[dat3$Lebensform == "Chamaephyt, Therophyt"] <- "Terr_Herb_ann"
dat3$Lifeform[dat3$Lebensform == "Hemikryptophyt, Therophyt"] <- "Terr_Herb_ann"
dat3$Lifeform[dat3$Lebensform == "Geophyt, Hemikryptophyt"] <- "Terr_Herb_per"
dat3$Lifeform[dat3$Lebensform == "Hydrophyt, Geophyt"] <- "Hydr_Herb"
dat3$Lifeform[dat3$Lebensform == "Hydrophyt, Hemikryptophyt"] <- "Hydr_Herb"
dat3$Lifeform[dat3$Lebensform == "Makrophanerophyt, Nanophanerophyt"] <- "Tree"
## convert to factor:
dat3$Lifeform <- as.factor(dat3$Lifeform)
str(dat3)
levels(dat3$Einführung)
## "Begleiter"; "Begleiter, Verwilderte Nutzpflanze";
## "Begleiter, Verwilderte Zierpflanze"; "Transportbegleiter";
## "Saatgutbegleiter"; "Saatgutbegleiter, Verwilderte Nutzpflanze";
## "Saatgutbegleiter, Verwilderte Zierpflanze" <-- "accompanying"
## "spontan"; "unbekannt"; "spontan, Verwilderte Nutzpflanze" <-- "spontaneous"
## "Verwilderte Nutzpflanze"; "Verwilderte Nutzpflanze, Verwilderte Zierpflanze";
## "Verwilderte Zierpflanze" <-- "cultivated"
dat3$Introduction <- rep(NA, nrow(dat3))
dat3$Introduction[dat3$Einführung == "Begleiter"|
dat3$Einführung == "Begleiter, Verwilderte Nutzpflanze"|
dat3$Einführung == "Begleiter, Verwilderte Zierpflanze"|
dat3$Einführung == "Transportbegleiter"|
dat3$Einführung == "Saatgutbegleiter"|
dat3$Einführung == "Saatgutbegleiter, Verwilderte Nutzpflanze"|
dat3$Einführung == "Saatgutbegleiter, Verwilderte Zierpflanze"] <- "accompanying"
dat3$Introduction[dat3$Einführung == "spontan"|
dat3$Einführung == "unbekannt"|
dat3$Einführung == "spontan, Verwilderte Nutzpflanze"] <- "spontaneous"
dat3$Introduction[dat3$Einführung == "Verwilderte Nutzpflanze, Verwilderte Zierpflanze"|
dat3$Einführung == "Verwilderte Nutzpflanze"|
dat3$Einführung == "Verwilderte Zierpflanze"] <- "agric./ornam."
## convert to factor and check:
dat3$Introduction <- as.factor(dat3$Introduction)
str(dat3)
levels(dat3$Blattanatomie)
## leaf-anatomy: i will leaf this one out in the analysis
## as it is partly correlated with lifeforms
levels(dat3$Reproduktionstyp)
## "meist Samen, selten vegetativ" = mostly seed propagation
## "meist vegetativ, selten Samen" = mostly vegetative propagation
## "Samen und vegetativ" = both to same parts
## "Samen/Sporen" = only seeds
## "vegetativ" = only vegetative
## "meist Samen, selten vegetativ"; "Samen/Sporen" <-- "mostly seeds"
## "meist vegetativ, selten Samen"; "vegetativ" <-- "mostly vegetative"
## "Samen und vegetativ" <-- "both equally"
dat3$Reproduction <- rep(NA, nrow(dat3))
dat3$Reproduction[dat3$Reproduktionstyp == "meist Samen, selten vegetativ"|
dat3$Reproduktionstyp == "Samen/Sporen"] <- "mostly seeds"
dat3$Reproduction[dat3$Reproduktionstyp == "meist vegetativ, selten Samen"|
dat3$Reproduktionstyp == "vegetativ"] <- "mostly vegetativ"
dat3$Reproduction[dat3$Reproduktionstyp == "Samen und vegetativ"] <- "both equally"
dat3$Reproduction <- as.factor(dat3$Reproduction)
levels(dat3$Einbürg_grad_Max)
## this will be the dependent (outcome) variable
## i'll also try to use an outcome variable with
## only two levels:
## "Agriophyt" --> "invasive"
## "Epökophyt" & "Ephemerophyt" --> "not invasive"
dat3$Invasivness <- rep(NA, nrow(dat3))
dat3$Invasivness[dat3$Einbürg_grad_Max == "Epökophyt"|
dat3$Einbürg_grad_Max == "Ephemerophyt"] <- "not invasive"
dat3$Invasivness[dat3$Einbürg_grad_Max == "Agriophyt"] <- "invasive"
dat3$Invasivness <- as.factor(dat3$Invasivness)
dat3$Invasivness <- relevel(dat3$Invasivness , ref = "not invasive")
## another approach to this would be to define
## alien taxa that are established (in the sense
## that its population persist independently) and
## not established taxa.
dat3$Establ <- rep(NA, nrow(dat3))
dat3$Establ[dat3$Einbürg_grad_Max == "Epökophyt"|
dat3$Einbürg_grad_Max == "Agriophyt"] <- "establ."
dat3$Establ[dat3$Einbürg_grad_Max == "Ephemerophyt"] <- "not establ."
dat3$Establ <- as.factor(dat3$Establ)
dat3$Establ <- relevel(dat3$Establ, ref = "not establ.")
str(dat3)
print(ct <- ctree(Einbürg_grad_Max ~ Introduction + Lifeform + Length_Class +
Blühdauer_Mon + Reproduction, data = dat3,
control = ctree_control(mincriterion = 0.8, minsplit = 10L,
minbucket = 10L)))
plot(ct, gp = gpar(fontsize = 7))
## the first node divides annula herbs from the rest
## thus it might be more representive to recode lifeforms
## into a lifecycle variable:
dat3$Life_Cycle <- rep(NA, nrow(dat3))
dat3$Life_Cycle[grep("_ann", dat3$Lifeform)] <- "annual"
dat3$Life_Cycle[-grep("_ann", dat3$Lifeform)] <- "perennial"
dat3$Life_Cycle <- as.factor(dat3$Life_Cycle)
## re-run:
print(ct <- ctree(Einbürg_grad_Max ~ Introduction + Life_Cycle + Length_Class +
Blühdauer_Mon + Reproduction, data = dat3,
control = ctree_control(mincriterion = 0.8, minsplit = 10L,
minbucket = 10L)))
plot(ct, gp = gpar(fontsize = 7))
## check predictions:
data.frame(Species = dat3$Name,
Naturalization = dat3$Einbürg_grad_Max, predict(ct),
Correspondence = dat3$Einbürg_grad_Max == predict(ct))
table(dat3$Einbürg_grad_Max == predict(ct))
## interpreting the result:
##
## (1) there is a large probability for agriophytes (= naturalized/invasive)
## to occure in the group of perennial plants which
## exhibit both, vegetative and generative reproduction
##
## (2) ephemerophytes most likely are present if plants are annual
## and plant were introduced intentionally (ornamental, agricultural
## purpose. within annuals the group of plants that made there way
## without intentional help of men are likely to have more potential
## to get established (-> portion of agriophytes and epoekophytes (=
## naturalized/not-invasive) is larger here).
##
## also the other dependent nominal variables, invasivness & establishment
## could be investigated similarly..
To cite package ‘partykit’ in publications use:
Torsten Hothorn and Achim Zeileis (2011). partykit: A Toolkit for Recursive
Partytioning. R package version 0.1-0/r179.
http://R-Forge.R-project.org/projects/partykit/
Subscribe to:
Posts (Atom)








