Skip to content
Projects

Karl's students

Download notebookView on GitHubRun when the site was built.

This tutorial recreates the classic “A picture for Karl’s students” example from the TikZ/PGF manual using the current tikzfigure Python API.

Most of the figure maps directly to high-level helpers:

  • figure-scoped named styles via add_style()
  • local option blocks via scope()
  • named colors via colorlet()
  • arc path segments via .arc(...) / arc segment options
  • per-segment labels via "node" in segment_options

The main approximation is the tangent intersection point: instead of using TikZ’s intersections library, this tutorial computes that helper point in Python and then draws the same geometry through the API.

import math
from tikzfigure import TikzFigure, arrows, colors, styles, units
alpha_deg = 30
alpha = math.radians(alpha_deg)
# Helper geometry computed in Python
point_on_circle = (math.cos(alpha), math.sin(alpha))
projection_on_x = (point_on_circle[0], 0)
tangent_point = (1, math.tan(alpha))
angle_label = (
0.2 * math.cos(alpha / 2),
0.2 * math.sin(alpha / 2),
)
fig = TikzFigure(
figure_setup="scale=3, line cap=round",
figsize=(13, 7),
)
fig.add_package("amsmath")
axes = fig.add_style("axes")
important_line = fig.add_style("important line", options=[styles.very_thick])
information_text = fig.add_style(
"information text",
options=["rounded corners"],
fill=colors.red.mix(percent=10),
inner_sep="1ex",
)
fig.colorlet("anglecolor", colors.green.mix(colors.black, percent=50))
fig.colorlet("sincolor", colors.red)
fig.colorlet("tancolor", colors.orange.mix(colors.black, percent=80))
fig.colorlet("coscolor", colors.blue)
# Background grid and unit circle
fig.grid(
(-1.4, -1.4),
(1.4, 1.4),
step="0.5cm",
color=colors.lightgray,
line_width="0.2pt",
)
fig.circle((0, 0), "1cm")
# Axes, ticks, and axis labels
with fig.scope(options=[axes]) as local:
local.draw(
[(-1.5, 0), (1.5, 0)],
options=[arrows.forward],
color=colors.black,
segment_options=[
{
"connector": "--",
"node": {"content": r"$x$", "right": True},
}
],
)
local.draw(
[(0, -1.5), (0, 1.5)],
options=[arrows.forward],
color=colors.black,
segment_options=[
{
"connector": "--",
"node": {"content": r"$y$", "above": True},
}
],
)
for x, xtext in [
(-1, "-1"),
(-0.5, r"-\frac{1}{2}"),
(1, "1"),
]:
local.draw(
[(x, 1 * units.pt), (x, -1 * units.pt)],
color=colors.black,
segment_options=[{"connector": "--"}],
)
local.node(
(x, -5 * units.pt),
content=rf"${xtext}$",
fill=colors.white,
draw="none",
anchor="north",
)
for y, ytext in [
(-1, "-1"),
(-0.5, r"-\frac{1}{2}"),
(0.5, r"\frac{1}{2}"),
(1, "1"),
]:
local.draw(
[(1 * units.pt, y), (-1 * units.pt, y)],
color=colors.black,
segment_options=[{"connector": "--"}],
)
local.node(
(-5 * units.pt, y),
content=rf"${ytext}$",
fill=colors.white,
... (6 lines skipped) ...
[(0, 0), (3 * units.mm, 0)],
fill=colors.green.mix(percent=20),
draw="anglecolor",
segment_options=[
{"connector": "--"},
{
"connector": "arc",
"start_angle": 0,
"end_angle": alpha_deg,
"radius": "3mm",
},
],
)
fig.node(
angle_label,
content=r"$\alpha$",
text="anglecolor",
draw="none",
)
# Sine and cosine legs
fig.draw(
[point_on_circle, projection_on_x],
options=[important_line],
color="sincolor",
segment_options=[
{
"connector": "--",
"node": {
"content": r"$\sin \alpha$",
"left": "1pt",
"fill": "white",
},
}
],
)
fig.draw(
[projection_on_x, (0, 0)],
options=[important_line],
color="coscolor",
segment_options=[
{
"connector": "--",
"node": {
"content": r"$\cos \alpha$",
"below": "2pt",
"fill": "white",
},
}
],
)
# Tangent segment and sloped radius line
tan_label = (
r"$\displaystyle \tan \alpha \color{black}="
r"\frac{{\color{red}\sin \alpha}}{{\color{blue}\cos \alpha}}$"
)
tan_base = fig.add_coordinate("tan_base", (1, 0))
tan_tip = fig.add_coordinate("tan_tip", tangent_point)
fig.draw(
tan_base.to(
tan_tip,
options=[styles.very_thick],
node={
"content": tan_label,
"right": "1pt",
"fill": "white",
},
),
color="tancolor",
)
fig.draw(
[(0, 0), tangent_point],
color=colors.black,
segment_options=[{"connector": "--"}],
)
# Explanatory text box
info_text = r"""
The {\color{anglecolor} angle $\alpha$} is $30^\circ$ in this
example ($\pi/6$ in radians). The {\color{sincolor}sine of
$\alpha$}, which is the height of the red line, is
\[
{\color{sincolor}\sin \alpha} = 1/2.
\]
The blue cosine segment and orange tangent segment complete
the same right-triangle picture.
"""
fig.node(
(1.85, 0.45),
anchor="west",
text_width="6cm",
align="left",
options=[information_text],
content=info_text,
)
fig.show()
/home/runner/work/tikzfigure/tikzfigure/.venv/lib/python3.12/site-packages/fitz/__init__.py:17: FutureWarning: The `fitz` API is deprecated and will be removed in future. Use `import pymupdf` instead.
warnings.warn(
Notebook output
Show the TikZ code
% --------------------------------------------- %
% Tikzfigure generated by tikzfigure v0.5.0 %
% https://github.com/max-models/tikzfigure %
% --------------------------------------------- %
\begin{tikzpicture}[
scale=3, line cap=round,
axes/.style={},
important line/.style={very thick},
information text/.style={rounded corners, fill=red!10!white, inner sep=1ex}
]
\colorlet{anglecolor}{green!50!black}
\colorlet{sincolor}{red}
\colorlet{tancolor}{orange!80!black}
\colorlet{coscolor}{blue}
\draw[color=lightgray, line width=0.2pt, step=0.5cm] ({-1.4}, {-1.4}) grid ({1.4}, {1.4});
\draw ({0}, {0}) circle (1cm);
\begin{scope}[axes]
\draw[->, color=black] (-1.5, 0) -- node[right] {$x$} (1.5, 0);
\draw[->, color=black] (0, -1.5) -- node[above] {$y$} (0, 1.5);
\draw[color=black] (-1, 1pt) -- (-1, -1pt);
\node[fill=white, draw=none, anchor=north] () at ({-1}, {-5pt}) {$-1$};
\draw[color=black] (-0.5, 1pt) -- (-0.5, -1pt);
\node[fill=white, draw=none, anchor=north] () at ({-0.5}, {-5pt}) {$-\frac{1}{2}$};
\draw[color=black] (1, 1pt) -- (1, -1pt);
\node[fill=white, draw=none, anchor=north] () at ({1}, {-5pt}) {$1$};
\draw[color=black] (1pt, -1) -- (-1pt, -1);
\node[fill=white, draw=none, anchor=east] () at ({-5pt}, {-1}) {$-1$};
\draw[color=black] (1pt, -0.5) -- (-1pt, -0.5);
\node[fill=white, draw=none, anchor=east] () at ({-5pt}, {-0.5}) {$-\frac{1}{2}$};
\draw[color=black] (1pt, 0.5) -- (-1pt, 0.5);
\node[fill=white, draw=none, anchor=east] () at ({-5pt}, {0.5}) {$\frac{1}{2}$};
\draw[color=black] (1pt, 1) -- (-1pt, 1);
\node[fill=white, draw=none, anchor=east] () at ({-5pt}, {1}) {$1$};
\end{scope}
\filldraw[fill=green!20!white, draw=anglecolor] (0, 0) -- (3mm, 0) arc[start angle=0, end angle=30, radius=3mm];
\node[draw=none, text=anglecolor] (node0) at ({0.19318516525781368}, {0.05176380902050415}) {$\alpha$};
\draw[important line, color=sincolor] (0.8660254037844387, 0.49999999999999994) -- node[left=1pt, fill=white] {$\sin \alpha$} (0.8660254037844387, 0);
\draw[important line, color=coscolor] (0.8660254037844387, 0) -- node[below=2pt, fill=white] {$\cos \alpha$} (0, 0);
\coordinate (tan_base) at ({1}, {0});
\coordinate (tan_tip) at ({1}, {0.5773502691896257});
\draw[color=tancolor] (tan_base) to[very thick] node[right=1pt, fill=white] {$\displaystyle \tan \alpha \color{black}=\frac{{\color{red}\sin \alpha}}{{\color{blue}\cos \alpha}}$} (tan_tip);
\draw[color=black] (0, 0) -- (1, 0.5773502691896257);
\node[information text, text width=6cm, align=left, anchor=west] (node1) at ({1.85}, {0.45}) {
The {\color{anglecolor} angle $\alpha$} is $30^\circ$ in this
example ($\pi/6$ in radians). The {\color{sincolor}sine of
$\alpha$}, which is the height of the red line, is
\[
{\color{sincolor}\sin \alpha} = 1/2.
\]
The blue cosine segment and orange tangent segment complete
the same right-triangle picture.
};
\end{tikzpicture}
Show the standalone LaTeX document
\documentclass[border=10pt]{standalone}
\PassOptionsToPackage{dvipsnames,svgnames,x11names}{xcolor}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepgfplotslibrary{groupplots}
\usetikzlibrary{arrows.meta}
\usepackage{amsmath}
\begin{document}
% --------------------------------------------- %
% Tikzfigure generated by tikzfigure v0.5.0 %
% https://github.com/max-models/tikzfigure %
% --------------------------------------------- %
\begin{tikzpicture}[
scale=3, line cap=round,
axes/.style={},
important line/.style={very thick},
information text/.style={rounded corners, fill=red!10!white, inner sep=1ex}
]
\colorlet{anglecolor}{green!50!black}
\colorlet{sincolor}{red}
\colorlet{tancolor}{orange!80!black}
\colorlet{coscolor}{blue}
\draw[color=lightgray, line width=0.2pt, step=0.5cm] ({-1.4}, {-1.4}) grid ({1.4}, {1.4});
\draw ({0}, {0}) circle (1cm);
\begin{scope}[axes]
\draw[->, color=black] (-1.5, 0) -- node[right] {$x$} (1.5, 0);
\draw[->, color=black] (0, -1.5) -- node[above] {$y$} (0, 1.5);
\draw[color=black] (-1, 1pt) -- (-1, -1pt);
\node[fill=white, draw=none, anchor=north] () at ({-1}, {-5pt}) {$-1$};
\draw[color=black] (-0.5, 1pt) -- (-0.5, -1pt);
\node[fill=white, draw=none, anchor=north] () at ({-0.5}, {-5pt}) {$-\frac{1}{2}$};
\draw[color=black] (1, 1pt) -- (1, -1pt);
\node[fill=white, draw=none, anchor=north] () at ({1}, {-5pt}) {$1$};
\draw[color=black] (1pt, -1) -- (-1pt, -1);
\node[fill=white, draw=none, anchor=east] () at ({-5pt}, {-1}) {$-1$};
\draw[color=black] (1pt, -0.5) -- (-1pt, -0.5);
\node[fill=white, draw=none, anchor=east] () at ({-5pt}, {-0.5}) {$-\frac{1}{2}$};
\draw[color=black] (1pt, 0.5) -- (-1pt, 0.5);
\node[fill=white, draw=none, anchor=east] () at ({-5pt}, {0.5}) {$\frac{1}{2}$};
\draw[color=black] (1pt, 1) -- (-1pt, 1);
\node[fill=white, draw=none, anchor=east] () at ({-5pt}, {1}) {$1$};
\end{scope}
\filldraw[fill=green!20!white, draw=anglecolor] (0, 0) -- (3mm, 0) arc[start angle=0, end angle=30, radius=3mm];
\node[draw=none, text=anglecolor] (node0) at ({0.19318516525781368}, {0.05176380902050415}) {$\alpha$};
\draw[important line, color=sincolor] (0.8660254037844387, 0.49999999999999994) -- node[left=1pt, fill=white] {$\sin \alpha$} (0.8660254037844387, 0);
\draw[important line, color=coscolor] (0.8660254037844387, 0) -- node[below=2pt, fill=white] {$\cos \alpha$} (0, 0);
\coordinate (tan_base) at ({1}, {0});
\coordinate (tan_tip) at ({1}, {0.5773502691896257});
\draw[color=tancolor] (tan_base) to[very thick] node[right=1pt, fill=white] {$\displaystyle \tan \alpha \color{black}=\frac{{\color{red}\sin \alpha}}{{\color{blue}\cos \alpha}}$} (tan_tip);
\draw[color=black] (0, 0) -- (1, 0.5773502691896257);
\node[information text, text width=6cm, align=left, anchor=west] (node1) at ({1.85}, {0.45}) {
The {\color{anglecolor} angle $\alpha$} is $30^\circ$ in this
example ($\pi/6$ in radians). The {\color{sincolor}sine of
$\alpha$}, which is the height of the red line, is
\[
{\color{sincolor}\sin \alpha} = 1/2.
\]
The blue cosine segment and orange tangent segment complete
the same right-triangle picture.
};
\end{tikzpicture}
\end{document}

Even without a first-class intersections helper yet, the current API already gets very close to the original:

  • named styles and local scopes match the manual structure closely
  • arc segments, labeled paths, and xcolor mixes all stay in the Python layer
  • only the tangent helper point is computed numerically instead of through a TikZ library-driven intersection