Plot feasible regions of two-variable linear programs in Typst, drawn with CeTZ. One call gives you the shaded region, the boundary lines, the vertices, the objective’s level lines and gradient, and a vertex table with the optimum highlighted.
It is built for teaching (secondary school / early undergraduate), and it handles the cases a synthetic example set usually forgets: unbounded regions, multiple optima, unbounded objectives, empty regions, strict inequalities and any quadrant.
Usage
#import "@preview/quick-vertex:0.1.0": feasible-region
#feasible-region(
((1, 1, 4, "<="), (1, 3, 6, "<=")),
objective: (3, 4),
sense: "max",
labels: ($x + y = 4$, $x + 3y = 6$),
)
// → Optimum (max): Z = 13 at C(3, 1)
This is exactly the first image in the gallery above.
Each constraint is a 4-tuple (a, b, c, op) meaning a·x + b·y op c, where
op is one of "<=", ">=", "<", ">". The objective is Z = c1·x + c2·y,
given as (c1, c2).
Parameters
| Parameter | Default | Meaning |
|---|---|---|
constraints |
(required) | Array of (a, b, c, op). op ∈ "<=", ">=", "<", ">". An optional 5th element sets that line’s color: (a, b, c, op, color). |
objective |
none |
(c1, c2) of Z = c1·x + c2·y. Omit to just draw the region. An optional 3rd element sets the objective color: (c1, c2, color). |
sense |
"max" |
Optimization sense: "max" or "min". |
gradient |
true |
Draw the ∇Z vector at the optimum. |
table |
true |
Show the vertex table; if false, a compact vertex legend. |
first-quadrant |
true |
Add x ≥ 0, y ≥ 0 implicitly. See the note below. |
labels |
none |
Line equations (content), in the order of constraints. |
lang |
"en" |
Language of the rendered labels: "en" or "es". |
region-color |
blue | Fill / hatch / border color of the feasible region. |
size |
(6, 4.5) |
Canvas size, in CeTZ units. |
margin |
1.15 |
Padding factor around the region. |
⚠️
first-quadrantistrueby default, sox ≥ 0andy ≥ 0are added automatically (the usual assumption in school problems). Passfirst-quadrant: falseto draw only the constraints you write — for example when the region lives in another quadrant.
Note on two “senses”. The 4th tuple element is the inequality operator (
"<=", …). Thesenseparameter is the optimization sense ("max"/"min"). They are unrelated.
Colors
Every boundary line gets a distinct color automatically — a curated palette first, then generated hues — so colors never repeat, no matter how many constraints you add. Override any of them explicitly:
#feasible-region(
(
(1, 1, 4, "<=", red), // this line in red
(1, 3, 6, "<="), // auto color
),
objective: (3, 4, olive), // objective, optimum and ∇Z in olive
region-color: rgb("#2b8a3e"), // the feasible region in green
)
What it handles
| Case | Behavior |
|---|---|
| Bounded region | Filled + hatched polygon. |
| Unbounded region | Filled correctly; arrows on the open sides + an “unbounded” note. |
| Unique optimum | Highlighted vertex, optimal level line, ∇Z, table with the optimal row marked. |
| Multiple optima | Detects the tie between adjacent vertices; highlights the segment (or ray) and labels it. |
| Unbounded objective | Detects that no finite max/min exists and says so, instead of inventing a vertex. |
| Empty region | Labels “Infeasible region”. |
Strict inequalities (<, >) |
Correct region + dashed boundary. |
| Any quadrant | first-quadrant: false works (frame, axes and ticks with negatives). |
Localization
Rendered labels default to English. Pass lang: "es" for Spanish. Adding a
language is a matter of copying one block in the _i18n dictionary in lib.typ
and translating it — contributions welcome.
How it works
The shading is obtained by clipping the visible frame against each half-plane (Sutherland–Hodgman), so open regions fill correctly whether bounded or not. A recession-cone sample decides whether the region is unbounded, extends the frame towards where it escapes, and detects when the objective has no finite optimum.
Compatibility
- Typst
>= 0.14.0 - CeTZ
0.5.2
Known limitations
See ROADMAP.md. In short: a couple of cosmetic issues (vertex
label overlaps, zero-area regions) and two rare semantic edge cases (a strict
inequality binding the optimum; more than two vertices tied in Z). None affect
ordinary textbook problems.
License
MIT.