datatool: 파일에서 테이블을 로드하고 회전 여부를 결정한 다음 사전 정의된 헤더를 적용하는 방법

datatool: 파일에서 테이블을 로드하고 회전 여부를 결정한 다음 사전 정의된 헤더를 적용하는 방법

에 대한 후속 질문입니다.내 이전 것.

이번 경우에는 다음 두 가지 경우를 다루고 싶습니다.

첫 번째, 열과 행 머리글을 직접 적용하면서 테이블을 그대로 로드합니다.

두번째, 테이블을 로드하고 회전한 다음 나만의 열 및 행 헤더를 적용합니다.

위에서 언급한 두 경우 모두 아래와 같이 서로 다른 두 가지 유형의 데이터베이스가 처리됩니다.

\documentclass{article}
\usepackage{datatool,filecontents,booktabs}

% 1st dataset
\begin{filecontents*}{data1.csv}
            ,   col1  , col2  , col3
    row1    ,   11    , 12    , 13
    row2    ,   21    , 22    , 23
\end{filecontents*}

% 2nd dataset
\begin{filecontents*}{data2.csv}
    11  , 12 , 13
    21  , 22 , 23
\end{filecontents*}

\begin{document}

\section{First case: without rotation}

The desired output for both datasets should be

\begin{table}[h]
    \centering
    \caption{without rotation}
    \begin{tabular}{@{}lccc@{}}
        \toprule
        & First Column  & Second Column & Third Column\\
        \midrule
        First Row   &   11  &   12  & 13 \\ 
        \midrule 
        Second Row  &   21  &   22  & 23 \\
        \bottomrule
    \end{tabular}
\end{table}

\section{Second case: with rotation}

The desired output for both datasets should be

\begin{table}[h]
    \centering
    \caption{with rotation}
    \begin{tabular}{@{}lcc@{}}
        \toprule
                    & First Column  & Second Column\\
        \midrule
        First Row   &   21  &   11 \\ 
        \midrule 
        Second Row  &   22  &   12 \\
        \midrule 
        Third Row   &   23  &   13 \\
        \bottomrule
    \end{tabular}
\end{table}
\end{document}

여기에 이미지 설명을 입력하세요

답변1

두 데이터베이스에 동일한 키가 할당되었는지 확인하는 것이 가장 좋습니다( keys의 옵션을 통해 \DTLloaddb). 이는 두 데이터베이스의 열 인덱스가 다르더라도 키를 사용하여 두 데이터베이스에서 동일한 열을 참조할 수 있음을 의미합니다.

\DTLloaddb[keys={rowheader,col1,col2,col3}]{database1}{database1.csv}
\DTLloaddb[noheader,keys={col1,col2,col3}]{database2}{database2.csv}

다음 키를 사용하여 두 데이터베이스 모두에 대해 열 헤더를 설정할 수 있습니다.

\newcommand{\setdatabaseheaders}[1]{%
  \DTLsetheader{#1}{col1}{First Column}%
  \DTLsetheader{#1}{col2}{Second Column}%
  \DTLsetheader{#1}{col3}{Third Column}%
}

\setdatabaseheaders{database1}
\setdatabaseheaders{database2}

그러나 열 헤더가 모든 테이블에서 공유되는 경우에는 etoolbox\csdef명령을 사용하여 액세스하기 쉬운 방식으로 저장하는 것이 더 간단합니다.

\csdef{columnheader1}{First Column}
\csdef{columnheader2}{Second Column}
\csdef{columnheader3}{Third Column}

행 헤더에 대한 개념은 없지만 datatool유사한 방식으로 행 인덱스를 기반으로 일부를 제공하는 것은 충분히 쉽습니다.

\csdef{rowheader1}{First Row}
\csdef{rowheader2}{Second Row}

데이터를 표시할 때 로 식별된 열은 rowheader무시되어야 합니다. 이 열의 존재는 로 확인할 수 있습니다 \DTLifhaskey. 데이터 표시를 위한 사용자 정의 명령은 다음 명령을 참조하여 행 머리글을 삽입할 수 있습니다.\csname rowheaderidx\endcsname(또는\csuse{rowheaderidx}) 각 행의 시작 부분에. 열 머리글도 마찬가지입니다.

MWE 완료:

\documentclass{article}

\usepackage{booktabs}
\usepackage{datatool}

% Case 1
\begin{filecontents*}{database1.csv}
            ,col1   , col2  , col3
    row1    , 11    , 12    , 13
    row2    , 21    , 22    , 23
\end{filecontents*}

% Case 2
\begin{filecontents*}{database2.csv}
    11  , 12 , 13
    21  , 22 , 23
\end{filecontents*}

\DTLloaddb[keys={rowheader,col1,col2,col3}]{database1}{database1.csv}
\DTLloaddb[noheader,keys={col1,col2,col3}]{database2}{database2.csv}

\csdef{rowheader1}{First Row}
\csdef{rowheader2}{Second Row}
\csdef{rowheader3}{Third Row}

\csdef{columnheader1}{First Column}
\csdef{columnheader2}{Second Column}
\csdef{columnheader3}{Third Column}


\newcount\columnidx
\newcount\rowidx
\newcount\columncount

\newcommand{\displaydatabase}[1]{%
  \DTLifhaskey{#1}{rowheader}%
  {%
    \columncount=\numexpr\DTLcolumncount{#1}-1\relax
    \def\columnoffset{1}%
  }%
  {%
    \columncount=\DTLcolumncount{#1}%
    \def\columnoffset{0}%
  }%
  % construct \begin{tabular} arguments
  \def\columnargs{}%
  \columnidx=0
  \loop
    \advance\columnidx by 1\relax
    \appto\columnargs{c}%
  \ifnum\columnidx<\columncount
  \repeat
  \edef\tabularcontents{\noexpand\begin{tabular}{l\columnargs}}%
  \appto\tabularcontents{\toprule}%
  % add table header
  \dtlforeachkey(\thiskey,\thiscol,\thistype,\thisheader)\in#1\do
  {%
    \ifdefstring{\thiskey}{rowheader}%
    {}%
    {%
      \eappto\tabularcontents{\noexpand& 
        \expandonce{\csname columnheader\number\numexpr\thiscol-\columnoffset\endcsname}}%
    }%
  }%
  % iterate over all rows
  \rowidx=0
  \loop
    \advance\rowidx by 1\relax
  % header
    \eappto\tabularcontents{\noexpand\\\noexpand\midrule 
      \expandonce{\csname rowheader\the\rowidx\endcsname}}%
  % columns
    \dtlforeachkey(\thiskey,\thiscol,\thistype,\thisheader)\in#1\do
    {%
      \ifdefstring{\thiskey}{rowheader}%
      {}%
      {%
        \DTLgetvalue{\thisvalue}{#1}{\rowidx}{\thiscol}%
        \eappto\tabularcontents{\noexpand& \expandonce\thisvalue}%
      }%
    }%
  \ifnum\rowidx<\DTLrowcount{#1}
  \repeat
  \appto\tabularcontents{\\\bottomrule\end{tabular}}%
  \tabularcontents
}

\newcommand{\displayrotateddatabase}[1]{%
  \DTLifhaskey{#1}{rowheader}%
  {%
    \def\columnoffset{1}%
  }%
  {%
    \def\columnoffset{0}%
  }%
  \columncount=\DTLrowcount{#1}%
  % construct \begin{tabular} arguments
  \def\columnargs{}%
  \columnidx=0
  \loop
    \advance\columnidx by 1\relax
    \appto\columnargs{c}%
  \ifnum\columnidx<\columncount
  \repeat
  \edef\tabularcontents{\noexpand\begin{tabular}{l\columnargs}}%
  \appto\tabularcontents{\toprule}%
  % add table header
  \columnidx=0
  \loop
    \advance\columnidx by 1\relax
    \eappto\tabularcontents{\noexpand& 
       \expandonce{\csname columnheader\the\columnidx\endcsname}}%
  \ifnum\columnidx<\columncount
  \repeat
  % iterate through all columns omitting rowheader
  \dtlforeachkey(\thiskey,\thiscol,\thistype,\thisheader)\in#1\do
  {%
    \ifdefstring{\thiskey}{rowheader}%
    {}%
    {%
      % header title
      \eappto\tabularcontents{%
        \noexpand\\\noexpand\midrule
           \expandonce{\csname rowheader\number\numexpr\thiscol-\columnoffset\endcsname}}%
      % row loop in reverse order
      \rowidx=\DTLrowcount{#1}\relax
      \loop
        \DTLgetvalue{\thisvalue}{#1}{\rowidx}{\thiscol}%
        \eappto\tabularcontents{\noexpand&\expandonce\thisvalue}%
        \advance\rowidx by -1\relax
      \ifnum\rowidx>0
      \repeat
    }%
  }%
  \appto\tabularcontents{\\\bottomrule\end{tabular}}%
  \tabularcontents
}

\newcommand{\displaytransposedatabase}[1]{%
  \DTLifhaskey{#1}{rowheader}%
  {%
    \def\columnoffset{1}%
  }%
  {%
    \def\columnoffset{0}%
  }%
  \columncount=\DTLrowcount{#1}%
  % construct \begin{tabular} arguments
  \def\columnargs{}%
  \columnidx=0
  \loop
    \advance\columnidx by 1\relax
    \appto\columnargs{c}%
  \ifnum\columnidx<\columncount
  \repeat
  \edef\tabularcontents{\noexpand\begin{tabular}{l\columnargs}}%
  \appto\tabularcontents{\toprule}%
  % add table header
  \columnidx=0
  \loop
    \advance\columnidx by 1\relax
    \eappto\tabularcontents{\noexpand& 
       \expandonce{\csname columnheader\the\columnidx\endcsname}}%
  \ifnum\columnidx<\columncount
  \repeat
  % iterate through all columns omitting rowheader
  \dtlforeachkey(\thiskey,\thiscol,\thistype,\thisheader)\in#1\do
  {%
    \ifdefstring{\thiskey}{rowheader}%
    {}%
    {%
      % header title
      \eappto\tabularcontents{%
        \noexpand\\\noexpand\midrule
           \expandonce{\csname rowheader\number\numexpr\thiscol-\columnoffset\endcsname}}%
      % row loop 
      \rowidx=0\relax
      \loop
        \advance\rowidx by 1\relax
        \DTLgetvalue{\thisvalue}{#1}{\rowidx}{\thiscol}%
        \eappto\tabularcontents{\noexpand&\expandonce\thisvalue}%
      \ifnum\rowidx<\DTLrowcount{#1}
      \repeat
    }%
  }%
  \appto\tabularcontents{\\\bottomrule\end{tabular}}%
  \tabularcontents
}

\begin{document}
\section{No rotation}
\subsection{database1}

\displaydatabase{database1}

\subsection{database2}

\displaydatabase{database2}

\subsection{Desired Output}

\begin{table}[h]
    \centering
    \caption{without rotation}
    \begin{tabular}{@{}lccc@{}}
        \toprule
        & First Column  & Second Column & Third Column\\
        \midrule
        First Row   &   11  &   12  & 13 \\ 
        \midrule 
        Second Row  &   21  &   22  & 23 \\
        \bottomrule
    \end{tabular}
\end{table}

\newpage
\section{Rotation}
\subsection{database1}

\displayrotateddatabase{database1}

\subsection{database2}
\displayrotateddatabase{database2}

\subsection{Desired Output}
\begin{table}[h]
    \centering
    \caption{with rotation}
    \begin{tabular}{@{}lcc@{}}
        \toprule
                    & First Column  & Second Column\\
        \midrule
        First Row   &   21  &   11 \\ 
        \midrule 
        Second Row  &   22  &   12 \\
        \midrule 
        Third Row   &   23  &   13 \\
        \bottomrule
    \end{tabular}
\end{table}

\newpage
\section{Transpose}
\subsection{database1}

\displaytransposedatabase{database1}

\subsection{database2}

\displaytransposedatabase{database2}

\end{document}

회전되지 않는 테이블:

회전되지 않은 테이블 이미지

회전된 테이블:

회전된 테이블 이미지

전치된 테이블:

전치된 테이블 이미지

노트:

  • \DTLloaddb후행 공백을 자르지 않으므로 를 사용하지 않았다면 keys={rowheader,col1,col2,col3}두 번째, 세 번째 및 네 번째 열의 키에 후행 공백이 포함됩니다. 다음 MWE는 작동하지 않습니다.

    \documentclass{article}
    
    \usepackage{datatool}
    
    \begin{filecontents*}{database1.csv}
                ,col1   , col2  , col3
        row1    , 11    , 12    , 13
        row2    , 21    , 22    , 23
    \end{filecontents*}
    
    \DTLloaddb{database1}{database1.csv}
    
    \DTLsetheader{database1}{col1}{First Column}
    
    \begin{document}
    
    \end{document}
    

    이로 인해 오류가 발생합니다.

    ! Package datatool Error: Database `database1' doesn't contain key `col1'.
    

    열 레이블에는 후행 공백이 포함되므로 할당은 다음과 같아야 합니다.

    \DTLsetheader{database1}{col1 }{First Column}
    
  • 선행 공백은 무시되므로

    \DTLsetheader{database1}{ col2 }{Second Column}
    

    CSV 파일에 선행 공백이 있어도 오류가 발생합니다. 다음과 같아야 합니다.

    \DTLsetheader{database1}{col2 }{Second Column}
    

각 항목에 대해서도 마찬가지입니다. 예를 들어:

\documentclass{article}

\usepackage{datatool}

\begin{filecontents*}{database1.csv}
            ,col1   , col2  , col3
    row1    , 11    , 12    , 13
    row2    , 21    , 22    , 23
\end{filecontents*}

\DTLloaddb{database1}{database1.csv}

\begin{document}

\DTLgetvalue{\thisvalue}{database1}{1}{2}`\thisvalue'.

\end{document}

이는 다음을 생성합니다.

'11'.

선행 공백은 무시되지만 후행 공백은 유지됩니다.

keys이 예에서는 공백이 포함되지 않은 키를 사용하여 키가 할당되므로 큰 차이가 없습니다 . 항목이 tabular환경에 있으므로 가짜 공간이 눈에 띄지 않지만 주의해야 할 부분입니다.

관련 정보