LuaMetaPost is a lua library which helps to generates MetaPost (.mp) files.
LaTeXer usually adopt MetaPost to draw figures. But for diagrams, e.g., trees, MetaPost is a bit low-level. Users must carefully arrange coordinates of nodes and calculate intersections of links and nodes.
LuaMetaPost fills the gap. It provides useful shapes (circle, rectangle, bullet, text) and layout algorithms (matrix and tree). So users can focus on high-level structures.
Here is an example of tree.
local luamp = require 'luamp'
local table = require 'table'
local tree = luamp.layouts.tree(
luamp.origin, 2, 2,
{luamp.bullet,
{luamp.bullet},
{luamp.bullet,
{luamp.bullet},
{luamp.bullet}},
{luamp.bullet}})
local figs = {}
local function draw(tree)
assert(#tree > 0, tostring(#tree))
local rt = tree[1]
table.insert(figs, rt)
for i = 2, #tree do
table.insert(figs, luamp.line(rt, tree[i][1]))
draw(tree[i])
end
end
draw(tree)
print(luamp.figure(table.unpack(figs)))
When this program is executed, it will show following metapost codes on stdout.
beginfig(0);
fill fullcircle scaled 0.20cm shifted (0.00cm,2.00cm);
fill fullcircle scaled 0.20cm shifted (-2.00cm,0.00cm);
fill fullcircle scaled 0.20cm shifted (0.00cm,0.00cm);
fill fullcircle scaled 0.20cm shifted (-1.00cm,-2.00cm);
fill fullcircle scaled 0.20cm shifted (1.00cm,-2.00cm);
fill fullcircle scaled 0.20cm shifted (2.00cm,0.00cm);
draw (-0.08cm,1.92cm)--(-1.92cm,0.08cm);
draw (0.00cm,1.89cm)--(0.00cm,0.11cm);
draw (-0.05cm,-0.10cm)--(-0.95cm,-1.90cm);
draw (0.05cm,-0.10cm)--(0.95cm,-1.90cm);
draw (0.08cm,1.92cm)--(1.92cm,0.08cm);
endfig;
end
Table of Contents
figure
accepts zero or more shapes,
turns them into MetaPost instructions,
and wraps the result by beginfig(0);
and endfig;end
.
Returns a point on (x,y).
origin
is the point whose x and y are both 0.
centroid
calculates the geometry centroid of a series of points.
center
returns the center of a shape.
vertices
returns a list of points of corners, if the shape has corners, such as lines, arrows and rectangles.
opts
is optional. See colors and line styles for details.
For example, feed the following snippet to figure
luamp.circle(luamp.origin, 1)
will generate the following MetaPost instructions
draw fullcircle scaled 2.00cm shifted (0.00cm,0.00cm);
Shows some text.
direction
can be directions.center
, directions.left
, directions.right
, directions.top
, directions.bottom
, directions.top_right
, directions.top_left
, directions.bottom_left
, directions.bottom_right
.
opts
is optional. See colors and line styles for details.
For example, feed the following snippet to figure
luamp.text(luamp.origin, luamp.directions.center, '$\\Sigma$')
will generate the following MetaPost instructions
label(btex $\Sigma$ etex, (0.00cm,0.00cm));
All of these three APIs draw a line from the point from
to the point to
, with no arrow, single arrow or double arrow respectively.
opts
is optional. See colors and line styles for details.
For example, feed the following snippet to figure
luamp.arrow(luamp.origin, luamp.point(1, 0))
will generate the following MetaPost instructions
drawarrow (0.00cm,0.00cm)--(1.00cm,0.00cm);
Draws a rectangle.
opts
is optional. See colors and line styles for details.
For example, feed the following snippet to figure
luamp.rectangle(luamp.origin, 2, 1)
will generate the following MetaPost instructions
draw (-1.00cm,0.50cm)--(1.00cm,0.50cm)--(1.00cm,-0.50cm)--(-1.00cm,-0.50cm)--cycle;
Draws a bullet.
opts
is optional. See colors and line styles for details.
For example, feed the following snippet to figure
luamp.bullet(luamp.origin)
will generate the following MetaPost instructions
fill fullcircle scaled 0.20cm shifted (0.00cm,0.00cm);
matrix
accepts a matrix of "shapes", calculates their positions by row_sep
and col_sep
.
And the center of the matrix will be located at center
.
To access nodes of the result matrix, please access shapes
field of the return value.
row_sep
is the distance between two adjacent rows.
col_sep
is the distance between two adjacent columns.
shapes
is a matrix. Each element can be either a function or false
.
If it is a function, the function must accept a point and returns a shape or layout whose center is located at this point.
If it is false
, it is just a place holder for points.
For example,
local m = luamp.layouts.matrix(luamp.origin, 2, 2,
{{luamp.bullet, luamp.bullet, luamp.bullet},
{luamp.bullet, false, luamp.bullet}})
local shapes = {}
for i = 1, #m do
local r = m[i]
for j = 1, #r do
table.insert(shapes, r[j])
end
end
luamp.figure(table.unpack(shapes))
will generate the following MetaPost instructions
fill fullcircle scaled 0.20cm shifted (-2.00cm,1.00cm);
fill fullcircle scaled 0.20cm shifted (0.00cm,1.00cm);
fill fullcircle scaled 0.20cm shifted (2.00cm,1.00cm);
fill fullcircle scaled 0.20cm shifted (-2.00cm,-1.00cm);
fill fullcircle scaled 0.20cm shifted (2.00cm,-1.00cm);
tree
accepts a tree of shapes, calculates their positions by row_sep
and col_sep
.
And the center of the matrix will be located at center
.
To access nodes of the result matrix, please access shapes
field of the return value.
row_sep
is the distance between two adjacent rows.
col_sep
is the distance between two adjacent columns.
shapes
is a tree.
Each element can be either a function or false
.
If it is a function, the function must accept a point and returns a shape or layout whose center is located at this point.
If it is false
, it is just a place holder for points.
Nothing will be drawn on false
s.
A tree is a list, whose first element is the root and the rest are its subtrees.
For example,
local luamp = require 'luamp'
local table = require 'table'
local tree = luamp.layouts.tree(
luamp.origin, 2, 2,
{luamp.bullet,
{luamp.bullet},
{luamp.bullet,
{luamp.bullet},
{luamp.bullet}},
{luamp.bullet}})
local figs = {}
local function draw(tree)
assert(#tree > 0, tostring(#tree))
local rt = tree[1]
table.insert(figs, rt)
for i = 2, #tree do
table.insert(figs, luamp.line(rt, tree[i][1]))
draw(tree[i])
end
end
draw(tree)
return luamp.figure(table.unpack(figs))
will generate the following MetaPost instructions
beginfig(0);
fill fullcircle scaled 0.20cm shifted (0.00cm,2.00cm);
fill fullcircle scaled 0.20cm shifted (-2.00cm,0.00cm);
fill fullcircle scaled 0.20cm shifted (0.00cm,0.00cm);
fill fullcircle scaled 0.20cm shifted (-1.00cm,-2.00cm);
fill fullcircle scaled 0.20cm shifted (1.00cm,-2.00cm);
fill fullcircle scaled 0.20cm shifted (2.00cm,0.00cm);
draw (-0.08cm,1.92cm)--(-1.92cm,0.08cm);
draw (0.00cm,1.89cm)--(0.00cm,0.11cm);
draw (-0.05cm,-0.10cm)--(-0.95cm,-1.90cm);
draw (0.05cm,-0.10cm)--(0.95cm,-1.90cm);
draw (0.08cm,1.92cm)--(1.92cm,0.08cm);
endfig;
end
LuaMetaPost supports RGB colors.
Just like MetaPost, R, G, or B are represented as a float number between 0 and 1.
For example, color(0, 0, 0)
is black, color(1, 1, 1)
is white, color(1, 1, 0)
is yellow.
LuaMetaPost also predefines some colors in luamp.colors
.
They are default
, invisible
, black
, white
, red
, green
, blue
, yellow
, purple
, brown
, magenta
, cyan
, gray
, and orange
.
Among them, default
and invisible
are special.
default
means the default color of MetaPost, which is usually black.
invisible
means, as the name indicated, nothing will be drawn.
For example,
-
a green circle with a red border
luamp.circle(luamp.origin, 1, {pen_color=luamp.colors.red, brush_color=luamp.colors.green})
-
a green circle without a border
luamp.circle(luamp.origin, 1, {pen_color=luamp.colors.invisible, brush_color=luamp.colors.green})
LuaMetaPost supports 3 line styles: solid
, dashed
, dotted
.
All are defined in luamp.line_styles
.
For example,
-
a dashed line from (0,0) to (1cm,0)
luamp.line(luamp.origin, luamp.point(1, 0), {line_style=luamp.line_styles.dashed})