From ca26a59daba4599945d310bf3dc6cab1b3a0efc7 Mon Sep 17 00:00:00 2001 From: nstarman Date: Sat, 3 Oct 2026 20:57:05 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20assets:=20add=20a=20logo,=20one?= =?UTF-8?q?=20plotting=20call=20dispatched=20to=20three=20backends?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit plotting_backends had no logo. It now has a dot, the plotting call, branching to three small charts, each the same plot drawn by a different backend in its own colour. docs/_static/make_logo.py writes it as an SVG (1 KB), and as a PNG at any size on request: uv run docs/_static/make_logo.py --size 2048 big.png Co-Authored-By: Claude Opus 5.5 --- docs/_static/favicon.svg | 14 ++++++ docs/_static/make_logo.py | 102 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 docs/_static/favicon.svg create mode 100644 docs/_static/make_logo.py diff --git a/docs/_static/favicon.svg b/docs/_static/favicon.svg new file mode 100644 index 0000000..7902d79 --- /dev/null +++ b/docs/_static/favicon.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docs/_static/make_logo.py b/docs/_static/make_logo.py new file mode 100644 index 0000000..376174e --- /dev/null +++ b/docs/_static/make_logo.py @@ -0,0 +1,102 @@ +# /// script +# requires-python = ">=3.11" +# dependencies = ["resvg-py"] +# /// +"""Draw the plotting_backends logo: one plotting call, three backends. + +A dot, the plotting call, branching to three small charts. Each shows the same +plot, drawn by a different backend in its own colour. The shapes are vector, so +the logo is written as an SVG, sharp at any size; for a bitmap, name a .png and +give its size:: + + uv run docs/_static/make_logo.py # favicon.svg + uv run docs/_static/make_logo.py --size 2048 big.png +""" + +import argparse +from pathlib import Path + +NAVY = "#030a23" # GalacticDynamics' navy +BACKENDS = ("#66a19a", "#4fb8e8", "#7738eb") # each backend's colour, top first + +# In a 64-unit square: the call's centre and radius, and each chart's left x, +# its side, and the top y of each. +CALL = (12, 32, 6) +CHART_X, CHART_SIZE, CHART_TOPS = 36, 16, (4, 24, 44) +# The plot every backend draws, as points in its chart: 0-1 across, 0-1 down. +PLOT = ((0.15, 0.78), (0.4, 0.42), (0.62, 0.6), (0.86, 0.18)) + +SVG = """\ + + + +{branches} +{charts} + + +""" + + +def chart(top: float, colour: str) -> str: + """Return one backend's chart: a frame, and the plot in ``colour``.""" + x, s = CHART_X, CHART_SIZE + line = "L".join(f"{x + u * s:.2f} {top + v * s:.2f}" for u, v in PLOT) + return ( + f' \n' + f' ' + ) + + +def svg() -> str: + """Return the logo as SVG text.""" + cx, cy, cr = CALL + middle = CHART_SIZE / 2 + branches = "\n".join( + f' ' + for top in CHART_TOPS + ) + charts = "\n".join( + chart(top, colour) for top, colour in zip(CHART_TOPS, BACKENDS, strict=True) + ) + return SVG.format( + cx=cx, + cy=cy, + cr=cr, + navy=NAVY, + branches=branches, + charts=charts, + ) + + +def main() -> None: + """Parse the command line and save the logo.""" + parser = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + parser.add_argument( + "out", + nargs="?", + type=Path, + default=Path(__file__).with_name("favicon.svg"), + help="output file, SVG or PNG by its extension (default: favicon.svg)", + ) + parser.add_argument( + "--size", + type=int, + default=512, + help="pixels per side, for a PNG", + ) + args = parser.parse_args() + + if args.out.suffix == ".svg": + args.out.write_text(svg()) + else: + import resvg_py # noqa: PLC0415 # only a PNG needs a renderer + + png = resvg_py.svg_to_bytes(svg_string=svg(), width=args.size) + args.out.write_bytes(bytes(png)) + + +if __name__ == "__main__": + main()