如何使用图表下的数据扩展 tikzpicture?
我写了下面的图表,在 LaTeX 中显示得很好。但是,图中的点非常接近,因此很难看出哪个图点高于另一个。
我需要的是一张表格,图表下方有数据,就像我在 Excel 中做的那样。如何在 LaTeX 中做到这一点?
\begin{figure}[htbp]
\centering
\begin{tikzpicture}
\begin{axis}[
title={\textbf{All-Pairs Shortest Path}},
scaled y ticks = false,
y tick label style={/pgf/number format/fixed,
/pgf/number format/1000 sep = \thinspace},
xlabel={Matrix Dimension},
ylabel={Gas},
xmin=0, xmax=25,
ymin=0, ymax=10500000,
xtick={1,4,8,12,16,20,24},
%ytick={},
legend pos=north west,
ymajorgrids=true,
grid style=dashed,
width = \linewidth
]
\addplot[
color=blue,
mark=*,
mark options={scale=1.50}
]
coordinates {
(1,23902)(4,78508)(8,426081)(12,1338366)(16,3086445)(20,5945874)(24,10182149)
};
\addplot[
color=red,
mark=triangle*,
mark options={scale=1.50},
]
coordinates {
(1,107391)(4,154467)(8,306647)(12,563926)(16,928604)(20,1411996)(24,2025096)
};
\legend{Local, Oraclize}
\end{axis}
\end{tikzpicture}
\caption{Gas cost of computing all-pairs shortest path (APSP) using Floyd-Warshall algorithm. (Source: Project)}
\label{fig:apsp}
\end{figure}
如果我使用 Torbjørn 的答案来绘制包含 10 个数据点的图表,
\pgfplotsset{compat=1.14}
% read in data
\pgfplotstableread{
x v nv
1 22147 107477
5 26844 120709
10 32674 137975
25 60060 188721
50 101523 274672
100 205331 445946
250 542985 982947
500 1208542 1914372
750 1956327 2901016
1000 2634826 3928101
}\datatable
% get number of rows
\pgfplotstablegetrowsof{\datatable}
% subtract 1 because table indices start at 0
\pgfmathsetmacro{\Nrows}{\pgfplotsretval-1}
% for convenience, macro to store width of axis
\pgfmathsetlengthmacro{\MyAxisW}{10cm}
\begin{figure}[htbp]
\centering
\begin{tikzpicture}[
cell/.style={ % style used for "table" cells
draw,
minimum width={\MyAxisW/(\Nrows+1)}, % +1 because -1 above
minimum height=4ex,
inner sep=0pt,
outer sep=0pt,
anchor=north west,
font=\sffamily\scriptsize
}]
\begin{axis}[
name=ax,
% so axis labels and ticklabels are not accounted for in size settings
scale only axis,
width=\MyAxisW,
height=4cm,
% we add the ticklabels as part of the table, so no xticks needed
xtick=\empty,
% and add grid lines
grid=major,
% only need left y-axis line
axis y line=left,
x axis line style={draw=none},
% and for that we need to make sure that the distance from the first/last tick
% to the axis edge is the same, so that there is a half a bar width of space
enlarge x limits={abs={\MyAxisW/(2*\Nrows+2)}},
ymin=0,
title={Array Sorting},
title style={font=\bfseries},
ylabel={Gas},
xlabel={\# matrix dimension},
% move xlabel to below table
xlabel shift=12ex,
% set yticks as sans serif
tick label style={
font=\sansmath\sffamily\small,
% and remove comma in 1,000
/pgf/number format/set thousands separator=},
% set axis labels as sans serif
label style={font=\sansmath\sffamily}
]
% because the x-values are not evenly spaced, used index as x-value instead
\addplot +[black!60] table[x expr=\coordindex,y=nv] {\datatable};
\label{dataNV}
\addplot +[black!20] table[x expr=\coordindex,y=v] {\datatable};
\label{dataV}
\end{axis}
% define a starter coordinate at the lower left corner of the axis
\coordinate (c-0-0) at (ax.south west);
% loop over the table
\foreach [count=\j from 1] \i in {0,...,\Nrows}
{
% get element \i from the x-column, stored in \pgfplotsretval
\pgfplotstablegetelem{\i}{x}\of\datatable
% add node with value
\node [cell] (c-0-\j) at (c-0-\i.north east) {\pgfplotsretval};
% repeat for other two columns
\pgfplotstablegetelem{\i}{v}\of\datatable
\node [cell] (c-1-\j) at (c-0-\j.south west) {\pgfplotsretval};
\pgfplotstablegetelem{\i}{nv}\of\datatable
\node [cell] (c-2-\j) at (c-1-\j.south west) {\pgfplotsretval};
}
% add "legend" on the left
\matrix [draw,nodes={cell,minimum width=0pt,draw=none},anchor=north east,row sep=0pt,column sep=5pt,outer sep=0pt,inner ysep=0pt] (m) at (c-1-1.north west)
{
\node {\ref{dataV}}; & \node{Gas: Oraclize}; \\
\node {\ref{dataNV}}; & \node{Gas: local}; \\
};
% draw center line of legend
\draw (m.west) -- (m.east);
\end{tikzpicture}
\end{figure}
我遇到的问题是关于 x 轴上的“点”(数据点)以及对于数据来说太小的列?
答案1
接受代码表格上方的堆叠条形图,并做以下几件事:
- 用您的数据替换其中
\pgfplotstableread
的数据。第一列为 x 值,然后两列为 y 数据。 - 从选项中删除
axis
:ybar stacked
(不需要条形图)bar width={...}
(不需要,不是条形图)ytick distance=200
(当 y 轴跨度达到 10^7 时就太荒谬了)
- 在选项中更改
ylabel
/ ,并添加。xlabel
axis
title
\matrix
在生成图例 的选项中:- 改成
nodes={cell,draw=none}
nodes={cell,minimum width=0pt,draw=none}
column sep=5pt
在 旁边添加row sep
。
- 改成
+[black!60]
从第一个\addplot
和+[black!20]
第二个中删除。
如果数字对于单元格来说太宽,您可以采取以下几种措施。
- 将样式中
\scriptstyle
的改为,以减小字体大小。即,您将在下面找到,将其改为。\tiny
cell
font=\sffamily\scriptsize
font=\sffamily\tiny
- 增加轴的宽度。宽度在
\MyAxisW
宏中定义,因此从 更改为\pgfmathsetlengthmacro{\MyAxisW}{10cm}
例如\pgfmathsetlengthmacro{\MyAxisW}{12cm}
。
或者两者都做,这取决于数字、数据点的数量等。
由于ymin=0
,数字最小的点位于 x 轴上。要解决这个问题,您可以做以下两件事之一:
ymin
例如,将值更改为ymin=-1e5
。ymin=0
用。。。来代替enlarge y limits
。
要添加第三个图,您需要
- 在表中添加新列
- 添加新的
\addplot
假设新列
nnv
名为\pgfplotstablegetelem{\i}{nnv}\of\datatable \node [cell] (c-3-\j) at (c-2-\j.south west) {\pgfplotsretval};
到构建表的循环
- 修改图例中水平线的绘制方法
- 增加
xlabel shift
, 以解释新的表格行
\documentclass[border=5mm]{standalone}
% for sans serif ticks (https://tex.stackexchange.com/questions/33325/)
\usepackage[eulergreek]{sansmath}
\usepackage{pgfplots,pgfplotstable}
\pgfplotsset{compat=1.14}
% read in data
\pgfplotstableread{
x v nv nnv
1 23902 107391 100391
4 78508 154467 254467
8 426081 306647 406647
12 1338366 563926 550926
16 3086445 928604 1028604
20 5945874 1411996 1511996
24 10182149 2025096 2525096
}\datatable
% get number of rows
\pgfplotstablegetrowsof{\datatable}
% subtract 1 because table indices start at 0
\pgfmathsetmacro{\Nrows}{\pgfplotsretval-1}
% for convenience, macro to store width of axis
\pgfmathsetlengthmacro{\MyAxisW}{10cm}
\begin{document}%
\begin{tikzpicture}[
cell/.style={ % style used for "table" cells
draw,
minimum width={\MyAxisW/(\Nrows+1)}, % +1 because -1 above
minimum height=4ex,
inner sep=0pt,
outer sep=0pt,
anchor=north west,
font=\sffamily\scriptsize
}]
\begin{axis}[
name=ax,
% so axis labels and ticklabels are not accounted for in size settings
scale only axis,
width=\MyAxisW,
height=4cm,
% we add the ticklabels as part of the table, so no xticks needed
xtick=\empty,
% and add grid lines
grid=major,
% only need left y-axis line
axis y line=left,
x axis line style={draw=none},
% and for that we need to make sure that the distance from the first/last tick
% to the axis edge is the same, so that there is a half a bar width of space
enlarge x limits={abs={\MyAxisW/(2*\Nrows+2)}},
ymin=0,
title={All-Pairs Shortest Path},
title style={font=\bfseries},
ylabel={Gas},
xlabel={\# matrix dimension},
% move xlabel to below table
xlabel shift=16ex,
% set yticks as sans serif
tick label style={
font=\sansmath\sffamily\small,
% and remove comma in 1,000
/pgf/number format/set thousands separator=},
% set axis labels as sans serif
label style={font=\sansmath\sffamily}
]
% because the x-values are not evenly spaced, used index as x-value instead
\addplot table[x expr=\coordindex,y=nnv] {\datatable};
\label{dataNNV}
\addplot table[x expr=\coordindex,y=nv] {\datatable};
\label{dataNV}
\addplot table[x expr=\coordindex,y=v] {\datatable};
\label{dataV}
\end{axis}
% define a starter coordinate at the lower left corner of the axis
\coordinate (c-0-0) at (ax.south west);
% loop over the table
\foreach [count=\j from 1] \i in {0,...,\Nrows}
{
% get element \i from the x-column, stored in \pgfplotsretval
\pgfplotstablegetelem{\i}{x}\of\datatable
% add node with value
\node [cell] (c-0-\j) at (c-0-\i.north east) {\pgfplotsretval};
% repeat for other two columns
\pgfplotstablegetelem{\i}{v}\of\datatable
\node [cell] (c-1-\j) at (c-0-\j.south west) {\pgfplotsretval};
\pgfplotstablegetelem{\i}{nv}\of\datatable
\node [cell] (c-2-\j) at (c-1-\j.south west) {\pgfplotsretval};
\pgfplotstablegetelem{\i}{nnv}\of\datatable
\node [cell] (c-3-\j) at (c-2-\j.south west) {\pgfplotsretval};
}
% add "legend" on the left
\matrix [draw,nodes={cell,minimum width=0pt,draw=none},anchor=north east,row sep=0pt,column sep=5pt,outer sep=0pt,inner ysep=0pt] (m) at (c-1-1.north west)
{
\node {\ref{dataV}}; & \node{Gas: Oraclize}; \\
\node {\ref{dataNV}}; & \node{Gas: local}; \\
\node {\ref{dataNNV}}; & \node{Foobar}; \\
};
% draw horizontal lines in legend
\draw (m.west |- c-1-1.south west) -- (c-1-1.south west);
\draw (m.west |- c-2-1.south west) -- (c-2-1.south west);
\end{tikzpicture}
\end{document}