我有一个项目需要许多如图所示的绘图,其中有按长度颜色编码的水平矩形堆栈(例如,所有正方形都是白色,所有 1 x 2 矩形都是红色,就像 Cuisenaire 棒一样)。我使用 \put 和 \framebox 以非常直接的方式对其进行了编码,如果使用 TikZ 会很高兴得到答案。理想情况下,像这样的图片的输入不会比长度列表多太多,即 {{4},{3,2},{2,3},{1,4}} 和 {{1,3,1},{1,2,2},{1,1,3}}。
\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}
答案1
这是一个相当简短的蒂克兹解决方案使用嵌套语句来解析以逗号分隔的矩形长度列表,从而构造彩色矩形\foreach
。使用下面两行代码
\ColouredRectangles{{4},{3,2},{2,3},{1,4}} \qquad
\ColouredRectangles[ultra thick]{{1,3,1},{1,2,2},{1,1,3}}
生成矩形:
矩形的着色有点巧妙,因为这是使用以下方法完成的蒂克兹样式:
\tikzset{
rectangle 1/.style = {fill=white},
rectangle 2/.style = {fill=red},
rectangle 3/.style = {fill=green},
rectangle 4/.style = {fill=violet},
}
在绘制每个矩形时,根据矩形的长度设置其样式,赋予其适当的颜色rectangle <length>
。
完整代码如下:
\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}
如第二个示例所示,该\ColouredRectangles
命令接受一个可选参数来设置底层tikzpicture
环境的样式。
答案2
与。expl3
tikz
命令
\fancyblock
接收一个二维数组来构造块。填充颜色默认是随机的(使用random=false
来更改它),您可以通过 设置路径样式[<style>]
或通过 快速设置填充颜色|<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}}
}
\randomblock
接收一个 1 维数组来绘制随机块,每行的长度为数组的对应元素。
\randomblock{4, 5, 4}
\randomrectangle
接收两个数字,分别是由多个随机块组成的矩形的宽度和高度。
\randomrectangle{4}{7}
完整代码
\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}
答案3
根据我在这里的回答:TikZ 可以创建像素艺术图像吗?
\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}
答案4
您可以使用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}