#r #latex #sweave
#r #Латекс #sweave
Вопрос:
Я использую latex для написания домашних заданий. Мне нужно включить в мое назначение как диаграммы, так и код R. Sweave до сих пор хорошо работал у меня, но я хотел бы упростить обычные блоки кода, подобные этому…
begin{rcode}
<<label=sol1, include=FALSE>>=
plot(c(2,3,5,7,11))
@
end{rcode}
begin{figure}[H]
<<fig=TRUE,echo=FALSE>>=
<<sol1>>
@
end{figure}
(Где rcode — это просто пользовательское значение с плавающей точкой … код идет в конце документа, диаграмма неподвижна.)
Итак, что-то вроде этого…
chart{sol1}{plot(c(2,3,4,5,7,11))}
где chart определяется
newcommand{chart}[2]{
begin{rcode}
<<label=#1, include=FALSE>>=
#2
@
end{rcode}
begin{figure}[H]
<<fig=TRUE,echo=FALSE>>=
<<#1>>
@
end{figure}
}
К сожалению, похоже, что sweave получает исходный код до того, как latex обрабатывает newcommand, и поэтому этот подход не работает. Есть ли способ настроить способ обработки исходного кода таким образом, чтобы макросы обрабатывались до того, как sweave увидит исходный код? Или есть лучший подход к такого рода проблемам?
Заранее спасибо за любые предложения..
Комментарии:
1. Нет, но Sweave может создавать управляющие последовательности LaTeX, что решает эту проблему, подходя к ней с прямо противоположного направления. То есть, хотя вы не можете создать R-код из LaTeX, вы можете создать LaTeX из R-кода. Хороший пример см. в решении Дитера.
Ответ №1:
Я надеюсь, что следующее о том, что вы хотели решить проблему курицы / яйца. Я украл его из своего собственного поста в R-list
% ----------------------------------
documentclass{article} %
usepackage{Sweave}
SweaveOpts{echo=FALSE}
newcommandbloodp[3]{
subsection{Patient #1} For patient #1, the mean value of systolic pressure was #2~mmHg, the diastolic pressure was #3~mmHg.
begin{figure}[!htb]%
begin{center}%
includegraphics{histo#1}%
caption{Histogram of systolic blood pressure for patient #1.}%
label{fig:histo#1}%
end{center}%
end{figure}%
clearpage % Better use FloatBarrier here
}
begin{document}
section{Blood Pressure}
<<results=tex>>=
n=100
dt = data.frame(
subj=sample(1:3,n,TRUE),
syst=round(rnorm(n,120,10)),
dia=round(rnorm(n,80,10))
)
# could also use tapply here
for (i in 1:3) {
dt1 = dt[dt$subj==i,]
cat("\bloodp{",i,"}{",
round(mean(dt1$syst)),"}{",
round(mean(dt1$dia)),"}n",sep="")
pdf(paste("histo",i,".pdf",sep=""))
hist(dt1$syst,main="",xlab="Blood pressure")
dev.off() }
@
end{document}
Комментарии:
1. Если я правильно понимаю ваш код, это сработало бы хорошо, если бы у меня были предварительно скомпилированные графики для включения в документ. Я создавал графики непосредственно в latex, поэтому я ищу что-то более оперативное…
2. @jessup: Если вы имеете в виду создание графиков в R фрагментах файла Sweave, это то, что делает этот пост; см.
hist
Команду. Идея в этом ответе действительно мощная; идея состоит в том, чтобы создавать команды R, которые создают нужные вам команды LaTeX, а затем вызывать их из R блоков. Используя эту технику, вы можете упростить свой код почти точно так, как вы хотите, за исключением того, что упрощение выполняется во всех блоках R, а не во всех блоках LaTeX.3. О, да. Я ошибся. Это отличный подход. Спасибо вам обоим.
Ответ №2:
Я написал скрипт на python, который, кажется, работает достаточно хорошо … Я УВЕРЕН, что есть кто-нибудь, кто может сказать мне, как сделать все это с помощью одной строки PERL 😉 пожалуйста, дайте мне знать.
floatstyle{ruled}
newfloat{rcode}{b}{R}
floatname{rcode}{R Code}
floatstyle{boxed}
newfloat{rout}{b}{R}
floatname{rout}{R Output}
begin{document}
!@plot A very informative plot
a <- c(2,3,5,7)
plot(a)
@;
!@print Some output
a<-c(2,5,5,7)
print(a)
@;
end{document}
Вот скрипт python, который я вставил в ~/Library/TexShop/Scripts/sweave_macros.py
import sys
if __name__ == "__main__":
old = open(sys.argv[1])
new = open(sys.argv[2],'w')
old_lines = old.readlines()
i = 0
out_file = ""
while i < len(old_lines):
if old_lines[i].lstrip()[0:2] == '!@':
line = old_lines[i]
obj = line[2:line.index(' ')].strip()
label = line[line.index(' ') 1:line.index('n')].strip()
obj_end = i
while old_lines[obj_end].strip() != "@;":
obj_end = 1
out_file = "\begin{rcode}[p]n"
out_file = "<<label=" label ", include=FALSE>>=n"
i = 1
while i < obj_end:
out_file = old_lines[i]
i = 1
out_file = "@n"
out_file = "\caption{" label "}n"
out_file = "\end{rcode}n"
if obj == "plot":
out_file = "\begin{figure}[H]setkeys{Gin}{width=3.5in}n"
out_file = "<<fig=TRUE, echo=FALSE>>=n"
out_file = "<<" label ">>"
out_file = "n@n"
out_file = "\caption{" label "}n"
out_file = "\end{figure}"
if obj == "print":
out_file = "\begin{rout}[H]n"
out_file = "<<echo=FALSE>>=n"
out_file = "<<" label ">>"
out_file = "n@n"
out_file = "\caption{" label "}n"
out_file = "\end{rout}"
i = 1
else:
out_file = old_lines[i]
i = 1
new.write(out_file)
new.close()
Наконец, я обновил движок Sweave, используемый TeXShop, найдите в ~/Library /TeXShop/Engines/Sweave.engine:
#!/bin/bash
export SWEAVE_STYLEPATH_DEFAULT="TRUE"
export PATH=$PATH:/usr/texbin:/usr/local/bin
python ~/Library/TexShop/Scripts/sweave_macros.py "$1" "fin_$1"
R CMD Sweave "fin_$1"
pdflatex "fin_${1%.*}"
Итак, теперь всякий раз, когда я запускаю движок sweave из TeXShop, сначала вызывается скрипт python, и он анализирует текст между @! и @; разделители так, как вы хотели бы.
Я надеюсь, что это кому-нибудь пригодится … теперь, чтобы начать с этой домашней работы….