Merci à tous deux pour vos réponses
Stéphane : Je suis sous GNU/Linux où x11() est l'équivalent de windows() ou quartz() je pense. Et j'utilise préférentielelment dev.new() qui est équivalent et indépendant de la plateforme. Le problème est que knitr ne donne aucun graphique quand on utilise ces commandes.
Par exemple dans le code suivant : le graphique 1 devrait apparaître deux fois : une fois normalement et une fois en plus petit or seul le premier apparaît :
Code : Tout sélectionner
#' #Analyse simple
#+ datagen, echo=FALSE, results = 'markup'
# On génère qq données
d <- data.frame(var1 = rnorm(100), var2 = rnorm(100), var3 = rnorm(100), var4 = rnorm(100))
d$y <- d$var1 + 2*d$var3 + rnorm(100)
mod <- lm(y ~ var1, data=d)
# plot des données et du modèle
plot(y~var1, data=d)
abline(mod)
# la même chose en définissant la taille de la fenêtre --> pas imprimé par knitr
dev.new(height = 4, width = 4)
plot(y~var1, data=d)
abline(mod)
dev.off()
# résultats du modèle linéaire
summary (mod)
# Plots de diagnostique du modèle
par(mfrow = c(2,2))
plot(mod)
Si ce script s'appelle "loop.R" on execute les comandes suivante pour obtenir le rapport :
Code : Tout sélectionner
library(knitr)
spin(hair = "loop.R" , knit = TRUE)
knit2html("loop.Rmd")
Dicko : ta solution est probablement ce qu'on peut faire de mieux en restant simple mais çà ne me satisfait pas pleinement (je sais, je suis difficile ;-) ). D'abord parce que çà m'oblige à changer mon script R spécialement pour le rapport (sans dev.new, dev.print ou une autre commande permettant de spécifier la taille de la fenêtre etc...) or l'avantage de spin() est, je trouve, justement d'éviter cela. J'aurais préféré une solution par exemple avec par(din= c(4,5)) qui me permettrait d'avoir le même code à la fois pour l'affichage à l'écran et le rapport. Mais je crains que je n'y échapperai pas.
L'autre problème est qu'on est obligé de fixer la taille des graphiques pour un "code chunk". Or ce type d'outils de reporting est particulièrement utile pour répéter la même analyse sur plusieurs objets avec une boucle. Et on voudrait pouvoir spécifier des tailles différentes pour les différents graphiques au sein de la boucle.
Par exemple pour les données ci-dessus on voudrait faire 5 régressions de Y en fonction de chaque variable (exemple un peu stupide j'en conviens...) et de sortir pour chaque un graphique des données avec une taille donnée puis les résultats de l'analyse suivi des graphiques diagnostiques des modèles qui auraient une taille différente :
Code : Tout sélectionner
#+ datagen, echo=FALSE, results = 'markup', warning = FALSE, error = FALSE, message = FALSE
# On génère qq données
d <- data.frame(var1 = rnorm(100), var2 = rnorm(100), var3 = rnorm(100), var4 = rnorm(100))
d$y <- d$var1 + 2*d$var3 + rnorm(100)
## # Analyses dans une boucle
#+ loop1, echo=FALSE, results = 'markup', fig.width= 6, fig.height = 6
models <- as.list(vector(length = nrow(d)-1)) # liste vide pour stocker les modèles
mod <- lm(y ~ var1, data=d)
for(i in 1:3) {
models[[i]] <- update(mod, .~ d[,i])
# plot des données et du modèle
print(colnames(d)[i])
par(mfrow = c(1,1))
plot(d$y ~ d[,i], main = colnames(d)[i])
abline (models[[i]])
# resultats du modèle linéaire
print(summary(models[[i]]))
# plots de diagnostique
par(mfrow = c(2,2))
plot(models[[i]])
}
Si on passe ce script par spin() et knit2html on se rend compte qu'il y a en plus un bug d'exécution dans les boucles. L'ordre des graphiques et des sorties de modèles n'est pas le bon. Apparemment le bug est connu mais je n'ai pas vu de solution :
https://github.com/hadley/evaluate/issues/14J'espérais m'en sortir en utilisant une solution similaire à ce qu'on aurait fait avec Sweave (d'après le document de Jean Lobry) et results = 'tex' qui devient results = 'asis' dans knitr (en sauvant d'abord les graphiques sur le disque). Le problème c'est que les graphiques s'affichent en taille énorme et je ne vois pas comment on peut changer la taille des graphiques dans le langage markdown (ce serait impossible ???). On ne peut toujours pas utiliser dev.new/dev.print que j'ai du commenter pour que le code s'exécute correctement.
Code : Tout sélectionner
#' # Analyses dans une boucle avec results = 'asis' et stockage des graphiques sur le disque
#+ loop3, echo=FALSE, results = 'markup', warning = FALSE, error = FALSE, message = FALSE
d <- data.frame(var1 = rnorm(100), var2 = rnorm(100), var3 = rnorm(100), var4 = rnorm(100))
d$y <- d$var1 + 2*d$var3 + rnorm(100)
mod <- lm(y ~ var1, data=d)
dir.create(file.path(getwd(), "mygraphs")) # répertoire pour stocker les graphiques
models <- as.list(vector(length = nrow(d)-1)) # liste vide pour stocker les modèles
for(i in 1:3) {
models[[i]] <- update(mod, .~ d[,i])
# graphique des données et du modèle
# dev.new(width = 7/cm(1), height = 7/cm(1))
png(paste("mygraphs/",colnames(d)[i],".png",sep=""),width= 7/cm(1), height= 7/cm(1), units="in", res = 300)
par(mfrow = c(1,1))
plot(d$y ~ d[,i], main = colnames(d)[i])
abline (models[[i]])
# dev.print(device = png, filename = paste("mygraphs/",colnames(d)[i],".png",sep=""),width= 7/cm(1), height= 7/cm(1), units="in", res = 300)
dev.off()
# graphiques diagnostiques
# dev.new(width = 15/cm(1), height = 15/cm(1))
png(filename = paste("mygraphs/diag",colnames(d)[i],".png",sep=""),width= 15/cm(1), height= 15/cm(1), units="in", res = 300)
par(mfrow = c(2,2))
plot(models[[i]])
# dev.print(device = png, filename = paste("mygraphs/diag",colnames(d)[i],".png",sep=""),width= 15/cm(1), height= 15/cm(1), units="in", res = 300)
dev.off()
}
# On imprime ce qu'on veut voir dans le rapport
#+ pri, echo=FALSE, results = 'asis', warning = FALSE, error = FALSE, message = FALSE
for(i in 1:3) {
#Titre
cat(paste("\n##", colnames(d)[i]), "\n")
# graphique 1
cat(paste("![aa](mygraphs/",colnames(d)[i],".png)",sep=""))
# résultats de la régression
cat("\n\n```\n\n")
print(summary(models[[i]]))
cat("\n\n```\n\n")
# graphique 2
cat(paste("![bb](mygraphs/diag",colnames(d)[i],".png)",sep=""))
}
Finalement çà fonctionne plus ou moins en utilisant directement du HTML et en spécifiant WIDTH='n%' dans les balises images. Mais çà deviens fort compliqué et plus tellement différent de solutions comme R2HTML ou même d'utiliser cat(file =):
Code : Tout sélectionner
#' <h1>Analyses dans une boucle avec results = 'asis' et stockage des graphiques sur le disque</h1>
#+ loop3, echo=FALSE, results = 'markup', warning = FALSE, error = FALSE, message = FALSE
d <- data.frame(var1 = rnorm(100), var2 = rnorm(100), var3 = rnorm(100), var4 = rnorm(100))
d$y <- d$var1 + 2*d$var3 + rnorm(100)
mod <- lm(y ~ var1, data=d)
dir.create(file.path(getwd(), "mygraphs")) # répertoire pour stocker les graphiques
models <- as.list(vector(length = nrow(d)-1)) # liste vide pour stocker les modèles
for(i in 1:3) {
models[[i]] <- update(mod, .~ d[,i])
# graphique des données et du modèle
# dev.new(width = 7/cm(1), height = 7/cm(1))
png(paste("mygraphs/",colnames(d)[i],".png",sep=""),width= 7/cm(1), height= 7/cm(1), units="in", res = 300)
par(mfrow = c(1,1))
plot(d$y ~ d[,i], main = colnames(d)[i])
abline (models[[i]])
# dev.print(device = png, filename = paste("mygraphs/",colnames(d)[i],".png",sep=""),width= 7/cm(1), height= 7/cm(1), units="in", res = 300)
dev.off()
# graphiques diagnostiques
# dev.new(width = 15/cm(1), height = 15/cm(1))
png(filename = paste("mygraphs/diag",colnames(d)[i],".png",sep=""),width= 15/cm(1), height= 15/cm(1), units="in", res = 300)
par(mfrow = c(2,2))
plot(models[[i]])
# dev.print(device = png, filename = paste("mygraphs/diag",colnames(d)[i],".png",sep=""),width= 15/cm(1), height= 15/cm(1), units="in", res = 300)
dev.off()
}
#+ printhtml, echo=FALSE, results = 'asis', warning = FALSE, error = FALSE, message = FALSE
for(i in 1:3) {
#Titre
cat(paste("\n<h2>", colnames(d)[i]), "</h2>\n")
# graphique 1
cat(paste("\n<p><img src=\"",getwd(), "/mygraphs/",colnames(d)[i],".png\" WIDTH=\"35%\" /> </p>",sep=""))
# résultats de la régression
cat("\n<pre><code> \n")
print(summary(models[[i]]))
cat("\n</code></pre>\n")
# graphique 2
cat(paste("\n<p><img src=\"",getwd(), "/mygraphs/diag",colnames(d)[i],".png\" WIDTH=\"60%\" /> </p>",sep=""))
}
Si ce script s'appelle "loop_for_html.R" on doit exécuter les commandes suivantes pour obtenir le rapport :
Code : Tout sélectionner
library(knitr)
spin(hair = "loop_for_html.R" , knit = TRUE, format = c("Rhtml"))
knit2html("loop_for_html.Rhtml",fragment.only=FALSE)
Si quelqu'un à une solution plus simple, je suis preneur.
Dans l'état actuel il me semble que knitr n'est utilisable que pour les rapports les plus simples (et sans graphiques dans des boucles en tous cas ). Ce qui est bien dommage...