Migrating from 2.0.0 to 3.0¶
Complexplorer 2.0.0 was published to PyPI on 2025-10-19 and was the latest release until 3.0, so
it is what pip install complexplorer gave you before this release. This page covers upgrading
from it. There is a short appendix for 1.x.
If you only do three things¶
- Rename your 3D calls.
plot_landscape→plot_landscape_pv,pair_plot_landscape→pair_plot_landscape_pv, and the 3Driemann→riemann_pv. The matplotlib 3D backend is gone; PyVista is now a required dependency and the sole 3D renderer. - Replace
show(...)withquick_plot(...), and the*_preset()functions withPlotPresetsmethods. - Catch
ComplexplorerErrororValidationError. The twelve specific exception classes are gone; the base classes cover them.
Everything else below is a lookup table for when something breaks.
Removed names and their replacements¶
Every public name 2.0.0 exported that 3.0 does not. This table is checked against the 2.0.0 tag by
tests/unit/test_v2_surface_accounted.py, so it cannot fall behind.
| 2.0.0 name | 3.0 replacement |
|---|---|
ComputationError |
ComplexplorerError — the base class covers computation failures |
DependencyError |
removed — PyVista is a required dependency, so the condition cannot arise |
DomainError |
ValidationError |
ensure_interactive_plots |
removed from the public API — use matplotlib directly (below) |
ExportError |
ComplexplorerError |
FunctionEvaluationError |
ComplexplorerError |
HAS_PYVISTA |
removed — PyVista is always installed |
HAS_STL_EXPORT |
removed — STL export is always available |
ImageExportError |
ComplexplorerError |
MeshGenerationError |
ComplexplorerError |
OptionalDependencyError |
removed — PyVista is a required dependency |
PyVistaNotAvailableError |
removed — PyVista is a required dependency |
ResolutionError |
ValidationError |
setup_matplotlib_backend |
removed from the public API — use matplotlib directly (below) |
STLExportError |
ComplexplorerError |
disable_logging |
removed — use the standard logging module |
enable_debug_logging |
removed — use logging.getLogger('complexplorer').setLevel(logging.DEBUG) |
get_logger |
removed — use logging.getLogger(__name__) |
high_contrast_preset |
PlotPresets.high_contrast() |
interactive_preset |
PlotPresets.interactive() |
pair_plot_landscape |
pair_plot_landscape_pv() |
plot_landscape |
plot_landscape_pv() |
publication_preset |
PlotPresets.publication_ready() |
riemann |
riemann_pv() (3D) or riemann_chart() / riemann_hemispheres() (2D charts) |
setup_logging |
removed — configure the standard library logging module directly |
show |
quick_plot() |
Renamed: Presets is now PlotPresets¶
If you used an unreleased 3.0 build, the render-settings class was briefly called Presets. It is
PlotPresets in the release, because Presets and catalog were too easy to confuse:
PlotPresetsconfigures a render;catalogsupplies a function.
2.0.0 had neither name — it had publication_preset() and friends — so if you are upgrading from
the published release, use the table above.
The backend helpers¶
These were thin wrappers over matplotlib, and choosing a backend is matplotlib's business:
# 2.0.0
cp.setup_matplotlib_backend()
cp.ensure_interactive_plots()
# 3.0
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use("QtAgg") # or whichever GUI backend you have
plt.ion()
Nothing else changes: the plotting functions behave the same way once a backend is active.
Renamed: n_phi is now phase_sectors¶
2.0.0 renamed the phase-sector count from n_phi to phase_sectors; 3.0 keeps that name. Code
written against 2.0.0 needs no change. Code written against 1.x does:
cp.Phase(n_phi=6, auto_scale_r=True) # 1.x
cp.Phase(phase_sectors=6, auto_scale_r=True) # 2.0.0 and 3.0
Passing n_phi raises ValidationError naming the replacement. The same applies to
PolarChessboard and every perceptual colormap, to preset cmap_spec records, and to the CLI
--cmap phase:N shorthand.
Unrelated: the PyVista renderers also accept
resolution, which replaced a differentn_phi— the 2.x sphere-mesh argument. That mapping is unchanged.
Stricter colormap validation¶
3.0 validates colormap configuration at construction. Values that 2.0.0 accepted and rendered as
nonsense now raise ValidationError immediately:
| Configuration | 2.0.0 | 3.0 |
|---|---|---|
Phase(phase_sectors=0) |
ZeroDivisionError from inside the constructor |
ValidationError naming the value |
Phase(phase_sectors=-1) or 2.5 |
accepted; meaningless sector count | ValidationError |
Phase(r_log_base=1) |
accepted; every pixel rendered as NaN | ValidationError |
Phase(r_linear_step<=0), scale_radius<=0 |
accepted; degenerate output | ValidationError |
If one of these starts raising, the previous output was not what you wanted.
Gallery manifest: schema_version 2 → 3¶
index.json records carry cmap_spec, whose sector-count key moved from n_phi to
phase_sectors. Consumers of the manifest should read the new key; the version bump marks the
change.
The manifest is byte-identical for the same selection and library version on any platform in 3.0 — derived coordinates are quantized, so a manifest generated on Windows and one generated on Linux are the same bytes. Portrait PNGs remain reproducible only best-effort.
A complete example¶
# ---- 2.0.0 ----
import complexplorer as cp
if cp.HAS_PYVISTA:
cp.setup_matplotlib_backend()
f = lambda z: (z**2 - 1) / (z**2 + 1)
cp.plot_landscape(cp.Rectangle(4, 4), f, **cp.publication_preset())
cp.show(f)
# ---- 3.0 ----
import complexplorer as cp
f = lambda z: (z**2 - 1) / (z**2 + 1)
# PyVista is always available, so there is no flag to check.
cp.plot_landscape_pv(cp.Rectangle(4, 4), f, **cp.PlotPresets.publication_ready())
cp.quick_plot(f)
Troubleshooting¶
ImportError: cannot import name 'plot_landscape'
The matplotlib 3D backend was removed. Use plot_landscape_pv. See the table above.
AttributeError: module 'complexplorer' has no attribute 'HAS_PYVISTA'
PyVista is a required dependency now, so the flag has no meaning. Delete the check.
ValidationError: Phase no longer accepts 'n_phi'
Rename the argument to phase_sectors. The message names the replacement.
ValidationError: phase_sectors must be a positive integer
3.0 validates this at construction. A zero, negative or fractional sector count never produced a
meaningful portrait.
ImportError for one of the twelve exception classes
Catch ComplexplorerError for anything the library raises, or ValidationError for bad
arguments. ColormapError is a ValidationError, so one clause covers both.
A 3D window does not open, or rendering fails on a server
Pass interactive=False with filename= to render off-screen. On Linux without a display, set
PYVISTA_OFF_SCREEN=true and run under a virtual framebuffer. See
3D landscapes and the Riemann sphere.
Appendix: coming from 1.x¶
1.x is two breaking releases behind, so read the 2.0 notes in the changelog as well. The parts that matter most:
n_phibecamephase_sectorsin 2.0 (above).- The perceptual colormap families —
OklabPhase,CubehelixPhaseand the rest — arrived in 2.0. - Everything in the table above applies, since those names existed in 1.x too.
Non-square rectangles mask differently than they did in 1.x¶
Rectangle takes square=True by default, which expands the viewing window to a square. In
1.x, contains() tested against that expanded window, so a non-square rectangle had no
out-of-domain region at all. From 2.0 onwards it tests against the dimensions you asked for:
r = cp.Rectangle(re_length=8, im_length=4) # window is 8x8; the domain is 8x4
r.contains(np.array([0 + 3j])) # 1.x: True 2.0 and 3.0: False
The visible effect is that portraits, masks and exported STLs of non-square rectangles now show
the out-of-domain colour above and below the rectangle, where 1.x rendered function values. Pass
square=False if you want the window to match the domain.