50

I’m developing a product as a part of my thesis for my university in Germany. We are supposed to use standard methodology for decision making. One of the tools is called “Auswahlliste”. (I don’t even know how to translate it. Maybe “choice list”.) It has a peculiar look, but it’s well accepted among academics in Germany. But just thinking about creating it in tabular environment scares me. What would you suggest? Would you try to make it with Tex-measures or would you just make a Table in Excel or any other WYSIWYG software and import it as PDF? Is there a suitable tool to draw such wicked tables in Tex-world?

Here is what it looks like: Auswahlliste

This figure was taken from the book Pahl/Beitz Konstruktionslehre, ISBN 978-3-642-29569-0.

To clear any confusion: I don’t have to make this table look like this at all costs. It’s just a standard table design used in German industry. I acknowledge all the flaws of this design and its lack of readability. I myself had a hard time understanding it at first glance. But still it’s the broadly accepted standard here and I would like to know whether it is possible to draw it with LaTeX tools. If I was trying to change the shape of it to fit my taste, I wouldn’t post this question.

10
  • 3
    Not really. Might be easier to draw than to code as a table.
    – daleif
    Mar 11, 2014 at 14:23
  • 4
    If you change the diagonal line to a "step" then you could just do it in latex tabular, no packages needed (other than the standard graphicx to rotate the text). If you want the diagonal line then you may want to use pstricks or tikz nodes to draw that line. Mar 11, 2014 at 14:25
  • The problem is that diagonal line at the right upper part of the table. With a lot of effort it might be possible to manage this by using the \slashbox package.
    – user31729
    Mar 11, 2014 at 14:29
  • 3
    If you have a digitized blank form, there are tools for overlaying text atop it. Mar 11, 2014 at 14:38
  • 2
    This is the most muddled table I've ever seen. You are supposed to use standard methodology - This does not mean you have to use ugly tables. How about redesigning the table with use of the same criterias: same method (which is what they want you to use) but different design!? Mar 11, 2014 at 15:45

3 Answers 3

73
+150

Here is the third revision of my approach to programmatically create such diagrams, using TiKZ.

Sample code

Preamble and definitions follow below: this code is meant to demonstrate the interface to the environments/macros which I define.

\begin{document}
\begin{assessmentTable}{%
    \newcommand\ItemTitle       {L\"osungsvariante (Lv) eintragen:}
    \newcommand\ItemHeading     {Lv}
    \newcommand\AssessmentTitle {Entscheidung}
    \newcommand\RemarksTitle    {Bemerkungen (Hinweise, Begr\"undungen)}

    \AddCriterion   {A}{Vertr\"aglichkeit gegeben}
    \AddCriterion   {B}{Forderungen der Anforderungsliste erf\"ult}
    \AddCriterion   {C}{Grunds\"atzlich realisiebar}
    \AddCriterion   {D}{Aufwand zul\"assig}
    \AddCriterion   {E}{Unmittelbare Sicherheitstechnik gegeben}
    \AddCriterion   {F}{Im eigenen Bereich bevorzugt}
}%
    1 & + & + & + & ? &   &     & Anzahl er Me{\ss}stellen                  & ? \\
    2 & + & - &   &   &   &     & Unterbringung der Masse                   & - \\
    3 & - &   &   &   &   &     & Radioaktivit\"at                          & - \\
    4 & + & + & + & + &   & (+) & (Weiterentwicklung bisheriger L\"osungen) & + \\
    5 & + & + & + & + &   &     &                                           & + \\
    6 & - &   &   &   &   &     & Fl\"ussigkeit nicht Leitend               & - \\
    7 & + & + & + & + &   &     &                                           & + \\
    8 & + & + & + & + &   &     & s.\ Lv 7                                  & +
\end{assessmentTable}
\end{document}

Sample output.

Sample output table

Remarks.

The table is constructed by making simple macro calls, and inputting the contents of the table as one would a normal table in LaTeX. This allows for the easy construction and customization of the output.

The code admittedly has some idiosyncracies. Some adjustment to the lengths may be necessary to prevent some of the text in the table from overlapping, for example. Also, some of the ways I chose to code this environment were to avoid mysterious errors: for example, it would appear that if any TiKZ code appears in the tikzpicture environment after the final \foreach loop, the routine which defines paths produces an error as a result of \A no longer being defined. (I do not know why this should happen.)

Having said that, this code should produce reasonable results for simple inputs, and is hopefully robust to minor tweaks.

Below is the code to produce the above example document.

Helper definitions

\documentclass[a4paper,10pt]{article}
\usepackage{pbox,tikz}
\usetikzlibrary{matrix,calc,fit,intersections}

\newlength\criterionwidth           % width for criterion table columns
\newlength\labelheight              % height for labels for assessment criteria
\newlength\labeldepth               % depth for labels for assessment criteria
\newlength\itemcolwidth             % width for the left-most column
\newlength\criterionlabelskip       % vert. skip between legend and first criterion label
\newlength\criterionlabelindent     % left indend for criterion labels from their columns
\newlength\assessmentdiagtopstretch % vert.dist. upwards to pull top of the diagonal
\newlength\assessmentdiagbotstretch % vert.dist. downwards to pull bottom of the diagonal
\newlength\remarkswidth             % absolute width of remarks column
\newlength\remarksxsep              % inner horiz. separation of remarks from column edge

\setlength\criterionwidth           {1.5em}
\setlength\labelheight              {3ex}
\setlength\labeldepth               {1ex}
\setlength\itemcolwidth             {3em}
\setlength\criterionlabelskip       {2ex}
\setlength\criterionlabelindent     {0ex}
\setlength\assessmentdiagtopstretch {5mm}
\setlength\assessmentdiagbotstretch {2mm}
\setlength\remarkswidth             {80mm}
\setlength\remarksxsep              {1em}

\newcommand\labeltypeface   {\itshape}      % face for description labels in the table
\newcommand\celltypesize    {\footnotesize} % size of evalutation cell contents
\newcommand\remarktypeface  {\small}        % size of remark cell contents

The various lengths can be varied to taste, and the typefaces can be used to control the appearance of the text in the table.

\makeatletter
\newcount\@RemarkCol            % Counter for position of the Remarks column
\newtoks\@CriterionNameToks     % Token list for labels of the criteria to asses
\@CriterionNameToks{}

\newcommand\AddCriterion[2]{%   Macro to define a new criterion column / label
    \edef\@tempa{\the\@CriterionNameToks}%
    \ifx\empty\@tempa\@CriterionNameToks{{#1}/{#2}}\else
       \expandafter\@CriterionNameToks\expandafter{\the\@CriterionNameToks,{#1}/{#2}}
    \fi}

The macro \AddCriterion is meant to be the user interface to define the criteria of assessment in the table. We also define a counter to keep track of the position of the Remarks column, depending on the number of criteria to be assessed.

Table environment definition

\newenvironment{assessmentTable}[1]{%
    \@CriterionNameToks{}%
    \@RemarkCol=2\relax
    #1%
    \begin{tikzpicture}
        \expandafter\def\expandafter\@CriterionNames\expandafter{\the\@CriterionNameToks}

        \node (CriterionLegend) [inner sep=1em] {\parbox{\paperwidth}{\CriterionLegend}};

        \coordinate (Criterion-first-anchor) at ($(CriterionLegend.south west) + (0,-\criterionlabelskip)$);
        \def\CriterionAnchor{Criterion-first-anchor}
        \foreach \A/\critLabel in \@CriterionNames {
            \global\advance\@RemarkCol by 1\relax
            \node [anchor=north west, text width=\criterionwidth, minimum height=\labelheight+\labeldepth, inner sep=0pt]
                        (\A-anchor) at (\CriterionAnchor) {};
            \node [anchor=west, text height=\labelheight, text depth=\labeldepth]
                        (\A-label) at  ($(\A-anchor.east) + (\criterionlabelindent,0)$)
                        {\labeltypeface\critLabel};
            \xdef\CriterionAnchor{\A-anchor.south east}%
        }
        \node [anchor=north west, inner xsep=\remarksxsep, inner ysep=0pt, text height=\labelheight, text depth=\labeldepth,
                    text width=\remarkswidth-2*\pgfkeysvalueof{/pgf/inner xsep}]
                    (Remarks-title) at (\CriterionAnchor)
                    {\labeltypeface\RemarksTitle};

        \node [anchor=south west, minimum height=\itemcolwidth,rotate=90]
                    (ItemTitle) at (Remarks-title.north -| CriterionLegend.west)
                    {\ItemTitle};
        \node [inner sep=0pt, fit=(ItemTitle)(ItemTitle |- CriterionLegend.north)]
                    (ItemTitle) {};

        \def\CriterionAnchor{ItemTitle.west}
        \node [anchor=north west, text height=\labelheight, text depth=\labeldepth, inner ysep=0pt]
                    (ItemHeading) at (ItemTitle.south west)  {\ItemHeading};

        \foreach \A/\critLabel in \@CriterionNames {%
            \node [inner sep=0pt, anchor=south, minimum width=\criterionwidth, text height=\labelheight, text depth=\labeldepth]
                        (\A-heading) at (ItemHeading.south -| \A-anchor)  {\A};
        }
        \node [anchor=north west, rotate=90, minimum height=\criterionwidth, inner ysep=0pt]
                    (AssessmentTitle) at (Remarks-title.south east)  {\AssessmentTitle};
        \node [inner sep=0pt, fit=(AssessmentTitle)] (AssessmentTitle)  {};
        \node [anchor=north east]
                    (AssessmentLegend) at (CriterionLegend.north -| AssessmentTitle.east) 
                    {\pbox{\paperwidth}{\AssessmentLegend}};

        \def\@GridFinalRow{0}

        \matrix [%
                anchor=north west, matrix of nodes,%
                nodes in empty cells,
                inner sep=0pt,
                nodes={%
                    draw=white, inner sep=0pt,
                    execute at begin node=\celltypesize$,
                    execute at end node=$\xdef\@GridFinalRow{\pgfmatrixcurrentrow},\iffalse$ Fix some syntax hilighting problems\fi
                    text height=3ex, text depth=1ex, minimum width=\criterionwidth},
                column 1/.style={%
                    execute at begin node=\expandafter\@gobble\@gobble,
                    execute at end node=\@gobble,
                    nodes={minimum width=\itemcolwidth}},
                column \the\@RemarkCol/.style={%
                    execute at begin node=\remarktypeface\expandafter\@gobble\@gobble,
                    execute at end node=\@gobble,
                    nodes={%
                        minimum width=\remarkswidth,
                        inner xsep=\remarksxsep,
                        text width=\remarkswidth-2*\pgfkeysvalueof{/pgf/inner xsep}}}
        ] (Grid) at (ItemHeading.south west)
        \bgroup
}{%
        \\ \egroup;

        \expandafter\ifnum\@GridFinalRow>0
            \foreach \row in {1,...,\@GridFinalRow} {%
                \draw (Grid-\row-1.south west) -- (Grid-\row-1.south west -| Grid.east);
            }
        \fi

        \draw (ItemTitle.north west)    -- (AssessmentLegend.north east)
                                                                    -- (AssessmentTitle.south east)
                                                                    -- (ItemHeading.south west) -- cycle;
        \draw (Grid.north east) -- (Grid.south east) -- (Grid.south west) -- (Grid.north west);                                                             
        \draw (CriterionLegend.north west) -- (Criterion-first-anchor);

        \draw [name path=AssessmentLegendBoundary]
                    (AssessmentLegend.north west) -- ($(AssessmentLegend.south west) + (0mm,\assessmentdiagtopstretch)$)
                                                                                -- ($(AssessmentTitle.north west) + (0mm,-\assessmentdiagbotstretch)$)
                                                                                -- (AssessmentTitle.south west |- Grid.south);

        \path [name path=Remarks-north-boundary] (Remarks-title.north west) -- ($(Remarks-title.north east) + (\paperwidth,0mm)$);
        \path [name intersections={of=AssessmentLegendBoundary and Remarks-north-boundary, by={Remarks-north-east-boundary}}];
        \draw (Remarks-north-east-boundary) -- (Remarks-title.north west) -- (Remarks-title.north west |- Grid.south);

        \foreach \A/\critLabel in \@CriterionNames {%
            \path [name path=\A-north-boundary] (\A-anchor.north west) -- ($(\A-anchor.north east) + (\paperwidth,0mm)$);
            \path [name intersections={of=AssessmentLegendBoundary and \A-north-boundary, by={\A-north-east-boundary}}];
            \draw (\A-north-east-boundary) -- (\A-anchor.north west) -- (\A-anchor.north west |- Grid.south);
        }       
    \end{tikzpicture}%
}
\makeatother

The environment clears the list of criteria and resets the number of the remarks column, and then allows the user to specify a list of commands to initialize the parameters of the table (e.g. the criteria list, the item title, etc.). It then constructs the table using the "legend" (the large table cell in your example containing the descriptions of the labels (+), (-), etc.) as the foundation.

  • The columns and the labels for the criteria are constructed iteratively from the lower-left corner of the legend, with each subsequent criterion column constructed further downwards and to the right. (The length \criterionlabelskip determines how much further down the first label is, from the lower-left corner of the legend.)

  • The label for Remarks column is defined relative to the position of the last criterion, and defines the bottom of the table-headers.

  • The position of the Legend cell and the Remarks column determines the position of the header of the left-most column, and its title.

  • The position of the Legend cell and the Remarks column also determines the position of the Assessment column, and its legend, which may in principle overlap some of the criteria labels.

  • The rest of the table is provided as the contents of the environment, and consists of a TiKZ matrix of nodes. The number of criteria columns determines which column is the "Remarks" column, which is given its own style; aside from this and the first column, every cell by default is in math-mode. (The code at the beginning of cells in the first column and the remarks column are to remove the math-mode and the resizing which is the default for all other nodes.)

At the end of the environment, all of the divider lines of the table are drawn.

Customization

Macros for the Legend and the description of the Assessment are likely to be the same for several tables: these are contained in \pboxes whose size will shrink down to the size of their contents.

\newcommand\CriterionLegend{%
%
        L\"osungsvariante {( Lv )} nach \\
        \underline{\MakeUppercase{Auswahlkriterien}} beurteilen: \\[2ex]
        \begin{tabular}{@{(}c@{)\quad}l}
          $+$   &   ja
        \\
            $-$ &   nein
        \\
            ?   &   Informationsmangel
        \\
            ! & Anforderungliste \"uberpr\"ufen
        \end{tabular}
%
}

\newcommand\AssessmentLegend{%
%
        \begin{tabular}{c@{\quad}l}
          \multicolumn{2}{c}{\MakeUppercase{Entscheiden}}
        \\
        \hline
                    &   L\"osungsvarianten (Lv) \\ & kennzeichnen:
        \\[2ex]
            ($+$)   &   L\"osung weiter verfolgen
        \\
            ($-$)   &   L\"osung scheidet aus
        \\
            (?)     & Information beschaffen \\& (L\"osung erneut beurteilen)
        \\
            (!)     &   Anforderungliste auf \\& \"Anderung pr\"ufen
        \end{tabular}
%
}

All other customizations presumably should be done on a table-by-table basis (and so should be done as part of the argument to the table), or involve the helper macros and lengths defined above.

2
  • 3
    There are some compromises which I made in coding this response due to my trying to work around non-obvious technicalities in TiKZ. (For the curious, look for "draw=white" in my code, and see what happens when you remove it.) Suggestions to simplify this answer are appreciated. Mar 12, 2014 at 16:39
  • let us continue this discussion in chat Mar 13, 2014 at 9:59
32
+100

enter image description here

\documentclass{article}

\usepackage{array,graphicx}
\setlength\extrarowheight{2pt}

\begin{document}

\noindent
\begin{tabular}{|*{13}{>{\centering\arraybackslash}p{10pt}|}}
\hline
\multicolumn{2}{|c|}{}&
\multicolumn{7}{p{75pt}|}{\raggedright
Stuff\\
\textbf{MORE STUFF}\\[4pt]
(+) yes\\
($-$) no\\
(?) who knows\\
(!) Run!}&
\multicolumn{4}{p{40pt}|}{\raggedright
\textbf{More Stuff}
Stuff\\
goes\\
here}\\
\cline{3-9}
\multicolumn{2}{|c|}{}&\multicolumn{11}{l|}{\ Some kind of title}\\
\cline{4-7}
\multicolumn{2}{|c|}{}&&\multicolumn{10}{l|}{\ Some kind of title 2}\\
\cline{5-8}
\multicolumn{2}{|c|}{}&&&\multicolumn{9}{l|}{\ Another title}\\
\cline{6-9}
\multicolumn{2}{|c|}{}&&&&\multicolumn{8}{l|}{\ Yet Another title}\\
\cline{7-10}
\multicolumn{2}{|c|}{}&&&&&\multicolumn{7}{l|}{\ Yet Another title 2}\\
\cline{8-11}
\multicolumn{2}{|c|}{}&&&&&&\multicolumn{6}{l|}{\ Title \ldots}\\
\cline{9-12}
\multicolumn{2}{|c|}{\rotatebox{90}{\makebox[0pt][l]{Long Column title}}}&&&&&&&\multicolumn{5}{l|}{}\\
\cline{10-12}
\multicolumn{2}{|c|}{Lv}&
A&B&C&D&E&F&G&\multicolumn{3}{l|}{\footnotesize Title (of some sort)}&
\rotatebox{90}{\makebox[0pt][l]{\footnotesize Column title}}\\
\hline
1&1&+&+&+&?& & & &\multicolumn{3}{l}{\footnotesize Something in German}&?\\
2&2&+&$-$& & & & & &\multicolumn{3}{l}{\footnotesize Something else in German}&-\\
\ &\ &\ &\ &\ &\ &\ &\ &\ &\multicolumn{1}{c}{\ }&\multicolumn{3}{c|}{\ }\\
\hline
\end{tabular}

\end{document}
6
  • Oops, I made a mistake... I planned to give a bounty to @user47919, but clicked the wrong place. Mar 18, 2014 at 11:09
  • @NieldeBeaudrap You'll have to contact the staff (via the help link) to get the bounty here reversed
    – Joseph Wright
    Mar 18, 2014 at 11:48
  • 1
    @NieldeBeaudrap I flagged your comment, I would guess the mods can move the bounty :) (oh apparently not: If it isn't possible I'll bouncy the bounty on, and award 100 to the other answer:-) Mar 18, 2014 at 11:49
  • @DavidCarlisle: That would be swell, thanks! Mar 18, 2014 at 11:57
  • 1
    @NieldeBeaudrap bounty started, can't be awarded until tomorrow I think. Mar 21, 2014 at 15:08
22
+100

The tap macros could be used to typeset this table:

\input tap
\input trans

\beginanchtable
\begintableformat & \center \endtableformat
%\B|+ | | | | | | | | \E|
\diagstroke \trth DOWN {0 0 0 1} a
\B"- " " " " \kern16mm " " " " \E"
\-
\B|: @3 Header | @4 Second header | @2 Last \E|
\-
\B|: | @4 Info | @4 Info 2 \E|
\B|- | @4 \- | " " " \E|
\uranchor8a
\B|: | " @4 Header A " " "  \E|
\B|- @2 | @4 \- " " "  \E|
\B|: | | "  @3 Header B " " "  \E|
\B|- @3 | @4 \- " "  \E|
\B|: | | | " @2 Header C " " "  \E|
\llanchor6a
\B|- @4 | @4 \- |  \E|
\B|: Lv | A | B | C | @4 Cos tam | \revolve\hbox{Head rot.} \E|
\=
\B|: 1 | + | + | + | @4 \left{Table position 1} | ?  \E|
\-
\B|: 2 | + | -- |  | @4 \left{Table position 2} | -- \E|
\-
\B|: 3 | -- |  |   | @4 \left{Table position 3} | +  \E|
\-
\endanchtable
\useanchors
\bye

Run the commands below to get PDF:

tex diagonal.tex
dvips diagonal.dvi
ps2pdf diagonal.ps

diagonal

3
  • This tap package looks like a proper way to do it since it looks tidier on the code side and could be easier to lear than TikZ solution. Unfortunately i havent found any documentation that would explain how to create such tables, so it's not so easy after all (for now). But it's definitely worth to look up later. Mar 14, 2014 at 12:23
  • Can you locate good PDF documentation for this package, @user47919? Mar 14, 2014 at 19:42
  • 2
    Download package from CTAN tap077.zip and unzip it. Change to tapdoc/ folder and typeset the documentation with these commands: tex tapdoc ; dvips tapdoc; ps2pdf tapdoc.ps.
    – user47919
    Mar 15, 2014 at 18:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .