herramienta de datos: Cómo cargar una tabla desde un archivo, rotarla o no, y luego imponer encabezados predefinidos

herramienta de datos: Cómo cargar una tabla desde un archivo, rotarla o no, y luego imponer encabezados predefinidos

Esta es una pregunta de seguimiento parami anterior.

En este, me gustaría abordar dos casos:

Primero, cargue la tabla tal como está mientras impone mis propios encabezados de columna y fila.

Segundo, cargue la tabla y gírela, luego imponga mis propios encabezados de columna y fila.

Para ambos casos mencionados anteriormente, se deben manejar dos tipos diferentes de bases de datos como se muestra a continuación.

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

ingrese la descripción de la imagen aquí

Respuesta1

Es mejor asegurarse de que a ambas bases de datos se les asignen las mismas claves (a través de la keysopción en \DTLloaddb). Esto significa que las claves se pueden usar para hacer referencia a la misma columna en ambas bases de datos, aunque tengan índices de columna diferentes:

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

Los encabezados de columna se pueden configurar para ambas bases de datos usando estas claves:

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

\setdatabaseheaders{database1}
\setdatabaseheaders{database2}

Sin embargo, si los encabezados de las columnas se comparten en todas las tablas, entonces es más sencillo almacenarlos de una manera de fácil acceso con la ayuda del etoolboxcomando \csdef:

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

No existe el concepto de encabezados de fila, datatoolpero es bastante fácil proporcionar algunos basados ​​en el índice de fila de una manera similar:

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

La columna identificada por rowheaderdebe ignorarse al mostrar los datos. La existencia de esta columna se puede comprobar con \DTLifhaskey. Los comandos personalizados para mostrar los datos pueden insertar los encabezados de fila haciendo referencia al comando proporcionado por\csname rowheaderidentificación\endcsname(o\csuse{rowheaderidentificación}) al comienzo de cada fila. Lo mismo ocurre con los encabezados de las columnas.

MWE completo:

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

Mesas no rotadas:

imagen de tablas no rotadas

Mesas rotadas:

imagen de mesas rotadas

Tablas transpuestas:

imagen de tablas transpuestas

Notas:

  • \DTLloaddbno recorta los espacios finales, por lo que si no hubiera usado keys={rowheader,col1,col2,col3}, las claves para la segunda, tercera y cuarta columnas incluirían un espacio final. El siguiente MWE no funciona:

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

    Esto produce el error

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

    La etiqueta de la columna incluye un espacio final, por lo que la asignación debe ser:

    \DTLsetheader{database1}{col1 }{First Column}
    
  • Los espacios iniciales se ignoran, por lo que

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

    produce un error, aunque hay un espacio inicial en el archivo CSV. Necesita ser:

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

Lo mismo para cada entrada. Por ejemplo:

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

Esto produce:

'11'.

El espacio inicial se ignora pero se conserva el espacio final.

En este ejemplo, no hay mucha diferencia ya que las claves se asignan usando keysun método que no contiene espacios. Las entradas están en un tabularentorno por lo que el espacio espurio no se nota, pero es algo con lo que hay que tener cuidado.

información relacionada