# BLAND
> Pure-Rust library for paper-ready, monochrome, hatch-patterned
> technical plots in the visual tradition of 1960s–80s engineering reports.
BLAND emits SVG. Plots look at home next to a title block, a set of
fastener callouts, and a stack of punched cards — black ink on white
paper, serif type, thin rules, hatched fills. No color, no gradients, no
drop shadows.
```rust
use bland::{Figure, PaperSize, Stroke, TitleBlock};
let envelope: Vec<f64> = xs.iter().map(|t| (-t / 4.0).exp()).collect();
let fig = Figure::new()
.size(PaperSize::A5Landscape)
.title("Damped oscillation")
.xlabel("t [s]")
.ylabel("x(t)")
.line(&xs, &response, |s| s.label("response"))
.line(&xs, &envelope, |s| s.label("envelope").stroke(Stroke::Dashed))
.hline(0.0, |s| s.stroke(Stroke::Dotted))
.legend_top_right()
.title_block(
TitleBlock::new()
.project("BLAND Reference")
.title("Fig. 1 · Damped oscillation")
.drawn_by("JM")
.date("2026-04-21")
.scale("1:1")
.sheet("1 of 1")
.rev("A"),
);
std::fs::write("oscillation.svg", fig.to_svg()).unwrap();
```
See the [docs.rs page](https://docs.rs/bland) for embedded example
images of every plot type.
## Why monochrome?
- **Prints clean.** Plots look the same on a laser printer, a color
printer, and a photocopy. No "figure unreadable in proceedings"
surprises.
- **Accessible by default.** Hatching, stroke dashing, and marker shape
distinguish series — so plots survive grayscale rendering and are
legible to readers with color vision deficiency.
## Features
- **Series**: line, scatter, bar (grouped), area, histogram, heatmap,
polygon, error bars, box plots, stem plots, quiver / vector fields,
contour iso-lines, reference rules
- **Hatch patterns**: 13 presets — diagonals, crosshatch, dots, brick,
zigzag, checker
- **Markers**: 12 shape presets, alternating open / filled
- **Stroke dashes**: solid, dashed, dotted, dash-dot, long-dash, fine
- **Paper presets**: A4, A5, Letter, Legal, Square — portrait & landscape
- **Themes**: `report_1972` (serif), `blueprint` (monospace), `gazette`
(newspaper)
- **Engineering title block** with project / drawn-by / date / scale /
sheet / revision
- **Annotations**: in-data text and arrows with anti-overlap halos
- **Linear and log axes** with nice-rounded tick placement
- **Projections**: polar, Smith chart, Mercator, equirectangular
- **Built-in basemaps**: Earth coastlines & borders (Natural Earth
1:110m, optional 1:50m), reference parallels, lunar maria
- **Multi-panel layouts** and composite helpers (Bode, Q-Q)
- **Pure Rust, zero runtime dependencies**
## Cargo features
- `gui` — adds `Figure::show()`: a matplotlib-style blocking display
window that renders the figure in an OS-native webview, with a
Save SVG button and zoom controls. Pulls in `tao` and `wry`. On
Linux you must have `libwebkit2gtk-4.1-dev` installed system-wide.
- `high-res-basemaps` — adds Natural Earth 1:50m coastline and country
data (~3 MB compiled). Off by default; the 1:110m datasets and the
schematic outlines are always available.
- `regen-basemaps` — builds the dev-only `regen_basemaps` binary that
re-converts Natural Earth GeoJSON into the static Rust data modules.
Off by default so `cargo install bland` does not install a developer
tool.
### Quick GUI usage
```rust,ignore
use bland::{Figure, PaperSize};
# fn main() {
Figure::new()
.size(PaperSize::A5Landscape)
.title("sin(t)")
.line(&xs, &ys, |s| s)
.show(); // blocks until the window is closed
# }
```
Run the bundled demo with:
```bash
cargo run --features gui --example show_demo
```
## Examples
The repo ships 22 runnable examples covering every plot type. Run any
of them via:
```bash
cargo run --example damped_oscillation
cargo run --example world_map
cargo run --example smith
```
Output goes to `out/`.
## License
MIT.
This crate ports the Elixir BLAND library; the Natural Earth data
embedded under `src/basemaps/data/` is in the public domain.