Macro para dibujar pilas de rectángulos horizontales coloreados

Macro para dibujar pilas de rectángulos horizontales coloreados

Tengo un proyecto que requiere muchos dibujos como el que se muestra, con pilas de rectángulos horizontales codificados por colores según su longitud (por ejemplo, todos los cuadrados son blancos, todos los rectángulos de 1 por 2 son rojos, como las varillas de Cuisenaire). Codifiqué esto de una manera muy directa usando \put y \framebox, me alegraría recibir una respuesta usando TikZ. Lo ideal sería que la entrada para una imagen como ésta no fuera mucho mayor que la lista de longitudes, es decir, {{4},{3,2},{2,3},{1,4}} y {{1, 3,1},{1,2,2},{1,1,3}}.

muestra

\documentclass{article}
\usepackage{graphicx}
\usepackage{color}

\begin{document}

\begingroup
\setlength{\unitlength}{.5cm}
\begin{picture}(10,5)
\setlength{\fboxsep}{0pt}
\thicklines
\put(0,0){\colorbox{white}{\framebox(1,1){}}}  \put(1,0){\colorbox[rgb]{.75,0,1}{\framebox(4,1){}}}
\put(0,1){\colorbox{red}{\framebox(2,1){}}}  \put(2,1){\colorbox{green}{\framebox(3,1){}}}
\put(0,2){\colorbox{green}{\framebox(3,1){}}}  \put(3,2){\colorbox{red}{\framebox(2,1){}}}
\put(0,3){\colorbox[rgb]{.75,0,1}{\framebox(4,1){}}} 
\put(6,0){\colorbox{white}{\framebox(1,1){}}}  \put(7,0){\colorbox{white}{\framebox(1,1){}}}  \put(8,0){\colorbox{green}{\framebox(3,1){}}}
\put(6,1){\colorbox{white}{\framebox(1,1){}}}  \put(7,1){\colorbox{red}{\framebox(2,1){}}}  \put(9,1){\colorbox{red}{\framebox(2,1){}}}
\put(6,2){\colorbox{white}{\framebox(1,1){}}}  \put(7,2){\colorbox{green}{\framebox(3,1){}}}  \put(10,2){\colorbox{white}{\framebox(1,1){}}} 
\end{picture}
\endgroup

\end{document}

Respuesta1

He aquí un resumen bastante breve.TikZsolución que construye los rectángulos coloreados utilizando \foreachdeclaraciones anidadas para analizar una lista separada por comas de longitudes de rectángulos. Con el código debajo de las dos líneas.

\ColouredRectangles{{4},{3,2},{2,3},{1,4}}    \qquad
\ColouredRectangles[ultra thick]{{1,3,1},{1,2,2},{1,1,3}}

producir los rectángulos:

ingrese la descripción de la imagen aquí

La coloración de los rectángulos es un poco complicada porque se hace usando lo siguienteTikZestilos:

\tikzset{
   rectangle 1/.style = {fill=white},
   rectangle 2/.style = {fill=red},
   rectangle 3/.style = {fill=green},
   rectangle 4/.style = {fill=violet},
}

Cuando se dibuja cada rectángulo, se le asigna el color apropiado utilizando la longitud del rectángulo para establecer su estilo rectangle <length>.

Aquí está el código completo:

\documentclass{article}
\usepackage{tikz}

\tikzset{
   % the rectangle size sets the style and hence the fill
   rectangle 1/.style = {fill=white},
   rectangle 2/.style = {fill=red},
   rectangle 3/.style = {fill=green},
   rectangle 4/.style = {fill=violet},
}

\newcommand\ColouredRectangles[2][]{%
  \begin{tikzpicture}[#1]
    \foreach \row [count=\rc] in {#2} {% loop through rows
      \xdef\offset{0} % need to remember how far we have drawn so far
      \foreach \col in \row {% loop through columns
         \draw[rectangle \col] (\offset,-\rc) rectangle ++ (\col, -1);
         \xdef\offset{\numexpr\offset+\col\relax}
      }
    }
  \end{tikzpicture}%
}

\begin{document}

    \ColouredRectangles{{4},{3,2},{2,3},{1,4}}    \qquad
    \ColouredRectangles[ultra thick]{{1,3,1},{1,2,2},{1,1,3}}

\end{document}

Como muestra el segundo ejemplo, el \ColouredRectanglescomando acepta un argumento opcional para diseñar el tikzpictureentorno subyacente.

Respuesta2

Con expl3y tikz.

Comandos

  • \fancyblockrecibe una matriz de 2 atenuaciones para construir bloques. El color de relleno es aleatorio de forma predeterminada (úselo random=falsepara cambiarlo) y puede configurar el estilo de trazado [<style>]o configurar el color de relleno rápidamente con |<color>|.
\fancyblock[
  at={(8, 0)}, name=b, random=false,
  transpose, y=0.5cm,
  block={
    very thick,
    line width=1pt,
    draw=teal,
  }
]{
  {2, 1, 1},
  {1, [fill=red]2, |green|1},
  {1, 3, {[line width=2pt, draw=black]|teal|1}}
}
  • \randomblockrecibe una matriz de 1 atenuación para dibujar bloques aleatorios, siendo la longitud de cada fila el elemento correspondiente de la matriz.
\randomblock{4, 5, 4}
  • \randomrectanglerecibe dos números, que son el ancho y el alto del rectángulo que está compuesto por múltiples bloques aleatorios.
\randomrectangle{4}{7}

ingrese la descripción de la imagen aquí

Código completo

\documentclass[tikz, border=1cm]{standalone}
\usepackage{xparse}

\ExplSyntaxOn
\makeatletter

\tl_new:N   \l__at_tl
\tl_new:N   \l__name_tl
\tl_new:N   \l__anchor_tl
\tl_new:N   \l__block_style_tl
\dim_new:N  \l__block_wd_dim
\dim_new:N  \l__x_coor_dim
\dim_new:N  \l__y_coor_dim
\dim_new:N  \l__block_x_unit_dim
\dim_new:N  \l__block_y_unit_dim
\int_new:N  \l__remain_int
\int_new:N  \l__temp_int
\bool_new:N \l__random_bool
\bool_new:N \l__transpose_bool

\keys_define:nn { fancyblock }
  {
    at          . tl_set:N   = \l__at_tl,
    name        . tl_set:N   = \l__name_tl,
    random      . bool_set:N = \l__random_bool,
    random      . default:n  = true,
    transpose   . bool_set:N = \l__transpose_bool,
    transpose   . default:n  = true,
    x           . dim_set:N  = \l__block_x_unit_dim,
    y           . dim_set:N  = \l__block_y_unit_dim,
    unit        . code:n     =
      {
        \dim_set:Nn \l__block_x_unit_dim { #1 }
        \dim_set:Nn \l__block_y_unit_dim { #1 }
      },
    block       . code:n     =
      {
        \tl_put_right:Nn \l__block_style_tl { ,#1 }
      },
    anchor      . choice:,
    anchor / l  . code:n     = { \tl_set:Nn \l__anchor_tl { west } },
    anchor / r  . code:n     = { \tl_set:Nn \l__anchor_tl { east } },
    anchor / t  . code:n     = { \tl_set:Nn \l__anchor_tl { north } },
    anchor / b  . code:n     = { \tl_set:Nn \l__anchor_tl { south } },
    anchor / lb . code:n     = { \tl_set:Nn \l__anchor_tl { south~west } },
    anchor / bl . code:n     = { \tl_set:Nn \l__anchor_tl { south~west } },
    anchor / lt . code:n     = { \tl_set:Nn \l__anchor_tl { north~west } },
    anchor / tl . code:n     = { \tl_set:Nn \l__anchor_tl { north~west } },
    anchor / rb . code:n     = { \tl_set:Nn \l__anchor_tl { south~east } },
    anchor / br . code:n     = { \tl_set:Nn \l__anchor_tl { south~east } },
    anchor / rt . code:n     = { \tl_set:Nn \l__anchor_tl { north~east } },
    anchor / tr . code:n     = { \tl_set:Nn \l__anchor_tl { north~east } },
  }

\NewDocumentCommand { \randomblock } { O{} m }
  {
    \generate_num_matrix:n { #2 }
    \fancyblock[#1]{\clist_use:Nn \l__matrix_clist {,}}
  }

\NewDocumentCommand { \randomrectangle } { O{} m m }
  {
    \seq_clear:N \l_tmpa_seq
    \int_step_inline:nn { #2 }
      {
        \seq_put_right:Nn \l_tmpa_seq { #3 }
      }
    \generate_num_matrix:x
      {
        \seq_use:Nn \l_tmpa_seq { , }
      }
    \fancyblock[#1]{\clist_use:Nn \l__matrix_clist {,}}
  }

\cs_new_protected:Nn \generate_num_matrix:n
  {
    \clist_clear_new:N \l__matrix_clist
    \clist_map_inline:nn { #1 }
      {
        \generate_num_seq:n { ##1 }
        \clist_put_right:Nx \l__matrix_clist
          {
            { { \clist_use:Nn \l__row_clist {,} } }
          }
      }
  }
\cs_generate_variant:Nn \generate_num_matrix:n { x }

\cs_new_protected:Nn \generate_num_seq:n
  {
    \clist_clear_new:N \l__row_clist
    \int_set:Nn \l__remain_int { #1 }
    \int_while_do:nn { \l__remain_int > 0 }
      {
        \int_set:Nn \l__temp_int {
          \int_rand:n { \l__remain_int }
        }
        \int_add:Nn \l__remain_int { -\l__temp_int }
        \clist_put_right:Nx \l__row_clist { \int_use:N \l__temp_int }
      }
  }

\NewDocumentCommand { \fancyblock } { O{} m }
  {
    \tl_clear:N \l__block_style_tl
    \keys_set:nn { fancyblock }
      {
        at        = { (0, 0) },
        block     = { draw, thick },
        unit      = 1cm,
        transpose = false,
        anchor    = lb,
        name      = block,
        random,
        #1
      }
    \draw_block_matrix:x { #2 }
  }

\cs_new_protected:Nn \draw_block_matrix:n
  {
    \clist_set:Nn \l_tmpa_clist { #1 }
    \bool_if:NTF \l__transpose_bool
      {
        \dim_zero:N \l__x_coor_dim
      }
      {
        \dim_zero:N \l__y_coor_dim
        \clist_reverse:N \l_tmpa_clist
      }
    \matrix [anchor=\l__anchor_tl] (\l__name_tl) at \l__at_tl {
      \clist_map_inline:Nn \l_tmpa_clist
        {
          \draw_row:n { ##1 }
          \bool_if:NTF \l__transpose_bool
            {
              \dim_add:Nn \l__x_coor_dim { \l__block_x_unit_dim }
            }
            {
              \dim_add:Nn \l__y_coor_dim { \l__block_y_unit_dim }
            }
        }\\
    };
  }
\cs_generate_variant:Nn \draw_block_matrix:n { x, v, f }

\cs_new_protected:Nn \draw_row:n
  {
    \bool_if:NTF \l__transpose_bool
      {
        \dim_zero:N \l__y_coor_dim
      }
      {
        \dim_zero:N \l__x_coor_dim
      }
    \clist_map_inline:nn { #1 }
      {
        \draw_block:n { ##1 }
      }
  }

\cs_new_protected:Nn \draw_block:n
  {
    \tl_clear_new:N \l__draw_block_tl
    \parse_args:n { #1 }
    \definecolor{random}{RGB}{
      \int_rand:n { 255 },
      \int_rand:n { 255 },
      \int_rand:n { 255 }
    }
    \tl_set:Nx \l_tmpb_tl
      {
        \bool_if:NTF \l__random_bool
          { fill=random }
          { }
      }
    \tl_set:Nx \l__draw_block_tl
      {
        \exp_not:N \path[
          \l__block_style_tl,
          \l_tmpb_tl,
          \seq_use:Nn \l__block_style_seq { , }]
          (\dim_use:N \l__x_coor_dim, \dim_use:N \l__y_coor_dim) --
        \bool_if:NTF \l__transpose_bool
          {
              ++(0, \dim_use:N \l__block_wd_dim) --
              ++(\dim_use:N \l__block_x_unit_dim, 0) --
              ++(0, \dim_eval:n { -\l__block_wd_dim }) -- cycle;
          }
          {
              ++(\dim_use:N \l__block_wd_dim, 0) --
              ++(0, \dim_use:N \l__block_y_unit_dim) --
              ++(\dim_eval:n { -\l__block_wd_dim }, 0) -- cycle;
          }
      }
    \tl_use:N \l__draw_block_tl
    \bool_if:NTF \l__transpose_bool
      {
        \dim_add:Nn \l__y_coor_dim { \l__block_wd_dim }
      }
      {
        \dim_add:Nn \l__x_coor_dim { \l__block_wd_dim }
      }
  }

\cs_new_protected:Nn \parse_args:n
  {
    \seq_clear_new:N \l__block_style_seq
    \fp_set:Nn \l__block_wd_fp { 1 }
    \parse_next_arg: #1\stop
  }

\cs_new_protected:Nn \parse_next_arg:
  {
    \peek_meaning_ignore_spaces:NTF [
      { \parse_style:w }
      {
        \peek_meaning_ignore_spaces:NTF |
          { \parse_fill:w }
          { \parse_len:w }
      }
  }

\cs_new_protected:Npn \parse_style:w [#1]
  {
    \seq_put_right:Nn \l__block_style_seq { #1 }
    \parse_next_arg:
  }

\cs_new_protected:Npn \parse_fill:w |#1|
  {
    \seq_put_right:Nn \l__block_style_seq { fill=#1 }
    \parse_next_arg:
  }

\cs_new_protected:Npn \parse_len:w #1\stop
  {
    \tikz@checkunit{#1}
    \legacy_if:nTF { tikz@isdimension }
      { \dim_set:Nn \l__block_wd_dim { #1 } }
      {
        \bool_if:NTF \l__transpose_bool
          {
            \dim_set:Nn \l__block_wd_dim { \l__block_y_unit_dim * #1 }
          }
          {
            \dim_set:Nn \l__block_wd_dim { \l__block_x_unit_dim * #1 }
          }
      }
  }

\makeatother
\ExplSyntaxOff

\begin{document}
\begin{tikzpicture}
\fancyblock[name=a]{
  {2, 2, 1},
  {1, 2, 1},
  {3, 1, 1}
}
\path (a.south) node [below] {\verb|\fancyblock|};

\fancyblock[
  at={(8, 0)}, name=b, random=false,
  transpose, y=0.5cm,
  block={
    very thick,
    line width=1pt,
    draw=teal,
  }
]{
  {2, 1, 1},
  {1, [fill=red]2, |green|1},
  {1, 3, {[line width=2pt, draw=black]|teal|1}}
}
\path (b.south) node [below] {\verb|\fancyblock| with options};

\randomblock[at={([yshift=1cm]a.north west)}, name=c]{4, 5, 4}
\path (c.south) node [below] {\verb|\randomblock|};

\randomrectangle[at={(c.south -| b.center)}, name=d, anchor=b]{4}{7}
\path (d.south) node [below] {\verb|\randomrectangle|};

\end{tikzpicture}
\end{document}

Respuesta3

Basado en mi respuesta aquí:¿Puede TikZ crear imágenes pixel art?

\documentclass{article}
\usepackage{xcolor}
\usepackage{stackengine}
\newlength\blocksize
\setlength\blocksize{1ex}
\newcommand\block[2]{\kern-\fboxrule\fboxsep=0pt%
  \fbox{\color{#1}\rule{%
    \dimexpr#2\blocksize+\numexpr#2-1\relax\fboxrule\relax}{\blocksize}}}
\newcommand\gr[1][1]{\block{green}{#1}}
\newcommand\rd[1][1]{\block{red}{#1}}
\newcommand\bl[1][1]{\block{blue}{#1}}
\newcommand\wh[1][1]{\block{white}{#1}}
\setstackgap{S}{-\fboxrule}
\begin{document}
\Shortstack[l]{
\rd\gr[2]\gr\rd[3]\\
\gr\bl[3]\gr\gr\\
\gr\bl\rd[2]\wh\wh\gr}
\end{document} 

ingrese la descripción de la imagen aquí

Respuesta4

Puedes usar pic.

\documentclass[tikz,margin=3mm]{standalone}
\usepackage{color}

\tikzset{
    pics/cube/.style args={#1-#2}{
      code = {
    \draw [black,fill=#2](0,0)--(#1,0)--(#1,1)--(0,1)--cycle;  
      }
      }
      }

\begin{document}

\begin{tikzpicture}
\pic at (0,0) {cube=1-white};
\pic at (1,0) {cube=1-white};
\pic at (2,0) {cube=3-green};
\pic at (0,1) {cube=1-white};
\pic at (1,1) {cube=2-red};
\pic at (3,1) {cube=2-red};
\pic at (0,2) {cube=1-white};
\pic at (1,2) {cube=3-green};
\pic at (4,2) {cube=1-white};
\end{tikzpicture}

\end{document}

ingrese la descripción de la imagen aquí

información relacionada