{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "# Tutorial 07 — TikZ Backend\n", "\n", "**TikZ** is the de-facto standard for drawing in LaTeX documents. \n", "maxplotlib can render your figures as native TikZ code via the `tikzfigure` backend,\n", "which wraps the [`tikzfigure`](https://github.com/max-models/tikzfigure) Python package.\n", "\n", "This tutorial covers **two complementary workflows**:\n", "\n", "| Workflow | When to use |\n", "|---|---|\n", "| **Canvas → TikZ** | Quick way to turn data plots into LaTeX-ready TikZ code |\n", "| **`tikzfigure` API directly** | Full control — nodes, shapes, annotations, arcs, colours … |\n", "\n", "**Prerequisites**\n", "\n", "```bash\n", "pip install tikzfigure\n", "```\n", "\n", "To actually *render* the figure (not just generate code) you also need `pdflatex` installed on your system." ] }, { "cell_type": "code", "execution_count": null, "id": "1", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import tikzfigure as tz\n", "from maxplotlib import Canvas" ] }, { "cell_type": "markdown", "id": "2", "metadata": {}, "source": [ "---\n", "## Part 1 — Canvas → TikZ\n", "\n", "The fastest path: build a plot with the standard Canvas API, then pass `backend='tikzfigure'` to get a `TikzFigure` object back." ] }, { "cell_type": "markdown", "id": "3", "metadata": {}, "source": [ "### 1.1 Basic usage" ] }, { "cell_type": "code", "execution_count": null, "id": "4", "metadata": {}, "outputs": [], "source": [ "x = np.linspace(0, 2 * np.pi, 60)\n", "\n", "canvas = Canvas(width=\"10cm\", ratio=0.6)\n", "canvas.plot(x, np.sin(x), label=\"sin\", color=\"steelblue\", line_width=1.5)\n", "canvas.plot(x, np.cos(x), label=\"cos\", color=\"tomato\", line_width=1.2)\n", "canvas.set_xlabel(\"x\")\n", "canvas.set_ylabel(\"y\")\n", "canvas.set_title(\"Trigonometric functions\")\n", "\n", "# backend='tikzfigure' returns a TikzFigure object\n", "tikz = canvas.render(backend=\"tikzfigure\")\n", "print(type(tikz))" ] }, { "cell_type": "markdown", "id": "5", "metadata": {}, "source": [ "### Plotly preview\n", "\n", "Before exporting to TikZ, you can preview the same `Canvas` interactively in a notebook using the Plotly backend:\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "6", "metadata": {}, "outputs": [], "source": [ "canvas.show(backend=\"plotly\")" ] }, { "cell_type": "code", "execution_count": null, "id": "7", "metadata": {}, "outputs": [], "source": [ "canvas.show(backend=\"tikzfigure\")" ] }, { "cell_type": "markdown", "id": "8", "metadata": {}, "source": [ "### 1.2 Inspecting the generated LaTeX\n", "\n", "`str(tikz)` returns the raw LaTeX source string (and `generate_tikz()` remains available explicitly). \n", "Each data line becomes a `\\draw` command connecting coordinate pairs." ] }, { "cell_type": "code", "execution_count": null, "id": "9", "metadata": {}, "outputs": [], "source": [ "print(tikz)" ] }, { "cell_type": "markdown", "id": "10", "metadata": {}, "source": [ "### 1.2.1 Checking explicit width and height\n", "\n", "When you set both `width=` and `ratio=`, the TikZ export now writes explicit pgfplots dimensions.\n", "This is useful when you want a tall figure for a column-sized layout in LaTeX." ] }, { "cell_type": "code", "execution_count": null, "id": "11", "metadata": {}, "outputs": [], "source": [ "canvas_ratio2, ax_ratio2 = Canvas.subplots(width=\"10cm\", ratio=2)\n", "ax_ratio2.plot(x, np.exp(-x / np.pi), color=\"purple\", line_width=1.5)\n", "ax_ratio2.set_title(\"ratio = 2 export\")\n", "\n", "tikz_ratio2 = canvas_ratio2.render(backend=\"tikzfigure\")\n", "ratio2_code = tikz_ratio2.generate_tikz()\n", "\n", "for line in ratio2_code.splitlines():\n", " if \"nextgroupplot\" in line:\n", " print(line.strip())\n", " break\n", "\n", "# Expected: width=10cm and height=20cm in the \\nextgroupplot options" ] }, { "cell_type": "markdown", "id": "12", "metadata": {}, "source": [ "### 1.3 TikZ-specific kwargs\n", "\n", "The TikZ backend passes extra keyword arguments straight to `tikzfigure.draw()`. \n", "Use **`line_width=`** (not matplotlib's `linewidth=`) to control stroke thickness." ] }, { "cell_type": "code", "execution_count": null, "id": "13", "metadata": {}, "outputs": [], "source": [ "canvas2, ax2 = Canvas.subplots(width=\"10cm\", ratio=0.5)\n", "ax2.plot(x, np.sin(x), color=\"navy\", line_width=0.5, label=\"thin\")\n", "ax2.plot(x, np.sin(x) + 0.5, color=\"steelblue\", line_width=1.5, label=\"medium\")\n", "ax2.plot(x, np.sin(x) + 1.0, color=\"royalblue\", line_width=3.0, label=\"thick\")\n", "ax2.set_xlabel(\"x\")\n", "ax2.set_title(\"Line width comparison\")\n", "\n", "tikz2 = canvas2.render(backend=\"tikzfigure\")\n", "print(tikz2.generate_tikz())" ] }, { "cell_type": "markdown", "id": "14", "metadata": {}, "source": [ "### 1.4 Layer-aware TikZ output\n", "\n", "Assign data to layers with `layer=N`. \n", "The TikZ backend respects the layer filter — useful for generating incremental reveal figures (e.g. in Beamer)." ] }, { "cell_type": "code", "execution_count": null, "id": "15", "metadata": {}, "outputs": [], "source": [ "canvas3, ax3 = Canvas.subplots(width=\"10cm\", ratio=0.55)\n", "ax3.plot(x, np.sin(x), color=\"steelblue\", line_width=1.5, layer=0, label=\"sin\")\n", "ax3.plot(x, np.cos(x), color=\"tomato\", line_width=1.5, layer=1, label=\"cos\")\n", "ax3.plot(\n", " x, np.sin(x) * np.cos(x), color=\"seagreen\", line_width=1.0, layer=2, label=\"sin·cos\"\n", ")\n", "\n", "# All layers available on the canvas\n", "print(\"Available layers:\", canvas3.layers)\n", "\n", "# Render only layer 0 — one \\draw command\n", "tikz_l0 = canvas3.render(backend=\"tikzfigure\", layers=[0])\n", "print(\"\\n--- Layer 0 only ---\")\n", "print(f\"\\\\draw count: {tikz_l0.generate_tikz().count(chr(92) + 'draw')}\")\n", "\n", "# Render layers 0 and 1\n", "tikz_l01 = canvas3.render(backend=\"tikzfigure\", layers=[0, 1])\n", "print(\"\\n--- Layers 0 & 1 ---\")\n", "print(f\"\\\\draw count: {tikz_l01.generate_tikz().count(chr(92) + 'draw')}\")" ] }, { "cell_type": "markdown", "id": "16", "metadata": {}, "source": [ "### 1.5 Saving TikZ code to a file\n", "\n", "You can embed the generated code directly in a LaTeX document:" ] }, { "cell_type": "code", "execution_count": null, "id": "17", "metadata": {}, "outputs": [], "source": [ "tikz_all = canvas3.render(backend=\"tikzfigure\")\n", "\n", "with open(\"figure.tex\", \"w\") as f:\n", " f.write(tikz_all.generate_tikz())\n", "\n", "print(\"Saved figure.tex\")\n", "\n", "# In your LaTeX document:\n", "# \\input{figure.tex}\n", "# or wrap it:\n", "# \\begin{figure}[h]\n", "# \\centering\n", "# \\input{figure.tex}\n", "# \\caption{My caption}\n", "# \\end{figure}" ] }, { "cell_type": "markdown", "id": "18", "metadata": {}, "source": [ "### 1.6 Rendering the figure (requires `pdflatex`)\n", "\n", "If `pdflatex` is installed, `tikz.show()` compiles the code and opens the PDF:" ] }, { "cell_type": "code", "execution_count": null, "id": "19", "metadata": {}, "outputs": [], "source": [ "# Requires pdflatex:\n", "tikz_all.show(transparent=False)" ] }, { "cell_type": "markdown", "id": "20", "metadata": {}, "source": [ "### 1.7 Canvas → TikZ limitations\n", "\n", "| Feature | Supported? |\n", "|---|---|\n", "| Line plots (`canvas.plot`) | ✅ |\n", "| Layer filtering | ✅ |\n", "| `line_width=` kwarg | ✅ |\n", "| Horizontal subplots (1×n) | ✅ |\n", "| `canvas.scatter`, `canvas.bar`, `canvas.barh` | ✅ |\n", "| `canvas.fill_between`, `canvas.errorbar` | ✅ |\n", "| Axis labels / titles | ✅ |\n", "\n", "For unsupported primitives, the Canvas API raises `NotImplementedError`; use the direct `tikzfigure` API for advanced TikZ shapes (Part 2 below)." ] }, { "cell_type": "markdown", "id": "21", "metadata": {}, "source": [ "---\n", "## Part 2 — The `tikzfigure` API\n", "\n", "The `tikzfigure` package gives you a full Python interface to TikZ primitives.\n", "You build figures by adding nodes, paths, shapes, and annotations, then\n", "call `generate_tikz()` (or `show()`) to obtain the output.\n", "\n", "```python\n", "import tikzfigure as tz\n", "tf = tz.TikzFigure()\n", "```" ] }, { "cell_type": "markdown", "id": "22", "metadata": {}, "source": [ "### 2.1 Drawing paths with `draw()`\n", "\n", "`tf.draw(nodes, ...)` produces a `\\draw` path through a list of `(x, y)` coordinates." ] }, { "cell_type": "code", "execution_count": null, "id": "23", "metadata": {}, "outputs": [], "source": [ "tf = tz.TikzFigure()\n", "\n", "x = np.linspace(0, 2 * np.pi, 60)\n", "sin_nodes = [(float(xi), float(np.sin(xi))) for xi in x]\n", "cos_nodes = [(float(xi), float(np.cos(xi))) for xi in x]\n", "\n", "tf.draw(sin_nodes, color=\"steelblue\", line_width=1.5)\n", "tf.draw(cos_nodes, color=\"tomato\", line_width=1.2)\n", "\n", "print(tf.generate_tikz())" ] }, { "cell_type": "markdown", "id": "24", "metadata": {}, "source": [ "### 2.2 Straight line segments with `line()`\n", "\n", "`tf.line(start, end, ...)` is a convenience wrapper for a two-point path. \n", "The `arrows` parameter adds arrowheads." ] }, { "cell_type": "code", "execution_count": null, "id": "25", "metadata": {}, "outputs": [], "source": [ "tf2 = tz.TikzFigure()\n", "\n", "# Baseline\n", "tf2.line((0, 0), (2 * np.pi, 0), color=\"gray\", dash_pattern=\"on 3pt off 3pt\")\n", "\n", "# Arrow showing direction\n", "tf2.line((0, -1.2), (0, 1.2), color=\"black\", arrows=\"->\", line_width=0.8)\n", "tf2.line((-0.2, 0), (2 * np.pi + 0.2, 0), color=\"black\", arrows=\"->\", line_width=0.8)\n", "\n", "# The curve\n", "tf2.draw(sin_nodes, color=\"steelblue\", line_width=1.5)\n", "\n", "print(tf2.generate_tikz())" ] }, { "cell_type": "markdown", "id": "26", "metadata": {}, "source": [ "### 2.3 Rectangles, circles, and arcs" ] }, { "cell_type": "code", "execution_count": null, "id": "27", "metadata": {}, "outputs": [], "source": [ "tf3 = tz.TikzFigure()\n", "\n", "# Bounding rectangle (coordinate space for context)\n", "tf3.rectangle((0, -1.2), (2 * np.pi, 1.2), draw=\"gray!40\", fill=\"gray!5\")\n", "\n", "# Circle at the origin\n", "tf3.circle((0, 0), radius=0.15, fill=\"red!60\", draw=\"red\")\n", "\n", "# Circle at peak of sine\n", "tf3.circle((np.pi / 2, 1.0), radius=0.12, fill=\"steelblue\", draw=\"none\")\n", "\n", "# Arc (quarter circle)\n", "tf3.arc(\n", " (0.4, 0),\n", " start_angle=0,\n", " end_angle=90,\n", " radius=0.4,\n", " draw=\"green!60!black\",\n", " line_width=1.0,\n", ")\n", "\n", "# The curve on top\n", "tf3.draw(sin_nodes, color=\"steelblue\", line_width=1.5)\n", "\n", "print(tf3.generate_tikz())" ] }, { "cell_type": "markdown", "id": "28", "metadata": {}, "source": [ "### 2.4 Nodes — text labels and markers\n", "\n", "`add_node()` places a text label (optionally inside a shape) at an `(x, y)` position." ] }, { "cell_type": "code", "execution_count": null, "id": "29", "metadata": {}, "outputs": [], "source": [ "tf4 = tz.TikzFigure()\n", "tf4.draw(sin_nodes, color=\"steelblue\", line_width=1.5)\n", "\n", "# Plain text label\n", "tf4.add_node(np.pi / 2, 1.15, content=r\"$\\max$\", color=\"steelblue\")\n", "\n", "# Boxed label\n", "tf4.add_node(\n", " 3 * np.pi / 2,\n", " -1.15,\n", " content=r\"$\\min$\",\n", " shape=\"rectangle\",\n", " fill=\"tomato!20\",\n", " draw=\"tomato\",\n", " inner_sep=\"2pt\",\n", ")\n", "\n", "# Circle marker at zero-crossing\n", "tf4.add_node(\n", " np.pi, 0, shape=\"circle\", fill=\"white\", draw=\"steelblue\", minimum_size=\"0.18cm\"\n", ")\n", "\n", "print(tf4.generate_tikz())" ] }, { "cell_type": "markdown", "id": "30", "metadata": {}, "source": [ "### 2.5 Custom colours with `colorlet()`\n", "\n", "TikZ colour mixing syntax (`blue!70!white`) lets you define reusable named colours." ] }, { "cell_type": "code", "execution_count": null, "id": "31", "metadata": {}, "outputs": [], "source": [ "tf5 = tz.TikzFigure()\n", "\n", "# Define named colours\n", "tf5.colorlet(\"myblue\", \"blue!70!white\")\n", "tf5.colorlet(\"myred\", \"red!80!black\")\n", "tf5.colorlet(\"myfill\", \"blue!10!white\")\n", "\n", "# Use them in draw calls\n", "tf5.draw(sin_nodes, color=\"myblue\", line_width=1.5)\n", "tf5.draw(cos_nodes, color=\"myred\", line_width=1.5)\n", "\n", "# Filled polygon using the fill colour\n", "closed_nodes = sin_nodes + [(float(x[-1]), 0.0), (float(x[0]), 0.0)]\n", "tf5.draw(closed_nodes, fill=\"myfill\", draw=\"none\", cycle=True)\n", "\n", "print(tf5.generate_tikz())" ] }, { "cell_type": "markdown", "id": "32", "metadata": {}, "source": [ "### 2.6 Filled paths and patterns\n", "\n", "Pass `fill=` and/or `pattern=` to `draw()` to create shaded regions." ] }, { "cell_type": "code", "execution_count": null, "id": "33", "metadata": {}, "outputs": [], "source": [ "tf6 = tz.TikzFigure()\n", "\n", "# Shaded area under sin curve (closed path)\n", "area_nodes = sin_nodes + [(float(x[-1]), 0.0), (float(x[0]), 0.0)]\n", "tf6.draw(area_nodes, fill=\"steelblue!20\", draw=\"none\", cycle=True)\n", "\n", "# Hatched region using a pattern\n", "cos_area = cos_nodes + [(float(x[-1]), 0.0), (float(x[0]), 0.0)]\n", "tf6.draw(\n", " cos_area,\n", " pattern=\"north east lines\",\n", " pattern_color=\"tomato\",\n", " draw=\"none\",\n", " cycle=True,\n", ")\n", "\n", "# Curves on top\n", "tf6.draw(sin_nodes, color=\"steelblue\", line_width=1.5)\n", "tf6.draw(cos_nodes, color=\"tomato\", line_width=1.2)\n", "\n", "print(tf6.generate_tikz())" ] }, { "cell_type": "markdown", "id": "34", "metadata": {}, "source": [ "### 2.7 Layers in `TikzFigure`\n", "\n", "The `layer=` parameter on every drawing call controls render order.\n", "Lower-numbered layers are drawn first (behind), higher layers on top." ] }, { "cell_type": "code", "execution_count": null, "id": "35", "metadata": {}, "outputs": [], "source": [ "tf7 = tz.TikzFigure()\n", "\n", "# layer 0: background fill (drawn first)\n", "tf7.rectangle((0, -1.2), (2 * np.pi, 1.2), fill=\"gray!8\", draw=\"gray!30\", layer=0)\n", "\n", "# layer 1: shaded area\n", "area = sin_nodes + [(float(x[-1]), 0), (float(x[0]), 0)]\n", "tf7.draw(area, fill=\"steelblue!25\", draw=\"none\", cycle=True, layer=1)\n", "\n", "# layer 2: the curve (drawn last, on top)\n", "tf7.draw(sin_nodes, color=\"steelblue\", line_width=2.0, layer=2)\n", "tf7.add_node(np.pi / 2, 1.15, content=r\"$\\sin(x)$\", color=\"steelblue\", layer=2)\n", "\n", "print(tf7.generate_tikz())" ] }, { "cell_type": "markdown", "id": "36", "metadata": {}, "source": [ "### 2.8 Escaping to raw TikZ code\n", "\n", "For anything not yet covered by the API, use `add_raw()` to inject verbatim TikZ." ] }, { "cell_type": "code", "execution_count": null, "id": "37", "metadata": {}, "outputs": [], "source": [ "tf8 = tz.TikzFigure()\n", "tf8.draw(sin_nodes, color=\"steelblue\", line_width=1.5)\n", "\n", "# Inject custom TikZ — a dashed grid line\n", "tf8.add_raw(r\"\\draw[gray!40, dashed] (0, 0) -- (6.28, 0);\")\n", "\n", "# Annotation with arrow using raw TikZ\n", "tf8.add_raw(\n", " r\"\\draw[->, gray] (1.0, 0.6) -- (1.57, 1.0) node[right, font=\\small] {peak};\"\n", ")\n", "\n", "print(tf8.generate_tikz())" ] }, { "cell_type": "markdown", "id": "38", "metadata": {}, "source": [ "### 2.9 Putting it all together — a complete figure\n", "\n", "Combine paths, shapes, nodes, and colours into a single publication-ready figure." ] }, { "cell_type": "code", "execution_count": null, "id": "39", "metadata": {}, "outputs": [], "source": [ "tf_final = tz.TikzFigure(figsize=(12, 7))\n", "\n", "# --- colours ---\n", "tf_final.colorlet(\"cblue\", \"blue!65!white\")\n", "tf_final.colorlet(\"cred\", \"red!75!black\")\n", "\n", "# --- background ---\n", "tf_final.rectangle((0, -1.3), (2 * np.pi, 1.3), fill=\"gray!5\", draw=\"gray!30\")\n", "\n", "# --- zero axis ---\n", "tf_final.line((0, 0), (2 * np.pi, 0), color=\"gray!60\", dash_pattern=\"on 2pt off 2pt\")\n", "\n", "# --- shaded area between curves ---\n", "# approximate: shade where sin > cos (first half)\n", "x_half = x[x <= np.pi]\n", "upper = np.sin(x_half)\n", "lower = np.cos(x_half)\n", "region = [(float(xi), float(u)) for xi, u in zip(x_half, upper)] + [\n", " (float(xi), float(l)) for xi, l in zip(reversed(x_half), reversed(lower))\n", "]\n", "tf_final.draw(region, fill=\"cblue!20\", draw=\"none\", cycle=True)\n", "\n", "# --- curves ---\n", "tf_final.draw(sin_nodes, color=\"cblue\", line_width=1.8)\n", "tf_final.draw(cos_nodes, color=\"cred\", line_width=1.5)\n", "\n", "# --- markers at key points ---\n", "tf_final.circle((np.pi / 2, 1.0), radius=0.08, fill=\"cblue\", draw=\"none\")\n", "tf_final.circle((np.pi, 0.0), radius=0.08, fill=\"cblue\", draw=\"none\")\n", "tf_final.circle((0, 1.0), radius=0.08, fill=\"cred\", draw=\"none\")\n", "\n", "# --- labels ---\n", "tf_final.add_node(\n", " np.pi / 2 + 0.3, 1.05, content=r\"$\\sin(x)$\", color=\"cblue\", anchor=\"west\"\n", ")\n", "tf_final.add_node(0.2, 1.1, content=r\"$\\cos(x)$\", color=\"cred\", anchor=\"west\")\n", "\n", "# --- save and show ---\n", "with open(\"complete_figure.tex\", \"w\") as f:\n", " f.write(tf_final.generate_tikz())\n", "print(\"Saved complete_figure.tex\")\n", "print()\n", "print(tf_final.generate_tikz())" ] }, { "cell_type": "code", "execution_count": null, "id": "40", "metadata": {}, "outputs": [], "source": [ "# Renders to PDF (requires pdflatex):\n", "tf_final.show()" ] }, { "cell_type": "markdown", "id": "41", "metadata": {}, "source": [ "### 2.10 Embedding in a LaTeX document\n", "\n", "The generated code is a standalone `tikzpicture` environment. \n", "Drop it into any LaTeX document:\n", "\n", "```latex\n", "\\usepackage{tikz}\n", "\n", "\\begin{figure}[h]\n", " \\centering\n", " \\input{complete_figure.tex}\n", " \\caption{Trigonometric functions with shaded region.}\n", " \\label{fig:trig}\n", "\\end{figure}\n", "```\n", "\n", "Or compile a standalone PDF with `tikzfigure`'s `generate_standalone()` method:\n", "\n", "```python\n", "standalone_src = tf_final.generate_standalone()\n", "with open('standalone.tex', 'w') as f:\n", " f.write(standalone_src)\n", "# Then: pdflatex standalone.tex\n", "```" ] }, { "cell_type": "markdown", "id": "42", "metadata": {}, "source": [ "---\n", "## Summary\n", "\n", "### Canvas → TikZ workflow\n", "```python\n", "canvas = Canvas(width='10cm', ratio=0.6)\n", "canvas.plot(x, y, color='steelblue', line_width=1.5)\n", "tikz = canvas.render(backend='tikzfigure')\n", "print(tikz.generate_tikz()) # inspect LaTeX\n", "tikz.show() # render (needs pdflatex)\n", "```\n", "\n", "### Direct `tikzfigure` API — key methods\n", "\n", "| Method | Purpose |\n", "|---|---|\n", "| `tf.draw(nodes, color=, line_width=, fill=, ...)` | Path through coordinate list |\n", "| `tf.line(start, end, arrows='->', ...)` | Straight line segment |\n", "| `tf.rectangle(corner1, corner2, fill=, draw=, ...)` | Rectangle |\n", "| `tf.circle(center, radius, fill=, ...)` | Circle |\n", "| `tf.arc(start, start_angle, end_angle, radius, ...)` | Arc |\n", "| `tf.add_node(x, y, content=, shape=, fill=, ...)` | Labelled node |\n", "| `tf.colorlet(name, color_expr)` | Define named colour |\n", "| `tf.add_raw(tikz_code)` | Inject verbatim TikZ |\n", "| `tf.generate_tikz()` | Return LaTeX string |\n", "| `tf.show()` | Compile + display (needs `pdflatex`) |\n", "\n", "### TikZ colour syntax cheatsheet\n", "| Expression | Meaning |\n", "|---|---|\n", "| `'red'`, `'blue'`, `'green'` | Standard colours |\n", "| `'blue!70!white'` | 70% blue + 30% white |\n", "| `'red!80!black'` | 80% red + 20% black |\n", "| `'blue!50!red'` | 50% blend |\n", "| `'gray!20'` | 20% gray (80% white) |" ] }, { "cell_type": "markdown", "id": "43", "metadata": {}, "source": [ "## Part 1.8 — Canvas primitives supported by TikZ\n", "\n", "The Canvas TikZ backend supports line, scatter, bar, horizontal-bar, filled-region,\n", "and error-bar plots. The following example renders the canvas as TikZ source." ] }, { "cell_type": "code", "execution_count": null, "id": "44", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from maxplotlib import Canvas\n", "\n", "x = np.arange(5)\n", "y = np.array([1.0, 2.2, 1.4, 3.0, 2.5])\n", "\n", "primitive_canvas = Canvas()\n", "primitive_canvas.plot(x, y, color=\"black\", linewidth=1.5)\n", "primitive_canvas.scatter(x, y + 0.35, color=\"crimson\")\n", "primitive_canvas.bar(x, y * 0.35, color=\"steelblue\", alpha=0.7)\n", "primitive_canvas.fill_between(x, y, 0, color=\"gold\", alpha=0.2)\n", "primitive_canvas.errorbar(x, y, yerr=0.15, color=\"darkgreen\")\n", "primitive_canvas.configure(\n", " title=\"TikZ-supported Canvas primitives\",\n", " xlabel=\"Sample\",\n", " ylabel=\"Value\",\n", " grid=True,\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "45", "metadata": {}, "outputs": [], "source": [ "tikz_primitive_figure = primitive_canvas.render(backend=\"tikzfigure\")\n", "print(str(tikz_primitive_figure)[:2000])" ] }, { "cell_type": "markdown", "id": "46", "metadata": {}, "source": [ "The next cell shows the TikZ generated from the canvas. Unsupported primitives now raise\n", "`NotImplementedError` instead of being silently omitted." ] }, { "cell_type": "markdown", "id": "47", "metadata": {}, "source": [ "## Part 1.9 — More TikZ-supported primitives\n", "\n", "Step and stairs plots, stems, reference lines, spans, and polygon fills are also\n", "translated to TikZ. The generated TikZ is printed below." ] }, { "cell_type": "code", "execution_count": null, "id": "48", "metadata": {}, "outputs": [], "source": [ "more_canvas = Canvas()\n", "more_canvas.step(x, y, color=\"black\", where=\"post\")\n", "more_canvas.stem(x, y, linefmt=\"m-\", markerfmt=\"mo\")\n", "more_canvas.hlines([1.5, 2.5], 0, 4, color=\"gray\", linestyle=\"--\")\n", "more_canvas.vlines([1, 3], 0, 3.5, color=\"gray\")\n", "more_canvas.axvspan(1, 2, color=\"orange\", alpha=0.2)\n", "more_canvas.axhspan(1, 2, color=\"green\", alpha=0.2)\n", "more_canvas.fill(x, [0.2, 0.8, 0.4, 1.0, 0.2], color=\"cyan\", alpha=0.2)\n", "more_canvas.configure(\n", " title=\"Additional TikZ primitives\", xlabel=\"Sample\", ylabel=\"Value\", grid=True\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "49", "metadata": {}, "outputs": [], "source": [ "more_tikz = more_canvas.render(backend=\"tikzfigure\")\n", "print(str(more_tikz)[:2000])" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 5 }