Esta é uma pergunta complementar parameu anterior.
Neste, gostaria de abordar dois casos:
Primeiro, carregue a tabela como ela está, apenas impondo meus próprios cabeçalhos de colunas e linhas.
Segundo, carregue a tabela e gire-a e, em seguida, imponha meus próprios cabeçalhos de coluna e linha.
Para ambos os casos mencionados acima, dois tipos diferentes de bancos de dados devem ser tratados conforme mostrado abaixo
\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}
Responder1
É melhor garantir que ambos os bancos de dados recebam as mesmas chaves (por meio da keys
opção em \DTLloaddb
). Isso significa que as chaves podem ser usadas para referenciar a mesma coluna em ambos os bancos de dados, mesmo que tenham índices de colunas diferentes:
\DTLloaddb[keys={rowheader,col1,col2,col3}]{database1}{database1.csv}
\DTLloaddb[noheader,keys={col1,col2,col3}]{database2}{database2.csv}
Os cabeçalhos das colunas podem ser definidos para ambos os bancos de dados usando estas chaves:
\newcommand{\setdatabaseheaders}[1]{%
\DTLsetheader{#1}{col1}{First Column}%
\DTLsetheader{#1}{col2}{Second Column}%
\DTLsetheader{#1}{col3}{Third Column}%
}
\setdatabaseheaders{database1}
\setdatabaseheaders{database2}
No entanto, se os cabeçalhos das colunas estiverem sendo compartilhados por todas as tabelas, será mais simples armazená-los de maneira fácil de acessar com a ajuda do comando etoolbox
' \csdef
:
\csdef{columnheader1}{First Column}
\csdef{columnheader2}{Second Column}
\csdef{columnheader3}{Third Column}
Não há conceito de cabeçalhos de linha, datatool
mas é fácil fornecer alguns com base no índice de linha de maneira semelhante:
\csdef{rowheader1}{First Row}
\csdef{rowheader2}{Second Row}
A coluna identificada por rowheader
precisa ser ignorada ao exibir os dados. A existência desta coluna pode ser verificada com \DTLifhaskey
. Os comandos personalizados para exibir os dados podem inserir os cabeçalhos das linhas referenciando o comando fornecido por\csname rowheader
idx\endcsname
(ou\csuse{rowheader
idx}
) no início de cada linha. Da mesma forma para os cabeçalhos das colunas.
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}
Tabelas não rotacionadas:
Tabelas giradas:
Tabelas transpostas:
Notas:
\DTLloaddb
não corta espaços à direita; portanto, se eu não tivesse usadokeys={rowheader,col1,col2,col3}
, as chaves da segunda, terceira e quarta colunas incluiriam um espaço à direita. O seguinte MWE não 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}
Isso produz o erro
! Package datatool Error: Database `database1' doesn't contain key `col1'.
O rótulo da coluna inclui um espaço à direita, portanto a atribuição precisa ser:
\DTLsetheader{database1}{col1 }{First Column}
Os espaços iniciais são ignorados, então
\DTLsetheader{database1}{ col2 }{Second Column}
produz um erro, mesmo que haja um espaço à esquerda no arquivo CSV. Precisa ser:
\DTLsetheader{database1}{col2 }{Second Column}
Da mesma forma para cada entrada. Por exemplo:
\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}
Isso produz:
O espaço inicial é ignorado, mas o espaço final é mantido.
Neste exemplo, não faz muita diferença, pois as chaves são atribuídas usando keys
which não contém espaços. As entradas estão em um tabular
ambiente onde o espaço espúrio não é perceptível, mas é algo com que se deve ter cuidado.