metapost 中的绘图问题

metapost 中的绘图问题

mydata.d我想要绘制图表的文件中有一些如下数据(第一列和第二列) :

8   98826   year 2008
9   104925  year 2009
10  140153  year 2010
11  178414  year 2011

由于第二个数字很大,我使用了宏sarith。这是我的绘图元帖子代码:

input graph
input sarith
beginfig(1);
draw begingraph(8cm,5cm);
setrange(8,whatever,12,whatever);
gdraw "mydata.d" withpen pencircle scaled 1.5pt;;
gdraw "mydata.d" plot btex $\bullet$ etex;
autogrid(otick.bot,);
gdotlabel.lrt(btex $98\;826$ etex, 8,"98826");
gdotlabel.lrt(btex $104\;925$ etex, 9,"104925");
gdotlabel.lrt(btex $140\;153$ etex, 10,"140153");
gdotlabel.lrt(btex $178\;414$ etex, 11,"178414");
endgraph;
endfig;
end

因此,我绘制了前两列,去掉了 y 轴刻度和标签,并在图中的每个坐标处写入了 y 值。我有以下问题:

  1. 我想显示年份,即 2008 年至 2010 年,但 metapost 仅在 x 轴上显示 2010 年,这就是为什么我选择数字 8 到 10。这是为什么?

  2. 如果绘制曲线,您将在每个坐标处看到两个点,其中写有相应的 y 值。为什么会发生这种情况?即使我删除行 gdraw ,也会出现这种情况mydata.d" plot btex $\bullet$ etex。在行中gdotlabel,我必须将第二列中的数字括在引号中,例如“98826”。这是否会导致 metapost 在如此大的数字下无法准确显示,从而出现两个点?

  3. 如果从 1 开始我们可以很好地显示 2008、2009、2010 和 2011 年,那么我们如何显示它们,但要逆时针旋转 90 度,以便标签不会在水平方向上占用太多空间?

  4. 如果我要求 metapost 在 y 轴上显示 y 值,那么它将以指数形式而不是纯十进制形式(如 100000、150000 等)显示。如何实现这一点?

  5. 我知道 metapost 会忽略除这两列之外的其他列,这对于在第一行写与该行相关的注释(例如 2008 年)很有用。但是,如果我想为整个文件添加全局注释(例如“我每年吃的苹果数量”),那么我无法在文件的开头执行此操作。我假设我们可以在文件末尾执行此操作,但是怎么做呢?我尝试过留空并以 % 符号开始注释行,但这样做不起作用。

我在 Win XP 下使用 TeXLive 2010 和 MetaPost,版本 1.211。我也尝试过 TL 2011 和 MetaPost 1.504。

非常感谢您的帮助...

答案1

我知道这已经过时了,但这些问题的答案相当简单,所以我想我会试一试。尽管我是 MP 的粉丝,但我认为我会同意 @percusse 的观点,即 pgfplots 可能比input graphMP 更好。

我马上就会列出问题清单,但首先我们可以简化一下。MP 图表输入的正确格式如下:

2008   98826  Your comments go here
2009  104925
2010  140153
2011  178414

所以我假设你已经改为mydata.d这种格式。

有了这个数据文件,我们就可以生成仅用一条线的图表gdraw

prologues := 3;
outputtemplate := "%j%c.eps";

input graph

beginfig(1);
draw begingraph(160, 100);
  gdraw "mydata.d" withpen pencircle scaled 1/2 withcolor 2/3 red;
endgraph;
endfig;
end.

我添加了一些选项,使线条变成红色,并具有合适的粗细。结果如下:

在此处输入图片描述

我们马上就发现了第一个问题,所有年份都被打印成了“2010”。仔细阅读手册后,我们发现这是因为所有数字标签的默认精度都是 3 位有效数字。因此所有年份都被四舍五入到最接近的 10 位。

执行此操作的命令是默认autogrid由命令添加的隐式命令endgraph。为了解决这个问题,我们必须半手动地格式化标签,如第 2.2 节末尾所述手册像这样更改我们的源代码:

prologues := 3;
outputtemplate := "%j%c.eps";

input graph

beginfig(1);
draw begingraph(160, 100);
  gdraw "mydata.d" withpen pencircle scaled 1/2 withcolor 2/3 red;
  for x=auto.x: otick.bot(format("%4g", x), x); endfor
  for y=auto.y: otick.lft(format("%g", y), y); endfor
endgraph;
endfig;
end.

产生更好的结果。我们在这里所做的是将年份四舍五入为 4 位有效数字。

在此处输入图片描述

第二个问题是将点标记整齐地放在每个数据点上。正确的方法是将选项添加plotgdraw命令中。OP 的问题是使用plot btex $\bullet$ etex将点放在了错误的位置。手册也解释了这一点,但不是很清楚。我的建议是你在 MP 中制作自己的点标记,如下所示:

prologues := 3;
outputtemplate := "%j%c.eps";

input graph

picture bullet; bullet = image(drawdot origin withpen pencircle scaled 2);

beginfig(1);
draw begingraph(160, 100);
  gdraw "mydata.d" plot bullet withpen pencircle scaled 1/2 withcolor 2/3 red;
  for x=auto.x: otick.bot(format("%4g", x), x); endfor
  for y=auto.y: otick.lft(format("%g", y), y); endfor
endgraph;
endfig;
end.

生成如下内容:

在此处输入图片描述

第三个问题是“如何旋转年份标签”?为此,我们需要提供一个函数来代替该format函数。输出应该是一个picture对象。以下是其中一种方法:

prologues := 3;
outputtemplate := "%j%c.eps";

input graph

picture bullet; bullet = image(drawdot origin withpen pencircle scaled 2);
vardef year_label(expr Y) = decimal Y infont "cmr10" rotated 60 enddef;

beginfig(1);
draw begingraph(160, 100);
  gdraw "mydata.d" plot bullet withpen pencircle scaled 1/2 withcolor 2/3 red;
  for x=auto.x: otick.bot(year_label(x), x); endfor
  for y=auto.y: otick.lft(format("%g", y), y); endfor
endgraph;
endfig;
end.

现在图表看起来是这样的。如果你真的想要 90° 的话,你可以调整一下旋转角度。

在此处输入图片描述

第四个问题是关于-轴标签。这里的问题也与舍入有关,但我们不能像更改年份那样更改精度,因为绝对值大于 4096,所以graph会自动使用 MP 的字符串算法,因此格式规则略有不同(在我看来不是很好)。如果您真的想要很多零,那么我建议的最好方法是我们“手动”输入标签:

prologues := 3;
outputtemplate := "%j%c.eps";

input graph

picture bullet; bullet = image(drawdot origin withpen pencircle scaled 2);
vardef year_label(expr Y) = decimal Y infont "cmr10" rotated 60 enddef;

beginfig(1);
draw begingraph(160, 100);
  gdraw "mydata.d" plot bullet withpen pencircle scaled 1/2 withcolor 2/3 red;
  for x=auto.x: otick.bot(year_label(x), x); endfor

  otick.lft("100,000" infont "cmr10", "100000");
  otick.lft("140,000" infont "cmr10", "140000");
  otick.lft("180,000" infont "cmr10", "180000");

  endgraph;
endfig;
end.

生成如下内容:

在此处输入图片描述

但明显的缺点是,你必须知道数据范围才能将标签放在正确的位置。所以我认为我最后的努力是通过转换它们来减小 y 值的大小,并在轴上添加一个刻度标签:

prologues := 3;
outputtemplate := "%j%c.eps";

input graph
input sarith

picture bullet; bullet = image(drawdot origin withpen pencircle scaled 2);
vardef year_label(expr Y) = decimal Y infont "cmr10" rotated 60 enddef;

beginfig(1);
draw begingraph(160, 100);
  gdraw "mydata.d" plot bullet withpen pencircle scaled 1/2 withcolor 2/3 red;
  for x=auto.x: otick.bot(year_label(x), x); endfor
  for y=auto.y: otick.lft(format("%g", y Sdiv "1000"), y); endfor
  glabel.lft("Thousands" infont "cmr8" rotated 90, OUT);
endgraph;
endfig;
end.

就像这样:

在此处输入图片描述

第五个问题关于将全局注释放在顶部和底部的答案是“不要这样做”。将全局注释放在前几列的右侧。

在每个数据集结束的空白行后添加注释,但请注意,如果您多次阅读该文件(如 OP 所做的那样),那么您的注释可能会被误认为是第二个数据集。所以我建议您不要这样做。

答案2

我强烈建议使用pgfplots对于此类图。下面是包括数据注释、年份处理千位分隔等的示例:

\documentclass{article}
\usepackage{pgfplots}


\pgfplotstableread[skip first n = 4]{%
% Some TeX comment
Comment line
The number days that the doctor
will be kept away...
Comment end
year n
2008 98826   
2009 104925  
2010 140153  
2011 178414  
}\mytable


\begin{document}
\begin{tikzpicture}
    \begin{axis}[scaled ticks=false,
    xtick=data,
    xticklabel={\pgfmathprintnumber[fixed,1000 sep=]{\tick}},
    xticklabel style={rotate=90},
    yticklabel={\pgfmathprintnumber[int detect,fixed,1000 sep={\;}]{\tick}}
    ]
    \addplot table[x=year,y=n]{\mytable};
    \end{axis}
\end{tikzpicture}
\end{document}

在此处输入图片描述

相关内容