\usepackage{tikz}
\usetikzlibrary{patterns, arrows}
\begin{document}
\begin{tikzpicture}
% Set the width and height of the rectangles
\pgfmathsetmacro{\rectHeight}{1} % Height of all rectangles
\pgfmathsetmacro{\totalWidth}{8} % Total width of the bottom rectangle
\pgfmathsetmacro{\toprecPercentage}{0.8} % Width of the top rectangle as a percentage of the bottom rectangle
% Define the number of rectangles
\def\numRectangles{9}
% Define an array of descriptions for the arrows
\def\descriptions{{"Desc 0", "Desc 1", "Desc 2", "Desc 3", "Desc 4", "Desc 5", "Desc 6", "Desc 7", "Desc 8"}}
% Define an array of segment counts
\def\segmentCounts{{3, 9, 1, 1, 1, 1, 1, 1, 1}} % Number of segments for each rectangle
% Define segmentFillPercentages for each rectangle
\def\segmentFillPercentages{
{70, 30, 50}, % Customize these percentages for rectangle 0
{20, 40, 60, 80, 10, 30, 50, 70, 90}, % Customize these percentages for rectangle 1
{10}, % Customize these percentages for rectangle 2
{40}, % Customize these percentages for rectangle 3
{20}, % Customize these percentages for rectangle 4
{10}, % Customize these percentages for rectangle 5
{40}, % Customize these percentages for rectangle 6
{20}, % Customize these percentages for rectangle 7
{100} % Customize these percentages for rectangle 8
}
% Calculate the width of the top rectangle
\pgfmathsetmacro{\toprecWidth}{\toprecPercentage*\totalWidth}
% Draw the rectangles and fill them with different patterns based on patterns based on fill percentages and segment counts
\foreach \i in {0,...,\numexpr\numRectangles-1} {
\pgfmathsetmacro{\currentWidth}{\totalWidth - (\i/\numRectangles)*\toprecWidth}
\pgfmathsetmacro{\startingPoint}{0.5*(\totalWidth-\currentWidth)} % Calculate the starting point
% Draw segments within each rectangle
\pgfmathsetmacro{\segmentCount}{\segmentCounts[\i]}
\pgfmathsetmacro{\segmentWidth}{\currentWidth/\segmentCount}
% Get the fill percentages for the current rectangle
\pgfmathparse{\segmentFillPercentages[\i]}
\let\currentSegmentFillPercentages\pgfmathresult
% Draw and fill each segment with different fill percentages
\foreach \j in {1,...,\segmentCount} {
\pgfmathparse{\currentSegmentFillPercentages[\j-1]}
\let\segmentFillPercentage\pgfmathresult
\pgfmathsetmacro{\segmentStartingPoint}{\startingPoint + (\j-1)*\segmentWidth}
\draw (\segmentStartingPoint,\rectHeight*\i) rectangle (\segmentStartingPoint + \segmentWidth,\rectHeight*\i+\rectHeight);
\fill[pattern=grid,pattern color=redpattern=grid,pattern color=red] (\segmentStartingPoint,\rectHeight*\i) rectangle (\segmentStartingPoint + \segmentWidth,\rectHeight*\i+(\segmentFillPercentage/100)*\rectHeight);
}
% Add arrows and descriptions within the loop
\draw[->] (\startingPoint + \currentWidth + 0.2, \rectHeight*\i + 0.5*\rectHeight) -- (\startingPoint + \currentWidth + 1.0, \rectHeight*\i + 0.5*\rectHeight) node[right,font=\footnotesize,text width=2cm] {\pgfmathparse{\descriptions[\i]}\pgfmathresult};
}
\end{tikzpicture}
\end{document}
尝试了不同的方法来获取片段的填充颜色,但无法获得正确的颜色。任何关于解决此问题的帮助都将不胜感激。
答案1
循环\fill
中\j
有一个错误的选项(缺少逗号):
\fill[pattern=grid,pattern color=redpattern=grid,pattern color=red] …;
让我们修复这个问题:
\fill[pattern=grid,pattern color=red] …;
相同的路径在坐标内使用括号进行计算。您将得到保护那些来自 TikZ 解析器的人加上另一副大括号:
(\segmentStartingPoint + \segmentWidth,
{\rectHeight*\i+(\segmentFillPercentage/100)*\rectHeight})
不过,括号不是必需的,您可以在这里使用相对坐标:
\fill[pattern=grid,pattern color=red]
(\segmentStartingPoint, \rectHeight*\i)
rectangle +(\segmentWidth, \segmentFillPercentage/100*\rectHeight);
对于数组,数组\segmentFillPercentages
需要另一组括号,如下所示手册指出:
{x}
(数组运算符)[…]
⟨array specification⟩
由逗号分隔的元素组成,例如{1, 2, 3, 4, 5}
。 […] 此外,数组的元素可以是数组本身,从而允许模拟多维数组:{1, {2,3}, {4,5}, 6}
。在宏中存储数组时,请不要忘记周围的括号:\def\myarray{{1,2,3}}
不是\def\myarray{1,2,3}
。
在这里,我选择在 PGFMath 公式中插入这些括号:
\pgfmathsetmacro\currentSegmentFillPercentages{{\segmentFillPercentages}[\i]}
不幸的是,此时列表内的列表将转换为数组的内部表示,这意味着以后的访问将\currentSegmentFillPercentages
不再起作用。您可以改用两个数组访问运算符:
\pgfmathsetmacro\segmentFillPercentage{{\segmentFillPercentages}[\i][\j]}
或者
\pgfmathArraysetmacro{\segmentFillPercentage}{\currentSegmentFillPercentages}{\j}
这样 PGFMath 就不需要[\i]
多次访问。
但是,对于只有一个段的矩形,这两种方法都无法正常工作,因为内部表示不再兼容。
对于这一点,我们直接采用即可\currentSegmentFillPercentages
。
(我还将\j
循环转换为 0,...,\segmentCount-1 循环。)
代码
\documentclass[tikz]{standalone}
\usepackage{tikz}
\usetikzlibrary{patterns, arrows}
\makeatletter
\newcommand*\pgfmathArraysetmacro[3]{%
\pgfmathtruncatemacro\@temp{#3}%
\expandafter\pgfmatharray@#2{\@temp}%
\let#1\pgfmathresult}
\makeatother
\begin{document}
\begin{tikzpicture}
% Set the width and height of the rectangles
\pgfmathsetmacro{\rectHeight}{1} % Height of all rectangles
\pgfmathsetmacro{\totalWidth}{8} % Total width of the bottom rectangle
\pgfmathsetmacro{\toprecPercentage}{0.8} % Width of the top rectangle as a percentage of the bottom rectangle
% Define the number of rectangles
\def\numRectangles{9}
% Define an array of descriptions for the arrows
\def\descriptions{{"Desc 0", "Desc 1", "Desc 2", "Desc 3", "Desc 4", "Desc 5", "Desc 6", "Desc 7", "Desc 8"}}
% Define an array of segment counts
\def\segmentCounts{{3, 9, 1, 1, 1, 1, 1, 1, 1}} % Number of segments for each rectangle
% Define segmentFillPercentages for each rectangle
\def\segmentFillPercentages{
{70, 30, 50}, % Customize these percentages for rectangle 0
{20, 40, 60, 80, 10, 30, 50, 70, 90}, % Customize these percentages for rectangle 1
{10}, % Customize these percentages for rectangle 2
{40}, % Customize these percentages for rectangle 3
{20}, % Customize these percentages for rectangle 4
{10}, % Customize these percentages for rectangle 5
{40}, % Customize these percentages for rectangle 6
{20}, % Customize these percentages for rectangle 7
{100} % Customize these percentages for rectangle 8
}
% Calculate the width of the top rectangle
\pgfmathsetmacro{\toprecWidth}{\toprecPercentage*\totalWidth}
% Draw the rectangles and fill them with different patterns based on patterns based on fill percentages and segment counts
\foreach \i in {0,...,\inteval{\numRectangles-1}} {
\pgfmathsetmacro{\currentWidth}{\totalWidth - (\i/\numRectangles)*\toprecWidth}
\pgfmathsetmacro{\startingPoint}{0.5*(\totalWidth-\currentWidth)} % Calculate the starting point
% Draw segments within each rectangle
\pgfmathsetmacro{\segmentCount}{\segmentCounts[\i]}
\pgfmathsetmacro{\segmentWidth}{\currentWidth/\segmentCount}
% Get the fill percentages for the current rectangle
\pgfmathsetmacro\currentSegmentFillPercentages{{\segmentFillPercentages}[\i]}
\typeout{\currentSegmentFillPercentages}
% Draw and fill each segment with different fill percentages
\foreach \j in {0,...,\inteval{\segmentCount-1}} {
\ifnum\segmentCount=1 % need to check special case of just one segment
\let\segmentFillPercentage\currentSegmentFillPercentages
\else
\pgfmathsetmacro\segmentFillPercentage{{\segmentFillPercentages}[\i][\j]} % Option 1
% \pgfmathArraysetmacro{\segmentFillPercentage}{\currentSegmentFillPercentages}{\j} % Option 2
\fi
\pgfmathsetmacro{\segmentStartingPoint}{\startingPoint + \j*\segmentWidth}
\draw (\segmentStartingPoint, \rectHeight*\i) rectangle +(\segmentWidth, \rectHeight);
\fill[pattern=grid,pattern color=red] (\segmentStartingPoint,\rectHeight*\i) rectangle + (\segmentWidth, \segmentFillPercentage/100*\rectHeight);
}
% Add arrows and descriptions within the loop
\draw[->] (\startingPoint + \currentWidth + 0.2, \rectHeight*\i + 0.5*\rectHeight) -- +(.8,0)
node[right, font=\footnotesize, text width=2cm] {\pgfmathprint{\descriptions[\i]}};
}
\end{tikzpicture}
\end{document}
输出
答案2
这是绘制该图的另一种方法。
您需要三个宏:
\botWidth
描述底部矩形的宽度,\topWidth
描述顶部矩形的宽度和\LIST
包含描述列表和百分比列表。
该宏\countList
用于计算的元素\LIST
,我们不能——与\Percs
后面不同——使用dim
函数,因为\LIST
它不仅包含数学。
该图的其余部分是一个大的\foreach
循环,循环遍历\LIST
。使用evaluate
键,将评估百分比数,并从和\Width
计算矩形的。(矩形的宽度实际上是指定数字的两倍。)\botWidth
\topWidth
矩形的高度已设置,1
但可以通过设置不同的y
矢量轻松调整。
将绘制矩形并将path picture
使用绘制图案:
为此设置一个坐标系,以便
(0, 0)
位于左下角,(1, 0)
位于右下角,(0, 1)
位于左上角,(1, 1)
位于右上角。
(这只在不使用旋转或倾斜等变换的情况下才有效。)这意味着我们可以使用1/\numPercs
图案矩形的宽度和\perc/100
高度。
代码
\documentclass[tikz]{standalone}
\usetikzlibrary{arrows.meta, calc, patterns}
\newcommand*\countList[2]{% not the most efficient but oh well
\setcounter{pgf@counta}{0}%
\foreach~in#1{\stepcounter{pgf@counta}}%
\edef#2{\the\value{pgf@counta}}}
\begin{document}
\begin{tikzpicture}[thick]
\newcommand*\botWidth{4}
\newcommand*\topWidth{1}
\newcommand*\LIST{%
Desc 0/{70, 30, 50},
Desc 1/{20, 40, 60, 80, 10, 30, 50, 70, 90},
Desc 2/{10},
Desc 3/{40},
Desc 4/{20},
Desc 5/{10},
Desc 6/{40},
Desc 7/{20},
Desc 8/{100}}
\countList\LIST\n
\foreach[
count=\i from 0,
evaluate={
\numPercs=dim({\Percs});
\Width=\botWidth-(\botWidth-\topWidth)/(\n-1)*\i;
}] \Title/\Percs in \LIST {
\draw (-\Width,\i) rectangle +(2*\Width,1) coordinate (tr) [
path picture={
\tikzset{shift=(path picture bounding box.south west),
x=(path picture bounding box.south east),
y=(path picture bounding box.north west)}
\coordinate (@) at (0, 0);
\foreach \perc in \Percs
\path[pattern=grid, pattern color=red]
(@) edge (@|-0,1)
(@) rectangle +(1/\numPercs,\perc/100)
coordinate (@) at (current path bounding box.south east);
},
];
\draw[->] ([shift=(down:.5), xshift=5mm]tr) -- +(right:8mm)
node[right] {\Title};
}
\end{tikzpicture}
\end{document}