McUtils 
McUtils is a set of utilities written by the McCoy group for the McCoy group to handle common things we do, like pulling data from electronic structure calculations, doing unit conversions, interpolating functions, making attractive plots, getting finite difference derivatives, performing fast, vectorized operations, etc.
We’re working on documenting the package, but writing good documentation takes more time than writing good code. Docs for the actively edited, unstable branch can be found here.
McUtils is a suite of mostly independent Python packages developed by the McCoy Group to support scientific computing, computational chemistry, and research-software development. It grew out of repeated needs across the group’s projects: extracting data from electronic structure calculations, converting molecular coordinate systems, performing vectorized numerical operations, differentiating and interpolating functions, building plots and notebook interfaces, and managing reproducible calculations.
The packages share a namespace and occasionally build on one another—especially
on Numputils and Devutils—but most can be used independently. McUtils also
provides much of the lower-level infrastructure used by
Psience.
Installation & Requirements
The easiest way to install is via pip, as
pip install mccoygroup-mcutils
This should install all dependencies.
The major requirement is that Python 3.9+ is required due to use of features in the types module.
For safety, it is best to install this in a virtual environment, which we can make like
python3.9 -m pip venv mcenv
and activate like
. mcenv/bin/activate
the most up-to-date development version can be installed with
python -m pip install git+https://github.com/McCoyGroup/McUtils.git
or to use it in a container or conda environment or some other place where we can control the environment.
The core required dependencies are numpy, scipy, h5py, numba, and matplotlib.
Some integrations have additional dependencies, mainly jupyter, ipywidgets,
rdkit, ase, and mpi4py
Jupyter Integrations
If you want to get all of the nice JHTML features for working in Jupyter, you’ll then need to run
from McUtils.Jupyter import JHTML
JHTML.load()
and then reload the browser window when prompted.
Package guide
Scientific and numerical tools
McUtils.Numputils
Numputils collects low-level, reusable numerical operations that are awkward
to express efficiently with NumPy alone. It is the numerical foundation for
many of the other McUtils packages.
Key functionality includes vector and coordinate operations; molecular geometry calculations; Euler angles, rotation matrices, and affine transformations; coordinate frames and embedding; sparse arrays and set operations; tensor derivative transformations; numerical optimization; permutation operations; and Lebedev quadrature grids for spheres and unions of spheres.
import numpy as np
from McUtils.Numputils import vec_crosses, vec_dots, vec_norms, vec_normalize, pts_angles
# Build a local frame from three atoms in a molecular geometry.
oxygen, hydrogen_1, hydrogen_2 = np.array([
[0.000, 0.000, 0.000], [0.958, 0.000, 0.000], [-0.240, 0.927, 0.000]
])
# direct vectorized embedding calculations
oh_1, oh_2 = hydrogen_1 - oxygen, hydrogen_2 - oxygen
normal = vec_crosses(oh_1, oh_2)
angle = np.arccos(vec_dots(oh_1, oh_2) / (vec_norms(oh_1) * vec_norms(oh_2)))
angle = np.degrees(angle)
print(f"H-O-H angle: {angle:.2f} degrees; plane normal: {normal}")
# a much more convenient way
angle_2, normal_2 = pts_angles(hydrogen_1, oxygen, hydrogen_2)
angle_2 = np.degrees(angle_2)
print(f"H-O-H angle: {angle_2:.2f} degrees; plane normal: {normal_2}")
McUtils.Zachary
Zachary provides the higher-order numerical machinery used when plain array
operations are not enough. It is aimed at derivatives, expansions, fitting,
interpolation, and structured numerical representations.
It includes arbitrary-order finite-difference derivatives, Taylor and function expansions, differentiable function composition, polynomial utilities, lazy and sparse tensors, regular- and unstructured-grid interpolation, coordinate-path interpolation, fitted models, multidimensional meshes, and surface construction including marching cubes and unions of spheres.
import numpy as np
from McUtils.Zachary import TensorExpression
# Construct ||q|| symbolically, then obtain its gradient and Hessian.
q = TensorExpression.CoordinateVector(3, name="coordinates")
radius = TensorExpression.VectorNormTerm(q)
point = np.array([1.0, 2.0, 2.0])
value = TensorExpression(radius, coordinates=point).eval()
gradient = TensorExpression(radius.dQ(), coordinates=point).eval()
hessian = TensorExpression(radius.dQ().dQ(), coordinates=point).eval()
print("radius:", value, "gradient:", gradient, "Hessian eigenvalues:", np.linalg.eigvalsh(hessian))
Finite-difference derivatives can be generated lazily and queried only to the order required:
import numpy as np
from McUtils.Zachary import FiniteDifferenceDerivative
def morse_potential(r, de=0.20, a=1.5, re=1.0):
return de * (1 - np.exp(-a * (r - re))) ** 2
derivatives = FiniteDifferenceDerivative(morse_potential, stencil=7)(
np.array([1.0]), mesh_spacing=0.005
)
gradient = derivatives[0]
force_constant = derivatives[0, 0]
print(f"equilibrium gradient: {gradient:.3e}")
print(f"harmonic force constant: {force_constant:.6f}")
SphereUnionSurface can construct and visualize a solvent-excluded surface
from atomic coordinates and van der Waals radii:
import numpy as np
from McUtils.Data import UnitsData
from McUtils.ExternalPrograms import RDMolecule
from McUtils.Zachary import SphereUnionSurface
mol = RDMolecule.from_smiles("C(C)(C)(C)COOC(c1ccccc1)", add_implicit_hydrogens=True)
angstrom_to_bohr = UnitsData.convert("Angstroms", "BohrRadius")
atoms = mol.atoms
coords = mol.coords * angstrom_to_bohr
surface = SphereUnionSurface.from_xyz(atoms, coords, samples=250)
mesh = surface.get_triangulation(
method="isosurface",
probe_type="ses",
probe_radius=1.4 * angstrom_to_bohr,
grid_samples=60
)
print(f"SES area: {mesh.surface_area() / angstrom_to_bohr**2:.2f} Ų")
figure = surface.plot()
figure = mesh.plot(figure=figure)
figure.show()
McUtils.Coordinerds
Coordinerds gives molecular coordinates an explicit, extensible type system.
Its CoordinateSet is an ndarray subclass that tracks its CoordinateSystem,
allowing normal NumPy workflows while retaining the information needed for
coordinate conversion.
The package supports Cartesian, spherical, Z-matrix, generic internal, redundant internal, and composite coordinate systems; converter registration; analytic and numerical conversion derivatives; internal-coordinate generation and pruning; molecular embedding; and iterative conversion back to Cartesian coordinates.
import numpy as np
from McUtils.Coordinerds import CoordinateSet, CartesianCoordinates3D, ZMatrixCoordinates
water = CoordinateSet([
[0.0, 0.0, 0.0], [0.96, 0.0, 0.0], [-0.24, 0.93, 0.0]
], system=CartesianCoordinates3D)
ordering = [[0, -1, -1, -1], [1, 0, -1, -1], [2, 0, 1, -1]]
internals = water.convert(ZMatrixCoordinates, ordering=ordering)
rebuilt = internals.convert(CartesianCoordinates3D)
distance = np.linalg.norm(water[1] - water[0])
angle = np.degrees(internals[1, 1])
print(f"O-H distance: {distance:.3f}; H-O-H angle: {angle:.2f}")
assert np.allclose(water, rebuilt)
McUtils.Combinatorics
Combinatorics supports the structured discrete spaces that arise in basis-set
and perturbative calculations. It emphasizes efficient enumeration and indexing
so that large combinatorial objects do not need to be searched naively.
The API covers integer partitions, unique permutations, Lehmer codes, permutation equivalence classes, symmetric-group spaces, lattice paths, direct sums, Young tableaux, binomial and Stirling numbers, prime factorizations, stable factorial ratios, and Halton and Sobol sequences.
import numpy as np
from McUtils.Combinatorics import IntegerPartitioner, UniquePermutations
# Enumerate and index every distinct distribution of four quanta over three modes.
_, partitions = IntegerPartitioner.partitions(4, pad=True, return_lens=True, max_len=3)
states = []
for partition in partitions:
states.extend(UniquePermutations(partition).permutations())
states = np.unique(np.asarray(states), axis=0)
space = UniquePermutations([2, 1, 1])
indices = space.index_permutations(space.permutations())
assert np.array_equal(space.permutations_from_indices(indices), space.permutations())
McUtils.Graphs
Graphs provides lightweight graph and tree structures for scientific data
without requiring a full graph-analysis framework. It includes edge-based
graphs, graph traversal and neighborhood operations, tree manipulation, and
basic graph-layout support.
from McUtils.Graphs import EdgeGraph
# Represent ethanol as a labeled molecular graph.
labels = ["C", "C", "O", "H", "H", "H", "H", "H", "H"]
edges = [(0, 1), (1, 2), (0, 3), (0, 4), (0, 5),
(1, 6), (1, 7), (2, 8)]
ethanol = EdgeGraph(labels, edges)
print("fragments:", ethanol.get_fragments(return_labels=True))
print("C-C-O path:", ethanol.get_path(0, 2))
print("graph centroid:", ethanol.get_centroid())
heavy_atoms = ethanol.take([0, 1, 2])
assert heavy_atoms.get_path(0, 2) == (0, 1, 2)
McUtils.Symmetry
Symmetry supplies basic molecular point-group analysis. It represents symmetry
elements and rotors, works with point groups and character data, identifies the
symmetry of molecular structures, and provides tools for symmetrizing
coordinates.
import numpy as np
from McUtils.Symmetry import CharacterTable
c2v = CharacterTable.point_group("Cv", 2)
water = np.array([
[0.000, 0.000, 0.126],
[1.437, 0.000, -0.999],
[-1.437, 0.000, -0.999]
])
reduction = c2v.coordinate_mode_reduction(water)
print(c2v.format())
print("Cartesian representation by irrep:", np.rint(reduction).astype(int))
assert np.allclose(reduction, [2, 0, 1, 0])
McUtils.Data
Data wraps frequently used scientific reference data in consistent, lazily
loaded interfaces. It includes atomic and bond properties, physical constants
and unit conversion, named colors, potential and wavefunction data containers,
and arrays that retain their physical units.
from McUtils.Data import AtomData, UnitsData
# Convert a computed O-H harmonic frequency and inspect isotope masses.
frequency_hartree = 0.0167
frequency_cm = frequency_hartree * UnitsData.convert("Hartrees", "Wavenumbers")
m_h = AtomData["Hydrogen", "Mass"]
m_d = AtomData["Deuterium", "Mass"]
m_o = AtomData["Oxygen", "Mass"]
reduced_mass_oh = m_h * m_o / (m_h + m_o)
reduced_mass_od = m_d * m_o / (m_d + m_o)
isotope_shift = (reduced_mass_oh / reduced_mass_od) ** 0.5
print(f"OH: {frequency_cm:.1f} cm^-1; estimated OD: {frequency_cm * isotope_shift:.1f} cm^-1")
Chemistry and external programs
McUtils.ExternalPrograms
ExternalPrograms provides a common layer over chemistry programs, toolkits,
file formats, web resources, and compute environments. Its purpose is to keep
program-specific details out of scientific workflows and make optional tools
discoverable at runtime.
It includes job generation and execution for Gaussian, ORCA, CREST, and Slurm; readers for Gaussian, ORCA, MOLPRO, CREST, CIF, cube, and formatted-checkpoint data; adapters for RDKit, ASE, Open Babel, and Pysisyphus; SMILES and 3-D molecular utilities; chemical-resource web APIs; subprocess and container execution; managed job queues; and lightweight services for remote or HPC evaluation.
from McUtils.ExternalPrograms import SLURMExecutionEngine, ExecutionStatus
# The execution layer can swap local processes for Slurm without changing callers.
engine = SLURMExecutionEngine()
future = engine.submit_job(
"frequency.sbatch",
watch_dir="frequency-job",
results_file="results.json",
poll_time=5
)
print("submitted:", future.job_id, "status:", future.get_status())
if future.get_status() is ExecutionStatus.COMPLETED:
print(future.get_result())
RDKit integration supports conformer generation, force-field optimization, coordinate manipulation, and interactive 3-D visualization:
import numpy as np
from McUtils.ExternalPrograms import RDMolecule
# RDKit is optional; generate an MMFF-optimized butane conformer ensemble.
conformers = RDMolecule.from_smiles(
"C(C)(C)(C)COOC(c1ccccc1)", add_implicit_hydrogens=True,
num_confs=5,
optimize=True,
take_min=False
)
energies = np.array([conf.calculate_energy() for conf in conformers])
best = conformers[np.argmin(energies)].copy()
best.coords = best.coords - best.coords.mean(axis=0) # recenter the conformer
print("relative energies:", energies - energies.min())
viewer = best.draw(image_size=(600, 400), use_coords=True)
viewer.show()
The program-specific parsers also provide a compact route from a completed CREST run to an ensemble ready for analysis:
import numpy as np
from McUtils.ExternalPrograms import CRESTParser
crest = CRESTParser("crest-run")
ensemble = crest.parse_conformers()
atoms, energies, coordinates = ensemble.atoms, ensemble.energies, ensemble.coords
order = np.argsort(energies)
energies = energies[order] - energies[order[0]]
coordinates = coordinates[order]
print(f"loaded {len(coordinates)} conformers of {len(atoms)} atoms")
print("lowest relative energies:", energies[:5])
best_geometry = coordinates[0]
McUtils.GaussianInterface
GaussianInterface is a compatibility-oriented entry point for importing
Gaussian results. It exposes log- and formatted-checkpoint readers together with
helpers for extracting energies, geometries, normal modes, force constants, and
higher derivative tensors. New program-neutral work generally belongs in
ExternalPrograms, where the underlying Gaussian implementation now lives.
from McUtils.GaussianInterface import GaussianLogReader
with GaussianLogReader("frequency.log") as reader:
parsed = reader.parse([
"StandardCartesianCoordinates",
"DipoleMoments",
"NormalModes",
"ScanEnergies"
])
atoms, geometries = parsed["StandardCartesianCoordinates"]
dipoles = parsed["DipoleMoments"]
print(f"read {len(geometries)} geometries for {len(atoms)} atoms")
print("final dipole:", dipoles[-1])
McUtils.Parsers
Parsers is a standalone toolkit for turning large or irregular text files into
structured Python and NumPy data. It combines efficient file streaming with a
composable regular-expression language and declarative structured types.
Use it to locate blocks without loading an entire file, build regex patterns as
Python objects, convert matches into typed or multidimensional arrays, and parse
common XYZ and TeX structures. These components underpin much of the electronic
structure parsing in ExternalPrograms.
from McUtils.Parsers import RegexPattern, Repeating, Capturing
from McUtils.Parsers import Number, Whitespace, Optional, StringParser
# Parse a Gaussian-style line into a numeric array without hand-written regex.
eigenvalues = RegexPattern(
("Eigenvalues --", Repeating(Capturing(Number), suffix=Optional(Whitespace))),
joiner=Whitespace
)
parser = StringParser(eigenvalues)
line = "Eigenvalues -- -0.1423 0.0781 0.2114"
values = parser.parse(line)
print("orbital energies:", values)
Visualization and interactive computing
McUtils.Plots
Plots is a high-level plotting framework built primarily on Matplotlib and
inspired by Mathematica’s Graphics model. It separates data, graphical
primitives, styling, and display properties so plots can be composed and
restyled consistently.
The package provides 2-D and 3-D graphics, graphics grids, common plot types, legends and axes management, geometric primitives, themes and color utilities, images and animations, SVG and scene serialization, and experimental X3D and VTK backends.
import numpy as np
from McUtils.Plots import Plot, ScatterPlot
x = np.linspace(0, 2 * np.pi, 40)
observations = np.sin(x) + np.random.default_rng(4).normal(0, 0.08, x.shape)
plot = Plot(x, np.sin(x), plot_label="model", plot_style={"color": "navy"})
ScatterPlot(
x, observations, figure=plot,
plot_label="measurements",
plot_style={"color": "crimson", "s": 18}
)
plot.axes_labels = ["phase / rad", "signal"]
plot.plot_label = "Model and measurements"
plot.show()
McUtils.Jupyter
Jupyter supports rich, programmatic notebook interfaces. Its JHTML layer
represents HTML and Bootstrap components as Python objects and can connect them
to interactive widgets without requiring a separate front-end application.
Additional tools cover reusable controls and app variables, notebook and script execution, notebook export, image handling, JavaScript and D3 integration, X3D/JSmol/NGL molecular visualization, and interactive molecule graphics.
from McUtils.Jupyter import JHTML
table = [["Method", "Energy / Eh"], ["HF", -75.983], ["CCSD(T)", -76.241]]
panel = JHTML.Bootstrap.Card(
JHTML.Bootstrap.Table(table, cls=["table-striped", "table-hover"]),
header="Water calculation"
)
layout = JHTML.Div(
JHTML.HTML.Header("Electronic-structure summary"),
panel,
JHTML.HTML.P("Values update as calculations finish."),
cls="container p-3"
)
layout.display()
Software and workflow infrastructure
McUtils.Scaffolding
Scaffolding contains the operational pieces needed to turn a scientific
calculation into a reliable application or job. The components are designed to
be adopted independently rather than forcing a single application framework.
It provides structured logging, caches, file-backed configurations, serializers, checkpointing, object persistence and reconstruction, job directories and runtime state, and helpers for building command-line interfaces.
import numpy as np
from McUtils.Numputils import SparseArray
from McUtils.Scaffolding import PseudoPickler
# Serialize a McUtils sparse object into a reloadable, implementation-neutral form.
hessian = SparseArray.from_diag([0.41, 0.83, 1.26, 1.72])
serializer = PseudoPickler()
payload = serializer.serialize(hessian)
restored = serializer.deserialize(payload)
assert np.allclose(restored.asarray(), hessian.asarray())
print("protocol:", payload["pseudopickle_protocol"], "shape:", restored.shape)
McUtils.Parallelizers
Parallelizers presents a common interface for serial execution,
multiprocessing, and MPI. Scientific functions can accept a parallelizer
without containing backend-specific branches, while the serial implementation
provides the same contract for debugging and small calculations.
The package also includes parallel task runners, synchronized execution helpers,
and wrappers around multiprocessing.shared_memory for sharing NumPy data
without unnecessary copies.
import numpy as np
from McUtils.Parallelizers import SerialNonParallelizer
# The same function can receive an MPI or multiprocessing backend later.
def block_energy(points, *, parallelizer=None):
return np.sum(points * points)
geometries = np.arange(36.0).reshape(4, 3, 3)
parallelizer = SerialNonParallelizer()
energies = parallelizer.map(
block_energy, geometries,
extra_kwargs={"parallelizer": parallelizer}, aggregate=True
)
print("batch energies:", energies)
McUtils.Extensions
Extensions makes compiled scientific code easier to load and call from Python.
It can discover and build native modules, describe Python/C argument signatures,
locate and manage shared libraries, and expose dynamically loaded functions
through a small foreign-function interface.
import numpy as np
from McUtils.Extensions import FunctionSignature, Argument, ArrayType, RealType, IntType
gradient_signature = FunctionSignature(
"evaluate_gradient",
Argument("natoms", IntType),
Argument("coordinates", ArrayType(RealType, ctypes_spec="double")),
Argument("gradient", ArrayType(RealType, ctypes_spec="double")),
return_type=None
)
coordinates = np.zeros((3, 3))
prepared = gradient_signature.prep_args(
(), {"natoms": 3, "coordinates": coordinates, "gradient": np.empty_like(coordinates)}
)
print(gradient_signature.cpp_signature)
print("prepared coordinate shape:", prepared[1].shape)
McUtils.Formatters
Formatters handles repeatable generation of text, source, and document-like
outputs. It includes file and string template engines, recursive object walkers,
template-directory writers, TeX construction helpers, plain-text tables, file
matching, and convenient formatting functions.
from McUtils.Formatters import TeX
# Assemble a typeset normal-mode eigenvalue equation from expression objects.
f = TeX.Symbol(TeX.bold("F"))
l = TeX.Symbol(TeX.bold("L"))
omega = TeX.Symbol("omega")
equation = (f * l).Equals(l * (omega ** 2))
document = TeX.Equation(
equation,
label="eq:normal-modes"
)
print(document.format_tex())
McUtils.Docs
Docs turns live Python objects and source trees into browsable documentation.
It can walk modules and their children, render interactive or static HTML API
pages, extract embedded examples, build documentation sites, and generate the
compact API stubs and summaries used to document McUtils itself.
from McUtils.Docs import jdoc, ExamplesParser
from McUtils.Zachary import FiniteDifferenceDerivative
from IPython.display import display
# Extract test-backed examples and open rich API documentation in a notebook.
examples = ExamplesParser.from_file("ci/tests/ZacharyTests.py")
finite_difference_examples = [
name for name in examples.functions
if "Deriv" in name or "FiniteDifference" in name
]
print("available examples:", finite_difference_examples)
documentation = jdoc(FiniteDifferenceDerivative, max_depth=2)
display(documentation)
McUtils.Devutils
Devutils collects small abstractions used throughout the suite to keep common
Python plumbing out of scientific code. These include option-set and default
management, lightweight schema validation, file helpers, logging adapters,
output redirection, and explicit singleton sentinels for values such as
“automatic” or “not provided.”
from McUtils.Devutils import OptionsSet, is_dict_like, is_list_like
def run_calculation(*, method, basis="cc-pVDZ", charge=0):
return method, basis, charge
options = OptionsSet(method="CCSD(T)", basis="aug-cc-pVTZ", charge=0, memory="8GB")
accepted, extra = options.split(run_calculation)
assert is_dict_like(accepted) and is_dict_like(extra)
assert not is_list_like(accepted)
print("call options:", accepted)
print("options for another layer:", extra)
McUtils.Iterators
Iterators provides compact helpers for consuming and chunking iterables,
splitting and grouping values, flattening nested data, transposing and
interleaving iterators, removing duplicates, and traversing Cartesian products.
These utilities are useful for streaming scientific datasets and expressing
nested iteration without repeating bookkeeping code.
from McUtils.Iterators import chunked, counts, delete_duplicates, flatten
# Turn a nested stream of calculation records into coherent work batches.
records = [[("water", -76.1), ("water", -76.2)],
[("ammonia", -56.2), ("methane", -40.4), ("methane", -40.5)]]
records = list(flatten(records, atomic_types=(tuple,)))
batch_sizes = counts(record[0] for record in records)
batches = list(chunked(records, 2))
systems = list(delete_duplicates(record[0] for record in records))
print("counts:", batch_sizes)
print("unique systems:", systems)
print("submission batches:", batches)
McUtils.Profilers
Profilers supplies lightweight timing and profiling tools for investigating
scientific workloads. It includes reusable timers, context-managed timing, and
profiling wrappers that can report where a calculation spends its time.
from McUtils.Profilers import Timer
from McUtils.Numputils import vec_dots
import numpy as np
rng = np.random.default_rng(7)
vectors = rng.normal(size=(100_000, 3))
with Timer("100k vector dot products", rounding=4) as timer:
norms_squared = vec_dots(vectors, vectors)
timer.start()
normalized = vectors / np.sqrt(norms_squared[:, None])
normalization_time = timer.stop()
print(f"normalization alone: {normalization_time:.4f} seconds")
assert np.allclose(np.linalg.norm(normalized, axis=1), 1)
McUtils.Misc
Misc is the home for focused helpers that do not warrant a larger package. It
currently includes debugging utilities, general decorators, optional-Numba
compatibility decorators, and lightweight symbolic-expression support.
import numpy as np
from McUtils.Misc import Abstract
x, np_symbol = Abstract.vars("x", "np")
potential = Abstract.Lambda(x)(
0.5 * np_symbol.sum(x * x, axis=-1)
)
energy = potential.compile({"np": np})
points = np.array([[1.0, 2.0, 3.0], [0.5, 0.5, 0.5]])
values = energy(points)
print("harmonic energies:", values)
assert np.allclose(values, [7.0, 0.375])
print("generated AST:", potential.to_eval_expr())
Contributing
If you’d like to help out with this, we’d love contributions. The easiest way to get started with it is to try it out. When you find bugs, please report them. If there are things you’d like added let us know, and we’ll try to help you get the context you need to add them yourself. One of the biggest places where people can help out, though, is in improving the quality of the documentation. As you try things out, add them as examples, either to the main page or to a child page. You can also edit the docstrings in the code to add context, explanation, argument types, return types, etc.
Contributions are welcome. The easiest way to begin is to use McUtils in a real workflow and report what is unclear or broken:
Documentation improvements are especially valuable. Examples, conceptual
explanations, type information, and clearer docstrings all make the broad API
easier to discover. When changing code, please add or update tests under
ci/tests and keep public docstrings current.
License and citation
McUtils is distributed under the MIT License. Citation metadata is
provided in CITATION.cff.
API Reference
Help Us Out!
The easiest way to help us out is to give feedback.
Each page should support examples, but unfortunately most do not, simply because writing that kind of thing by hand is time consuming.
If you see a page without examples and you want some, let us know!
To do that, just open and issue on GitHub.
You can use the Feedback button at the bottom of each page to do so.
If you want to be a bit more proactive, feel free to provide examples and docstrings yourself!
There are links at the bottom of each page to edit the examples, templates, and docstrings for that page.
Just create a new one if needed or edit the old one, commit your changes, and Peeves will rebuild the site
which what you’ve added.
It is a huge, huge help, so please take advantage of the opportunity if you’re looking for ways to get involved.