Возможно ли заставить управляющую последовательность newcommand обрабатывать код sweave?

#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, и он анализирует текст между @! и @; разделители так, как вы хотели бы.

Я надеюсь, что это кому-нибудь пригодится … теперь, чтобы начать с этой домашней работы….