ehtim: regularized maximum likelihood imaging for VLBI data in Python
Imaging, analysis, and simulation software for radio interferometry
At a glance
- What is it?
- eht-imaging (ehtim) is a GPL-3.0 Python package for simulating and manipulating VLBI data and reconstructing images with regularized maximum likelihood methods. It is built for radio astronomers who already have interferometric data, not for people who want to look at a black hole picture.
- Who is it for?
- Adopt ehtim if you have VLBI data or a simulated u-v dataset and you want to run RML imaging inside Python, and accept that the stable release still carries a Development Status of Alpha. Do not adopt it if you need a maintained, dependency-light tool or if you cannot install pyNFFT on your Python version.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What ehtim is for, and who is actually supposed to use it
Radio interferometry does not hand you a picture. A VLBI array records visibilities on a set of u-v tracks, and turning those into an image is an inverse problem with far more unknowns than measurements. ehtim exists to solve that problem in Python: the README describes it as "Python modules for simulating and manipulating VLBI data and producing images with regularized maximum likelihood methods." The package is organized around six primary classes, Image, Movie, Array, Obsdata, Imager, and Caltable, which cover loading and simulating data, producing simulated data from realistic u-v tracks, calibrating, inspecting and plotting, and imaging data sets "in various polarizations using various data terms and regularizing functions."
The audience is narrow on purpose. You need to know what a closure phase is before the output means anything. The repository ships an examples directory with scripts for calibration, closure imaging, polarimetry, multifrequency work, scattering, stochastic optics and star warps, plus a survey notebook. The README is explicit that those scripts "have not been recently validated," so treat them as reading material rather than a supported API. If you are looking for a general astronomy plotting library, this is not it.
How the classes fit together, from u-v track to image
The data flow visible in the repository layout runs through the class names. An Array holds the station geometry. Obsdata holds the visibilities, and the README states that the package can produce simulated data from realistic u-v tracks, so the same container type serves both a simulation and a real observation. Caltable holds calibration terms applied to that data. Imager takes the calibrated data and a set of regularizing functions and produces an Image, and Movie extends the same idea to time-variable sources for dynamical imaging.
The imaging method is regularized maximum likelihood rather than CLEAN. That means the reconstruction is driven by a likelihood term plus explicit regularizers, and the choice of regularizers is yours. The README names the papers behind specific techniques, including Chael et al. 2018 on "Interferometric Imaging Directly with Closure Phases and Closure Amplitudes" and Johnson et al. 2017 on dynamical imaging. Those citations are the real documentation for what each regularizer does; the prose docs are thinner.
One architectural detail matters more than it looks. Fast Fourier transforms are not part of the base install. The README states that to use fast Fourier transforms in this version you must separately install NFFT and its pyNFFT wrapper, and that the dev branch has replaced pyNFFT with finufft. That is a hard split between the stable release and the development line.
Installing ehtim and running the first imaging pass
The README points at PyPI for the latest stable version, which the release list identifies as 1.3.2. Install it with pip:
pip install ehtimThat pulls in numpy, scipy, matplotlib, astropy, ephem, future, h5py and pandas automatically, according to the README. Note that pyproject.toml lists skyfield, requests, networkx, paramsurvey and others as dependencies as well, so the installed set is wider than the README paragraph suggests.
If you want the fast Fourier transforms, install pyNFFT separately. The README gives conda as the simplest route:
conda install -c conda-forge pynfftBefore you do that, check your versions. The README states plainly that pyNFFT is only supported for Python versions at or below 3.11 and numpy versions at or below 1.26.4. On an M1 Mac or later with macOS 12.0 and above, the README directs you to an updated fork of pyNFFT and a manual build of fftw, nfft and then pynfft.
To run the very latest code instead of the release, the README says to check out the dev branch and install from the directory:
pip install .The dev branch is described as unstable but replaces pyNFFT with finufft, which removes the Python 3.11 ceiling. For a first real use, open tutorials/ehtim_tutorial.ipynb in the repository. The README describes it as the imaging tutorial notebook, and the linked slides walk through the basic steps of reconstructing EHT images with the code. Expect to construct an Obsdata object, attach an Imager, choose regularizers, and read back an Image.
The pyNFFT version ceiling is the real adoption cost
Most Python packages let you install and move on. ehtim does not, in the stable line. The README's note that pyNFFT is only supported for Python versions at or below 3.11 and numpy at or below 1.26.4 is not a footnote; it decides which machines can run the fast transform path at all. If your environment is pinned to a newer numpy because something else in your stack needs it, you are choosing between the fast transforms and the rest of your stack.
The workaround exists but is not the released code. The dev branch swaps pyNFFT for finufft, and the README calls that branch unstable. So the stable release carries the constraint and the unconstrained version carries the instability. That is a genuine trade-off, not a packaging oversight someone will fix next week.
There is a second cost signal in pyproject.toml: the classifier reads "Development Status :: 3 - Alpha" while the version number is 1.3.2. The README opens by calling this "an early release" and asks users to raise an issue, submit a pull request, or email the maintainer if they have trouble. A project at version 1.3.2 that still labels itself Alpha is telling you the interfaces are not frozen. Pin your version.
Finally, several functions need packages that are not installed automatically. The README lists networkx for image comparison, requests for dynamical imaging, and scikit-image for a few analysis functions, and says the vast majority of the code works without them. Check pyproject.toml before assuming a missing import is a bug.
ehtim versus a general radio interferometry package
The obvious alternative for someone doing interferometric imaging in Python is a general-purpose radio astronomy toolkit, where the imaging path is typically a CLEAN-based deconvolution wrapped around a wide set of calibration and data-format utilities. The difference in approach is not cosmetic. CLEAN builds an image from point-source components and then convolves with a restoring beam; ehtim's stated method is regularized maximum likelihood, where you specify the regularizing functions and the reconstruction is the result of that optimization. On sparse VLBI data with few stations, the RML formulation is the reason the package exists, and the README's citation list is dominated by papers about closure quantities and dynamical imaging rather than deconvolution.
That also means the two tools fail differently. With CLEAN you get a beam and a familiar notion of resolution. With ehtim you get whatever your regularizer choices imply, and the result is only as defensible as the justification you can give for those choices. If your data are dense and well covered, or if your team already has a validated CLEAN pipeline, there is no reason to switch. If you are working on closure-phase imaging of a source observed by a handful of stations, the RML approach is the point.
Maintenance, licensing and what an upgrade actually costs
The repository is not archived and the last push was on 2026-09-22. Releases are recent and reasonably close together: v1.3 on 2026-05-13, v1.3.1 on 2026-06-10, and v1.3.2 on 2026-06-16. The project is moving. What it is not doing is stabilizing its own label, since pyproject.toml still classifies it as Alpha.
Upgrade cost is dominated by the pyNFFT constraint rather than by API churn. Any environment refresh that moves Python past 3.11 or numpy past 1.26.4 breaks the fast transform path in the stable release until you either pin back or move to the dev branch. Budget for that pinning explicitly, and check the release notes before bumping, because the README does not document a rollback procedure for a version that turns out to be incompatible with your data pipeline.
On licensing: the package is GPL-3.0, stated in the README badge, the pyproject.toml license field, and the LICENSE.txt file at the repository root. GPL-3.0 is a copyleft licence, so if you distribute software that links against ehtim, the terms of that distribution are affected. Reading the licence text and your own obligations is your call; this is not legal advice. The README also asks that you cite Chael et al. 2018 if you use ehtim in a publication, and notes a static DOI on Zenodo for the latest version.
Editorial conclusion
Adopt ehtim if you have VLBI data or a simulated u-v dataset and you want to run RML imaging inside Python, and accept that the stable release still carries a Development Status of Alpha. Do not adopt it if you need a maintained, dependency-light tool or if you cannot install pyNFFT on your Python version. Before committing, check that your Python is at or below 3.11 and numpy at or below 1.26.4, and open tutorials/ehtim_tutorial.ipynb to confirm the workflow matches your data.
Frequently asked questions
How do I install ehtim?
The README points to PyPI for the latest stable version and gives a single pip install ehtim command. That installs most required libraries automatically, but fast Fourier transforms need NFFT and pyNFFT installed separately.
Does ehtim work with the newest Python and numpy versions?
Not on the stable release if you need fast Fourier transforms. The README states that pyNFFT is only supported for Python versions at or below 3.11 and numpy versions at or below 1.26.4. The dev branch replaces pyNFFT with finufft but is described as unstable.
Where is the ehtim tutorial for imaging?
The README points to tutorials/ehtim_tutorial.ipynb in the repository as the imaging tutorial notebook, and links slides that walk through the basic steps of reconstructing EHT images with the code.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/achael-eht-imaging)