Simple example#

The example below shows how to create a custom eye model from clinical parameters, build it in OpticStudio, and interact with the model.

Import visisipy and other dependencies#

import matplotlib.pyplot as plt
import seaborn as sns

import visisipy
Matplotlib is building the font cache; this may take a moment.
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
Cell In[1], line 4
      1 import matplotlib.pyplot as plt
      2 import seaborn as sns
----> 4 import visisipy

File ~/checkouts/readthedocs.org/user_builds/visisipy/checkouts/latest/visisipy/__init__.py:8
      5 import platform
      6 from importlib.metadata import version
----> 8 from visisipy import analysis, models, optiland, plots, refraction, wavefront
      9 from visisipy._zospy_loader import install_zospy_loader
     10 from visisipy.backend import get_backend, get_optic, get_oss, load_model, save_model, set_backend, update_settings

File ~/checkouts/readthedocs.org/user_builds/visisipy/checkouts/latest/visisipy/optiland/__init__.py:5
      1 """Analyze optical eye models in Optiland."""
      3 from __future__ import annotations
----> 5 from visisipy.optiland.backend import OptilandBackend
      6 from visisipy.optiland.models import OptilandEye
      8 __all__ = ("OptilandBackend", "OptilandEye")

File ~/checkouts/readthedocs.org/user_builds/visisipy/checkouts/latest/visisipy/optiland/backend.py:22
     13 from optiland.optic import Optic
     15 from visisipy.backend import (
     16     DEFAULT_BACKEND_SETTINGS,
     17     BackendAccessError,
   (...)     20     Unpack,
     21 )
---> 22 from visisipy.optiland.analysis import OptilandAnalysisRegistry
     23 from visisipy.optiland.models import OptilandEye
     25 if TYPE_CHECKING:

File ~/checkouts/readthedocs.org/user_builds/visisipy/checkouts/latest/visisipy/optiland/analysis/__init__.py:9
      7 from visisipy.backend import BaseAnalysisRegistry, _AnalysisMethod
      8 from visisipy.optiland.analysis.cardinal_points import cardinal_points
----> 9 from visisipy.optiland.analysis.mtf import fft_mtf
     10 from visisipy.optiland.analysis.psf import fft_psf, huygens_psf, strehl_ratio
     11 from visisipy.optiland.analysis.raytrace import raytrace

File ~/checkouts/readthedocs.org/user_builds/visisipy/checkouts/latest/visisipy/optiland/analysis/mtf.py:8
      5 from typing import TYPE_CHECKING, Literal
      7 from optiland.backend import to_numpy
----> 8 from optiland.mtf import FFTMTF, ScalarFFTMTF, VectorialFFTMTF
      9 from pandas import Series
     11 from visisipy.analysis.mtf import MTFResult, SingleMTFResult

File ~/checkouts/readthedocs.org/user_builds/visisipy/envs/latest/lib/python3.13/site-packages/optiland/mtf/__init__.py:11
      1 """Modulation Transfer Function (MTF) subpackage.
      2 
      3 This subpackage provides classes for calculating the MTF of optical systems
   (...)      6 Kramer Harrison, 2025
      7 """
      9 from __future__ import annotations
---> 11 from .fft import FFTMTF, ScalarFFTMTF
     12 from .geometric import GeometricMTF
     13 from .huygens_fresnel import HuygensMTF, ScalarHuygensMTF, VectorialHuygensMTF

File ~/checkouts/readthedocs.org/user_builds/visisipy/envs/latest/lib/python3.13/site-packages/optiland/mtf/fft.py:13
     10 from __future__ import annotations
     12 import optiland.backend as be
---> 13 from optiland.psf.fft import ScalarFFTPSF, calculate_grid_size
     14 from optiland.utils import get_working_FNO
     16 from .base import BaseMTF

File ~/checkouts/readthedocs.org/user_builds/visisipy/envs/latest/lib/python3.13/site-packages/optiland/psf/__init__.py:6
      4 from .vectorial_fft import VectorialFFTPSF
      5 from .mmdft import MMDFTPSF
----> 6 from .huygens_fresnel import HuygensPSF, ScalarHuygensPSF
      7 from .vectorial_huygens import VectorialHuygensPSF

File ~/checkouts/readthedocs.org/user_builds/visisipy/envs/latest/lib/python3.13/site-packages/optiland/psf/huygens_fresnel.py:27
     22 from optiland.psf.base import BasePSF
     23 from optiland.psf.huygens_fresnel_strategies import (
     24     NumbaSummation,
     25     TorchSummation,
     26 )
---> 27 from optiland.visualization.system.utils import transform
     28 from optiland.wavefront import Wavefront
     31 class ScalarHuygensPSF(BasePSF):

File ~/checkouts/readthedocs.org/user_builds/visisipy/envs/latest/lib/python3.13/site-packages/optiland/visualization/__init__.py:9
      7 from .analysis import SurfaceSagViewer
      8 from .info import LensInfoViewer
----> 9 from .system import OpticViewer, OpticViewer3D

File ~/checkouts/readthedocs.org/user_builds/visisipy/envs/latest/lib/python3.13/site-packages/optiland/visualization/system/__init__.py:8
      1 """System visualization package for Optiland.
      2 
      3 Kramer Harrison, 2025
      4 """
      6 from __future__ import annotations
----> 8 from .optic_viewer import OpticViewer
      9 from .optic_viewer_3d import OpticViewer3D
     11 __all__ = ["OpticViewer", "OpticViewer3D"]

File ~/checkouts/readthedocs.org/user_builds/visisipy/envs/latest/lib/python3.13/site-packages/optiland/visualization/system/optic_viewer.py:18
     15 import matplotlib.pyplot as plt
     17 from optiland.visualization.base import BaseViewer
---> 18 from optiland.visualization.system.interaction import InteractionManager
     19 from optiland.visualization.system.rays import Rays2D
     20 from optiland.visualization.system.system import OpticalSystem

File ~/checkouts/readthedocs.org/user_builds/visisipy/envs/latest/lib/python3.13/site-packages/optiland/visualization/system/interaction.py:14
     11 from threading import Timer
     13 from optiland.visualization.info.providers import INFO_PROVIDER_REGISTRY
---> 14 from optiland.visualization.system.lens import Lens2D
     15 from optiland.visualization.system.surface import Surface2D
     18 class InteractionManager:

File ~/checkouts/readthedocs.org/user_builds/visisipy/envs/latest/lib/python3.13/site-packages/optiland/visualization/system/lens.py:12
     10 import matplotlib.pyplot as plt
     11 import numpy as np
---> 12 import vtk
     13 from matplotlib.patches import Polygon
     15 import optiland.backend as be

File ~/checkouts/readthedocs.org/user_builds/visisipy/envs/latest/lib/python3.13/site-packages/vtk.py:58
     56 from vtkmodules.vtkRenderingLabel import *
     57 from vtkmodules.vtkRenderingLOD import *
---> 58 from vtkmodules.vtkRenderingLICOpenGL2 import *
     59 from vtkmodules.vtkRenderingImage import *
     60 from vtkmodules.vtkRenderingGridAxes import *

KeyboardInterrupt: 
# Use the open-source Optiland backend for calculations; to use OpticStudio, replace
# "optiland" with "opticstudio"
visisipy.set_backend("optiland")

Define and build the eye model#

Yes, it’s only two lines of code!

# Initialize the default Navarro model
model = visisipy.EyeModel()

# Build the model in OpticStudio
model.build()

Perform a raytrace analysis#

# List of (x, y) coordinates
coordinates = [(0, 0), (0, 10), (0, 20), (0, 30), (0, 40)]
raytrace = visisipy.analysis.raytrace(coordinates=coordinates)

# Alternatively, the model can be built and analyzed in one go:
# raytrace = visisipy.analysis.raytrace(model, coordinates=zip([0] * 5, range(0, 60, 10)))

Visualize the eye model and the raytrace results#

fig, ax = plt.subplots()
visisipy.plots.plot_eye(ax, model.geometry, lens_edge_thickness=0.5)

sns.lineplot(raytrace, x="z", y="y", hue="field", ax=ax)
sns.move_legend(ax, loc="lower right", title="Field")
../_images/ba69960efb2192bbac1fcdda587639614a8baf76d4b7d3e0b3f77cd184f516d2.png