Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

MNWE

Background

In this site there are excellent examples of How to draw up a hierarchical tree diagram for taxonomic classification of several groups but often you must show only the position of a concrete group or single species across a long classification. Then a tree is not useful. A solution is simply show the ordered taxons in plain text:

Class Mammalia C. Linnaeus, 1758
Order Primates C. Linnaeus, 1758
Superfamily Hominoidea (Gray, 1825) 
Family Hominidae  Gray, 1825
Genus Homo C. Linnaeus, 1758
Homo sapiens  C. Linnaeus, 1758

This is correct, but usually is showed with a hierarchical indentation that make a slopping margin (that looks much better and it is easier to follow IMHO):

Class Mammalia Linnaeus, 1758
 Order Primates Linnaeus, 1758
  Superfamily Hominoidea (Gray, 1825) 
   Family Hominidae  Gray, 1825
    Genus Homo Linnaeus, 1758
     Species Homo sapiens Linnaeus, 1758

Obtain the above manually in LaTeX is easy, but it could look much better if the scientific names are also indented in parallel to the left margin. Make this manually is possible with a tabular environments, so you can obtain:

Class           Mammalia Linnaeus, 1758
 Order           Primates Linnaeus, 1758
  Superfamily     Hominoidea (Gray, 1825)
   Family          Hominidae  Gray, 1825
    Genus           Homo Linnaeus, 1758
     Especies        Homo sapiens Linnaeus, 1758

But need a lot of typing and any taxon as Mammalia must be at the right of all the groups levels (Family,Genus, etc.). This could be fine in one column with this example but in a long classifications (20-25 lines) or a two column document, the horizontal space is limited, and then it is better start Mamalia at the left of the end of Species:

Class        Mammalia Linnaeus, 1758
  Order        Primates Linnaeus, 1758
    Superfamily  Hominoidea (Gray, 1825) 
      Family       Hominidae Gray, 1825
        Genus        Homo Linnaeus, 1758
          Species      Homo sapiens Linnaeus, 1758

And reduce the indentation length as needed:

Class        Mammalia Linnaeus, 1758
 Order        Primates Linnaeus, 1758
  Superfamily  Hominoidea (Gray, 1825) 
   Family       Hominidae Gray, 1825
    Genus        Homo Linnaeus, 1758
     Species      Homo sapiens Linnaeus, 1758

As this cannot be done (easily) within a table, I think in a environment to make this (more or less) "automagically".

Desired goals

Ideally, the environment (or any other approach) should work without typing any (= as less as possible) LaTeX command in the plain text:

\begin{taxonomy}
Class Mammalia Linnaeus, 1758
Order Primates Linnaeus, 1758
Superfamily Hominoidea (Gray, 1825) 
Family Hominidae Gray, 1825
Genus Homo Linnaeus, 1758
Homo sapiens  Linnaeus, 1758
\end{taxonomy}

And:

  • Do not break any line as far it is possible without reducing the font size. That is, if text of some line take more than 1\linewidth with the default spacing, this spacing must be reduced to a reasonable value.

  • If the whole environment take less than \linewidth, it must be centered (without losing the format, obviously).

But this is my naive attempt so far:

\documentclass[12pt]{article}
\usepackage{lipsum,xcolor}

\newcounter{line}
\def\doline#1{\addtocounter{line}{1}\hspace{\value{line}\parindent}#1}

\def\marker{\end{taxonomicon}}
{\obeylines
\gdef\getlines#1
  {\def\text{#1}%
  \ifx\text\marker \let\next\text
    \else \doline{#1}\let\next\getlines \fi
  \next}}
\newenvironment{taxonomicon}{\sffamily\hfill\begingroup\obeylines\getlines}%
  {\setcounter{line}{0}\endgroup}

\newcommand\taxon[2]{
\makebox[7em][l]{\color{gray}#1\dotfill}
#2
}

\begin{document}

\lipsum[1]

% poor man's version

\parindent=1.7em % adjust as needed

\begin{taxonomicon} 
Class Mammalia C. Linnaeus, 1758
Order Primates C. Linnaeus, 1758
Superfamily Hominoidea (Gray, 1825) 
Family Hominidae  Gray, 1825
Genus Homo C. Linnaeus, 1758
Homo sapiens  C. Linnaeus, 1758

\end{taxonomicon}

\lipsum[2]

\parindent=1.2em % adjust as needed

\begin{taxonomicon} 
\taxon{Class}{Mammalia Linnaeus, 1758}
\taxon{Order}{Primates Linnaeus, 1758}
\taxon{Superfamily}{Hominoidea (Gray, 1825)}
\taxon{Family}{Hominidae  Gray, 1825}
\taxon{Genus}{Homo Linnaeus, 1758}
\taxon{Species}{Homo sapiens} Linnaeus, 1758

\end{taxonomicon}

\lipsum[3]
\end{document}

Note: I asking only a solution for a classification that always descend 1 level in each line (no matter of the real meaning of the text), but suggestion for more complex classifications (with two families, and several genera, for example) would be wonderful.

share|improve this question
add comment

1 Answer

up vote 8 down vote accepted

Your specifications are quite complicated. Here's a non complete solution where the second parts will always start right of the longest first part.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentEnvironment{taxonomy}{O{1em}}
 {
  \begin{center}
  \taxon_get_line:
 }
 {
  \taxon_print:n { #1 }
  \end{center}
 }

\seq_new:N \l_taxon_item_seq
\seq_new:N \l_taxon_itemsA_seq
\seq_new:N \l_taxon_itemsB_seq
\dim_new:N \l_taxon_width_dim
\dim_new:N \l_taxon_indent_dim
\dim_new:N \l_taxon_default_indent_dim
\box_new:N \l_taxon_item_box

\cs_new_protected:Npn \taxon_get_line:
 {
  \peek_meaning_ignore_spaces:NF \end { \taxon_get_line:w }
 }

\cs_new_protected:Npn \taxon_get_line:w #1 \\
 {
  \seq_set_split:Nnx \l_taxon_items_seq { ~ } { \tl_trim_spaces:n { #1 } }
  \seq_pop_left:NN \l_taxon_items_seq \l_tmpa_tl
  \seq_put_right:NV \l_taxon_itemsA_seq \l_tmpa_tl
  \seq_put_right:Nx \l_taxon_itemsB_seq { \seq_use:Nn \l_taxon_items_seq { ~ } }
  \taxon_get_line:
 }

\cs_new_protected:Npn \taxon_print:n #1
 {
  \dim_zero:N \l_taxon_indent_dim
  \dim_set:Nn \l_taxon_default_indent_dim { #1 }
  \seq_map_inline:Nn \l_taxon_itemsA_seq
   {
    \hbox_set:Nn \l_taxon_item_box { \hspace{ \l_taxon_indent_dim } ##1 }
    \dim_compare:nT { \l_taxon_width_dim < \box_wd:N \l_taxon_item_box }
     {
      \dim_set:Nn \l_taxon_width_dim { \box_wd:N \l_taxon_item_box }
     }
    \dim_add:Nn \l_taxon_indent_dim { \l_taxon_default_indent_dim }
   }
  \dim_add:Nn \l_taxon_width_dim { \l_taxon_default_indent_dim }
  \dim_zero:N \l_taxon_indent_dim
  \leavevmode
  \vbox:n
   {
    \seq_mapthread_function:NNN \l_taxon_itemsA_seq \l_taxon_itemsB_seq \taxon_print_line:nn
   }
 }
\cs_new_protected:Npn \taxon_print_line:nn #1 #2
 {
  \hbox:n { \hspace{ \l_taxon_indent_dim } \makebox[\l_taxon_width_dim][l]{#1\dotfill}#2 }
  \dim_add:Nn \l_taxon_indent_dim { \l_taxon_default_indent_dim }
 }

\cs_generate_variant:Nn \seq_set_split:Nnn { Nnx }
\ExplSyntaxOff

\begin{document}

\begin{taxonomy}
Class Mammalia Linnaeus, 1758 \\
Order Primates Linnaeus, 1758 \\
Superfamily Hominoidea (Gray, 1825) \\
Family Hominidae Gray, 1825 \\
Genus Homo Linnaeus, 1758 \\
Species Homo sapiens  Linnaeus, 1758 \\
\end{taxonomy}

\begin{taxonomy}[.5em]
Class Mammalia Linnaeus, 1758 \\
Order Primates Linnaeus, 1758 \\
Superfamily Hominoidea (Gray, 1825) \\
Family Hominidae Gray, 1825 \\
Genus Homo Linnaeus, 1758 \\
Species Homo sapiens  Linnaeus, 1758 \\
\end{taxonomy}

\end{document}

enter image description here

Adding a “backing up” correction

The idea in a comment can be implemented by adding a second optional argument.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentEnvironment{taxonomy}{O{1em}O{0pt}}
 {
  \begin{center}
  \taxon_get_line:
 }
 {
  \taxon_print:nn { #1 } { #2 }
  \end{center}
 }

\seq_new:N \l_taxon_item_seq
\seq_new:N \l_taxon_itemsA_seq
\seq_new:N \l_taxon_itemsB_seq
\dim_new:N \l_taxon_width_dim
\dim_new:N \l_taxon_indent_dim
\dim_new:N \l_taxon_default_indent_dim
\dim_new:N \l_taxon_corr_dim
\box_new:N \l_taxon_item_box

\cs_new_protected:Npn \taxon_get_line:
 {
  \peek_meaning_ignore_spaces:NF \end { \taxon_get_line:w }
 }

\cs_new_protected:Npn \taxon_get_line:w #1 \\
 {
  \seq_set_split:Nnx \l_taxon_items_seq { ~ } { \tl_trim_spaces:n { #1 } }
  \seq_pop_left:NN \l_taxon_items_seq \l_tmpa_tl
  \seq_put_right:NV \l_taxon_itemsA_seq \l_tmpa_tl
  \seq_put_right:Nx \l_taxon_itemsB_seq { \seq_use:Nn \l_taxon_items_seq { ~ } }
  \taxon_get_line:
 }

\cs_new_protected:Npn \taxon_print:nn #1 #2
 {
  \dim_zero:N \l_taxon_indent_dim
  \dim_set:Nn \l_taxon_default_indent_dim { #1 }
  \dim_set:Nn \l_taxon_corr_dim { #2 }
  \seq_map_inline:Nn \l_taxon_itemsA_seq
   {
    \hbox_set:Nn \l_taxon_item_box { \hspace{ \l_taxon_indent_dim } ##1 }
    \dim_compare:nT { \l_taxon_width_dim < \box_wd:N \l_taxon_item_box }
     {
      \dim_set:Nn \l_taxon_width_dim { \box_wd:N \l_taxon_item_box }
     }
    \dim_add:Nn \l_taxon_indent_dim { \l_taxon_default_indent_dim }
   }
  \dim_add:Nn \l_taxon_width_dim { \l_taxon_default_indent_dim }
  \dim_zero:N \l_taxon_indent_dim
  \leavevmode
  \vbox:n
   {
    \seq_mapthread_function:NNN \l_taxon_itemsA_seq \l_taxon_itemsB_seq \taxon_print_line:nn
   }
 }
\cs_new_protected:Npn \taxon_print_line:nn #1 #2
 {
  \hbox:n
   {
    \hspace{ \l_taxon_indent_dim }
    \makebox[\l_taxon_width_dim][l]{#1\dotfill\hspace{ -\l_taxon_corr_dim }}
    \hspace{ \l_taxon_corr_dim }
    #2
   }
  \dim_add:Nn \l_taxon_indent_dim { \l_taxon_default_indent_dim }
 }

\cs_generate_variant:Nn \seq_set_split:Nnn { Nnx }
\ExplSyntaxOff

\begin{document}

\begin{taxonomy}
Class Mammalia Linnaeus, 1758 \\
Order Primates Linnaeus, 1758 \\
Superfamily Hominoidea (Gray, 1825) \\
Family Hominidae Gray, 1825 \\
Genus Homo Linnaeus, 1758 \\
Species Homo sapiens  Linnaeus, 1758 \\
\end{taxonomy}

\begin{taxonomy}[2em][-6em]
Class Mammalia Linnaeus, 1758 \\
Order Primates Linnaeus, 1758 \\
Superfamily Hominoidea (Gray, 1825) \\
Family Hominidae Gray, 1825 \\
Genus Homo Linnaeus, 1758 \\
Species Homo sapiens  Linnaeus, 1758 \\
\end{taxonomy}

\end{document}

enter image description here

share|improve this answer
    
Yes, they are complicated, that's why I asked. ;-) Joking aside, although the solution is not complete, I take my hat off to you for the solved parts. With values ​​between 0.3-1em (which seem reasonable for a normal text) the result is quite elegant and compact anyway. The problem is mainly with higher values​​, as 2em, because then the dotted space become too long. –  Fran Dec 20 '13 at 1:48
    
For a setting of 2em, the change of \makebox[\l_taxon_width_dim][l]{#1\dotfill}}#2} to \makebox[\l_taxon_width_dim][l]{#1\dotfill\hspace{6em}}\hspace{-6em}#2} is near to I want. But with 1em the added spaces must be only about 2em and -2em, etc. Now the point is only how to find automatically a reasonable \hspaces for each setting. –  Fran Dec 20 '13 at 4:26
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.