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}
Respuesta1
Es mejor asegurarse de que a ambas bases de datos se les asignen las mismas claves (a través de la keys
opció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 etoolbox
comando \csdef
:
\csdef{columnheader1}{First Column}
\csdef{columnheader2}{Second Column}
\csdef{columnheader3}{Third Column}
No existe el concepto de encabezados de fila, datatool
pero 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 rowheader
debe 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 rowheader
identificación\endcsname
(o\csuse{rowheader
identificació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:
Mesas rotadas:
Tablas transpuestas:
Notas:
\DTLloaddb
no recorta los espacios finales, por lo que si no hubiera usadokeys={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:
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 keys
un método que no contiene espacios. Las entradas están en un tabular
entorno por lo que el espacio espurio no se nota, pero es algo con lo que hay que tener cuidado.