5

I need to produce a figure that looks similar to this one from another paper. What would be the simplest way to achieve this? lattice5.

So far I have figured out how to draw the ovals using TikZ but I can't find a way to get the spacing to look right.

\newcommand{\A}{\tikz \draw     (0,0) circle [x radius=3pt, y radius=6pt ];}
\newcommand{\B}{\tikz \filldraw (0,0) circle [x radius=3pt, y radius=6pt ];}
\newcommand{\ovals}[2]{\parbox{25pt}{\centering#1\\#2}}

\begin{center}
\ovals{\B\B}{0.05} \\
\ovals{\A\B}{0.10} \ovals{\B\A}{0.20}  \\
\ovals{\A\A}{1.00} \\
\end{center}

Here is the best I could get so far, for N=2:

my lattice

  • How can I reduce the vertical space between the ovals and the associated numbers under them?
  • How can I increase the vertical space between the bottom of the numbers and the row of ovals under them?
1
  • I think it is a problem of combinations in probability. So, I'd recommend you to have such flowchart: 1) write a python or other code to produce all combinations of binaries in a society of 7 members and store them in a text list. 2) import this list to a tikz routine to draw your black and white labels. This post on stackoverflow helps you: stackoverflow.com/questions/127704/…
    – enthu
    Jan 9, 2020 at 8:07

3 Answers 3

8

If you already load TikZ then you can use it for all aspects. Your problem can be solved using the parser module, pics and matrices. This answer defines a pic, ovals, whose first part of the argument can be a series of * and o, which translate into ovals.

enter image description here

The table can be done with matrices.

enter image description here

with the code being simply

\begin{tikzpicture}[column sep=1ex]
 \path (0,0) node[matrix]{\pic{ovals={******/0.7}};\\}
 (0,-1) node[matrix]{\pic{ovals={o*****/103.4}}; & 
    \pic{ovals={*o****/81.5}}; & \pic{ovals={**o***/1.7}};
     & \pic{ovals={***o**/0.7}};  & \pic{ovals={****o*/11.4}};
      & \pic{ovals={*****o/3.3}};\\}; 
\end{tikzpicture}

Full document with definition of the pic:

\documentclass{article}
\usepackage{tikz}
\usepgfmodule{parser}
\newcounter{oval}
\newif\ifdrawovals
\pgfparserdef{ovalparser}{initial}{the letter o}% 
{\ifdrawovals
\draw (\ovalshift*1pt+\number\value{oval}*6pt,6pt) circle [x radius=3pt, y radius=6pt ];
\fi
\stepcounter{oval}}% 
\pgfparserdef{ovalparser}{initial}{the character *}% 
{\ifdrawovals
\draw[fill] (\ovalshift*1pt+\number\value{oval}*6pt,6pt) circle [x radius=3pt, y radius=6pt ];
\fi
\stepcounter{oval}}% 
\pgfparserdef{ovalparser}{initial}{the character ;}% 
{\pgfparserswitch{final}}
\pgfmathtruncatemacro\ovalshift{0}
\tikzset{pics/ovals/.style args={#1/#2}{code={
   \setcounter{oval}{0}
   \drawovalsfalse
   \pgfparserparse{ovalparser}#1;
   \pgfmathtruncatemacro\ovalshift{3-3*\number\value{oval}}
   \setcounter{oval}{0}
   \drawovalstrue
   \pgfparserparse{ovalparser}#1;
   \path (0,0) node[below]{#2x};
   }},pics/ovals/.default=o/{}}

\begin{document}
For instance,
\begin{quote}
 \verb|\pic{ovals={**o*o*/1.4}};|
\end{quote}
inside a \verb|tikzpicture| environment yields
\begin{quote}
 \tikz{\pic{ovals={**o*o*/1.4}};}
\end{quote}

You can use stack matrices to produce your table, you will have perfect control
over all aspect. The \verb|column sep| controls the horizontal space between the
cells, the vertical distance is controlled by the coordinate in fron of the
matrix node. This is a start.
\begin{center}
\begin{tikzpicture}[column sep=1ex]
 \path (0,0) node[matrix]{\pic{ovals={******/0.7}};\\}
 (0,-1) node[matrix]{\pic{ovals={o*****/103.4}}; & 
    \pic{ovals={*o****/81.5}}; & \pic{ovals={**o***/1.7}};
     & \pic{ovals={***o**/0.7}};  & \pic{ovals={****o*/11.4}};
      & \pic{ovals={*****o/3.3}};\\}; 
\end{tikzpicture}
\end{center}
\end{document}

Of course, if there is a formula that derives the numbers in front of the x from the binary code of filled and empty indices, the whole tabular can be done programmatically.

\documentclass[tikz,border=3mm]{standalone}
\usepackage{etoolbox}
\usepackage{tikz}
\tikzset{pics/ovals/.style args={#1/#2}{code={
   \foreach \XX [count=\YY] in {#1}
   {\draw (-21pt+\YY*6pt,6pt) \ifnum\XX=1 [fill] \fi circle[x radius=3pt,y radius=6pt];]}
   \path (0,0) node[below]{\pgfmathprintnumber{#2}x};
   }},pics/ovals/.default=o/{}}

\begin{document}
\begin{tikzpicture}[column sep=1ex,ampersand replacement=\&]
\def\mylst{{{0, 0, 0, 0, 0, 0}}, {{0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 1, 0}, {0, 0,
    0, 1, 0, 0}, {0, 0, 1, 0, 0, 0}, {0, 1, 0, 0, 0, 0}, {1, 0, 0, 0, 
   0, 0}}, {{0, 0, 0, 0, 1, 1}, {0, 0, 0, 1, 0, 1}, {0, 0, 0, 1, 1, 
   0}, {0, 0, 1, 0, 0, 1}, {0, 0, 1, 0, 1, 0}, {0, 0, 1, 1, 0, 0}, {0,
    1, 0, 0, 0, 1}, {0, 1, 0, 0, 1, 0}, {0, 1, 0, 1, 0, 0}, {0, 1, 1, 
   0, 0, 0}, {1, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 1, 0}, {1, 0, 0, 1, 0, 
   0}, {1, 0, 1, 0, 0, 0}, {1, 1, 0, 0, 0, 0}}, {{0, 0, 0, 1, 1, 
   1}, {0, 0, 1, 0, 1, 1}, {0, 0, 1, 1, 0, 1}, {0, 0, 1, 1, 1, 0}, {0,
    1, 0, 0, 1, 1}, {0, 1, 0, 1, 0, 1}, {0, 1, 0, 1, 1, 0}, {0, 1, 1, 
   0, 0, 1}, {0, 1, 1, 0, 1, 0}, {0, 1, 1, 1, 0, 0}, {1, 0, 0, 0, 1, 
   1}, {1, 0, 0, 1, 0, 1}, {1, 0, 0, 1, 1, 0}, {1, 0, 1, 0, 0, 1}, {1,
    0, 1, 0, 1, 0}, {1, 0, 1, 1, 0, 0}, {1, 1, 0, 0, 0, 1}, {1, 1, 0, 
   0, 1, 0}, {1, 1, 0, 1, 0, 0}, {1, 1, 1, 0, 0, 0}}, {{0, 0, 1, 1, 1,
    1}, {0, 1, 0, 1, 1, 1}, {0, 1, 1, 0, 1, 1}, {0, 1, 1, 1, 0, 
   1}, {0, 1, 1, 1, 1, 0}, {1, 0, 0, 1, 1, 1}, {1, 0, 1, 0, 1, 1}, {1,
    0, 1, 1, 0, 1}, {1, 0, 1, 1, 1, 0}, {1, 1, 0, 0, 1, 1}, {1, 1, 0, 
   1, 0, 1}, {1, 1, 0, 1, 1, 0}, {1, 1, 1, 0, 0, 1}, {1, 1, 1, 0, 1, 
   0}, {1, 1, 1, 1, 0, 0}}, {{0, 1, 1, 1, 1, 1}, {1, 0, 1, 1, 1, 
   1}, {1, 1, 0, 1, 1, 1}, {1, 1, 1, 0, 1, 1}, {1, 1, 1, 1, 0, 1}, {1,
    1, 1, 1, 1, 0}}, {{1, 1, 1, 1, 1, 1}}}
\foreach \Lst [count=\Y] in \mylst
{\let\myrow\empty
\foreach \Bin [count=\Z] in \Lst
{\pgfmathsetmacro{\myrnd}{int(100*rnd+50)/100}\begingroup\edef\tmp{\endgroup
       \noexpand\gappto\noexpand\myrow{\noexpand\pic{ovals={\Bin/\myrnd}}; \&}}\tmp
}
\gappto\myrow{\\}
\path (0,\Y)  node[matrix]{\myrow}; 
}   
\end{tikzpicture}
\end{document}

enter image description here

2
  • Thanks, this one looks the prettiest so far, but I'll have to digest it a bit to understand all the details. In case you are wondering, the numbers in that chart are empyrical. They are measurements of a computer program's running time. There are N modules, and 2 versions of each module, which results in 2^N possible configurations. The goal is to keep everything under 1.0x. If there are any nodes over 100x then there is room for improvement :)
    – hugomg
    Jan 9, 2020 at 3:10
  • @hugomg Interesting! Even if you have the numbers in a list, one could probably do this automagically. If the list was such that the index of a number was the binary number represented by the ovals, it should be rather straightforward (I think). I may try later.
    – user194703
    Jan 9, 2020 at 3:13
6

I'd use a tabular for stacking the ovals and the label.

Also a simpler input for the ovals using binary strings is provided.

\documentclass{article}
\usepackage{tikz,xparse}

\newcommand{\emptyoval}{\tikz \draw     (0,0) circle [x radius=3pt, y radius=6pt ];}
\newcommand{\filledoval}{\tikz \filldraw (0,0) circle [x radius=3pt, y radius=6pt ];}
\newcommand{\ovals}[2]{%
  \begin{tabular}{@{}c@{}}\makeovals{#1}\\#2\end{tabular}%
}

\ExplSyntaxOn
\NewDocumentCommand{\makeovals}{m}
 {
  \str_map_inline:nn { #1 }
   {
    \str_case:nn { ##1 }
     {
      {0}{\emptyoval}
      {1}{\filledoval}
     }
   }
 }
\ExplSyntaxOff

\begin{document}

\begin{center}
\ovals{11}{0.05} \\[1ex]
\ovals{01}{0.10} \ovals{10}{0.20}  \\[1ex]
\ovals{00}{1.00}
\end{center}

\end{document}

enter image description here

A version with a friendlier syntax for the input, showing also how you can squeeze the big diagram (but avoid it if you can). The additional space between rows can be customized with an optional argument (use it after seeing how the squeezing acts).

\documentclass{article}
\usepackage{tikz,xparse,varwidth,graphicx}

\newsavebox{\emptyoval}\newsavebox{\filledoval}
\sbox{\emptyoval}{\tikz \draw     (0,0) circle [x radius=3pt, y radius=6pt ];}
\sbox{\filledoval}{\tikz \filldraw (0,0) circle [x radius=3pt, y radius=6pt ];}

\ExplSyntaxOn
\NewDocumentCommand{\ovals}{O{1ex}m}
 {
  \seq_set_split:Nnn \l_hugomg_ovals_rows_seq { \\ } { #2 }
  \seq_pop_right:NN \l_hugomg_ovals_rows_seq \l_hugomg_ovals_lastrow_tl
  \seq_map_inline:Nn \l_hugomg_ovals_rows_seq
   {
    \hugomg_ovals_row:n { ##1 } \\[#1]
   }
  \hugomg_ovals_row:V \l_hugomg_ovals_lastrow_tl
 }

\cs_new_protected:Nn \hugomg_ovals_row:n
 {
  \clist_map_function:nN { #1 } \hugomg_ovals_entry:n
 }
\cs_generate_variant:Nn \hugomg_ovals_row:n { V }
\cs_new_protected:Nn \hugomg_ovals_entry:n
 {
  \hugomg_ovals_entry:w #1 \q_nil
 }
\cs_new_protected:Npn \hugomg_ovals_entry:w #1 / #2 \q_nil
 {
  \begin{tabular}[b]{c}\hugomg_ovals_make:n {#1} \\ #2 \end{tabular}
 }
\cs_new_protected:Nn \hugomg_ovals_make:n
 {
  \str_map_inline:nn { #1 }
   {
    \str_case:nn { ##1 }
     {
      {0}{\usebox{\emptyoval}}
      {1}{\usebox{\filledoval}}
     }
   }
 }
\ExplSyntaxOff

\begin{document}

\begin{center}
\ovals{
  11/0.05x \\
  01/0.10x, 10/0.20x \\
  00/1.00x
}
\end{center}

\noindent
\resizebox{\textwidth}{!}{%
  \begin{varwidth}{4\textwidth}
  \centering
  \ovals[3ex]{
    111111/0.7x
    \\
    011111/103.4x, 101111/81.5x, 110111/1.7x, 111011/11.4x, 111110/3.3x
    \\
    001111/44.1x, 010111/99.2x, 011011/100.8x, 011101/93.9x, 011110/105.3x,
    100111/81.9x, 101011/81.9x, 101101/77.5x, 101110/82.7x,
    110011/1.8x, 110101/12.1x, 110110/4.3x,
    111001/11.2x, 111010/3.3x, 111100/10.3x,
  }
  \end{varwidth}%
}

\end{document}

enter image description here

4

A possibility with a tabular, cellspace and stackengine:

\documentclass{article}
\usepackage{tikz}
\usepackage[usestackEOL]{stackengine}
\usepackage{cellspace}
\setlength{\cellspacetoplimit}{5pt}
\setlength{\cellspacebottomlimit}{5pt}
\newcommand{\A}{\tikz \draw (0,0) circle [x radius=3pt, y radius=6pt ];}
\newcommand{\B}{\tikz \filldraw (0,0) circle [x radius=3pt, y radius=6pt ];}
\newcommand{\ovals}[2]{\setstackgap{S}{2pt}\Shortstack{#1\\#2}}

 \begin{document}

\begin{center}
\begin{tabular}{Sc}
\ovals{\B\B}{0.05} \\
\ovals{\A\B}{0.10}\quad\ovals{\B\A}{0.20} \\
\ovals{\A\A}{1.00}
\end{tabular}
\end{center}

\end{document} 

enter image description here

You must log in to answer this question.

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