datatool: So laden Sie eine Tabelle aus einer Datei, drehen sie oder nicht, und fügen dann vordefinierte Kopfzeilen ein

datatool: So laden Sie eine Tabelle aus einer Datei, drehen sie oder nicht, und fügen dann vordefinierte Kopfzeilen ein

Dies ist eine Folgefrage zumein vorheriger.

In diesem Artikel möchte ich auf zwei Fälle eingehen:

Erste, lade die Tabelle so wie sie ist und füge nur meine eigenen Spalten- und Zeilenüberschriften ein.

Zweite, lade die Tabelle und drehe sie, dann füge ich meine eigenen Spalten- und Zeilenüberschriften ein.

Für die beiden oben genannten Fälle müssen zwei verschiedene Datenbanktypen verwendet werden, wie unten gezeigt

\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}

Bildbeschreibung hier eingeben

Antwort1

Am besten stellen Sie sicher, dass beiden Datenbanken die gleichen Schlüssel zugewiesen werden (über die keysOption in \DTLloaddb). Das bedeutet, dass mit den Schlüsseln auf die gleiche Spalte in beiden Datenbanken verwiesen werden kann, obwohl sie unterschiedliche Spaltenindizes haben:

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

Die Spaltenüberschriften können für beide Datenbanken mit diesen Schlüsseln festgelegt werden:

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

\setdatabaseheaders{database1}
\setdatabaseheaders{database2}

Wenn die Spaltenüberschriften jedoch für alle Tabellen gleich sind, ist es einfacher, sie mithilfe des etoolboxBefehls von in einer leicht zugänglichen Weise zu speichern \csdef:

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

Es gibt kein Konzept für Zeilenüberschriften, datatoolaber es ist recht einfach, auf ähnliche Weise welche basierend auf dem Zeilenindex bereitzustellen:

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

Die durch gekennzeichnete Spalte rowheadermuss bei der Anzeige der Daten ignoriert werden. Die Existenz dieser Spalte kann mit überprüft werden \DTLifhaskey. Die benutzerdefinierten Befehle zur Anzeige der Daten können die Zeilenüberschriften einfügen, indem sie auf den Befehl verweisen, der durch angegeben wird.\csname rowheaderidx\endcsname(oder\csuse{rowheaderidx}) am Anfang jeder Zeile. Gleiches gilt für die Spaltenüberschriften.

Komplettes 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}

Nicht gedrehte Tabellen:

Bild von nicht gedrehten Tabellen

Gedrehte Tabellen:

Bild von gedrehten Tischen

Transponierte Tabellen:

Bild transponierter Tabellen

Anmerkungen:

  • \DTLloaddbschneidet keine nachstehenden Leerzeichen ab. Wenn ich also nicht verwendet hätte keys={rowheader,col1,col2,col3}, würden die Schlüssel für die zweite, dritte und vierte Spalte ein nachstehendes Leerzeichen enthalten. Das folgende MWE funktioniert nicht:

    \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}
    

    Dies erzeugt den Fehler

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

    Die Spaltenbeschriftung enthält am Ende ein Leerzeichen, deshalb muss die Zuweisung folgendermaßen lauten:

    \DTLsetheader{database1}{col1 }{First Column}
    
  • Führende Leerzeichen werden ignoriert,

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

    erzeugt einen Fehler, obwohl in der CSV-Datei ein führendes Leerzeichen steht. Es muss lauten:

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

Gleiches gilt für jeden Eintrag. Beispiel:

\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}

Das Ergebnis:

'11 '.

Das führende Leerzeichen wird ignoriert, das nachfolgende Leerzeichen bleibt jedoch erhalten.

In diesem Beispiel macht es keinen großen Unterschied, da die Schlüssel mit einem zugewiesen werden keys, das keine Leerzeichen enthält. Die Einträge befinden sich in einer tabularUmgebung, sodass das falsche Leerzeichen nicht auffällt, aber man sollte darauf achten.

verwandte Informationen