Current Version: kmwcd_viewer_v0.7.8.py
Scope: Raw amplitude plotting (no dB), navigation metadata from #SPO, static X-scale option, image export, progress feedback, display bottom detections, data replay and geo-picking.
This tool was created using valschmidt work and his KMALL file reader, and was heavily influenced the KMWCD Viewer for EM2040 from ReeceClark2.
The tool reads the water column data and navigation directly from KMWCD/KMALL files. No conversion and/or importing are required.
The KMWCD Viewer loads .kmwcd/.kmall files, parses their datagrams via your local kmall.py, and renders water-column amplitude as a 2D color image (samples × beams). It also reads #SPO (sensor position) datagrams to show nearest-in-time vessel metadata (UTC time, speed over ground, latitude, longitude).
The tool is built with PySide6 (Qt6 for Python) for the UI and matplotlib for plotting. It features:
- Depth windowing (min/max)
- Amplitude range control (min/max)
- Static across-track X-scale (symmetric limits) so the plot doesn't jump across pings
- One-step mouse wheel, slider, and left/right arrow navigation
- Export to PNG/JPEG at 2× resolution with filename + meta overlay
- Status-bar loading percentage during pre-scan of the file Shows per‑ping "MRZ points: " and a startup blip like "Nav summary: MRZ=, SKM=, SPO="
- Bottom detections by type (Amplitude/Phase) and class (Normal/Extra)
- Replay (0.1–10 pings/s) with the slider kept in sync
- Pick mode with a modeless Picked Positions dialog (save to
.txt) - Lightweight diagnostic prints to the terminal (kept intentionally)
- Open file →
KMALL.kmall(path)thenloader.index_file()builds a pandasIndexDataFrame listing all datagrams (types, offsets, timestamps). - Filter pings: robust detection of
#MWC(handles string/bytes/substring representations). - Collect NAV: read all
#SPOrecords; each yieldssensorDatawithdatetime,correctedLat_deg,correctedLong_deg,speedOverGround_mPerSec. We store them in a time-indexed DataFrame for nearest-time lookup. - Pre-scan (progress): iterate pings once to compute file-wide:
amp_min,amp_maxfrom raw amplitudedepth_maxfrom computed depth gridacross_maxfrom max|across-track|grid While scanning, update status bar withLoading pings… XX%.
- Render ping: for the selected ping
beamData.sampleAmplitude05dB_p→ amplitude array (no dB conversion)beamPointAngReVertical_deg→ per-beam anglesrange[m] = sample_index * 0.5 * soundVelocity / sampleFreqdepth Z = -cos(angle) * range,across-track Y = sin(angle) * range- Mask depths outside
[dmin, dmax] - Plot using
pcolormesh(Y, Z, A)withvmin=amp_min,vmax=amp_max - Set X limits to
[-Xmax, Xmax]if Xmax > 0; else autoscale - Invert Y so depth grows downward
- Metadata line: find nearest
#SPOto ping time usingDatetimeIndex.get_indexer(..., method='nearest')and format time, SOG, lat, lon.
-
MainWindow (QMainWindow)
- Header row:
- Open (QPushButton)
- Save Image (QPushButton)
- Filename (QLabel)
- Metadata (QLabel; time/SOG/lat/lon)
- Controls:
- Depth Min/Max (QDoubleSpinBox)
- Amp Min/Max (QDoubleSpinBox)
- Across-track Max (m) (QDoubleSpinBox)
- Plot area: Matplotlib FigureCanvas with a fixed-position colorbar Axes (
self.cax) to avoid re-layout creep. - Ping slider row: Ping: label, slider (one-step wheel), current ping label.
- Status bar: shows loading % during pre-scan.
- Header row:
-
Keyboard & Wheel
- Left/Right arrows move one ping.
- Mouse wheel: one ping per notch (custom QSlider).
-
Picked Positions: modeless dialog sized to the main window’s width and ~one‑third height. Closing it clears all picks and unchecks Pick in the main window.
-
Status bar: shows file name, ping number, UTC time, SOG (see note below), and MRZ points count.
- Raw amplitude: The viewer plots raw amplitude values directly (no dB).
- Normalization: Linear normalization controlled by Amp Min / Amp Max. No per-ping auto unless you set those controls.
- Geometry:
Y=sin(angle)*range(across-track),Z=-cos(angle)*range(depth). - Static X-scale: If Across-track Max is set, use symmetric
[-Xmax, Xmax]to stop jitter between pings. - Bottom (MRZ) overlay:
- Always flipped so that the across‑track sign matches the water‑column plot.
- Color by detectionMethod (from MRZ):
1= Amplitude → Red2= Phase → Dark Blue
- Fill by detectionType (from MRZ):
0= Normal → solid markers1= Extra → hollow markers2= Rejected → currently drawn in green (hollow)
Enable Pick, then click in the plot. Each click appends a row to Picked Positions with:
Ping(index),UTCAcrossTrack_m(signed),Depth_mShipLat,ShipLon(from nav at ping time)PointLat,PointLon(computed by across‑track offset using COG/Heading when available)Azimuth(COG preferred; Heading used when available)
Use Save to export a tab‑separated .txt. Close clears all rows and disables Pick.
- Fixed colorbar axes: avoids the colorbar pushing the plot left on every redraw.
- Nearest-time NAV lookup: robust against small timing offsets between ping and
#SPOtimestamps. - Pre-scan with progress: preserves interactivity later (no surprises when ranges change mid-session).
- Sanitizing arrays:
fill_nonfinite_colshandles columns of NaN/inf for stablepcolormesh.
- No
#SPO→ N/A metadata: If a file lacks#SPO, SOG/lat/lon remainN/A. - Large files: Pre-scan touches all pings once; on very large files this can take some time (status shows %).
- Amplitude units: raw units from the driver (may not be absolute calibrated dB).
- Angles: relies on
beamPointAngReVertical_degbeing present/valid; missing/NaN are forward/back-filled safely. - Dual Swath & Coverage: acrosstrack range is dynamic and affected by the data. If swath width appears to jump, set the acrosstrack max distance, and plotting will then remain static and based on the max value.
- Python ≥ 3.11 (3.13 recommended)
- PySide6 (Qt6 for Python)
- matplotlib
- numpy
- pandas
- kmall.py (your KMALL reader; importable as
KMALL)
Optional: If your kmall.py is named differently or lives elsewhere, ensure sys.path includes its folder or adjust the import (import kmall as KMALL).
kmwcd_viewer.py– main viewer.kmall.py– local KMALL driver (required).
- dB mode with per-file or per-ping auto-scaling.
- Interpolation mode with
scipy.interpolate.griddata(cubic), saved as a secondary render mode. - QProgressBar in the status bar, in addition to % text.
- Export presets (color map selection, DPI multiplier, caption layout).
- Confirmed robust
#MWC/#SPOfiltering for string/bytes formats. - Verified colorbar remains fixed across UI actions.
- Confirmed keyboard and one-step wheel navigation.
- Verified export includes filename + metadata and honors 2× DPI.
- Add capability of opening a list of files (datalist) or directory.
- Add a stacked view (alongtrack).
- Add support to more WCD formats (WCD/ALL, S7K, R2Sonics, etc).
- Integrate the tool in MB-System, and use MB I/O drivers to read the data (including KMALL).
- Add filters to remove noise from data.
- Add possibility to detect and export features.
- A C++ version for better performance.
- Add a small window showing the navigation and/or bathymetry and where we are.
- Maybe integrate it in MBeditviz or MBgrdviz?
This guide covers macOS 15 (Sequoia) via MacPorts, Ubuntu 24.04 LTS and Windows10/11.
- A local copy of:
kmwcd_viewer.py(the viewer script)kmall.py(your KMALL reader)
- Python 3.11+ (3.13 recommended)
-
Install required ports:
sudo port selfupdate sudo port install python313 py313-pip py313-pyside6 py313-matplotlib py313-numpy py313-pandas py313-pyproj py313-scipy
-
(Optional) Select python/pip defaults:
sudo port select --set python python311 sudo port select --set pip pip313
-
Run the viewer:
cd /path/to/your/folder python3.13 kmwcd_viewer.py
-
Install Python and pip via MacPorts (if not already):
sudo port install python313 py313-pip
-
Create and activate venv:
python3.13 -m venv .venv source .venv/bin/activate -
Install packages from PyPI:
pip install --upgrade pip pip install PySide6 matplotlib numpy pandas pyproj scipy
-
Run the viewer:
python kmwcd_viewer.py
Ensure
kmall.pyis in the same directory or onPYTHONPATH. If your KMALL module is namedkmall.py, the script expects it importable asKMALL(you can rename import toimport kmall as KMALLif needed).
-
Install base packages:
sudo apt update sudo apt install -y python3 python3-venv python3-pip build-essential
-
Create and activate venv:
python3 -m venv .venv source .venv/bin/activate -
Install Python dependencies:
pip install --upgrade pip pip install PySide6 matplotlib numpy pandas pyproj scipy
-
Run the viewer:
python kmwcd_viewer.py
- Import path: Keep
kmall.pynext to the viewer. The script adds its folder tosys.pathto help importKMALL. - Missing
#SPO: SOG/lat/lon will display asN/Aif your file doesn’t carry#SPOdatagrams. - Colorbar creep: The viewer uses a fixed colorbar axes; if it ever shifts, ensure you’re on the latest version.
- Static X-scale: Set “Across-track Max (m)” to a positive value to lock X; set to 0 for autoscale.
- Go to https://www.python.org/downloads/windows/ and download Python 3.x (64‑bit).
- Run the installer and check “Add Python to PATH.”
- After install, open PowerShell and verify:
python --version pip --version
If PowerShell blocks script execution when activating virtualenvs, you can temporarily allow it for the current shell:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
# Create a working folder (adjust path as desired)
mkdir C:\KMWCD
cd C:\KMWCD
# Copy your files into this folder
# - kmwcd_viewer.py
# - kmall.py
# Create and activate a virtual environment
python -m venv .venv
.\.venv\Scripts\Activate.ps1
# Upgrade pip
python -m pip install --upgrade pippip install PySide6 matplotlib numpy pandas proj scipyVerify:
python - << 'PY'
import PySide6, matplotlib, numpy, pandas
print("OK: PySide6", PySide6.__version__, "| matplotlib", matplotlib.__version__)
PYpython .\kmwcd_viewer.py- Use Open to load a
.kmwcd/.kmallfile. - You should see:
- Depth & amplitude controls, Across‑track Max (m) to lock X scale
- Ping slider with Left/Right keys and 1‑step mouse wheel
- Metadata line from #SPO (UTC time, SOG, latitude, longitude)
- Save Image for PNG/JPEG at 2× DPI with filename + meta overlay
- Status bar shows Loading pings… XX% during pre‑scan
Create a file run_viewer.bat in C:\KMWCD:
@echo off
setlocal
call .\.venv\Scripts\activate.bat
python kmwcd_viewer.pyDouble‑click run_viewer.bat to start the app next time.
You can bundle the app with PyInstaller:
pip install pyinstaller
pyinstaller --noconfirm --windowed --onefile ^
--name KMWCDViewer ^
--collect-submodules PySide6 --collect-data PySide6 ^
--collect-data matplotlib ^
--add-data "kmall.py;." ^
kmwcd_viewer.py- The EXE will be in
dist\KMWCDViewer.exe. - Ship it together with your test
.kmwcdfiles. - If your KMALL driver reads auxiliary files, add them via extra
--add-datalines.
-
“DLL not found” or Qt errors
Install Microsoft Visual C++ Redistributable (x64) (2015–2022).
https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist -
Black/blank window or OpenGL issues
Force software rendering (rare on Widgets apps):setx QT_OPENGL software
-
ImportError: cannot import KMALL
Ensurekmall.pyis in the same folder as the viewer script, or add its folder toPYTHONPATH. -
Activation blocked
Temporarily bypass execution policy:Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
kmwcd_viewer.py(or your latest)kmall.py(your KMALL reader)- Optional:
run_viewer.batlauncher
That’s it! If you want an MSI installer later, we can generate one from the PyInstaller build using tools like wixl or msi-packager.
