Metadata-Version: 2.4
Name: viewer4a1
Version: 0.3.0
Summary: Viewer and analysis tool for beamline 4A1 scan data and ARPES spectra
License-Expression: GPL-3.0-only
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Requires-Dist: h5py>=3.8
Requires-Dist: matplotlib>=3.7
Provides-Extra: gui
Requires-Dist: erlab<3.28,>=3.27; extra == "gui"
Requires-Dist: PyQt6>=6.6; extra == "gui"
Requires-Dist: qtpy>=2.4; extra == "gui"
Requires-Dist: pyqtgraph>=0.13; extra == "gui"
Requires-Dist: xarray>=2024.1; extra == "gui"
Requires-Dist: scipy>=1.11; extra == "gui"
Requires-Dist: lmfit>=1.3; extra == "gui"
Requires-Dist: igor2>=0.5; extra == "gui"
Provides-Extra: test
Requires-Dist: pytest>=7; extra == "test"
Provides-Extra: tested
Requires-Dist: annotated-types==0.8.0; extra == "tested"
Requires-Dist: appnope==1.0.0; sys_platform == "darwin" and extra == "tested"
Requires-Dist: asteval==1.0.10; extra == "tested"
Requires-Dist: asttokens==3.0.2; extra == "tested"
Requires-Dist: cffi==2.1.1; implementation_name == "pypy" and extra == "tested"
Requires-Dist: click==8.5.0; extra == "tested"
Requires-Dist: cloudpickle==3.1.2; extra == "tested"
Requires-Dist: colorama==0.4.6; extra == "tested"
Requires-Dist: comm==0.2.3; extra == "tested"
Requires-Dist: contourpy==1.3.3; extra == "tested"
Requires-Dist: cycler==0.12.1; extra == "tested"
Requires-Dist: dask==2026.8.0; extra == "tested"
Requires-Dist: debugpy==1.8.21; extra == "tested"
Requires-Dist: dill==0.4.1; extra == "tested"
Requires-Dist: distributed==2026.8.0; extra == "tested"
Requires-Dist: erlab==3.27.2; extra == "tested"
Requires-Dist: executing==2.2.1; extra == "tested"
Requires-Dist: findiff==0.13.1; extra == "tested"
Requires-Dist: fonttools==4.65.0; extra == "tested"
Requires-Dist: fsspec==2026.7.0; extra == "tested"
Requires-Dist: greenlet==3.5.5; (platform_machine == "AMD64" or platform_machine == "WIN32" or platform_machine == "aarch64" or platform_machine == "amd64" or platform_machine == "ppc64le" or platform_machine == "win32" or platform_machine == "x86_64") and extra == "tested"
Requires-Dist: h5netcdf==1.8.1; extra == "tested"
Requires-Dist: h5py==3.16.0; extra == "tested"
Requires-Dist: hdf5plugin==7.1.0; extra == "tested"
Requires-Dist: igor2==0.5.13; extra == "tested"
Requires-Dist: igorwriter==0.7.1; extra == "tested"
Requires-Dist: ipykernel==7.3.0; extra == "tested"
Requires-Dist: ipython==9.17.1; extra == "tested"
Requires-Dist: ipython-pygments-lexers==1.1.1; extra == "tested"
Requires-Dist: jedi==0.20.0; extra == "tested"
Requires-Dist: jinja2==3.1.6; extra == "tested"
Requires-Dist: joblib==1.6.0; extra == "tested"
Requires-Dist: jupyter-client==8.10.0; extra == "tested"
Requires-Dist: jupyter-core==5.9.1; extra == "tested"
Requires-Dist: kiwisolver==1.5.1; extra == "tested"
Requires-Dist: lazy-loader==0.5; extra == "tested"
Requires-Dist: llvmlite==0.45.1; (platform_machine == "x86_64" and sys_platform == "darwin") and extra == "tested"
Requires-Dist: llvmlite==0.49.0; (platform_machine != "x86_64" or sys_platform != "darwin") and extra == "tested"
Requires-Dist: lmfit==1.3.4; extra == "tested"
Requires-Dist: locket==1.0.0; extra == "tested"
Requires-Dist: markupsafe==3.0.3; extra == "tested"
Requires-Dist: matplotlib==3.11.1; extra == "tested"
Requires-Dist: matplotlib-inline==0.2.2; extra == "tested"
Requires-Dist: mpmath==1.3.0; extra == "tested"
Requires-Dist: msgpack==1.2.2; extra == "tested"
Requires-Dist: nest-asyncio2==1.7.2; extra == "tested"
Requires-Dist: numba==0.62.1; (platform_machine == "x86_64" and sys_platform == "darwin") and extra == "tested"
Requires-Dist: numba==0.67.0; (platform_machine != "x86_64" or sys_platform != "darwin") and extra == "tested"
Requires-Dist: numexpr==2.14.2; extra == "tested"
Requires-Dist: numpy==2.3.5; (platform_machine == "x86_64" and sys_platform == "darwin") and extra == "tested"
Requires-Dist: numpy==2.5.3; (platform_machine != "x86_64" or sys_platform != "darwin") and extra == "tested"
Requires-Dist: packaging==26.3; extra == "tested"
Requires-Dist: pandas==3.0.5; extra == "tested"
Requires-Dist: parso==0.8.7; extra == "tested"
Requires-Dist: partd==1.4.2; extra == "tested"
Requires-Dist: pexpect==4.9.0; (sys_platform != "emscripten" and sys_platform != "win32") and extra == "tested"
Requires-Dist: pickleshare==0.7.5; extra == "tested"
Requires-Dist: pillow==12.3.0; extra == "tested"
Requires-Dist: platformdirs==4.11.8; extra == "tested"
Requires-Dist: prompt-toolkit==3.0.53; extra == "tested"
Requires-Dist: psutil==7.2.2; extra == "tested"
Requires-Dist: ptyprocess==0.7.0; (sys_platform != "emscripten" and sys_platform != "win32") and extra == "tested"
Requires-Dist: pure-eval==0.2.4; extra == "tested"
Requires-Dist: pycparser==3.11; implementation_name == "pypy" and extra == "tested"
Requires-Dist: pydantic==2.13.5; extra == "tested"
Requires-Dist: pydantic-core==2.46.5; extra == "tested"
Requires-Dist: pygments==2.21.0; extra == "tested"
Requires-Dist: pyparsing==3.3.2; extra == "tested"
Requires-Dist: pyperclip==1.11.0; extra == "tested"
Requires-Dist: pyqt6==6.11.0; extra == "tested"
Requires-Dist: pyqt6-qt6==6.11.2; extra == "tested"
Requires-Dist: pyqt6-sip==13.12.0; extra == "tested"
Requires-Dist: pyqtgraph==0.14.0; extra == "tested"
Requires-Dist: python-dateutil==2.9.0.post0; extra == "tested"
Requires-Dist: pyyaml==6.0.3; extra == "tested"
Requires-Dist: pyzmq==27.2.0; extra == "tested"
Requires-Dist: qtawesome==1.4.2; extra == "tested"
Requires-Dist: qtconsole==5.7.2; extra == "tested"
Requires-Dist: qtpy==2.4.3; extra == "tested"
Requires-Dist: scipy==1.18.1; extra == "tested"
Requires-Dist: six==1.17.0; extra == "tested"
Requires-Dist: sortedcontainers==2.4.0; extra == "tested"
Requires-Dist: sqlalchemy==2.0.52; extra == "tested"
Requires-Dist: stack-data==0.6.3; extra == "tested"
Requires-Dist: sympy==1.14.0; extra == "tested"
Requires-Dist: tblib==3.2.2; extra == "tested"
Requires-Dist: toolz==1.1.0; extra == "tested"
Requires-Dist: tornado==6.5.8; extra == "tested"
Requires-Dist: tqdm==4.70.0; extra == "tested"
Requires-Dist: traitlets==5.16.1; extra == "tested"
Requires-Dist: typing-extensions==4.16.0; extra == "tested"
Requires-Dist: typing-inspection==0.4.4; extra == "tested"
Requires-Dist: tzdata==2026.5; (sys_platform == "emscripten" or sys_platform == "win32") and extra == "tested"
Requires-Dist: uncertainties==3.2.3; extra == "tested"
Requires-Dist: varname==1.0.0; extra == "tested"
Requires-Dist: wcwidth==0.8.3; extra == "tested"
Requires-Dist: xarray==2026.7.0; extra == "tested"
Requires-Dist: xarray-lmfit==0.6.0; extra == "tested"
Requires-Dist: xraydb==4.5.8; extra == "tested"
Requires-Dist: zict==3.0.0; extra == "tested"
Dynamic: license-file

# viewer4a1

A viewer and analysis tool for the scan data of beamline 4A1 and for ARPES
spectra from several instruments, built on the ImageTool of
[erlab](https://github.com/kmnhan/erlabpy).

It reads

| Format | From |
|---|---|
| `.h5` with its `.jsonl` | 4A1 scans |
| `.ibw`, `.pxt`, `.pxp` | Igor Pro |
| `.itx` | Igor text, from the 4A1 ARPES program |
| `.zip` | Scienta analyser scans |
| `.krx` | MB Scientific analyser |
| `.fits` | ALS beamline 7.0.2 (MAESTRO) |

and shows them in a browser of a folder and in ImageTool. An Analysis menu
holds Fermi edge fitting, normalisation and background subtraction, peak
fitting, cuts along a line, momentum and kz conversion, MAESTRO's detector
pixels to angle and the removal of spikes; a session keeps a piece of work, its data, fits and windows, in one
file; figures are copied or saved as vector artwork.

## Install

[uv](https://docs.astral.sh/uv/) installs the viewer and the Python it runs
on, without administrator rights, apart from any other Python on the
computer.

1. Install uv, once. On Windows, in PowerShell:

       powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

   On macOS or Linux, in Terminal:

       curl -LsSf https://astral.sh/uv/install.sh | sh

   Then close the window and open a new one.

2. Install the viewer:

       uv tool install --python 3.12 "viewer4a1[tested]"

   `[tested]` installs every package the viewer needs at the version it was
   tested with. If uv says the folder it put the viewer in is not on your
   `PATH`, run `uv tool update-shell` and open a new window.

3. Start it:

       viewer4a1 gui

   opens the folder you are in; `viewer4a1 gui FOLDER` opens another.
   `viewer4a1 --help` lists the other commands.

To update: `uv tool upgrade viewer4a1`. To see which version you have:
`uv tool list`. To remove it: `uv tool uninstall viewer4a1`.

## Computers

The viewer is developed and tested on Linux and used on Windows and macOS.
Every package it needs is published for

- Windows 10 and 11 on Intel or AMD processors,
- macOS 12 or newer on Apple silicon,
- Linux with glibc 2.34 or newer on Intel or AMD processors (Ubuntu 22.04,
  Debian 12, RHEL 9 and later), and with glibc 2.39 or newer on ARM
  (Ubuntu 24.04 and later).

On an Intel Mac, `[tested]` installs numba 0.62 and numpy 2.3, the newest
published for it, and that combination has not been tested. On Windows on
an ARM processor it does not install: `hdf5plugin`, which erlab needs, has
no build for it.

If the install says that no version of a package fits the computer,

    uv tool install --python 3.12 "viewer4a1[gui]"

takes the newest versions that do fit, which have not been tested with the
viewer.

## Licence

GPL-3.0-only; see `LICENSE`. The viewer uses erlab and PyQt6, which are GPL
as well.
