辦法2. 適用于勤快人(啟動更快):可以在你的每個TeX字體目錄下編輯一個叫 Fontmap 的文件,里面記錄一些字體映射關系。比如,
文件 $TEXMF/fonts/type1/bluesky/cm/Fontmap 里有如下內(nèi)容:
/CMB10 (cmb10.pfb);
/CMBSY10 (cmbsy10.pfb);
/CMBX10 (cmbx10.pfb);
/CMBX12 (cmbx12.pfb);
/CMBX5 (cmbx5.pfb);
...
(注意大小寫!)
文件 $TEXMFLOCAL/fonts/type1/chinese/gbksong/Fontmap 里有如下內(nèi)容:
/gbksong01 (gbksong01.pfb);
/gbksong02 (gbksong02.pfb);
/gbksong03 (gbksong03.pfb);
/gbksong04 (gbksong04.pfb);
/gbksong05 (gbksong05.pfb);
/gbksong06 (gbksong06.pfb);
...
然后把這些路徑都放到 GS_LIB 環(huán)境變量里:
export GS_LIB=/usr/share/ghostscript/7.05/lib
:$TEXMFMAIN/fonts/type1/bluesky/cm:$TEXMFLOCAL/fonts/type1/chinese/gbksong
:$TEXMFLOCAL/fonts/type1/chinese/gbkstcaiyun
(為了美觀,斷了行,在你的 ~/.bashrc 里可不能這樣!)
以后在 mp 文件最開頭加入 prologues:=1; 搞定。
這里說的環(huán)境變量設置都是 UNIX 的 Bourne Shell 用法。csh 和 ksh 用戶以及 Windows 用戶可以靈活變通一下。
如何在MetaPost圖形里插入已有的EPS圖片
使用 epsincl 可以往MetaPost里插入已有的EPS圖片。epsincl 由兩個文件epsincl.mp和epsincl.awk 組成。epsincl.mp 放在 MetaPost 的系統(tǒng)目錄里。epsincl.awk 是AWK語言腳本,需要 AWK 解釋執(zhí)行。
下面是一個例子。use_eps會用EPS文件構(gòu)造一個picture類型的對象。它可以被作為 label 放在任何地方。
input epsincl;
tertiarydef p scaledto x = p scaled (x/xpart(urcorner(p)-llcorner(p))) enddef;
beginfig(100);
dist:=5cm;
z0=origin;
z1=z0+(dist,0);
picture tex,meta;
tex=use_eps("tex.eps");
meta=use_eps("meta.eps");
label(tex scaledto 100, z0);
label(meta scaledto 100, z1);
label(btex $\sqrt{x^2+y^2}$ etex rotated 60 scaled 1.44, .5[z0,z1]);
endfig;
end
之后運行 MetaPost,再運行AWK 腳本處理生成的文件。假設這里我們的文件是 texmeta.mp。那么用這樣的命令行:
mpost texmeta.mp
gawk -f epsincl.awk texmeta.100 >texmeta.eps
之后得到的圖片會是這個樣子:
怎樣在 MetaPost 里繪制數(shù)學函數(shù)和數(shù)據(jù)文件圖形?
使用 mpgraph 宏包
MetaPost 提供了一個 graph 宏包可以根據(jù)一個數(shù)據(jù)文件繪制 2D plot。
graph 有非常多樣的樣式,你并不受它的約束,你只是擁有了更多的處理外部數(shù)據(jù)的方式,而且有了“自動坐標縮放”。
你自己看看說明就知道了。你可以用 graph.mp 提供的 gdata 宏來從任意的數(shù)據(jù)文件讀取數(shù)據(jù):
首先你需要
input graph;
你必須把你畫圖表的語句都放在
draw begingraph(圖表寬度,圖表高度);
...
endgraph;
之間。
比如你的一個數(shù)據(jù)文件 countries.d 有這些內(nèi)容:
20.910 75.7 US
1.831 66.7 Alg
1.694 70.9 Arg
16.430 77.3 Aus
0.180 53.0 Ban
...
你寫一個 MetaPost 文件來繪制這樣一幅圖:
把第3個域的那個國家名字,比如 "US", "Alg", ... 標在前兩個域指出的坐標的位置。
你可以這樣寫:
beginfig(5);
draw begingraph(3in,2in);
gdata("countries.d", s, glabel(s3,s1,s2););
endgraph;
endfig;
其中, gdata("文件名", 一個變量名,你的操作);
可以對這些數(shù)據(jù)進行任意的操作。“一個變量名”是你任意給的名字,比如你給一個 s, 那么數(shù)據(jù)文件的第一列 會被賦值給 s1, 第二列 s2, 第3列 s3, ...
其實 gdata 功能太強了,大部分時候 gdraw 已經(jīng)能滿足你的需要。
gdraw("文件名");
就可以把你存在一個文件里的像這樣的數(shù)據(jù):
00 4.011
01 3.969
02 3.806
...
畫成圖表,太簡單了!你還可以在 gdraw("文件名") 之后使用任何 MetaPost 繪圖選項,比如 withcolor ... withpen ...。你還可以用一個特別的參數(shù) plot,比如:
gdraw("file") plot btex $\bullet$ etex;
就可以在每個數(shù)據(jù)點上畫上一個 TeX 的 $\bullet$ 符號??聪旅孢@些就是用同樣的數(shù)據(jù)點畫出的不同樣式的圖:



mpgraph 缺省會把數(shù)據(jù)文件里所有的數(shù)據(jù)點都畫出來。如果你想限制數(shù)據(jù)點的范圍可以用 setrange, 但是 setrange 只是把圖片的外框修改了一下,實際上曲線會超出外框顯示。這個問題直接用 graph 宏包提供的接口無法解決,必須進行 hack. 請看這里。
使用其它工具輸出 MetaPost
某些繪圖工具可以輸出 MetaPost 圖形文件。你還可以自己修改這個文件,得到非常好的效果。比如 gnuplot 就可以輸出 MetaPost 圖形文件。你只要在 gnuplot 里輸入:
set terminal mp
set output "gnuplot.mp"
set isosamples 40
splot [-2.5:2.5] [-2.5:2.5] (x**2+3*y**2)*exp(1-(x**2+y**2))
就可以把輸出寫到一個叫做 gnuplot.mp 的 MetaPost 文件里。由 MetaPost 處理生成 eps 再插入 LaTeX 文檔。下面就是一個例子,里面的標號是我手工修改的。
其實 gnuplot 可以畫出很多好看的數(shù)學圖形。請參考 這個網(wǎng)頁。
MetaPost 里怎樣才能顯示程序生成的數(shù)字呢?
有人想要用
u:=.5cm;
for p=1 upto 100: label(btex $10^p$ etex, (p*u,p*u)); endfor
這樣的語句在100個位置標注 101, 102, 103 ... 這樣的標號。這是不行的。因為 btex ... etex 之間的部分是原封不動交給 TeX 處理的,這樣你得到的是100個10p。如果你要使用很大的數(shù)字,想要用科學計數(shù)法表示,那么可以用 format 宏包,如果你想使用這些大數(shù)字計算,可以用 sarith 宏包來計算。
- format 宏包。
format 宏包就可以處理數(shù)字的格式化,你首先 input format, 然后你可以用
init_numbers(s, m, x, sn, e);
設定你的 TeX 數(shù)字格式,其中:
s: 表示負數(shù)開頭用什么符號表示它是負數(shù)。一般這個符號是 btex$-$etex
m: 一個TeX的一位數(shù),隨便給一個數(shù)字就行,比如 btex$1$etex
x: 科學計數(shù)法里面怎樣表示 x10^{...}, 通常這樣做: btex${\times}10$etex
sn: 上標的負號怎么表示? 一般是 btex${}^-$etex
e: 上標的示例數(shù),用來計算上標占的位置,隨便給它一個 btex${}^2$etex 之類的就行。
MetaPost 有一個缺省的設定是:
init_numbers(btex$-$etex, btex$1$etex, btex${\times}10$etex,
btex${}^-$etex, btex${}^2$etex);
只有當你對缺省的格式不滿意才需要改變 init_numbers 的設定。
當你用 format(格式串,數(shù)字) 時 format 會為你生成漂亮的 TeX 數(shù)字。格式串可以是 %e, %f, %g, %G 之一,可以在字母前加數(shù)字表示有效數(shù)字,比如 "%10f"。
你可以試試:
label.bot(format("%3g","6.022e23"), origin);
- sarith 宏包
MetaPost 繼承了 METAFONT 的定點運算方式。因為印在紙上的東西尺寸不會很大,所以 MetaPost 只允許輸入 32768 以內(nèi)的數(shù)。這不是一個很嚴重的限制,因為你用 MetaPost 畫的只是一些很小的樣例圖片,你不會把一個 10000x10000 的矩陣印在紙上,對吧?但是如果你的圖形里需要計算少量的大數(shù),你可以用 sarith 宏包。
sarith 宏包可以計算用字符串表示的數(shù)字,你可以用很多種方式表示你的數(shù)字,非常自由,比如 "6.022e23"。
數(shù)字之間的操作必需用專門的 sarith 提供的運算符 Sadd, Ssub, Smul, Sdiv。Sabs 可以得到一個數(shù)字的絕對值。
Scvnum 可以把一個字符串表示的數(shù)轉(zhuǎn)換成 MetaPost 使用的 numeral,如果這不會使 MetaPost 的定點計算溢出的話。如果你的數(shù)字里沒有 "e",就可以用 scantokens 來得到一個字符串表示的數(shù)字的值。因為 scantokens 把后面的字符串當成一段 MetaPost 的輸入。
下面是一個比較 hack 一點的例子,我把 format 內(nèi)部的宏 dofmt_ 挖出來,這樣就可以隨便表示任意的上標數(shù)了。
input format;
input marith;
init_numbers(btex$-$etex, btex$1$etex, btex${\times}10$etex,
btex${}^-$etex, btex${}^2$etex);
%Fe_plus:="*" infont defaultfont;
beginfig(1);
u:=2cm;
n:=3;
pickup pencircle scaled 1pt;
for i=0 upto n: draw (0*u,i*u)--(n*u,i*u); endfor;
for i=0 upto n: draw (i*u,0*u)--(i*u,n*u); endfor;
string mylabel;
for i=0 upto n-1:
for j=0 upto n-1:
l:=j*n+i+1;
label(dofmt_.relax("%3f",(l*1000,l)), (i*u+0.5u,j*u+0.5u));
endfor;
endfor;
a=Mlog_Str("3213000000");
label.bot(Mformat("%e",a), (0,0));
endfig;
end
還有不清楚的就自己看看 sarith 和 format 的 mp 文件。
怎樣從外部文件讀入數(shù)據(jù)?
很多人想要從外部文件得到數(shù)據(jù)進行繪圖,可是 MetaPost manual 里沒有介紹怎么做。因為這個功能是 0.60 版本以后才有的。
你可以用
readfrom "文件"
得到一行數(shù)據(jù)。再次使用 readfrom 就會得到后面的行。如果到達文件末尾,readfrom 會返回一個空字符串 EOF,你可以根據(jù)這個來判斷數(shù)據(jù)是否畫完了。
讀入的數(shù)據(jù)都是作為一個字符串,如果你想要得到數(shù)字,你必須用 scantokens 把字符串 evaluate 一下。舉個例子,比如你的一個文件 points.dat 里有這些內(nèi)容:
40,60,70
....
你可以編輯一個 MetaPost 文件:
beginfig(8);
j:=1;
draw
for p=scantokens readfrom "points.dat":
(j*10,p)--
hide(j:=j+1)
endfor (j*10,80);
endfig;
來根據(jù)這個文件里每行提供的離散數(shù)據(jù)畫圖。
另外,你可以用
write <string expression> to <file name>
把字串內(nèi)容寫到一個外部文件。
MetaPost 能繪制餅狀圖(piechart)和柱狀圖(bar chart)嗎?

顯然 piechart 對于 MetaPost 來說是小事一樁,但是我沒有找到專門用來畫這種圖的 MetaPost 宏包。因為對于大多數(shù)場合, piechart 都是一個不好的選擇。心理學研究表明,piechart 不適合表示重要的數(shù)據(jù),因為人腦對于 piechart 表示的數(shù)值關系不敏感,不能有深刻的印象。
但是如果你的項目很少,比如 2–5 個,而且數(shù)值之間差別很大,而且你不是用在很正式的場合,你可以用一個小程序叫做 ascii_chart 來畫 piechart,它用起來極其簡單,可以輸出很多種格式。ascii_chart 也可以作 bar chart.
另外 piechart 程序可以作出有“拉出效果的” piechart。ascii_chart 和 piechart 都需要 GNU plotutil 庫。你可以到 GNU 的 ftp 服務器下載。
哪里有更多的 MetaPost 的材料?
- John Hobby 寫的 MetaPost 說明書
這當然是 MetaPost 的權(quán)威指南。
- MetaFun
這是 ConTeXt 的 MetaFun 說明書 — 一個圖文并茂,非常漂亮的全屏幕 PDF 文檔。前面講的都是 MetaPost,有很多實例。特別注意的是,這個文檔本身的背景,按鈕,……都是 MetaPost 繪制的。
- METAFONTbook
D. E. Knuth 的大作 The METAFONTbook. 由于 MetaPost 實際上用了 MetaFont 的語言,學習 MetaPost 實際上學會了 MetaFont 的一部分。MetaFont 是 Knuth 跟 TeX 配套設計的一種用來制造字體的程序語言。MATAFONTbook 可以在這里下載 PDF 版本, 請[點擊]。
- 大量實例
一個法國人提供的大量實例。你也可以看看我這里的“本地版”,我美化過的 :)
- 用 MetaPost 做三維動畫
http://www./~roegel/animations.html介紹怎樣用MetaPost制作三維動畫。
- 用MetaPost畫Feynman圖
一個用來繪制專業(yè)級質(zhì)量 Feynman 圖的 MetaPost 宏包,它已經(jīng)被 CERN(歐洲原子能研究中心)采用。用它可以用簡簡單單幾行字就畫出非常漂亮的 Feynman 圖:



我不懂粒子物理,根本不知道這些圖什么意思 //blush …… 如果你有興趣可以看看這個說明。
- MetaGraf: 一個Java程序,可以“隨手”畫出 MetaPost 圖形。這個程序可以彌補 MetaPost 的太精確的缺點,你可以用 MetaGraf 畫出一些隨手圖形插到你的精確的文件里 :)
- 其它資料請參考John Hobby 的主頁
給幾個例子吧
下面給出一些我用 MetaPost 畫出的簡單圖形。點擊圖片可以看到對應的 MetaPost 源文件。我開始時用 MetaPost 還不是很熟,有時會用一些“笨”辦法來畫東西,但是我每次看 MetaPost 說明書都會發(fā)現(xiàn)新的東西。我能用不同的方法,更好的方法完成我曾經(jīng)做過的事情。這恐怕是所有優(yōu)秀工具的特點。
- 我的本科畢業(yè)論文里的 Linux 內(nèi)核 vfs 結(jié)構(gòu)示意圖:
- 我上次作的有關串擾布線的報告里的圖片。
第一幅電路圖的所有元件都是我自己設計的 MetaPost 宏產(chǎn)生的,我可以多次復用這些宏,而且可以隨意制造自己需要的元件圖。
- 我的VLSI布圖理論考試答案里的圖片
時延樹
迷宮算法
steiner 樹
最小生成樹
- 我的計算幾何作業(yè)里的圖片
- Scheme 48 的模塊名字解析示意圖
- DrScheme 的標志
- 我用程序生成的一個圖片
顯示了 rectilinear Delaunay triangulation 對應的 minimum spanning tree 和 triple center
返回