ejeschke/ginga: Ginga v7.1.0
Authors: ejeschke, P. L. Lim, Rajul, Rupak, Erik Tollerud, Stuart Mumford, Brigitta Sipőcz, Christoph Deil, Chi-Hung Yan, Sourabh Cheedella, Thomas Robitaille, Sergio Pascual, J. Xavier Prochaska, Joe Catera, Ray Plante, Sandra, Ole Streicher, Jonathan Eisenhamer, Nabil Freij, Megan Sosey, Christine Chang, Austin Beauchamp, Henry Ferguson, Matt Craig, Matthew K Brown, Matthew Thompson, Michael Kelley, Peter Teuben, Simon Krughoff
Type: Software
Published: 2026-07-31

<ul>
<li>Added an experimental <strong>Vulkan renderer</strong> (<code>renderer='vulkan'</code>), a
GPU-accelerated, toolkit-agnostic renderer built as an alternative to the
OpenGL one.  It renders GPU-native (images colormapped in-shader with live
cut levels/distribution, shapes/wide/dashed lines, native Pillow text, RGBA
alpha, and a 3D camera mode) into an <em>offscreen</em> Vulkan image and hands the
result back as an array, so every backend (qt, gtk3, gtk4, tk, and the pg
web/websocket backend) can use it via the same array path as the pil/agg
renderers.  Select it with <code>ginga -t <toolkit> -r vulkan</code> or the new
per-viewer <code>renderer</code> setting; it falls back automatically when the
<code>vulkan</code> binding or a device is unavailable.  Requires the optional
<code>vulkan</code> dependency (<code>pip install ginga[vulkan]</code>) and a system Vulkan
driver (Mesa lavapipe works for a CPU/headless device).  See the developer
manual ("The Vulkan renderer") for details.  Not available in-situ under
Pyodide/PyScript.</li>
<li>The OpenGL renderer now draws text by rasterizing it with Pillow and
blitting a texture (filled, anti-aliased) instead of converting it to
cairo path outlines, and supports wide and dashed lines by expanding them
into filled triangles (OpenGL does not guarantee <code>lineWidth > 1</code> or
stippling).  This drops the cairo dependency for OpenGL text.</li>
<li>bump required version of a few dependencies</li>
<li>Menu items can now show an icon as well as (or instead of) text, like
toolbar actions.  <code>Menu.add_name()</code>, <code>Menu.add_menu()</code> and
<code>Menubar.add_name()</code> accept <code>iconpath</code>/<code>iconsize</code> keyword arguments,
and <code>MenuAction</code> gains a <code>set_icon()</code> method.  An <code>icon_only</code> flag
requests showing just the icon where the backend can render it, always
falling back to the text label otherwise, so the same calling code shows
the icon, the text, or both depending on the backend.  Fully supported on
the qt, gtk3, and pg (web) backends; the gtk4 backend accepts the
arguments for API parity but renders text only for now</li>
<li>The qt <code>RadioButton</code> now honors the <code>group</code> keyword across different
containers.  Previously qt only made radio buttons mutually exclusive when
they shared a parent widget; grouped buttons now use a shared
<code>QButtonGroup</code>, matching the gtk3/gtk4/pg backends</li>
<li>Added a <code>TreeView.delete_tree()</code> method (qt/gtk3/gtk4/pg) that removes
the nodes named by a subtree of keys -- individual leaves or whole
subtrees -- from a loaded tree, optionally pruning branches left empty,
preserving the selection on surviving items, and firing the <code>selected</code>
callback if the selection changed and <code>changed</code> if anything was deleted</li>
<li>The <code>ColorDist</code> color distribution classes now produce a normalized
0.0-1.0 floating point curve; the RGB mapping <code>Distribute</code> stage scales
that to the output level (bit depth) and quantizes to the index type.
This preserves precision (no longer capped at 256 levels for deeper
outputs) and is slightly faster.  The <code>colorlen</code> argument to the
<code>ColorDist</code> classes is now vestigial and deprecated (it has no effect).
Custom <code>ColorDist</code> subclasses should now install their curve as a
normalized 0.0-1.0 float array via the new public <code>set_hash()</code> method
(formerly <code>_set_hash</code>).  For backward compatibility, a subclass whose
<code>calc_hash()</code> still stores a pre-7.1 integer/<code>colorlen</code>-scaled hash is
detected at build time and normalized automatically, with a
<code>PendingDeprecationWarning</code>; this shim will be removed in a future
release (github issue #1148)</li>
<li>Color maps are now resolution-independent: <code>ginga.cmap.ColorMap</code> gains
<code>get_colors(n)</code>, which samples/interpolates the map to any size, and can
be built from a discrete list (as before), piecewise-linear control points
(<code>ColorMap.from_control_points</code>), or a callable (<code>from_function</code>).
matplotlib color maps are captured without retaining a runtime dependency
on matplotlib</li>
<li>Added a <code>color_depth</code> viewer setting that controls the resolution (in
bits) at which pseudocolor is distributed, decoupled from the RGB output
depth.  Raising it (e.g. to 12) yields much smoother gradients -- many more
distinct colors and far less banding -- for colorful color maps on a
standard 8-bit display, at negligible cost.  The default (8) is unchanged.
Both the standard and OpenGL renderers honor the setting (the OpenGL
renderer sizes its GPU colormap texture up to 4096 entries)</li>
<li>The DS9-derived color maps (<code>gray</code>, <code>ramp</code>, <code>red</code>, <code>green</code>,
<code>blue</code>, <code>heat</code>, <code>ds9_cool</code>, <code>ds9_a</code>, <code>ds9_b</code>, <code>ds9_bb</code>,
<code>ds9_he</code>) are now defined by their authoritative SAOImageDS9
piecewise-linear control points instead of baked 256-entry arrays.  They
are exact, resolution-independent (smooth at any color depth), and small
(this also removed ~2600 lines from <code>ginga/cmap.py</code>)</li>
<li>Fixed an issue with matplotlib plots getting their axes labels cut off</li>
</ul>