Ginga: Image Viewer and Toolkit

About Ginga

Ginga is a toolkit designed for building viewers for scientific image data in Python, visualizing 2D pixel data in NumPy arrays. It can view astronomical data such as contained in files based on the FITS (Flexible Image Transport System) file format. It is written and is maintained by software engineers at the Subaru Telescope, National Astronomical Observatory of Japan.

The Ginga toolkit centers around an image display class which supports zooming and panning, color and intensity mapping, a choice of several automatic cut levels algorithms and canvases for plotting scalable geometric forms. In addition to this widget, a general purpose “reference” FITS viewer is provided, based on a plugin framework.

A fairly complete set of “standard” plugins are provided for features that we expect from a modern FITS viewer: panning and zooming windows, star catalog access, cuts, star pick/FWHM, thumbnails, etc.

Requirements and Supported Platforms

Because Ginga is written in pure Python, it can run on any platform that has the required Python modules and has a supported widget set. The basic Ginga display class supports the Qt (4 and 5), PySide, Gtk (2 and 3), Tk widget sets natively as well as any Matplotlib Figure, and HTML5 canvases in a web browser. The full reference viewer supports Qt and Gtk variants. Ginga can also be used in Jupyter notebooks.

Getting the Source

Clone from Github:

$ git clone https://github.com/ejeschke/ginga.git

To get a zip or tar ball instead, see the links on About Ginga.

Building and Installation

Download and install from pip:

$ pip install ginga

Or, if you have downloaded the source, go into the top-level directory and run the following:

$ python setup.py install

The reference viewer can then be run using the command ginga.

Detailed Installation Instructions for Ginga

Dependences

Ginga is written entirely in Python, and only uses supporting Python packages. There is nothing to compile (unless you need to compile one of the supporting packages).

On recent Linux, Mac and Windows versions, all of the packages are available in binary (installable) form. It should not be necessary to compile anything, but as always, your mileage may vary.

REQUIRED
  • python (either v. 2.7 OR v. 3.4 or higher)
  • numpy (v. 1.7 or higher)

Highly recommended, because some features will not be available without it:

  • scipy
  • pillow
  • opencv

For opening FITS files you will need one of the following packages:

  • astropy
  • fitsio

For WCS resolution you will need one of the following packages:

  • astropy
  • kapteyn
  • astLib
  • starlink
BACKENDS (one or more)

Ginga can draw its output to a number of different back ends. Depending on which GUI toolkit you prefer (and what you want to do), you will need at least one of the following:

  • python-qt4
  • python-qt5
  • python-pyside (qt4 alternative)
  • python-gtk (gtk2) AND python-cairo
  • python gtk3 (gi) AND python-cairo
  • python-Tkinter
  • matplotlib
  • tornado
  • aggdraw
  • PIL (pillow)
  • OpenCv

Notes on Supported Widget Sets

In the discussion below, we differentiate between the Ginga viewing widget, such as used in the examples/\*/example\*.py programs and the full reference viewer, which includes many plugins (scripts/ginga).

Note

For the full reference viewer, Mac and Windows users should probably install the Qt version, unless you are the tinkering sort. Linux can use either Qt or Gtk fine.

Qt/PySide

Ginga can use either PyQt or PySide, version 4 or 5. It will auto-detect which one is installed. There is support for both the basic widget and the full reference viewer.

Note

If you have both installed and you want to use a specific one then set the environment variable QT_API to either “pyqt” or “pyside”. This is the same procedure as for Matplotlib.

Gtk

Ginga can use either Gtk 2 (with pygtk) or gtk 3 (with gi). (If you have an older version of pycairo package you may need to install a newer version from github.com/pygobject/pycairo).

Tk

Ginga’s Tk support is limited to the viewing widget itself. For overplotting (graphics) support, you will also need:

  • “pillow”/PIL package
  • “OpenCv” module
  • “aggdraw” module (which you can find here ; supports Python 2 only).
Matplotlib

Ginga can render directly into a Matplotlib figure. Support is limited to the viewing widget itself. Any of the backends that Matplotlib supports is usable. Performance is not as good as to one of the “native” backends listed above, but oh, the overplot options!

HTML5 web browser

Ginga can render into an HTML5 canvas via a web server. Support is limited to the viewing widget itself. See the notes in example/pg/example1_pg.py. Tested browsers include Chromium (Chrome), Firefox, and Safari.

Installation from Source

  1. Clone from github:

    $ git clone https://github.com/ejeschke/ginga.git
    

    Or see links on this page to get a zip or tar ball.

  2. Unpack, go into the top level directory, and run:

    $ python setup.py install
    

    The reference viewer can then be run using the command ginga.

Alternatively you can download and install via pip:

$ pip install ginga

Platform Specific Instructions

Linux
  1. Install the necessary dependences. If you are on a relatively recent version of Ubuntu (e.g. v14.04 or later), something like the following will work:

    $ apt-get install python-numpy python-scipy python-matplotlib \
      python-astropy python-qt4 python-webkit python-magic git pip
    

    Or:

    $ apt-get install python-numpy python-scipy python-matplotlib \
      python-astropy python-gtk python-cairo python-webkit \
      python-magic git pip
    

    (if you want to use the Gtk version)

  2. Install ginga with pip:

    $ pip install ginga
    

    or by obtaining the source and installing as described above.

Mac
  1. For Mac users, we recommend installing the Anaconda distribution. This distribution already includes all of the necessary packages to run Ginga.

    As an alternative, you also have the choice of Enthought Canopy. The free version works fine. After installing this, open the Canopy package manager, search for “astropy” and install it. Also search for and install “pyside” (free version of Qt bindings).

  2. After installing one of these distributions, open a Terminal and install Ginga via “pip install ginga”. You can then run the reference viewer via the command “ginga”.

Note

Ginga can be installed and run fine using a working Macports or Homebrew installation. Simply follow the package advice given above under the Linux instructions.

Windows
Anaconda

For Windows users, we recommend installing the Anaconda distribution. This distribution already includes all of the necessary packages to run Ginga.

After installing Anaconda, you can find the reference viewer script as:

Start -> All Programs -> Anaconda -> Anaconda Command Prompt
pythonw Scripts\ginga
Enthought Canopy

As an alternative, you also have the choice of Enthought Canopy.

  1. Install the free version.

  2. Open the Canopy package manager.

  3. Search for and install “astropy”.

  4. Search for and install “pyside” (free version of Qt bindings).

    Start -> All Programs -> Enthought Canopy -> Canopy command prompt pip install ginga pythonw AppDataLocalEnthoughtCanopyUserScriptsginga

Documentation

What’s New in Ginga?

Ver 2.7.1 (2018-07-09)

  • Fix for image rendering bug which shows last row and column of image being drawn twice
  • Added option to “Compass” draw type to be in pixels (X/Y) or wcs (N/E)
  • Changed Pan plugin to attempt to draw both kinds of compasses
  • Log plugin enhanced to show lines logged before it was opened
  • Info plugin adds convenience controls for “Follow New” and “Raise New”
  • WCSMatch plugin enhanced to offer fine grained control over sync
  • fixed an issue in Debian build that caused long start up times
  • User can dynamically add scrollbars to channel viewers in Preferences
  • Made Gtk backend default to ‘gtk3’ - “-t gtk” now invokes gtk3 instead of gtk2 - choose “-t gtk2” if you want the gtk2 back end
  • Fixed a bug with opening wildcard-type filespec from the command line
  • Fixed an issue in Thumbs plugin with opening FITS tables from the command line
  • Fixes for some keyboard focus (Gtk) and unintentional channel changes (Qt) when viewer is in MDI mode
  • IRAF plugin moved to experimental folder
  • Allow setting of initial channel list, local, global and disabled plugins from general configuration file
  • Fix for a bug when using OpenCv acceleration on dtype(‘>f8’) arrays
  • Fixed a bug where colormap scale markers were sometimes not spaced wide enough
  • Workaround for failed PDF build in RTD documentation

Ver 2.7.0 (2018-02-02)

  • Fix for gtk 4.0 (use “gtk3” backend, it works for 4.0)
  • Fix for broken polygon containment test
  • Addition of configurable zoom handlers for pan gestures
  • Fix for some broken tests under python 2.7
  • Update to mode handling via keyboard shortcuts
    • addition of a new “meta” mode used primarily for mode switching
    • most modes now initiated from meta mode, which frees up keys for other uses
    • see Ginga quick reference for details on how the new bindings work
  • Efficiency update for Thumbs plugin when many thumbs are present
  • Default for the save_layout option is now True, so the reference viewer will write out its layout state on exit and restore it on startup. See documentation in the “customization” section of the manual.
  • Plugins can now be organized by category and these categories are used to construct a hierarchical Operations menu
  • Zoom and Header plugins are now not started by default
  • Fix for “sortable” checkbox behavior on Header plugin
  • Default keyboard mode type is now ‘locked’ (prev ‘oneshot’)
  • Fixes for missing CSS file in installation script
  • Less confusing behavior for workspace and toolbar arrow buttons

Ver 2.6.6 (2017-11-02)

  • Fix for broken sorting in Contents plugin in gtk backends
  • Fix for resize bug in switching in and out of grid view in gtk backends
  • Updated to have efficient support for gtk3
    • please install compatible pycairo from github.com/pygobject/pycairo if you get a “Not implemented yet” exception bubbling up from a method called cairo.ImageSurface.create_for_data()
  • Addition of a “Quick Mode” to the Pick plugin–see documentation
  • More consistent font handing between widgets and Ginga canvases
  • Bug fix for importing some types of matplotlib color maps
  • Add antialiasing for Qt back end
  • Bug fixes and enhancements for Qt gestures - holding shift with pinch now keeps position under cursor
  • New Jupyter notebooks back end based on ipywidgets - requirements: $ pip install ipyevents - see examples/jupyter-notebook/
  • Fixes to various reference viewer plugins

Ver 2.6.5 (2017-07-31)

  • Coordinate transforms refactored for speed and code clarity
  • Some canvas shapes refactored for better code reuse
  • Allow max and min scale limits to be disabled (by None)
  • Fixed a bug that prevented the reference viewer from resizing correctly with Qt back end
  • Refactored WCS wrapper module for code clarity
  • Set minimum astropy version requirement to 1.X
  • Fixed a bug in NAXIS selection GUI (MultiDim plugin)
  • Fixed MDI window resizing with Gtk back ends
  • Fixed an error where zoom 100% button did not correctly zoom to 1:1 scale
  • Several fixes for astropy 2.0 compatibility
  • Fixed a bug in the FBrowser plugin when channel displaying a table and attempting to load a new file
  • Fixed a bug when setting the pan position manually by wcs coordinates
  • Updates for changes in PIL.ImageCms module
  • Fix for window corruption on certain expose events
  • New default bindings for touch pads and differentiation from wheel zoom

Ver 2.6.4 (2017-06-07)

  • Added new ScreenShot plugin to take PNG/JPEG snaps of the viewer window
  • Enhancements to the Pick plugin
    • Added ability to make shapes besides rectangles for enclosing pick area. Masks out unwanted pixels. Choose the shape in the Settings tab.
    • Changed behavior of pick log to only write the log when the user clicks the save button.
    • Changed the name of the save button to “Save as FITS table” to make it clear what is being written.
    • If “Show candidates” is selected in Settings, then ALL of the candidates are saved to the log.
    • Added documentation to the manual
    • Bug fix for error when changing radius
  • Improvements to layout of Operations menu (plugin categories)
  • Colorbar scale now placed below the color wedge and is more legible
  • Bug fixes for LineProfile plugin
  • Slit function for Cuts plugin can be enabled from GUI
  • Bug fixes for Slit function
  • Info plugin can now control new image cut/zoom/center settings
  • Fixed an issue with the MultiDim plugin that could result in a hang with some back ends
  • New canvas type for displaying WCS grid overlay and new WCSAxes plugin that uses it
  • Bug fixes to scrolling via scrollbars and vert/horiz percentages
  • Enhancements to the LineProfile plugin
    • several new shapes besides the standard point
    • plot multiple lines

Ver 2.6.3 (2017-03-30)

  • Fix for issue that stops ginga startup when loading externally distributed plugins that have errors
  • Fix for an issue loading plugins from the command line when they are nested in a package
  • Added bindings for moving +/- pixel delta in X or Y and centering on the pixel
  • Fixes for some key mappings for tk, matplotlib and HTML5 canvas backends
  • Fixes for IRAF plugin under python 3
  • Fix for a bug using remote control (RC) plugin from python2 client to python 3 ginga
  • Documentation updates

Ver 2.6.2 (2017-02-16)

  • Added some colormaps from ds9 that don’t have equivalents in Ginga or matplotlib
  • Fix for recognizing CompImage HDU type when using astropy.io.fits
  • Add new experimental OpenGL back end
  • Fixes for Tk back end on python 3
  • You can now write separately distributed and installable plugins for the reference viewer that Ginga will find and load on startup
  • Added –sep option to load command line files into separate channels
  • New help screen feature available for plugins
  • Lots of updates to documentation
  • Fixed a stability issue with drag and dropping large number of files under Linux
  • Fixes for python3 and several example programs
  • Fix for interactive rotation bug under matplotlib back end

Ver 2.6.1 (2016-12-22)

  • Added a working MDI workspace for gtk2/gtk3.
  • Added scrollbar frames. See examples/qt/example1_qt.py for standalone widget. Can be added to reference viewer by putting ‘scrollbars = “on”’ in your channel_Image.cfg preferences.
  • Reorganized reference viewer files under “rv” folder.
  • Improved Pick plugin: nicer contour plot, pick log uses table widget, pick log saved as a FITS table HDU
  • Pick and Zoom plugins can now use a specific color map, rather than always using the same one as the channel window
  • gtk3 reference viewer can now be resized smaller than the original layout (gtk2 still cannot)
  • added ability to save the reference viewer size, layout and position on screen
  • gtk MDI windows now remember their size and location when toggling workspace types
  • Fixes for problems with pinch and scroll gestures with Qt5 backend
  • Fixed a bug where scale changes between X and Y axes unexpectedly at extreme zoom levels
  • Fixed a bug where cursor could get stuck on a pan cursor
  • Added ability to define a cursor for any mode
  • Added documented virtual methods to ImageView base class
  • Added a workaround for a bug in early versions of Qt5 where excessive mouse motion events accumulate in the event queue

Ver 2.6.0 (2016-11-16)

With release 2.6.0 we are moving to a new versioning scheme that makes use of github tagged releases and a “dev” versioning scheme for updates between releases.

This release includes many bugfixes and improvements, new canvas types (XRange and YRange), a Command plugin, WCSMatch plugin, dynamically configurable workspaces, OpenCv acceleration, an HTML5 backend and much much more.

Ver 2.2.20160505170200

Ginga has merged the astropy-helpers template. This should make it more compatible management-wise with other astropy-affiliated packages.

Ver 2.2.20150203025858

Ginga drawing canvas objects now can specify points and radii in world coordinates degrees and sexigesimal notation.

  • default is still data coordinates
  • can play with this from Drawing plugin in reference viewer

Ver 2.1.20141203011503

Major updates to the drawing features of ginga:

  • new canvas types including ellipses, boxes, triangles, paths, images
  • objects are editable: press ‘b’ to go into edit mode to select and manipulate objects graphically (NOTE: ‘b’ binding is considered experimental for now–editing interface is still evolving)
  • editing: scale, rotate, move; change: fill, alpha transparency, etc.
  • editing features available in all versions of the widget
  • updated Drawing plugin of reference viewer to make use of all this

Ver 2.0.20140905210415

Updates to the core display and bindings classes:

  • improvements to interactive rotation command–now resume rotation from current value and direction is relative to horizontal motion of mouse
  • most keyboard modes are now locking and not oneshot (press to turn on, press again (or hit escape) to turn off
  • additional mouse button functionality in modes (see quick reference)
  • some changes to default keyboard bindings (see quick reference)
  • changes to auto cuts parameters always result in a new autocut being done (instead of having to explicity perform the autocut)–users seem to expect this
  • autocenter preference changed from True/False to on/override/off

Reference viewer only: new global plugin “Toolbar” provides GUI buttons for many operations that previously had only keyboard bindings

Ver 2.0.20140811184717

Codebase has been refactored to work with python3 via the “six” module. Tests can now be run with py.test as well as nosetest.

Ver 2.0.20140626204441

Support has been added for image overlays. It’s now possible to overlay RGB images on top of the canvas. The images scale, transform and rotate wrt the canvas.

Ver 2.0.20140520035237

Auto cut levels algorithms have been updated. “zscale” has been reinforced by using the module from the “numdisplay” package, which does a fair sight closer to IRAF than the previous one Ginga was using. Also, the algorithm “median” (median filtering) makes a comeback. It’s now fast enough to include and produces more usable results.

Ver 2.0.20140417032430

New interactive command to orient the image by WCS to North=Up. The default binding to ‘o’ creates left-handed orientation (‘O’ for right-handed). Added a command to rotate the image in 90 deg increments. Default binding to ‘e’ rotates by 90 deg (‘E’ for -90 deg).

Ver 2.0.20140412025038

Major update for scale (mapping) algorithms

The scale mapping algorithms (for mapping data values during rendering) havebeen completely refactored. They are now separated from the RGBMap class and are pluggable. Furthermore I have redone them modeled after the ds9 algorithms.

There are now eight algorithms available: linear, log, power, sqrt, squared, asinh, sinh, histeq. You can choose the mapping from the Preferences plugin or cycle through them using the binding to the ‘s’ key (Use ‘S’ to reset to linear). There is also a mouse wheel mapping than can be assigned to this function if you customize your bindings. It is not enabled by default.

The Preferences plugin has been updated to make the function a little clearer, since there was some confusion also with the intensity map feature that is also part of the final color mapping process.

Ver 2.0.20140114070809

  • The SAMP plugin has been updated to work with the new astropy.vo.samp module.
  • The Catalogs plugin has been updated to allow the user to define the radius of the conesearch or image search by drawing a circle (as well as the previous option–a rectangle).

Ver 2.0.20131218034517

The user interface mapping just got a bit easier to use. Ginga now provides a way to do most UI remapping just by placing a simple config file in your ~/.ginga directory. An example for ds9 users is in the new “examples” folder.

Many simple examples were moved out of “scripts” and stored under subdirectories (by GUI toolkit) in “examples”.

Ver 2.0.20131201230846

Ginga gets trackpad gestures! The Qt rendering class gets support for pinch and pan gestures:

  • The pinch/rotate gesture works as expected on a Mac trackpad
  • The pan gesture is not a two-finger pan but a “non-standard”, Qt-specific one-finger pan. These are experimental for now, but are enabled by default in this release.

Also in this release there has been a lot of updates to the documentation. The developer and internals sections in particular have a lot of new material.

Ver 2.0.20131030190529

The great renaming

I really dislike it when developers do this, so it pains me to do it now, but I have performed a mass renaming of classes. FitsImage ended up being the View in the MVC way of doing things, yet it shared the same naming style as the model classes AstroImage and PythonImage. This would have been the source of endless confusion to developers down the road. Also, PythonImage needed to get renamed to something more akin to what it actually represents.

So the renaming went like this:

  • FitsImage -> ImageView
  • FitsImage{XYZ} -> ImageView{XYZ}
  • PythonImage -> RGBImage

So we have:

  • M: BaseImage, AstroImage, RGBImage
  • V: ImageView{XYZ}
  • C: Bindings, BindMap

I did this in the brand new 2.0 version so at least devs have a heads up that things will not be backward compatible.

And I apologize in advance for any renaming and support issues this may cause for you. Fire up your editor of choice and do a query/replace of “FitsImage” with “ImageView” and you should be good to go.

Ver 1.5-20131022230350

Ginga gets a Matplotlib backend!

Ginga can now render to any Matplotlib FigureCanvas. The performance using this backend is not as fast as the others, but it is acceptable and opens up huge opportunities for overplotting.

See scripts/example{1,2,3,4,5}_mpl.py

Also merges in bug fixes for recent changes to astropy, and support for other python WCS packages such as kapteyn and astLib.

Ver 1.5-20130923184124

Efficiency improvements

Efforts to improve speed of entire rendering pipeline and widget specific redrawing

  • Decent improvements, Ginga can now render HD video (no sound) at 30 FPS on older hardware (see scripts/example1_video.py). This translates to a slightly speedier feel overall for many operations viewing regular scientific files.
  • Fixed a bug that gave an error message of Callback.py:83 (make_callback) | Error making callback ‘field-info’: ‘Readout’ object has no attribute ‘fitsimage’
  • Version bump

Ver 1.4.20130718005402

New Agg backend

There is now an Agg rendering version of the ImageView object.

  • uses the python “aggdraw” module for drawing; get it here –> https://github.com/ejeschke/aggdraw
  • this will make it easy to support all kinds of surfaces because the graphics drawing code does not have to be replicated for each toolkit
  • see example code in /scripts/example1_agg_gtk.py
  • currently not needed for Gtk, Qt versions of the object
New Tk backend

There is now a Tk rendering version of the ImageView object.

  • see ginga.tkw.ImageViewTk
  • renders on a Tk canvas
  • see example code in /scripts/example{1,2}_tk.py
  • you will need the aggdraw module (see above) to use it
AutoCuts
  • the ginga.AutoCuts module has been refactored into individual classes for each algorithm
  • The Preferences plugin for ginga now exposes all of the parameters
    used for each cut levels algorithm and will save them
Etc
  • additions to the manual (still incomplete, but coming along)
  • lots of docstrings for methods added (sphinx API doc coming)
  • many colors added to the color drawing example programs
  • WhatsNew.txt file added

Ginga Quick Reference

Main image window

These keyboard and mouse operations are available when the main image window has the focus.

Mode control commands
About modes

Certain keystrokes invoke a mode—modes are usually indicated by the mode indicator: a small black rectangle with the mode name in one corner of the view. In a mode, there are usually some special key, cursor, and scroll bindings that override some of the default ones.

Modes additionally have a mode type which can be set to one of the following:

  • held: mode is active while the activating key is held down
  • oneshot: mode is released by initiating and finishing a cursor drag or when Esc is pressed, if no cursor drag is performed
  • locked: mode is locked until the mode key is pressed again (or Esc)
  • softlock: mode is locked until another mode key is pressed (or Esc)

By default, most modes are activated in “oneshot” type, unless the mode lock is toggled. The mode type is indicated in the brackets after the mode name in the mode indicator. The following keys are important for initiating a mode:

Commmand Description
Space Enter “meta” mode. Next keystroke will trigger a particular mode.
Esc Exit any mode. Does not toggle the lock.
l Toggle the soft lock to the current mode or any future modes.
L Toggle the normal lock to the current mode or any future modes.
“meta” mode

Most modes are defined so that they are invoked from a special intermediate mode called “meta”. In that case a two-key sequence is required to enter the mode: pressing the key that invokes “meta” and then pressing the key that invokes the desired mode. The following table shows the modes that can be triggered from meta mode.

Commmand Description
Space Exit/Enter “meta” mode.
b Enter draw mode (canvas must be enabled to draw).
q Enter pan mode.
w Enter freepan mode.
r Enter rotate mode.
t Enter contrast mode.
y Enter cmap (color map) mode.
s Enter cuts mode.
d Enter dist (distribution) mode.

Note

For modes initiated from meta mode, the locked and softlock mode types work the same way, which is slightly different from that described above: you press the meta mode key to switch back to meta mode, from which you can enter another mode by pressing its key. You can always press Esc in any mode (including meta mode) to exit the mode.

Panning and zooming commands
Commmand Description
Scroll wheel turned Zoom in or out.
Shift + scroll wheel Zoom while keeping location under the cursor.
Ctrl + scroll wheel turned Pan in direction of scroll.
Digit (1234567890) Zoom image to zoom steps 1, 2, …, 9, 10.
Shift + Digit Zoom image to zoom steps -1, -2, …, -9, -10.
Backquote (`) Zoom image to fit window and center it.
Minus, Underscore (-, _) Zoom out.
Equals, Plus (=, +) Zoom in.
Middle (scroll) button click Set pan position (under cursor).
p Set pan position (under cursor) for zooming.
Shift + left-click Set pan position for zooming.
Shift + arrow key Move pan position 1 pixel in that direction.
c Set pan position to the center of the image.
q Enter Pan mode.
w Free Freepan mode.
Ctrl + left-drag Proportional pan (press and drag left mouse button.
slash (/) Set autocenter for new images to override.
question (?) Toggle autocenter for images to on or off.
apostrophe (‘) Set autozoom for new images to override.
double quote (“) Toggle autozoom for new images to on or off.
Cut levels and colormap commands
Commmand Description
a Auto cut levels.
d Enter Color Distribution (“dist”) mode. See Dist mode.
D Reset color distribution algorithm to “linear”.
s Enter Cuts mode.
t Enter Contrast mode.
T Restore the contrast (via colormap) to its original (unstretched, unshifted) state.
y Enter CMap (color map) mode.
Y Restore the color map to default (gray).
I Invert the color map.
semicolon (;) Set autocuts for new images to override.
colon (:) Toggle autocuts for new images to on or off.
Transform commands
Commmand Description
Left bracket ([) Toggle flip image in X.
Left brace ({) Reset to no flip of image in X.
Right bracket (]) Toggle flip image in Y.
Right brace (}) Reset to no flip image in Y.
Backslash (\) Swap X and Y axes.
Vertical bar (|) Reset to no swap of X and Y axes.
r Enter Rotate mode.
R Restore rotation to 0 degrees and additionally undo any flip/swap transformations.
period (.) Increment current rotation by 90 degrees.
comma (,) Decrement current rotation by 90 degrees.
o Orient image by transforms and rotation so that WCS indicates North=Up and East=Left.
O Orient image by transforms and rotation so that WCS indicates North=Up and East=Right.
Pan mode
Commmand Description
left-drag Pan proportionally to drag.
middle-click Set pan position.
right-drag Zoom in/out proportionally to L/R drag.
<Modifier> + arrow key Pan in direction of arrow key. Adding Ctrl reduces amount, adding Shift reduces more.
p Pan to position under cursor.
z Save current scale (see below for use).
backquote (`) Zoom to fit window and center.
1 Pan to cursor and zoom to saved scale level (or 1:1 if no scale level saved).
c Set pan position to the center of the image.
slash (/) Set autocenter for new images to override.
question (?) Toggle autocenter for images to on or off.
apostrophe (‘) Set autozoom for new images to override.
double quote (“) Toggle autozoom for new images to on or off.
Freepan mode
Commmand Description
Turn scroll wheel Zoom while keeping location under the cursor.
left-click Set pan position, zoom in a step and warp cursor to pan position (if supported on backend).
right-click Set pan position, zoom out a step and warp cursor to pan position (if supported on backend).
middle-drag Pans freely over entire image in proportion to cursor position versus window.
p, z, backquote, 1, c, arrow keys (Same as for Pan mode.)
Dist mode
Commmand Description
scroll Select distribution from linear, log, etc.
b, up-arrow Select prev distribution in list.
n, down-arrow Select next distribution in list.
D Reset color distribution algorithm to “linear”.
Cuts mode
Commmand Description
left-drag Interactive cut both low and high levels (vertical cuts low, horizontal cuts high).
Ctrl + left-drag Interactive cut low level only (horizontal drag).
Shift + left-drag Interactive cut high level only (horizontal drag).
scroll Coarse (10%) adjustment in/out.
Ctrl + scroll Fine (1%) adjustment in/out.
a, right-click Do an auto level to restore cuts.
S Set cuts to min/max values.
A Set cuts to 0/255 values (for 8bpp RGB images).
b, up-arrow Select prev auto cuts algorithm in list.
n, down-arrow Select next auto cuts algorithm in list.
semicolon (;) Set autocuts for new images to override.
colon (:) Toggle autocuts for new images to on or off.
Contrast mode
Commmand Description
left-drag Interactive shift/stretch colormap (AKA contrast and bias). L/R controls shift, U/D controls stretch.
right-click Restore the contrast (via colormap) to its original (unstretched, unshifted) state.
T Restore the contrast (via colormap) to its original (unstretched, unshifted) state.
Rotate mode
Commmand Description
left-drag Drag around center of window to rotate image.
right-click Restore rotation to 0 degrees (does not reset any flip/swap transformations).
R Restore rotation to 0 degrees and additionally undo any flip/swap transformations.
Left bracket ([) Toggle flip image in X.
Left brace ({) Reset to no flip of image in X.
Right bracket (]) Toggle flip image in Y.
Right brace (}) Reset to no flip image in Y.
Backslash (\) Swap X and Y axes.
Vertical bar (|) Reset to no swap of X and Y axes.
period (.) Increment current rotation by 90 degrees.
comma (,) Decrement current rotation by 90 degrees.
o Orient image by transforms and rotation so that WCS indicates North=Up and East=Left.
O Orient image by transforms and rotation so that WCS indicates North=Up and East=Right.
Cmap mode
Commmand Description
scroll Select color map.
left-drag Rotate color map.
right-click Unrotate color map.
b, up-arrow Select prev color map in list.
n, down-arrow Select next color map in list.
I Toggle invert color map.
r Restore color map to unrotated, uninverted state.
Ctrl + scroll Select intensity map.
j, left-arrow Select prev intensity map in list.
k, right-arrow Select next intensity map in list.
i Restore intensity map to “ramp”.
c Toggle a color bar overlay on the image.
Y Restore the color map to default (‘gray’).
Autozoom setting

The “autozoom” setting can be set to one of the following: “on”, “override”, “once” or “off”. This affects the behavior of the viewer when changing to a new image (when done in the typical way) as follows:

  • on: the image will be scaled to fit the window
  • override: like on, except that once the zoom/scale is changed by the user manually it turns the setting to off
  • once: like on, except that the setting is turned to off after the first image
  • off: an image scaled to the current viewer setting

(In the Reference Viewer, this is set under the “Zoom New” setting in the channel preferences.)

Autocenter setting

The “autocenter” setting can be set to one of the following: “on”, “override”, “once” or “off”. This affects the behavior of the viewer when changing to a new image (when done in the typical way) as follows:

  • on: the pan position will be set to the center of the image
  • override: like on, except that once the pan position is changed by the user manually it turns the setting to off
  • once: like on, except that the setting is turned to off after the first image
  • off: the pan position is taken from the current viewer setting

(In the Reference Viewer, this is set under the “Center New” setting in the channel preferences.)

Autocuts setting

The “autocuts” setting can be set to one of following: “on”, “override”, “once” or “off”. This affects the behavior of the viewer when changing to a new image (when done in the typical way) as follows:

  • on: the cut levels for the image will be calculated and set according to the autocuts algorithm setting
  • override: like on, except that once the cut levels are changed by the user manually it turns the setting to off
  • once: like on, except that the setting is turned to off after the first image
  • off: the cut levels are applied from the current viewer setting

(In the ref:Reference Viewer, this is set under the “Cut New” setting in the channel preferences.)

Reference Viewer Only
Commmand Description
H Raise Header tab.
Z Raise Zoom tab.
D Raise Dialogs tab.
C Raise Contents tab.
less than (<) Toggle collapse left pane.
greater than (>) Toggle collapse right pane.
f Toggle full screen.
F Panoramic full screen.
m Maximize window.
J Cycle workspace type (tabs/mdi/stack/grid). Note that “mdi” type is not supported on all platforms.
k Add a channel with a generic name.
Left, Right (arrow keys) Previous/Next channel.
Up, Down (arrow keys) Previous/Next image in channel.

Note

If there are one or more plugins active, additional mouse or keyboard bindings may be present. In general, the left mouse button is used to select, pick or move, and the right mouse button is used to draw a shape for the operation.

On the Mac, Ctrl + mouse button can also be used to draw or right-click. You can also invoke draw mode as described above in the section on modes.

The Ginga FAQ

Platforms

Does Ginga run on Mac/Windows/Linux/XYZ?

Ginga is written entirely in the Python programming language, and uses only supporting Python packages. As long as a platform supports Python and the necessary packages, it can run some version of Ginga. On recent Linux, Mac and Windows versions, all of these packages are available.

Does Ginga work with Python 3?

Yes. Just install with Python 3. Of course, you need all the supporting modules for Python 3 (NumPy, SciPy, Qt 5, etc.)

Toolkits

What GUI toolkit does Ginga use?

It depends what exactly you want to run. Ginga is both a toolkit for building viewers and also includes a “reference viewer”. The example programs currently support Qt, GTK, Tk, matplotlib and web browser via HTML5 canvas. Some other toolkits are being worked on and may be partially supported.

The full reference viewer currently supports Qt and Gtk. The difference is explained here, in Section Developing with Ginga.

Can Ginga work with PyQt5?

Yes.

Can Ginga work with Gtk3?

Yes, although the performance is not on par with Gtk2 yet. Cairo for Python 3 still lacks the important ImageSurface.create_for_data() API call, so we have to use a workaround. Detailed instructions can be found in Section Detailed Installation Instructions for Ginga.

Control Bindings

Can I get DS9-like user interface mappings?

Save the file called bindings.cfg.ds9 and drop it in your $HOME/.ginga folder as “bindings.cfg”. Then restart Ginga.

Can I customize the user interface mappings?

Yes. There is more information in the Rebinding Controls section.

Where can I find a quick reference of the bindings?

See Section Ginga Quick Reference.

Miscellaneous

Does Ginga work with SAMP?

Yes. See Section SAMP Control.

Is it possible to control Ginga remotely?

Yes. See Section RC.

When are you going to add the XYZ feature that DS9 has?

Maybe never. The Ginga package design goal was never to replace DS9, but to provide a full featured Python FITS widget that we could use to build directly in Python. This is clearly seen if you look at the example programs in examples//example.py. The idea was to make it easy for someone to build any kind of custom viewer by having a full-featured widget to build on.

That said, we did write a reference viewer because we needed something with many of the convenience features of a modern FITS viewer. DS9 is almost the size of a small OS, however, and I’m not sure it is wise to try to match it feature for feature. Instead, since Ginga is plugin-based, you can write plugins to give you the features you need. DS9 is a “everything including kitchen sink” kind of viewer, whereas ginga reference viewer is more like a “take what you need from the pantry and whip it up” type viewer.

Please send a pull request!

Can I get Ginga reference viewer to save its size and position?

Yes. Add the line “save_layout = True” to your ~/.ginga/general.cfg

If the file does not exist, create it, or copy the one from ginga/examples/configs/general.cfg.

World Coordinate System

What library are you using for WCS?

We are lucky to have several possible choices for a Python WCS package compatible with Ginga: AstLib, Kapteyn, Starlink and Astropy WCS.

Kapteyn and Astropy wrap Mark Calabretta’s “WCSLIB”, astLib wraps Jessica Mink’s “wcstools”, and I’m not sure what Starlink uses. Note that Astlib and starlink require pyfits (or Astropy) to be installed in order to create a WCS object from a FITS header.

To force the use of a particular one add this to your “general.cfg” in $HOME/.ginga:

WCSpkg = ‘package’

Replace ‘package’ with one of {‘Astropy’, ‘Kapteyn’, ‘Starlink’ or ‘astlib’, ‘choose’}. If you pick ‘choose’ Ginga will try to pick one for you.

How easy is it for Ginga to support a custom WCS?

Pretty easy. See Section I want to use my own World Coordinate System!.

I/O and File Formats

What library are you using for FITS I/O?

There are two possible choices for a Python FITS file reading package compatible with Ginga: Astropy FITS and fitsio. Both are originally based on the CFITSIO library (although Astropy’s version uses very little of it any more, while fitsio is still tracking the current version).

To force the use of a particular one add this to your “general.cfg” in $HOME/.ginga:

FITSpkg = ‘package’

Replace ‘package’ with one of {‘Astropy’, ‘fitsio’, ‘choose’}. If you pick ‘choose’, Ginga will try to pick one for you.

How easy is it for Ginga to support a new file formats besides FITS?

Pretty easy. See Section I want to use my own file storage format, not FITS!.

Problems Displaying Images

Nothing changes in the image when I change settings under “Preferences”.

Note

The Preferences plugin sets the preferences on a per-channel basis. Make sure the channel you are looking at has the same name as the prefix for the preferences. For example: “Image” and “Image: Preferences” or “Image1” and “Image1: Preferences”.

The preferences for a given channel are copied from the default “Image” channel until they are explicitly set and saved using this plugin. So if you want preferences that follow around from channel to channel, save them as preferences for “Image” and any new channels created will get those as well, unless you have saved different ones under those channel names.

Nothing changes in the image when I change the “Auto Cuts” settings under Preferences. I’ve checked that I’m adjusting preferences for the same channel that I’m viewing.

Note

What is the setting for “Cut New” under the New Images section in Preferences for this channel?

If that setting is “Off” then you have elected not to have Ginga apply Auto Levels when an image is loaded in that channel. Press ‘a’ in the image window to force an auto cut levels–it will use the new settings.

No image shows in the display, and I get an error in the terminal about histogram and keyword “density”.

Note

You need a slightly newer version of NumPy.

I recommend getting at least NumPy>1.9.

The Ginga Viewer and Toolkit Manual

銀河

Ginga is a toolkit for building viewers for scientific data in Python, particularly astronomical data. It also includes a reference viewer for viewing FITS (Flexible Image Transport System) files.

The Ginga viewer is based on an image display widget that supports:

  • Zooming and panning
  • Color and intensity mapping
  • A choice of several automatic cut levels algorithms, and
  • Canvases for plotting scalable geometric forms.

In addition to the image display widget, the Ginga viewer provides a flexible plugin framework for extending the viewer with many different features.

A relatively complete set of standard plugins is provided for features that we expect from a modern viewer: panning and zooming windows, star catalog access, cuts, star pick/fwhm, and thumbnails.

Introduction

About

Ginga is a toolkit designed for building viewers for scientific image data in Python, visualizing 2D pixel data in numpy arrays. The Ginga toolkit can view astronomical data such as contained in files based on the FITS (Flexible Image Transport System) file format.

The Ginga toolkit is written and maintained by software engineers at the Subaru Telescope, National Astronomical Observatory of Japan. The code is released as open-source under a BSD license and maintained at http://ejeschke.github.io/ginga/

Features

The Ginga toolkit centers around an image display widget that supports zooming and panning, color and intensity mapping, a choice of several automatic cut levels algorithms, and canvases for plotting scalable geometric forms.

In addition to this widget, a general purpose reference FITS viewer is provided, based on a plugin framework. A relatively complete set of standard plugins are provided for features that we expect from a modern FITS viewer: panning and zooming windows, star catalog access, cuts, star pick/fwhm, thumbnails, etc.

Core Concepts

The Ginga reference viewer operation is organized around several basic concepts: workspaces, channels, plugins, modes. Understanding these will greatly aid in using and modifying Ginga.


Workspaces

Ginga has a flexible workspace layout algorithm that allows customizing the appearance of the program. The majority of the Ginga interface is constructed as hierarchical series of horizontally or vertically-adjustable panels. Each panel is eventually a workspace. Each workspace is implemented by a GUI toolkit container widget such as a notebook widget, where each item in the workspace is identified by a tab.

However, workspaces can also take the form of a stack (like a tabbed widget but with no tabs showing), or a Multiple Document Interface (MDI) style container (subwindow desktop-style layout), or a grid layout.

Workspaces typically contain either a channel viewer, a plugin UI or another workspace. In its default configuration, Ginga starts up with a single row (horizontal) panel of three workspaces, as shown in the image below.

_images/gingadefault.png

The panel is sandwiched vertically between a menu bar and a status bar. The left workspace is further subdivided into an upper and lower, and there are also thin horizontal workspaces below the central workspace. The central workspace is mainly used for viewers, while the other workspaces hold the plugin UIs.

The initial layout of the workspaces is controlled by a table in the Ginga startup script (see Customizing Ginga). By changing this table the layout can be substantially altered.

Note

Note that workspaces may be implemented by several types of container widgets such as fixed position subwindows, sliding panes, MDI-style subwindows, etc.

A notebook widget is simply the most common (default) case.

Some workspaces can be converted dynamically between the different types. If the workspace contains a workspace toolbar, the workspace type selector can be used to change the type:

_images/wstype_selector.png

In the example shown below, we show a cutout of the main workspace (tabbed), which has two tabs: a channel viewer (Image) and a second workspace (ws1).

The ws1 workspace is configured as type MDI and has two windows: a viewer (Image0) and a third workspace (ws2). The third workspace contains a grid of four viewers. Depending on the the support of the back end widget set, tabs can be dragged between workspaces (or out onto the desktop if you are using the Gtk widget set), forming a new, detached workspace.

_images/nested_workspaces.png
Channels

Another core tenet of Ginga is that that image content is organized into channels. A channel can be thought of as simply a named category under which similar types of images might be organized. A few examples are:

  • A channel for each type of instrument at a telescope
  • A channel for each observation or calibration target
  • Channels based on time or program or proposal identifier

If no channels are specified when Ginga starts up it simply creates a default channel named Image. New channels can be created using the Channel/Add channel menu item. Pressing the + button in the workspace menu also adds a new channel using a default name.

A channel always has an image viewer associated with it, and may additionally have a table viewer. The viewer is what you see in the active window representing that channel.

_images/channels.png

In the workspace toolbar, pressing - removes the currently selected channel, while pressing the up or down arrows moves between images in the selected channel.

In the case where multiple channels are present, they are usually visually organized as tabs, windows, and grid within the central workspace of the interface (as shown in the figure above) depending on how the workspace is configured. To change channels you simply click on the tab of the channel you want to view, or press the left or right arrow buttons in the workspace menu. There is also a channel selector in the plugin manager toolbar at the bottom of the center pane. You can change the channel by using the drop-down menu or by simply scrolling the mouse wheel on the control.

_images/channel_selector.png

Channels occupy a flat namespace, i.e., there is no hierarchy in channel names.

By default, images are loaded into the same channel you are currently viewing (unless your viewer has been customized to load images according to special rules).

Note

To keep images organized, simply change to the desired channel before opening a new image, or drag the image to the desired channel viewer.

Many preferences in Ginga are set on a per-channel basis. Some per-channel settings include:

  • Color distribution algorithm
  • Color map
  • Intensity map
  • Cut levels
  • Auto cut levels algorihm
  • Transforms (flip, swap)
  • Rotation
  • WCS display coordinates
  • Zoom algorithm
  • Scale
  • Interpolation type
  • Pan position

A new channel will generally inherit the settings for the generic Image channel until new preferences are defined and saved.

If you create a new channel and had previously saved preferences for a channel with that name, the new channel will adopt those preferences. Thus you can set up channels configured for certain telescopes or for types of data and easily reuse them in later sessions.

Another idea embodied in the channel concept is that the user should not have to manage memory usage too explicitly. Each channel has a setting that limits how many images it should keep in memory. If the number of images exceeds the limit then Ginga will remove older images and load them back in as needed without user intervention.


Plugins

Almost all functionality in Ginga is achieved through the use of a plugin architecture.

Plugins are quasi-independent Python modules that can optionally have a Graphical User Interface. If they do have a GUI, it can be loaded at program startup or be dynamically opened and closed during the duration of the viewer’s execution.

Plugins can be global, in which case they don’t have any particular affiliation with a channel and are generally invoked singularly, or local in which case they can be invoked in multiple instances–one per channel.

In this documentation we will also use the word operation to describe activating a plugin. For example, a “pick” operation would use the Pick plugin.

Plugins are written as encapsulated Python modules that are loaded dynamically when Ginga starts. There is an API for programming plugins (see Developing with Ginga).

The plugins are each described in more detail in Plugins.

For those plugins that do have a visible interface, the Ginga startup script can map them to certain workspaces. By manipulating this mapping (and manipulating the workspace layout) we can customize to achieve flexible layouts.

In the image at the top, the left workspace contains three global plugin UIs: the Info, Header and Zoom panes. The middle workspace holds all the viewing panes for each channel. The right workspace has the Dialogs, Thumbs, Contents and Error panes. The operation of these plugins is described in Plugins.


Modes

Ginga provides a number of default bindings for key and pointer actions. However, there are too many different actions to bind to a limited set of keys and pointer buttons. Modes allow us to overcome this limitation.

Modes are a mechanism that allow Ginga to accommodate many key and pointer bindings for a large number of operations.

Modes are set on a per-channel basis. Pressing a particular mode key in a channel viewer puts that viewer into that mode.

When in a mode, the behavior is that some special key, and the cursor and scroll bindings will override the default ones. An adjacent viewer for a different channel may be in a different mode, or no mode.

Note

If a mode does not override a particular binding, the default one will still be active.

Modes have an associated mode type which can be set to one of:

  • held: The mode is active while the activating key is held down
  • oneshot: The mode is released by initiating and finishing a cursor drag, or when Esc is pressed, if no cursor drag is performed
  • locked: The mode is locked until the mode key is pressed again (or Esc)
  • softlock: The mode is locked until another mode key is pressed (or Esc)

By default most modes are activated in “oneshot” type, unless the mode lock is toggled. The mode lock is typically toggled in and out of softlock by the l (lowercase letter l) key and “locked” with L.

Modes are usually indicated by a small black rectangle with the mode name in one corner of the viewer, usually in the lower right corner of the viewer.

Note

When the lock is active it is signified by an additional “[SL]” (softlock) or “[L]” (locked) appearing in the mode indicator.

_images/mode_indicator.png

In the above figure, you can see the mode indicator showing that the viewer is in “contrast” mode, with the softlock on. The same information can be seen in the Toolbar plugin. On the Toolbar plugin you can click to set the mode and toggle the lock on/off.

General Operation

This chapter describes the general manipulations of images using Ginga.

For the most part these manipulations apply both to Ginga ImageView classes that can be embedded in a Python application, as well as to the reference viewer distributed with Ginga.

Note

In cases where we are referring to something that is only available in the reference viewer these will be prefixed by the notation [RV].


Keyboard and mouse operations

In this documentation we will use the following terms to describe the operations performed with the mouse:

  • Click or Left-click means to click on an item with the left mouse button;
  • Drag or Left-drag means to click, hold and drag with the left mouse button;
  • Scroll means to scroll with the middle mouse wheel or a trackpad/touchpad;
  • Scroll-click means to click with the middle mouse wheel/button;
  • Scroll-drag means to click, hold and drag with the middle mouse wheel/button;
  • Right-click means to click on an item with the right mouse button;
  • Right-drag means to click, hold and drag with the right mouse button.

Mouse operations are also modified by the keyboard buttons Shift, and Ctrl.

Shift-click means to press and hold the Shift key while clicking with left mouse button. Shift-right-click is the same using the right mouse button, etc.

Some mouse-controlled operations in Ginga are initiated by a key stroke. In these cases the key is pressed and released (not held), and then the mouse is used to control the operation. Such operations are either terminated by releasing the mouse button (if the operation employs a drag), and clicking on the image or by pressing the Esc key (if not a drag operation).

Note

We describe the standard key and mouse bindings here. However these bindings can be changed completely by the user. For more information on changing the bindings, see Section Rebinding Controls.


Loading a FITS image file

There are several ways to load a file into Ginga:

  • Ginga supports drag-and-drop in a typical desktop environment, so you can simply drag and drop files from a graphical file manager such as the Mac Finder or Linux Nautilus onto a Ginga viewing pane to load an image.
  • [RV] Another way is to invoke the FBrowser plugin, which opens in the Dialogs tab. The plugin pane shows file and folder contents and allows navigation up and down the filesystem hierarchy by double-clicking on folder names. Simply navigate to the location of the FITS file and double-click on the file name to load it, or drag it onto the image pane.
  • [RV] Use the Load Image entry from the File menu on the main menu bar at the top of the window. This opens a standard file dialog popup window where you can navigate to the file you wish to load.
Zooming and panning

The display object used throughout most of the Ginga panels has built-in support for zooming and panning. The Ginga Quick Reference has the complete listing of default keyboard and mouse bindings.

For example:

  • The scroll wheel of the mouse can be used to zoom in and out, along with the “+” and “-” keys.
  • The backquote key will fit the image to the window.
  • Digit keys (1, 2, etc.) will zoom in to the corresponding zoom level, while holding Shift and pressing a zoom key zooms out to the corresponding level.

When zoomed in, panning is enabled. Panning takes two forms:

  1. Proportional panning or “drag panning” pans the image in direct proportion to the distance the mouse is moved. You can think of this as dragging the image canvas in the direction you want to move it under the window portal. To utilize a proportional pan, Ctrl-drag the canvas, or press Space followed by “q” to go into pan mode, and then drag the canvas.

2) Free panning allows scrolling around the entire image by mapping the entire image boundaries to the window boundaries. For example, moving the mouse to the upper right-hand corner of the window will pan to the upper right hand corner of the image, etc. You can think of this mode as moving the window portal around over the canvas. To initiate a free pan, press Space followed by “w” to enter “freepan” mode and then Scroll-drag to move around the window.

[RV] The Pan plugin (usually embedded under the Info tab) shows the outline of the current pan position as a rectangle on a small version of the whole image. Dragging this outline will also pan the image in the main window. You can also click anywhere in the Pan window to set the pan position, or right drag an outline to roughly specify the region to zoom and pan to together.

Pan position

Panning in Ginga is based on an (X, Y) coordinate known as the pan position. The pan position determines what Ginga will try to keep in the middle of the window as the image is zoomed.

When zoomed out, you can Shift-click on a particular point in the image (or press the “p” key while hovering over a spot), setting the pan position. Zooming afterward will keep the pan position in the center of the window. To reset the pan position to the center of the image, press ‘c’.

Ginga has an auto zoom feature to automatically fit newly loaded images to the window, similar to what happens when the backquote key is pressed. See “Zoom Preferences” section in Preferences for details.


How Ginga maps an image to color

The process of mapping a monochrome science image to color in Ginga involves four steps, in order:

  1. Applying the cut levels, which scales all values in the image to a specified range [1],
  2. Applying a color distribution algorithm, which distributes values within that range to indexes into a color map table, and
  3. Applying a shift map, which shifts and stretches or shrinks the values according to the user’s contrast adjustment [2], and finally,
  4. Applying an intensity map and color map to map the final output to RGB pixel values.

Setting cut levels

When visualizing pixel data with an arbitrary value range, the range is first scaled into a limited range based on the low and high cut levels defined in the view object. These cut levels can be set manually by the user or automatically based on an algorithm. This eliminates the effect of outlier pixel/flux values.

Manually setting cut levels

There are several ways to manually set the cut levels:

  • Pressing Space followed by “s” key will put the viewer into “cuts” mode. Here you can invoke a dual (high and low) interactive cut levels. Click and drag the mouse horizontally in the window to interactively set the high level, and vertically to set the low level; and when you reach the desired levels, release the mouse button. Scrolling the mouse wheel in this mode will also change the low and high cut levels simultaneously–toward or away from each other, resulting in lower or higher contrast.
  • [RV] The “Cut Low” and “Cut High” boxes in the Info plugin panel can be used. The current values are shown to the left; simply type a new value in the corresponding box and press Enter or click the “Cut Levels” button below. Cut values can also be set from the “Histogram” plugin.
Automatically setting cut levels

Ginga can algorithmically estimate and set the cut levels–called auto (cut) levels. To activate the auto levels:

  • Press the (“a”) key when the viewing widget has the focus.
  • [RV] Click the “Auto Levels” button in the Info plugin panel.

[RV] The auto cut levels feature is controlled by several factors in the preferences, including the choice of algorithm and some parameters to the algorithm. See “Auto Cuts Preferences” section in Preferences for details.

Ginga can also automatically set the cut levels for new images displayed in the view. See “New Image Preferences” section in Preferences for details.

Setting the color distribution algorithm

Ginga supports a number of color scale distribution algorithms, including:

  • “linear”,
  • “log”,
  • “power”,
  • “sqrt”,
  • “squared”,
  • “asinh”,
  • “sinh”, and
  • “histeq” (histogram equalization).

These can be sampled with the current color and intensity maps by pressing Space followed by “d” key to go into “dist” mode, and then scrolling the mouse, pressing the up/down keys, or the “b” and “n” keys.

Press Esc to exit the “dist” mode.

To reset to the default (“linear”) map, press “D” (capital D).

[RV] The color scale distribution algorithms can also be set from the Preferences plugin, under the heading “Color Distribution”.

Making contrast adjustments

The value range can be shifted and stretched or squeezed to alter the visibility and contrast of the image. This is sometimes called a “bias/contrast” adjustment in other viewers.

In most Ginga configurations the shift map adjustment is bound to the Ctrl-right drag combination (hold Ctrl down and right drag). Dragging left/right shifts the map, and up/down stretches or shrinks the map.

You can also press “t” to enter “contrast” mode, where you can then use a regular Left-drag.

Changing the color and intensity maps

The color and intensity maps control the final mapping of colors to the values in the image.

Intensity Maps

Intensity maps are available to produce a final permutation on the value range of the image before color is applied. The function of these largely overlaps the function of the color distribution algorithm, so most users will typically use either one or the other, but not both.

For example, the intensity map “log” essentially applies a log distribution to the range. If this has already been done with the color distribution “log”, the effect is doubly applied.

Possible values for the intensity map are:

  • “equa”,
  • “expo”,
  • “gamma”,
  • “jigsaw”,
  • “lasritt”,
  • “log”,
  • “neg”,
  • “neglog”,
  • “null”, “ramp” and
  • “stairs”.

“ramp” is the default value.

While in “cmap” mode (described below), the “j” and “k” keys can be used to cycle through the intensity maps.

Color Maps

To change color maps from the keyboard shortcuts, press Space followed by “y” to go into “cmap” mode. While in “cmap” mode you can change color maps by scrolling the mouse, pressing the up/down keys, or the “b” and “n” keys.

While in “cmap” mode, pressing “I” (uppercase) will invert the current color map. Press Esc to exit cmap mode.

Note

Setting a new color map will cancel the color map inversion. Some color maps are available in both regular and inverted forms. If selecting an already inverted (aka “reversed”) color map it is not necessary to explicitly invert it.

While many color maps are available built in, users can also define their own color maps or use matplotlib color maps, if the matplotlib package is installed.

[RV] The ColorMapPicker global plugin is useful you to visualize all of the colormaps and apply one to the currently active channel viewer.

Transforming the image view

Ginga provides several controls for transforming the image view. The image can be flipped in the X axis (“horizontally”), Y axis (“vertically”), have the X and Y axes swapped, or any combination thereof. These operations can be done by keyboard shortcuts:

  • Press “[” to flip in X, “{” to restore.
  • Press “]” to flip in Y, “}” to restore.
  • Press “” to swap X and Y axes, “|” to restore.

The image can also be rotated in arbitrary amounts.

An interactive rotate operation can be initiated by pressing Space follwed by “r” in the image and then dragging the mouse horizontally left or right to set the angle. Press “R” (Shift+R) to restore the angle to 0 (unrotated).

Note

It is less computationally-intensive to rotate the image using the simple transforms (flip, swap) than by the rotation feature. Rotation may slow down some viewing operations.

[RV] The image can also be transformed in the channel Preferences (see “Transform Preferences”) which has checkboxes for flip X, flip Y, swap XY and a box for rotation by degrees.

Footnotes

[1]Some image viewers or graphing programs use the term “limits” for what we call “cut levels”.
[2]What some programs call a “contrast/bias” adjustment.

Ginga Canvas Graphics

This chapter describes the basic architecture of Ginga’s canvas-viewer-renderer model, and describes how to do graphics operations on canvases.

Canvases and Canvas Objects

Ginga’s canvas is based on the DrawingCanvas class. On the canvas can be placed a number of different kinds of canvas objects, including many geometric shapes. The set of canvas objects includes:

  • Text: a piece of text having a single point coordinate.
  • Polygon: a closed polygon defined by N points.
  • Path: an open polygon defined by N points.
  • Box: a rectangular shape defined by a single center point, two radii and a rotation angle.
  • Ellipse: an elliptical shape defined by a single center point, two radii and a rotation angle.
  • Triangle: an equilateral triangular shape defined by a single center point, two radii and a rotation angle.
  • Circle: a circular shape defined by a center point and a radius.
  • Point: a marker for a point defined by a single point and a radius for the “arms”.
  • Rectangle – a rectangular shape defined by two points.
  • Line – a line defined by two points.
  • RightTriangle – a right triangle defined by two points.
  • Compass – a compass defined by a point and a radius.
  • Ruler – a ruler defined by two points.
  • Crosshair – a crosshair defined by one point.
  • Annulus – an annulus defined by one point and two radii.
  • Image – a raster image anchored by a point.
  • NormImage – a subclass of Image, with rendering done with the aid of a colormap, a color distribution algorithm (linear, log, etc), and defined low and high cut levels.
  • CompoundObject: a compound object combining a series of other canvas objects.
  • Canvas: a transparent subcanvas on which items can be placed.
  • DrawingCanvas: Like a Canvas, but also can support manual drawing operations initiated in a viewer to create shapes on itself.
  • ColorBar: a bar with a color range and ticks and value markers to help indicate the mapping of color to the value range of the data.
  • ModeIndicator: a small rectangular overlay with text indicating that the user has entered a special keyboard/mouse mode.

All canvas objects are subclasses of CanvasObjectBase and may also contain mixin classes that define common attributes or behavior. For example, Line, Ruler and RightTriangle are all subclasses of the mixin class TwoPointMixin.

Note

In most general canvas systems you can layer objects in any order. In Ginga there is an optimization of canvas redrawing that merges image bitmaps before updating other kinds of canvas objects. This means that while images can be stacked in any order, effectively you cannot have other objects appear underneath image objects. For most uses of the viewer this is not a big limitation.

Viewers

All Ginga viewers are subclasses of ImageViewBase. These objects implement a viewport onto a DrawingCanvas object. Each viewer contains a handle to a canvas and provides a particular view onto that canvas defined by:

  • dimensions of their viewport (i.e. the height and width of the native widget’s window into which the viewer is rendering),
  • scale in X and Y dimensions,
  • a pan position linking the center of the viewport to a canvas coordinate,
  • a transform consisting of possible flips in X, Y axes and/or swapping of X/Y axes, and
  • a rotation.

Two different ImageView-based viewers can share the same canvas handle, providing different views into the same canvas. Another typical arrangement for sharing is where each viewer has a private canvas, and on each private canvas is placed a shared transparent subcanvas, an arrangement which allows each viewer to have a mix of private and shared canvas objects. Another common idiom is to layer multiple DrawingCanvas objects to more easily manage multiple collections of overlaid graphics.

The various subclasses of ImageView are designed to render into a different widget set’s “native” canvas using a CanvasRenderer customized for that target.

Plugins

Ginga is written so that most of the functionality of the program is achieved through the use of plugins. This modular approach allows a large degree of flexibility and customization, as well as making overall design and maintenance of the program simpler.

Plugins are divided into two types: global and local. A global plugin has a single instance shared by all channels, while a local plugin creates a unique instance for each channel. If you switch channels, a global plugin will respond to the change by updating itself, while a local plugin will remain unchanged if the channel is switched, because its operation is specific to a given channel. (Ginga’s concept of channels is discussed in Channels.)

This chapter describes the set of plugins that come with Ginga. Those interested in writing their own custom plugins should refer to Writing a Global Plugin or Anatomy of a Local Ginga Plugin.

Global plugins
Toolbar

Toolbar provides a set of convenience UI controls for common operations on viewers.

Plugin Type: Global

Toolbar is a global plugin. Only one instance can be opened.

Usage

Hovering over an icon on the toolbar should provide you with usage tool tip.

It is customizable using ~/.ginga/plugin_Toolbar.cfg, where ~ is your HOME directory:

#
# Toolbar plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Toolbar.cfg"

# Accepted value: 'oneshot' or 'locked'
mode_type = 'oneshot'
Pan
Pan plugin

The Pan plugin provides a small panning image that gives an overall “birds-eye” view of the channel image that last had the focus. If the channel image is zoomed in 2X or greater, then the pan region is shown graphically in the Pan image by a rectangle.

Plugin Type: Global

Pan is a global plugin. Only one instance can be opened.

Usage

The channel image can be panned by clicking and/or dragging to place the rectangle. Using the right mouse button to drag a rectangle will force the channel image viewer to try to match the region (taking into account the differences in the aspect ratio between the drawn rectangle and the window dimensions). Scrolling in the Pan image will zoom the channel image.

The color/intensity map and cut levels of the Pan image are updated when they are changed in the corresponding channel image. The Pan image also displays the World Coordinate System (WCS) compass, if valid WCS metadata is present in the FITS HDU being viewed in the channel.

The Pan plugin usually appears as a sub-pane under the “Info” tab, next to the Info plugin.

It is customizable using ~/.ginga/plugin_Pan.cfg, where ~ is your HOME directory:

#
# Pan plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Pan.cfg"

# Share a canvas with the channel viewer
use_shared_canvas = False

# color of pan position marker
pan_position_color = 'yellow'

# color of pan rectangle
pan_rectangle_color = 'red'

# color of compass
compass_color = 'skyblue'

# rotate the pan image if the main image is rotated?
rotate_pan_image = True
Info
_images/info-plugin.png

The Info plugin provides a pane of commonly useful metadata about the associated channel image. Common information includes some metadata header values, coordinates, dimensions of the image, minimum and maximum values, etc. As the cursor is moved around the image, the X, Y, Value, RA, and DEC values are updated to reflect the value under the cursor.

Plugin Type: Global

Info is a global plugin. Only one instance can be opened.

Usage

At the bottom of the Info interface the cut levels controls. Here the low and high cut levels are shown and can be adjusted. Pressing the “Auto Levels” button will recalculate cut levels based on the current auto cut levels algorithm and parameters defined in the channel preferences.

Below the “Auto Levels” button, the status of the settings for “Cut New”, “Zoom New”, and “Center New” are shown for the currently active channel. These indicate how new images that are added to the channel will be affected by auto cut levels, fitting to the window and panning to the center of the image.

The “Follow New” checkbox controls whether the viewer will automatically display new images added to the channel. The “Raise New” checkbox controls whether an image viewer window is raised when a new image is added. These two controls can be useful, for example, if an external program is adding images to the viewer, and you wish to prevent interruption of your work examining a particular image.

As a global plugin, Info responds to a change of focus to a new channel by displaying the metadata from the new channel. It typically appears under the “Synopsis” tab in the user interface.

Zoom
Zoom plugin

The Zoom plugin shows an enlarged image of a cutout region centered under the cursor position in the associated channel image. As the cursor is moved around the image, the zoom image updates to allow close inspection of the pixels or precise control in conjunction with other plugin operations.

Plugin Type: Global

Zoom is a global plugin. Only one instance can be opened.

Usage

The size of the cutout radius can be adjusted by the slider below the zoom image labeled “Zoom Radius”. The default radius is 30 pixels, making a 61x61 zoom image. The magnification can be changed by adjusting the “Zoom Amount” slider.

Two modes of operation are possible – absolute and relative zoom:

  • In absolute mode, the zoom amount controls exactly the zoom level shown in the cutout; For example, the channel image may be zoomed into 10X, but the zoom image will only show a 3X image if the zoom amount is set to 3X.
  • In relative mode, the zoom amount setting is interpreted as relative to the zoom setting of the channel image. If the zoom amount is set to 3X and the channel image is zoomed to 10X then the zoom image shown will be 13X (10X + 3X). Note that the zoom amount setting can be < 1, so a setting of 1/3X with a 3X zoom in the channel image will produce a 1X zoom image.

The “Refresh Interval” setting controls how quickly the Zoom plugin responds to the movement of the cursor in updating the zoom image. The value is specified in milliseconds.

Tip

Usually setting a small refresh interval improves the overall responsiveness of the zoom image, and the default value of 20 is a reasonable one. You can experiment with the value if the zoom image seems too jerky or out of sync with the mouse movement in the channel image window.

The “Defaults” button restores the default settings of the controls.

It is customizable using ~/.ginga/plugin_Zoom.cfg, where ~ is your HOME directory:

#
# Zoom plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Zoom.cfg"

# default zoom radius in pixels
zoom_radius = 30

# default zoom level
zoom_amount = 3

# refresh interval (sec)
# NOTE: usually a small delay speeds things up
refresh_interval = 0.02

# rotate the zoom image if the channel image is rotated?
rotate_zoom_image = True

# use a different color map than channel image?
zoom_cmap_name = None

# use a different intensity map than channel image?
zoom_imap_name = None
Thumbs
Thumbs plugin

The Thumbs plugin provides a thumbnail index of all images viewed since the program was started.

Plugin Type: Global

Thumbs is a global plugin. Only one instance can be opened.

Usage

By default, Thumbs appear in cronological viewing history, with the newest images at the bottom and the oldest at the top. The sorting can be made alphanumeric by a setting in the “plugin_Thumbs.cfg” configuration file.

Clicking on a thumbnail navigates you directly to that image in the associated channel. Hovering the cursor over a thumbnail will show a tool tip that contains a couple of useful pieces of metadata from the image.

The “Auto Scroll” checkbox, if checked, will cause the Thumbs pan to scroll to the active image.

It is customizable using ~/.ginga/plugin_Thumbs.cfg, where ~ is your HOME directory:

#
# Thumbs plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Thumbs.cfg"

# If you revisit the same directories frequently
# caching thumbs saves a lot of time when they need to be regenerated
cache_thumbs = False

# cache location-- "local" puts them in a .thumbs subfolder, otherwise
# they are cached in ~/.ginga/thumbs
cache_location = 'local'

# Scroll the pane automatically when new thumbnails arrive
auto_scroll = True

# Keywords to extract and show if we mouse over the thumbnail
tt_keywords = ['OBJECT', 'FRAMEID', 'UT', 'DATE-OBS']

# Mandatory unique image identifier in tooltip
mouseover_name_key = 'NAME'

# How many seconds to wait after an image is altered to begin trying
# to rebuild a matching thumb.  Usually a few seconds is good in case
# there is ongoing adjustment of the image
rebuild_wait = 0.5

# Max length of thumb on the long side
thumb_length = 180

# Separation between thumbs in pixels
thumb_hsep = 15
thumb_vsep = 15

# Sort the thumbs alphabetically: 'alpha' or None
sort_order = None

# Thumbnail label length in num of characters (None = no limit)
label_length = 25

# Cut off long label ('left', 'right', or None)
label_cutoff = 'right'

# Option to highlight images that are displayed in channels.
# If set to True this option will only highlight the image that is in the
# channel with the keyboard focus
highlight_tracks_keyboard_focus = True

# Highlighted label colors
label_bg_color = 'lightgreen'
label_font_color = 'white'

label_font_size = 10

# Load visible thumbs in the background to replace placeholder icons
autoload_visible_thumbs = True

# Length of time to wait after scrolling to begin autoloading
autoload_interval = 1.0

# list of attributes to transfer from the channel viewer to the
# thumbnail generator if the channel has an image in it
transfer_attrs = ['transforms', 'cutlevels', 'rgbmap']
Contents
Contents plugin

The Contents plugin provides a table of contents-like interface for all the images viewed since the program was started. Unlike Thumbs, Contents is sorted by channel. The contents also shows some configurable metadata from the image.

Plugin Type: Global

Contents is a global plugin. Only one instance can be opened.

Usage

Click on a column heading to sort the table by that column; Click again to sort the other way.

Note

The columns and their values are drawn from the FITS header, if applicable. This can be customized by setting the “columns” parameter in the “plugin_Contents.cfg” settings file.

The active image in the currently focused channel will normally be highlighted. Double-click on an image will force that image to be shown in the associated channel. Single-click on any image to activate the buttons at the bottom of the UI:

  • “Display”: Make the image the active image.
  • “Move”: Move the image to another channel.
  • “Copy”: Copy the image to another channel.
  • “Remove”: Remove the image from the channel.

If “Move” or “Copy” is done on an image that has been modified in Ginga (which would have an entry under ChangeHistory, if used), the modification history will be retained as well. Removing an image from a channel destroys any unsaved changes.

It is customizable using ~/.ginga/plugin_Contents.cfg, where ~ is your HOME directory:

#
# Contents plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Contents.cfg"

# columns to show from metadata -- NAME and MODIFIED recommended
# format: [(col header, keyword1), ... ]
columns = [ ('Name', 'NAME'), ('Object', 'OBJECT'), ('Filter', 'FILTER01'), ('Date', 'DATE-OBS'), ('Time UT', 'UT'), ('Modified', 'MODIFIED')]

# If set to True, will always expand the tree in Contents when new entries are added
always_expand = True

# Option to highlight images that are displayed in channels.
# If set to True this option will only highlight the image that is in the
# channel with the keyboard focus
highlight_tracks_keyboard_focus = False

# If True, color every other row in alternating shades to improve
# readability of long tables
color_alternate_rows = True

# Highlighted row colors (in addition to bold text)
row_font_color = 'green'

# Maximum number of rows that will turn off auto column resizing (for speed)
max_rows_for_col_resize = 100
Colorbar
Colorbar plugin

The Colorbar plugin shows a colorbar indicating the colormap applied to the image and showing the example values along the range.

Plugin Type: Global

Colorbar is a global plugin. Only one instance can be opened.

Usage

Clicking and dragging in the Colorbar window will shift the colormap left or right. Scrolling will stretch or shrink the colormap at the cursor position. Right-clicking will restore the colormap from any shift or stretch.

If the focus shifts to another channel, the colorbar will be updated to reflect that channel’s colormap and value information.

It is customizable using ~/.ginga/plugin_Colorbar.cfg, where ~ is your HOME directory:

#
# Colorbar plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Colorbar.cfg"

# Set colorbar height, if default is too big or little
cbar_height = 36

# size of font used in the color bar
fontsize = 10
Cursor
Cursor plugin

The Cursor plugin displays a summary line of text that changes as the user moves the cursor around an image. In the standard reference viewer configuration, it appears as a line containing green text just below the Colorbar plugin.

Plugin Type: Global

Cursor is a global plugin. Only one instance can be opened.

Usage

Cursor simply tracks the cursor as it moves around an image and displays information about the pixel coordinates, WCS coordinates (if available) and the value of the pixel under the cursor.

There is no associated configuration GUI.

Note

Pixel coordinates are affected by the general setting “pixel_coords_offset” which can be set in the “general.cfg” configuration file for ginga. The default is value for this setting is 1.0, which means pixel coordinates are reported from an origin of 1, as per the FITS standard.

It is customizable using ~/.ginga/plugin_Cursor.cfg, where ~ is your HOME directory:

#
# Cursor plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Cursor.cfg"

share_readout = True
Operations

This plugin defines the GUI for managing local plugins, a.k.a., “operations”.

Plugin Type: Global

Operations is a global plugin. Only one instance can be opened.

Usage

The Operations plugin acts as a visual interface to the reference viewer plugin manager. With this plugin, you can change the active channel, start, stop, or unfocus a local plugin on a channel, and see which local plugins are running.

Note

By replacing or subclassing this plugin, you can customize the way the reference viewer starts and manages operations.

It is customizable using ~/.ginga/plugin_Operations.cfg, where ~ is your HOME directory:

#
# Operations plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Operations.cfg"

# Show the change channel drop-down control
show_channel_control = True

# Color to highlight focused plugins in the operations control tray
focuscolor = "lightgreen"

# Change to False to use combobox+button launch approach
use_popup_menu = True
WBrowser

Web browser plugin for Ginga.

Plugin Type: Global

WBrowser is a global plugin. Only one instance can be opened.

Usage

This global plugin is used to browse help pages for Ginga.

When a “Help” button is pressed from a plugin (e.g., Pick), Ginga will attempt to download an existing documentation build from ReadTheDocs for the matching version. If successful, plugin documentation from that download is displayed. If not successful or deliberately disabled in “plugin_WBrowser.cfg”, Ginga will render the plugin’s docstring locally.

It is customizable using ~/.ginga/plugin_WBrowser.cfg, where ~ is your HOME directory:

#
# WBrowser plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_WBrowser.cfg"

# Set to True to force offline doc browsing, otherwise download from RTD
offline_doc_only = False
FBrowser (Open File)

This brings up FBrowser local plugin from the global menu for convenience.

ColorMapPicker
ColorMapPicker plugin

The ColorMapPicker plugin is used to graphically browse and select a colormap for a channel image viewer.

Plugin Type: Global

ColorMapPicker is a global plugin. Only one instance can be opened.

Usage

Operation of the plugin is very simple: the colormaps are displayed in the form of colorbars and labels in the main view pane of the plugin. Click on any one of the bars to set the colormap of the currently active channel in the viewer.

Change the channel to set the colormap on a different channel.

You can scroll vertically or use the scroll bars to move through the colorbar samples.

Note

When the plugin starts for the first time, it will generate a bitmap RGB image of colorbars and labels corresponding to all the available colormaps. This can take a few seconds depending on the number of colormaps installed.

Colormaps are shown with the “ramp” intensity map applied.

It is customizable using ~/.ginga/plugin_ColorMapPicker.cfg, where ~ is your HOME directory:

#
# ColorMapPicker plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_ColorMapPicker.cfg"

cbar_ht = 20
cbar_wd = 300
cbar_sep = 10
cbar_pan_accel = 1.0
Errors

The Errors plugin reports error messages on the viewer.

Plugin Type: Global

Errors is a global plugin. Only one instance can be opened.

Usage

When an error occurs in Ginga, its message may be reported here.

RC

The RC plugin implements a remote control interface for the Ginga viewer.

Plugin Type: Global

RC is a global plugin. Only one instance can be opened.

Usage

The RC (Remote Control) plugin provides a way to control Ginga remotely through the use of an XML-RPC interface. Start the plugin from the “Plugins” menu (invoke “Start RC”) or launch ginga with the --modules=RC command line option to start it automatically.

By default, the plugin starts up with server running on port 9000 bound to the localhost interface – this allows connections only from the local host. If you want to change this, set the host and port in the “Set Addr” control and press Enter – you should see the address update in the “Addr:” display field.

Please note that the host part (before the colon) does not indicate which host you want to allow access from, but to which interface to bind. If you want to allow any host to connect, leave it blank (but include the colon and port number) to allow the server to bind on all interfaces. Press “Restart” to then restart the server at the new address.

Once the plugin is started, you can use the ggrc script (included when ginga is installed) to control Ginga. Take a look at the script if you want to see how to write your own programmatic interface.

Show example usage:

$ ggrc help

Show help for a specific Ginga method:

$ ggrc help ginga <method>

Show help for a specific channel method:

$ ggrc help channel <chname> <method>

Ginga (viewer shell) methods can be called like this:

$ ggrc ginga <method> <arg1> <arg2> ...

Per-channel methods can be called like this:

$ ggrc channel <chname> <method> <arg1> <arg2> ...

Calls can be made from a remote host by adding the options:

--host=<hostname> --port=9000

(In the plugin GUI, be sure to remove the “localhost” prefix from the “addr”, but leave the colon and port.)

Examples

Create a new channel:

$ ggrc ginga add_channel FOO

Load a file:

$ ggrc ginga load_file /home/eric/testdata/SPCAM/SUPA01118797.fits

Load a file into a specific channel:

$ ggrc ginga load_file /home/eric/testdata/SPCAM/SUPA01118797.fits FOO

Cut levels:

$ ggrc channel FOO cut_levels 163 1300

Auto cut levels:

$ ggrc channel FOO auto_levels

Zoom to a specific level:

$ ggrc -- channel FOO zoom_to -7

(Note the use of -- to allow us to pass a parameter beginning with -.)

Zoom to fit:

$ ggrc channel FOO zoom_fit

Transform (arguments are a boolean triplet: flipx flipy swapxy):

$ ggrc channel FOO transform 1 0 1

Rotate:

$ ggrc channel FOO rotate 37.5

Change colormap:

$ ggrc channel FOO set_color_map rainbow3

Change color distribution algorithm:

$ ggrc channel FOO set_color_algorithm log

Change intensity map:

$ ggrc channel FOO set_intensity_map neg

In some cases, you may need to resort to shell escapes to be able to pass certain characters to Ginga. For example, a leading dash character is usually interpreted as a program option. In order to pass a signed integer, you may need to do something like:

$ ggrc -- channel FOO zoom -7

Interfacing from within Python

It is also possible to control Ginga in RC mode from within Python. The following describes some of the functionality.

Connecting

First, launch Ginga and start the RC plugin. This can be done from the command line:

ginga --modules=RC

From within Python, connect with a RemoteClient object as follows:

from ginga.util import grc
host='localhost'
port=9000
viewer = grc.RemoteClient(host, port)

This viewer object is now linked to the Ginga using RC.

Load an Image

You can load an image from memory in a channel of your choosing. First, connect to a channel:

ch = viewer.channel('Image')

Then, load a Numpy image (i.e., any 2D ndarray):

import numpy as np
img = np.random.rand(500, 500) * 10000.0
ch.load_np('Image_Name', img, 'fits', {})

The image will display in Ginga and can be manipulated as usual.

Overlay a Canvas Object

It is possible to add objects to the canvas in a given channel. First, connect:

canvas = viewer.canvas('Image')

This connects to the channel named “Image”. You can clear the objects drawn in the canvas:

canvas.clear()

You can also add any basic canvas object. The key issue to keep in mind is that the objects input must pass through the XMLRC protocol. This means simple data types (float, int, list, or str); No arrays. Here is an example to plot a line through a series of points defined by two Numpy arrays:

x = np.arange(100)
y = np.sqrt(x)
points = list(zip(x.tolist(), y.tolist()))
canvas.add('path', points, color='red')

This will draw a red line on the image.

WCSMatch
WCSMatch plugin

WCSMatch is a global plugin for the Ginga image viewer that allows you to roughly align images with different scales and orientations using the images’ World Coordinate System (WCS) for viewing purposes.

Plugin Type: Global

WCSMatch is a global plugin. Only one instance can be opened.

Usage

To use, simply start the plugin, and from the plugin GUI select a channel from the drop-down menu labeled “Reference Channel”. The image contained in that channel will be used as a reference for synchronizing the images in the other channels.

The channels will be synchronized in viewing (pan, scale (zoom), transforms (flips) and rotation. The checkboxes “Match Pan”, “Match Scale”, “Match Transforms” and “Match Rotation” can be checked or not to control which attributes are synchronized between channels.

To completely “unlock” the synchronization, simply select “None” from the “Reference Channel” drop-down menu.

Currently, there is no way to limit the channels that are affected by the plugin.

ChangeHistory
ChangeHistory plugin

Keep track of buffer change history.

Plugin Type: Global

ChangeHistory is a global plugin. Only one instance can be opened.

This plugin is used to log any changes to data buffer. For example, a change log would appear here if a new image is added to a mosaic via the Mosaic plugin. Like Contents, the log is sorted by channel, and then by image name.

Usage

History should stay no matter what channel or image is active. New history can be added, but old history cannot be deleted, unless the image/channel itself is deleted.

The redo() method picks up an 'add-image-info' event and displays related metadata here. The metadata is obtained as follows:

channel = self.fv.get_channel_info(chname)
iminfo = channel.get_image_info(imname)
timestamp = iminfo.time_modified
description = iminfo.reason_modified  # Optional

Both 'time_modified' and 'reason_modified' have to be explicitly set by the calling plugin in the same method that issues the 'add-image-info' callback, like this:

# This changes the data buffer
image.set_data(new_data, ...)
# Add description for ChangeHistory
info = dict(time_modified=datetime.utcnow(),
            reason_modified='Data has changed')
self.fv.update_image_info(image, info)

It is customizable using ~/.ginga/plugin_ChangeHistory.cfg, where ~ is your HOME directory:

#
# ChangeHistory plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_ChangeHistory.cfg"

# If set to True, will always expand the tree in ChangeHistory when
# new entries are added
always_expand = True

# If set to True, rows will have alternate colors
color_alternate_rows = True

# Timestamp column width
ts_colwidth = 250
SAMP Control
SAMP plugin

The SAMP plugin implements a SAMP interface for the Ginga reference viewer.

Note

To run this plugin, you need to install astropy that has the samp module.

Plugin Type: Global

SAMP is a global plugin. Only one instance can be opened.

Usage

Ginga includes a plugin for enabling SAMP (Simple Applications Messaging Protocol) support. With SAMP support, Ginga can be controlled and interoperate with other astronomical desktop applications.

The SAMP module is not started by default. To start it when Ginga starts, specify the command line option:

--modules=SAMP

Otherwise, start it using “Start SAMP” from the “Plugins” menu.

Currently, SAMP support is limited to image.load.fits messages, meaning that Ginga will load a FITS file if it receives one of these messages.

Ginga’s SAMP plugin uses the astropy.samp module, so you will need to have astropy installed to use the plugin. By default, Ginga’s SAMP plugin will attempt to start a SAMP hub if one is not found running.

It is customizable using ~/.ginga/plugin_SAMP.cfg, where ~ is your HOME directory:

#
# SAMP plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_SAMP.cfg"

SAMP_channel = 'Image'

# Default location is set by Ginga's viewer.
#cache_location = '/my/cache/path/'

default_connect = True

start_hub = True
Log
Log plugin

See the logging output of the reference viewer.

Plugin Type: Global

Log is a global plugin. Only one instance can be opened.

Usage

The Log plugin builds a UI that includes a large scrolling text widget showing the active output of the logger. The latest output shows up at the bottom. This can be useful for troubleshooting problems.

There are four controls:

  • The combo box on the lower left allows you to choose the level of logging desired. The four levels, in order of verbosity are: “debug”, “info”, “warn”, and “error”.
  • The box with the number on the lower right allows you to set how many lines of input to keep in the display buffer (e.g., keep only the last 1000 lines).
  • The checkbox “Auto scroll”, if checked, will cause the large text widget to scroll to the end as new log messages are added. Uncheck this if you want to peruse the older messages and study them.
  • The “Clear” button is used to clear the text widget, so that only new logging shows up.
Command

This plugin provides a command line interface to the reference viewer.

Note

The command line is for use within the plugin UI. If you are looking for a remote command line interface, please see the RC plugin.

Plugin Type: Global

Command is a global plugin. Only one instance can be opened.

Usage

Get a list of commands and parameters:

g> help

Execute a shell command:

g> !cmd arg arg ...

Notes

An especially powerful tool is to use the reload_local and reload_global commands to reload a plugin when you are developing that plugin. This avoids having to restart the reference viewer and laboriously reload data, etc. Simply close the plugin, execute the appropriate “reload” command (see the help!) and then start the plugin again.

Note

If you have modifed modules other than the plugin itself, these will not be reloaded by these commands.

SaveImage (Save File)
SaveImage plugin

Save images to output files.

Plugin Type: Global

SaveImage is a global plugin. Only one instance can be opened.

Usage

This global plugin is used to save any changes made in Ginga back to output images. For example, a mosaic image that was created by the Mosaic plugin. Currently, only FITS images (single or multiple extensions) are supported.

Given the output directory (e.g., /mypath/outputs/), a suffix (e.g., ginga), an image channel (Image), and a selected image (e.g., image1.fits), the output file will be /mypath/outputs/image1_ginga_Image.fits. Inclusion of the channel name is optional and can be omitted using plugin configuration file, plugin_SaveImage.cfg. The modified extension(s) will have new header or data extracted from Ginga, while those not modified will remain untouched. Relevant change log entries from the ChangeHistory global plugin will be inserted into the history of its PRIMARY header.

Note

This plugin uses the module astropy.io.fits to write the output images, regardless of what is chosen for FITSpkg in the general.cfg configuration file.

It is customizable using ~/.ginga/plugin_SaveImage.cfg, where ~ is your HOME directory:

#
# SaveImage plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_SaveImage.cfg"

# Default output parameters. Can also be changed in the GUI.
output_directory = '.'
output_suffix = 'ginga'

# Include channel name in the suffix.
# If False, only output_suffix is used regardless of channel.
include_chname = True

# Clobber existing output files or not
clobber = False

# Only list modified images from the channel
modified_only = True

# Maximum mosaic size to allow for writing out.
# This is useful to prevent super large mosaic from being written.
# Default is 10k x 10k
max_mosaic_size = 1e8

# Maximum number of rows that will turn off auto column resizing (for speed)
max_rows_for_col_resize = 5000
Local plugins

An operation is the activation of a local plugin to perform some function. The plugin manager toolbar at the bottom of the center pane is the graphical way to start an operation.

Pick
Pick plugin

Perform quick astronomical stellar analysis.

Plugin Type: Local

Pick is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

The Pick plugin is used to perform quick astronomical data quality analysis on stellar objects. It locates stellar candidates within a drawn rectangle and picks the most likely candidate based on a set of search settings. The Full Width Half Max (FWHM) is reported on the candidate object, as well as its size based on the plate scale of the detector. Rough measurement of background, sky level and brightness is also done.

Defining the pick area

The default pick area is defined as a rectangle of approximately 30x30 pixels that encloses the search area.

The move/draw/edit selector at the bottom of the plugin is used to determine what operation is being done to the pick area:

Move, Draw and Edit buttons

“Move”, “Draw”, and “Edit” buttons.

  • If “move” is selected, then you can move the existing pick area by dragging it or clicking where you want the center of it placed. If there is no existing area, a default one will be created.
  • If “draw” is selected, then you can draw a shape with the cursor to enclose and define a new pick area. The default shape is a rectangle, but other shapes can be selected in the “Settings” tab.
  • If “edit” is selected, then you can edit the pick area by dragging its control points, or moving it by dragging in the bounding box.

After the area is moved, drawn or edited, Pick will perform one of three actions:

  1. In “Quick Mode” ON, with “From Peak” OFF, it will simply attempt to perform a calculation based on the coordinate under the crosshair in the center of the pick area.
  2. In “Quick Mode” ON, with “From Peak” ON, it will perform a quick detection of peaks in the pick area and perform a calculation on the first one found, using the peak’s coordinates.
  3. In “Quick Mode” OFF, it will search the area for all peaks and evaluate the peaks based on the criteria in the “Settings” tab of the UI (see “The Settings Tab” below) and try to locate the best candidate matching the settings.

If a candidate is found

The candidate will be marked with a point (usually an “X”) in the channel viewer canvas, centered on the object as determined by the horizontal and vertical FWHM measurements.

The top set of tabs in the UI will be populated as follows:

Image tab of Pick area

“Image” tab of Pick area.

The “Image” tab will show the contents of the cutout area. The widget in this tab is a Ginga widget and so can be zoomed and panned with the usual keyboard and mouse bindings (e.g., scroll wheel). It will also be marked with a point centered on the object and additionally the pan position will be set to the found center.

Contour tab of Pick area

“Contour” tab of Pick area.

The “Contour” tab will show a contour plot. This is a contour plot of the area immediately surrounding the candidate, and not usually encompassing the entire region of the pick area. You can use the vertical slider to the right of the plot to increase or decrease the area of the contour plot.

FWHM tab of Pick area

“FWHM” tab of Pick area.

The “FWHM” tab will show a FWHM plot. The blue lines show measurements in the X direction and the green lines show measurements in the Y direction. The solid lines indicate actual pixel values and the dotted lines indicate the fitted 1D function. The shaded green and blue regions indicate the FWHM measurements.

Radial tab of Pick area

“Radial” tab of Pick area.

The “Radial” tab contains a radial profile plot. Plotted points in blue are data values, and a line is fitted to the data.

Cut tab of Pick area

“Cut” tab of Pick area.

The “Cuts” tab contains a profile plot for the vertical and horizontal cuts represented by the crosshairs present in “Quick Mode” ON. This plot is updated in real time as the pick area is moved. In “Quick Mode” OFF, this plot is not updated.

Readout tab of Pick area

“Readout” tab of Pick area.

The “Readout” tab will be populated with a summary of the measurements. There are two buttons and two check boxes in this tab:

  • The “Default Region” button restores the pick region to the default shape and size.
  • The “Pan to pick” button will pan the channel viewer to the located center.
  • The “Quick Mode” check box toggles “Quick Mode” on and off. This affects the behavior of the pick region as described above.
  • The “From Peak” check box changes the behavior of “Quick Mode” slightly as described above.
Controls tab of Pick area

“Controls” tab of Pick area.

The “Controls” tab has a couple of buttons that will work off of the measurements.

  • The “Bg cut” button will set the low cut level of the channel viewer to the measured background level. A delta to this value can be applied by setting a value in the “Delta bg” box (press “Enter” to change the setting).
  • The “Sky cut” button will set the low cut level of the channel viewer to the measured sky level. A delta to this value can be applied by setting a value in the “Delta sky” box (press “Enter” to change the setting).
  • The “Bright cut” button will set the high cut level of the channel viewer to the measured sky+brightness levels. A delta to this value can be applied by setting a value in the “Delta bright” box (press “Enter” to change the setting).
Report tab of Pick area

“Report” tab of Pick area.

The “Report” tab is used to record information about the measurements in tabular form.

By pressing the “Add Pick” button, the information about the most recent candidate is added to the table. If the “Record Picks automatically” checkbox is checked, then any candidates are added to the table automatically.

Note

If the “Show candidates” checkbox in the “Settings” tab is checked, then all objects found in the region (according to the settings) will be added to the table instead of just the selected candidate.

You can clear the table at any time by pressing the “Clear Log” button. The log can be saved to a table by putting a valid path and filename in the “File:” box and pressing “Save table”. File type is automatically determined by the given extension (e.g., “.fits” is FITS and “.txt” is plain text).

If no candidate is found

If no candidate can be found (based on the settings), then the pick area is marked with a red point centered on the pick area.

Marker when no candidate found

Marker when no candidate found.

The image cutout will be taken from this central area and so the “Image” tab will still have content. It will also be marked with a central red “X”.

The contour plot will still be produced from the cutout, and the cuts plot will be updated in “Quick Mode”.

Contour when no candidate found.

Contour when no candidate found.

All the other plots will be cleared.

The Settings Tab

Settings tab of Pick plugin

“Settings” tab of Pick plugin.

The “Settings” tab controls aspects of the search within the pick area:

  • The “Show candidates” checkbox controls whether all detected sources are marked or not (as shown in the figure below). Additionally, if checked, then all the found objects are added to the pick log table when using the “Report” controls.
  • The “Draw type” parameter is used to choose the shape of the pick area to be drawn.
  • The “Radius” parameter sets the radius to be used when finding and evaluating bright peaks in the image.
  • The “Threshold” parameter is used to set a threshold for peak finding; if set to “None”, then a reasonable default value will be chosen.
  • The “Min FWHM” and “Max FWHM” parameters can be used to eliminate certain sized objects from being candidates.
  • The “Ellipticity” parameter is used to eliminate candidates based on their asymmetry in shape.
  • The “Edge” parameter is used to eliminate candidates based on how close to the edge of the cutout they are. NOTE: currently this works reliably only for non-rotated rectangular shapes.
  • The “Max side” parameter is used to limit the size of the bounding box that can be used in the pick shape. Larger sizes take longer to evaluate.
  • The “Coordinate Base” parameter is an offset to apply to located sources. Set to “1” if you want sources pixel locations reported in a FITS-compliant manner and “0” if you prefer 0-based indexing.
  • The “Calc center” parameter is used to determine whether the center is calculated from FWHM fitting (“fwhm”) or centroiding (“centroid”).
  • The “FWHM fitting” parameter is used to determine which function is is used for FWHM fitting (“gaussian” or “moffat”).
  • The “Contour Interpolation” parameter is used to set the interpolation method used in rendering the background image in the “Contour” plot.

The “Redo Pick” button will redo the search operation. It’s convenient if you have changed some parameters and want to see the effect based on the current pick area without disturbing it.

The channel viewer when "Show candidates" is checked.

The channel viewer when “Show candidates” is checked.

User Configuration

It is customizable using ~/.ginga/plugin_Pick.cfg, where ~ is your HOME directory:

#
# Pick plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Pick.cfg"

color_pick = 'green'
shape_pick = 'box'
color_candidate = 'purple'

# Offset to add to Pick results. Default is 1.0 for FITS like indexing,
# set to 0.0 here if you prefer numpy-like 0-based indexing
pixel_coords_offset = 0.0

# Maximum side for a pick region
max_side = 1024

# For contour plot
num_contours = 8
# How big of a radius are we willing to consider from the center of the
# pick?  bigger numbers == slower
contour_size_min = 10
contour_size_limit = 70

# Start in Quick Mode?
quick_mode = False
quick_from_peak = True
# for future use
quick_update_interval = 0.25
quick_drag_only = True

# Star candidate search parameters
radius = 10
# Set threshold to None to auto calculate it
threshold = None
# Minimum and maximum fwhm to be considered a candidate
min_fwhm = 2.0
max_fwhm = 50.0
# Minimum ellipticity to be considered a candidate
min_ellipse = 0.5
# Percentage from edge to be considered a candidate
edge_width = 0.01
# Graphically indicate all possible considered candidates
show_candidates = False

# Center of object is based on FWHM ("fwhm") or centroid ("centroid")
# calculation:
calc_center_alg = 'centroid'

# Fitting function to use for FWHM ("gaussian" or "moffat")
calc_fwhm_alg = 'gaussian'

# Defaults for delta cut levels (in Controls tab)
delta_sky = 0.0
delta_bright = 0.0

# use a different color/intensity map than channel image?
pick_cmap_name = None
pick_imap_name = None

# For Reports tab
record_picks = True

# Set this to a file name, if None a filename will be automatically chosen
report_log_path = None
Ruler
Ruler plugin

Ruler is a simple plugin designed to measure distances on an image.

Plugin Type: Local

Ruler is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

Ruler measures distance by calculating a spherical triangulation via WCS mapping of three points defined by a single line drawn on the image. By default, the distance is shown in arcminutes of sky, but using the “Units” control, it can be changed to show degrees or pixel distance instead.

Click and drag to establish a ruler between two points.

Display the “Zoom” tab at the same time to precisely see detail while drawing the ruler, if desired.

To erase the old and make a new ruler, click and drag again. When another line is drawn, it replaces the first one. When the plugin is closed, the graphic overlay is removed. Should you want “sticky rulers”, use the Drawing plugin (and choose “Ruler” as the drawing type).

Editing

To edit an existing ruler, click the radio button in the plugin UI labeled “Edit”. If the ruler does not become selected immediately, click on it. This should establish a bounding box around the ruler and show its control points. Drag within the bounding box to move the ruler or click and drag the endpoints to edit the ruler.

Units

The units shown for distance can be selected from the drop-down box in the UI. You have a choice of “arcmin”, “degrees”, or “pixels”. The first two require a valid and working WCS in the image.

MultiDim
MultDim image display MultDim table display

A plugin to navigate HDUs in a FITS file or planes in a 3D cube or higher dimension dataset.

Plugin Type: Local

MultiDim is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

MultiDim is a plugin designed to handle data cubes and multi-HDU FITS files. If you have opened such an image in Ginga, starting this plugin will enable you to browse to other slices of the cube or view other HDUs.

For a data cube, you can save a slice as an image using the “Save Slice” button or create a movie using the “Save Movie” button by entering the “Start” and “End” slice indices. This feature requires mencoder to be installed.

For a FITS table, its data are read in using Astropy table. Column units are displayed right under the main header (“None” if no unit). For masked columns, masked values are replaced with pre-defined fill values.

Browsing HDUs

Use the HDU drop down list in the upper part of the UI to browse and select an HDU to open in the channel.

Navigating Cubes

Use the controls in the lower part of the UI to select the axis and to step through the planes in that axis.

User Configuration

It is customizable using ~/.ginga/plugin_MultiDim.cfg, where ~ is your HOME directory:

#
# MultiDim plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_MultiDim.cfg"

# If set to True, will auto open the plugin when an image is loaded
# with NAXIS >= 3
auto_start_naxis = False
Cuts
Cuts plugin

A plugin for generating a plot of the values along a line or path.

Plugin Type: Local

Cuts is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

Cuts plots a simple graph of pixel values vs. index for a line drawn through the image. Multiple cuts can be plotted.

There are four kinds of cuts available: line, path, freepath and beziercurve:

  • The “line” cut is a straight line between two points.
  • The “path” cut is drawn like an open polygon, with straight segments in-between.
  • The “freepath” cut is like a path cut, but drawn using a free-form stroke following the cursor movement.
  • The “beziercurve” path is a cubic Bezier curve.

If a new image is added to the channel while the plugin is active, it will update with the new calculated cuts on the new image.

If the “enable slit” setting is enabled, this plugin will also allow slit image functionality (for multidimensional images) via a “Slit” tab. In the tab UI, select one axis from the “Axes” list and draw a line. This will create a 2D image that assumes the first two axes are spatial and index the data along the selected axis. Much like Cuts, you can view the other slit images using the cut selection drop down box.

Drawing Cuts

The “New Cut Type” menu let you choose what kind of cut you are going to draw.

Choose “New Cut” from the “Cut” dropdown menu if you want to draw a new cut. Otherwise, if a particular named cut is selected then that will be replaced by any newly drawn cut.

While drawing a path or beziercurve cut, press ‘v’ to add a vertex, or ‘z’ to remove the last vertex added.

Keyboard Shortcuts

While hovering the cursor, press ‘h’ for a full horizontal cut and ‘j’ for a full vertical cut.

Deleting Cuts

To delete a cut, select its name from the “Cut” dropdown and click the “Delete” button. To delete all cuts, press “Delete All”.

Editing Cuts

Using the edit canvas function, it is possible to add new vertices to an existing path and to move vertices around. Click the “Edit” radio button to put the canvas in edit mode. If a cut is not automatically selected, you can now select the line, path, or curve by clicking on it, which should enable the control points at the ends or vertices – you can drag these around. To add a new vertex to a path, hover the cursor carefully on the line where you want the new vertex and press ‘v’. To get rid of a vertex, hover the cursor over it and press ‘z’.

You will notice one extra control point for most objects, which has a center of a different color – this is a movement control point for moving the entire object around the image when in edit mode.

You can also select “Move” to just move a cut unchanged.

Changing Width of Cuts

The width of ‘line’ cuts can be changed using the “Width Type” menu:

  • “none” indicates a cut of zero radius; i.e., only showing the pixel values along the line
  • “x” will plot the sum of values along the X axis orthogonal to the cut.
  • “y” will plot the sum of values along the Y axis orthogonal to the cut.
  • “perpendicular” will plot the sum of values along an axis perpendicular to the cut.

The “Width radius” controls the width of the orthogonal summation by an amount on either side of the cut – 1 would be 3 pixels, 2 would be 5 pixels, etc.

Saving Cuts

Use the “Save” button to save the Cuts plot as as image and data as a Numpy compressed archive.

User Configuration

It is customizable using ~/.ginga/plugin_Cuts.cfg, where ~ is your HOME directory:

#
# Cuts plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Cuts.cfg"

# If set to True will always select a cut after drawing it
select_new_cut = True

# If set to True will automatically change to "move" mode after draw
draw_then_move = True

# If set to True will label cuts with a text annotation
label_cuts = True

# If set to True will add a legend to the cuts plot
show_cuts_legend = False

# If set to True will add Slit tab
enable_slit = False

# Default cut colors
colors = ['magenta', 'skyblue2', 'chartreuse2', 'cyan', 'pink', 'burlywood2', 'yellow3', 'turquoise', 'coral1', 'mediumpurple2']

# If set to True, will update graph continuously as cursor is dragged
# around image
drag_update = False
Histogram
Histogram plugin

Histogram plots a histogram for a region drawn in the image, or for the entire image.

Plugin Type: Local

Histogram is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

Click and drag to define a region within the image that will be used to calculate the histogram. To take the histogram of the full image, click the button in the UI labeled “Full Image”.

Note

Depending on the size of the image, calculating the full histogram may take time.

If a new image is selected for the channel, the histogram plot will be recalculated based on the current parameters with the new data.

UI Controls

Three radio buttons at the bottom of the UI are used to control the effects of the click/drag action:

  • select “Move” to drag the region to a different location
  • select “Draw” to draw a new region
  • select “Edit” to edit the region

To make a log plot of the histogram, check the “Log Histogram” checkbox. To plot by the full range of values in the image instead of by the range within the cut values, uncheck the “Plot By Cuts” checkbox.

The “NumBins” parameter determines how many bins are used in calculating the histogram. Type a number in the box and press “Enter” to change the default value.

Cut Levels Convenience Controls

Because a histogram is useful feedback for setting the cut levels, controls are provided in the UI for setting the low and high cut levels in the image, as well as for performing an auto cut levels, according to the auto cut levels settings in the channel preferences.

User Configuration

It is customizable using ~/.ginga/plugin_Histogram.cfg, where ~ is your HOME directory:

#
# Histogram plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Histogram.cfg"

# Switch to "move" mode after selection
draw_then_move = True

# Number of bins for histogram
num_bins = 2048

# Histogram color
hist_color = 'aquamarine'
Crosshair
Crosshair plugin

Crosshair is a simple plugin to draw crosshairs labeled with the position of the cross in pixels coordinates, WCS coordinates, or data value at the cross position.

Plugin Type: Local

Crosshair is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

Select the appropriate type of output in the “Format” drop-down box in the UI: “xy” for pixel coordinates, “coords” for the WCS coordinates, and “value” for the value at the crosshair position.

Then, click and drag to position the crosshair.

Overlays
Overlays plugin

A plugin for generating color overlays representing under- and over-exposure in the loaded image.

Plugin Type: Local

Overlays is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

Choose colors from the drop-down menus for the low-limit and/or high-limit (“Lo color” and “Hi color”, respectively). Specify the limits for low and high values in the limit boxes (“Lo limit” and “Hi limit”, respectively). Set the opacity of the overlays with a value between 0 and 1 in the “Opacity” box. Finally, press the “Redo” button.

The color overlay should show areas below the low limit with a low color and the areas above the high limit in the high color. If you omit a limit (leave the box blank), that color won’t be shown in the overlay.

If a new image is selected for the channel, the overlays image will be recalculated based on the current parameters with the new data.

WCSAxes
WCSAxes plugin

A plugin for generating WCS axes overlay in the loaded image.

Plugin Type: Local

WCSAxes is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

As long as image as a valid WCS, WCS axes will be displayed. Use plugin GUI or configuration file to customize axes display.

It is customizable using ~/.ginga/plugin_WCSAxes.cfg, where ~ is your HOME directory:

#
# WCSAxes plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_WCSAxes.cfg"

# Color, style, and width of grid lines
linecolor = 'cyan'
linestyle = 'solid'
linewidth = 1

# Alpha (opacity) of grid lines; 1=opaque, 0=transparent
alpha = 1

# Number of RA and DEC lines to draw
n_ra_lines = 10
n_dec_lines = 10

# Show RA and DEC values of grid lines
show_label = True

# Label font size
fontsize = 8

# Label offset from grid lines (pixels)
label_offset = 4
TVMark
TVMark plugin

Mark points from file (non-interative mode) on an image.

Plugin Type: Local

TVMark is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

This plugin allows non-interactive marking of points of interest by reading in a file containing a table with RA and DEC positions of those points. Any text or FITS table file that can be read by astropy.table is acceptable but user must define the column names correctly in the plugin configuration file (see below). An attempt will be made to convert RA and DEC values to degrees. If the unit conversion fails, they will be assumed to be in degrees already.

Alternately, if the file has columns containing the direct pixel locations, you can read these columns instead by unchecking the “Use RADEC” box. Again, the column names must be correctly defined in the plugin configuration file (see below). Pixel values can be 0- or 1-indexed (i.e., whether the first pixel is 0 or 1) and is configurable (see below). This is useful when you want to mark the physical pixels regardless of WCS (e.g., marking hot pixels on a detector). RA and DEC will still be displayed if the image has WCS information but they will not affect the markings.

To mark different groups (e.g., displaying galaxies as green circles and background as cyan crosses, as shown above):

  1. Select green circle from the drop-down menus. Alternately, enter desired size or width.
  2. Make sure “Use RADEC” box is checked, if applicable.
  3. Using “Load Coords” button, load the file containing RA and DEC (or X and Y) positions for galaxies only.
  4. Repeat Step 1 but now select cyan cross from the drop-down menus.
  5. Repeat Step 2 but choose the file containing background positions only.

Selecting an entry (or multiple entries) from the table listing will highlight the marking(s) on the image. The highlight uses the same shape and color, but a slightly thicker line.

You can also highlight all the markings within a region both on the image and the table listing by drawing a rectangle on the image while this plugin is active.

Pressing the “Hide” button will hide the markings but does not clear the plugin’s memory; That is, when you press “Show”, the same markings will reappear on the same image. However, pressing “Forget” will clear the markings both from display and memory; That is, you will need to reload your file(s) to recreate the markings.

To redraw the same positions with different marking parameters, press “Forget” and repeat the steps above, as necessary. However, if you simply wish to change the line width (thickness), pressing “Hide” and then “Show” after you entered the new width value will suffice.

If images of very different pointings/dimensions are displayed in the same channel, markings that belong to one image but fall outside another will not appear in the latter.

To create a table that this plugin can read, one can use results from the Pick plugin, in addition to creating a table by hand, using astropy.table, etc.

Used together with TVMask, you can overlay both point sources and masked regions in Ginga.

It is customizable using ~/.ginga/plugin_TVMark.cfg, where ~ is your HOME directory:

#
# TVMark plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_TVMark.cfg"

# Marking type -- 'circle' or 'cross'
marktype = 'circle'

# Marking color -- Any color name accepted by Ginga
markcolor = 'green'

# Marking size or radius
marksize = 5

# Marking line width (thickness)
markwidth = 1

# Specify whether pixel values are 0- or 1-indexed
pixelstart = 1

# True -- Use 'ra' and 'dec' columns to extract RA/DEC positions. This option
#         uses image WCS to convert to pixel locations.
# False -- Use 'x' and 'y' columns to extract pixel locations directly.
#          This does not use WCS.
use_radec = True

# Columns to load into table listing (case-sensitive).
# Whether RA/DEC or X/Y columns are used depend on associated GUI selection.
ra_colname = 'ra'
dec_colname = 'dec'
x_colname = 'x'
y_colname = 'y'
# Extra columns to display; e.g., ['colname1', 'colname2']
extra_columns = []
TVMask
TVMask plugin

Display masks from file (non-interative mode) on an image.

Plugin Type: Local

TVMask is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

This plugin allows non-interactive display of mask by reading in a FITS file, where non-zero is assumed to be masked data.

To display different masks (e.g., some masked as green and some as pink, as shown above):

  1. Select green from the drop-down menu. Alternately, enter desired alpha value.
  2. Using “Load Mask” button, load the relevant FITS file.
  3. Repeat (1) but now select pink from the drop-down menu.
  4. Repeat (2) but choose another FITS file.
  5. To display a third mask as pink too, repeat (4) without changing the drop-down menu.

Selecting an entry (or multiple entries) from the table listing will highlight the mask(s) on the image. The highlight uses a pre-defined color and alpha (customizable below).

You can also highlight all the masks within a region both on the image and the table listing by drawing a rectangle on the image while this plugin is active.

Pressing the “Hide” button will hide the masks but does not clear the plugin’s memory; That is, when you press “Show”, the same masks will reappear on the same image. However, pressing “Forget” will clear the masks both from display and memory; That is, you will need to reload your file(s) to recreate the masks.

To redraw the same masks with different color or alpha, press “Forget” and repeat the steps above, as necessary.

If images of very different pointings/dimensions are displayed in the same channel, masks that belong to one image but fall outside another will not appear in the latter.

To create a mask that this plugin can read, one can use results from the Drawing plugin (press “Create Mask” after drawing and save the mask using SaveImage), in addition to creating a FITS file by hand using astropy.io.fits, etc.

Used together with TVMark, you can overlay both point sources and masked regions in Ginga.

It is customizable using ~/.ginga/plugin_TVMask.cfg, where ~ is your HOME directory:

#
# TVMask plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_TVMask.cfg"

# Mask color -- Any color name accepted by Ginga
maskcolor = 'green'

# Mask alpha (transparency) -- 0=transparent, 1=opaque
maskalpha = 0.5

# Highlighted mask color and alpha
hlcolor = 'white'
hlalpha = 1.0
LineProfile
LineProfile plugin

A plugin to graph the pixel values along a straight line bisecting a cube.

Plugin Type: Local

LineProfile is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

Warning

There are no restrictions to what axes can be chosen. As such, the plot can be meaningless.

The LineProfile plugin is used for multidimensional (i.e., 3D or higher) images. It plots the values of the pixels at the current cursor position through the selected axis; or if a region is selected, it plots the mean in each frame. This can be used to create normal spectral line profiles. A marker is placed at the data point of the currently displayed frame.

Displayed X-axis is constructed using CRVAL*, CDELT*, CRPIX*, CTYPE*, and CUNIT* keywords from FITS header. If any of the keywords are unavailabled, the axis falls back to NAXIS* values instead.

Displayed Y-axis is constructed using BTYPE and BUNIT. If they are not available, it simply labels pixel values as “Flux”.

To use this plugin:

  1. Select an axis.
  2. Pick a point or draw a region using the cursor.
  3. Use MultiDim to change step values of axes, if applicable.

It is customizable using ~/.ginga/plugin_LineProfile.cfg, where ~ is your HOME directory:

#
# LineProfile plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_LineProfile.cfg"

# Default mark type. This can be change in the GUI.
mark_type = 'point'

# Properties of a point mark type. Radius can be change in Edit mode.
mark_radius = 10
mark_style='cross'

# Mark color.
mark_color = 'cyan'
PixTable
PixTable plugin

PixTable provides a way to check or monitor the pixel values in a region.

Plugin Type: Local

PixTable is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Basic Use

In the most basic use, simply move the cursor around the channel viewer; an array of pixel values will appear in the “Pixel Values” display in the plugin UI. The center value is highlighted, and this corresponds to the value under the cursor.

You can choose a 3x3, 5x5, 7x7, or 9x9 grid from the left-most combobox control. It may help to adjust the “Font Size” control to prevent having the array values cut off on the sides. You can also enlarge the plugin workspace to see more of the table.

Note

The order of the value table shown will not necessarily match to the channel viewer if the images is flipped, transposed, or rotated.

Using Marks

If you click in the channel viewer, it will set a mark. There can be any number of marks, and they are each noted with an “X” annotated with a number. When that mark is selected, it will only show the values around the mark. Simply change the mark control to select a different mark to see the values around it.

The marks will stay in position even if a new image is loaded and they will show the values for the new image. In this way you can monitor the area around a spot if the image is updating frequently.

If the “Pan to mark” checkbox is selected, then when you select a different mark from the mark control, the channel viewer will pan to that mark. This can be useful to inspect the same spots in several different images.

Note

If you change the mark control back to “None”, then the pixel table will again update as you move the cursor around the viewer.

Deleting Marks

To delete a mark, select it in the mark control and then press the button marked “Delete”. To delete all the marks, press the button marked “Delete All”.

User Configuration

It is customizable using ~/.ginga/plugin_PixTable.cfg, where ~ is your HOME directory:

#
# PixTable plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_PixTable.cfg"

# Default font
font = 'fixed'

# Default font size
fontsize = 12
Preferences

Make changes to channel settings graphically in the UI.

Plugin Type: Local

Preferences is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

The Preferences plugin sets the preferences on a per-channel basis. The preferences for a given channel are inherited from the “Image” channel until they are explicitly set and saved using this plugin.

If “Save Settings” is pressed, it will save the settings to the user’s home Ginga folder so that when a channel with the same name is created in future Ginga sessions it will obtain the same settings.

Color Distribution Preferences

Color Distribution preferences

“Color Distribution” preferences.

The “Color Distribution” preferences control the preferences used for the data value to color index conversion that occurs after cut levels are applied and just before final color mapping is performed. It concerns how the values between the low and high cut levels are distributed to the color and intensity mapping phase.

The “Algorithm” control is used to set the algorithm used for the mapping. Click the control to show the list, or simply scroll the mouse wheel while hovering the cursor over the control. There are eight algorithms available: linear, log, power, sqrt, squared, asinh, sinh, and histeq. The name of each algorithm is indicative of how the data is mapped to the colors in the color map. “linear” is the default.

Color Mapping Preferences

Color Mapping preferences

“Color Mapping” preferences.

The “Color Mapping” preferences control the preferences used for the color map and intensity map, used during the final phase of the color mapping process. Together with the “Color Distribution” preferences, these control the mapping of data values into a 24-bpp RGB visual representation.

The “Colormap” control selects which color map should be loaded and used. Click the control to show the list, or simply scroll the mouse wheel while hovering the cursor over the control.

The “Intensity” control selects which intensity map should be used with the color map. The intensity map is applied just before the color map, and can be used to change the standard linear scale of values into an inverted scale, logarithmic, etc.

Ginga comes with a good selection of color maps, but should you want more, you can add custom ones or, if matplotlib is installed, you can load all the ones that it has. See “Customizing Ginga” for details.

Zoom Preferences

Zoom preferences

“Zoom” preferences.

The “Zoom” preferences control Ginga’s zooming/scaling behavior. Ginga supports two zoom algorithms, chosen using the “Zoom Alg” control:

  • The “step” algorithm zooms the image inwards in discrete steps of 1X, 2X, 3X, etc. or outwards in steps of 1/2X, 1/3X, 1/4X, etc. This algorithm results in the least artifacts visually, but is a bit slower to zoom over wide ranges when using a scrolling motion because more “throw” is required to achieve a large zoom change (this is not the case if one uses of the shortcut zoom keys, such as the digit keys).
  • The “rate” algorithm zooms the image by advancing the scaling at a rate defined by the value in the “Zoom Rate” box. This rate defaults to the square root of 2. Larger numbers cause larger changes in scale between zoom levels. If you like to zoom your images rapidly, at a small cost in image quality, you would likely want to choose this option.

Note that regardless of which method is chosen for the zoom algorithm, the zoom can be controlled by holding down Ctrl (coarse) or Shift (fine) while scrolling to constrain the zoom rate (assuming the default mouse bindings).

The “Stretch XY” control can be used to stretch one of the axes (X or Y) relative to the other. Select an axis with this control and roll the scroll wheel while hovering over the “Stretch Factor” control to stretch the pixels in the selected axis.

The “Scale X” and “Scale Y” controls offer direct access to the underlying scaling, bypassing the discrete zoom steps. Here, exact values can be typed to scale the image. Conversely, you will see these values change as the image is zoomed.

The “Scale Min” and “Scale Max” controls can be used to place a limit on how much the image can be scaled.

The “Zoom Defaults” button will restore the controls to the Ginga default values.

Pan Preferences

Pan Preferences

“Pan” preferences.

The “Pan” preferences control Ginga’s panning behavior.

The “Pan X” and “Pan Y” controls offer direct access to set the pan position in the image (the part of the image located at the center of the window) – you can see them change as you pan around the image.

The “Center Image” button sets the pan position to the center of the image, as calculated by halving the dimensions in X and Y.

The “Mark Center” check box, when checked, will cause Ginga to draw a small reticle in the center of the image. This is useful for knowing the pan position and for debugging.

Transform Preferences

Transform Preferences

“Transform” preferences.

The “Transform” preferences provide for transforming the view of the image by flipping the view in X or Y, swapping the X and Y axes, or rotating the image in arbitrary amounts.

The “Flip X” and “Flip Y” checkboxes cause the image view to be flipped in the corresponding axis.

The “Swap XY” checkbox causes the image view to be altered by swapping the X and Y axes. This can be combined with “Flip X” and “Flip Y” to rotate the image in 90 degree increments. These views will render more quickly than arbitrary rotations using the “Rotate” control.

The “Rotate” control will rotate the image view the specified amount. The value should be specified in degrees. “Rotate” can be specified in conjunction with flipping and swapping.

The “Restore” button will restore the view to the default view, which is unflipped, unswapped, and unrotated.

Auto Cuts Preferences

Auto Cuts Preferences

“Auto Cuts” preferences.

The “Auto Cuts” preferences control the calculation of auto cut levels for the view when the auto cut levels button or key is pressed, or when loading a new image with auto cuts enabled.

The “Auto Method” control is used to choose which auto cuts algorithm used: “minmax” (minimum maximum values), “histogram” (based on an image histogram), “stddev” (based on the standard deviation of pixel values), or “zscale” (based on the ZSCALE algorithm popularized by IRAF). As the algorithm is changed, the boxes under it may also change to allow changes to parameters particular to each algorithm.

WCS Preferences

WCS Preferences

“WCS” preferences.

The “WCS” preferences control the display preferences for the World Coordinate System (WCS) calculations used to report the cursor position in the image.

The “WCS Coords” control is used to select the coordinate system in which to display the result.

The “WCS Display” control is used to select a sexagesimal (H:M:S) readout or a decimal degrees readout.

New Image Preferences

New Image Preferences

“New Image” preferences.

The “New Images” preferences determine how Ginga reacts when a new image is loaded into the channel. This includes when an older image is revisited by clicking on its thumbnail in the Thumbs plugin pane.

The “Cut New” setting controls whether an automatic cut-level calculation should be performed on the new image, or whether the currently set cut levels should be applied. The possible settings are:

  • “on”: calculate a new cut levels always;
  • “override”: calculate a new cut levels until the user overrides it by manually setting a cut levels, then turn “off”; or
  • “off”: always use the currently set cut levels.

Tip

The “override” setting is provided for the convenience of having automatic cut levels, while preventing a manually set cuts from being overridden when a new image is ingested. When typed in the image window, the semicolon key can be used to toggle the mode back to override (from “off”), while colon will set the preference to “on”. The Info panel shows the state of this setting.

The “Zoom New” setting controls whether a newly visited image should be zoomed to fit the window. There are three possible values: on, override, and off:

  • “on”: the new image is always zoomed to fit;
  • “override”: images are automatically fitted until the zoom level is changed manually, then the mode automatically changes to “off”, or
  • “off”: always use the currently set zoom levels.

Tip

The “override” setting is provided for the convenience of having an automatic zoom, while preventing a manually set zoom level from being overridden when a new image is ingested. When typed in the image window, the apostrophe (a.k.a. “single quote”) key can be used to toggle the mode back to “override” (from “off”), while quote (a.k.a. double quote) will set the preference to “on”. The global plugin Info panel shows the state of this setting.

The “Center New” box, if checked, will cause newly visited images to always have the pan position reset to the center of the image. If unchecked, the pan position is unchanged from the previous image.

The “Follow New” setting is used to control whether Ginga will change the display if a new image is loaded into the channel. If unchecked, the image is loaded (as seen, for example, by its appearance in the Thumbs tab), but the display will not change to the new image. This setting is useful in cases where new images are being loaded by some automated means into a channel and the user wishes to study the current image without being interrupted.

The “Raise New” setting controls whether Ginga will raise the tab of a channel when an image is loaded into that channel. If unchecked, then Ginga will not raise the tab when an image is loaded into that particular channel.

The “Create Thumbnail” setting controls whether Ginga will create a thumbnail for images loaded into that channel. In cases where many images are being loaded into a channel frequently (e.g., a low frequency video feed), it may be undesirable to create thumbnails for all of them.

Catalogs

A plugin for plotting object locations from a catalog on an image.

Plugin Type: Local

Catalogs is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

Before Catalogs can be used, you need to define at least one catalog or image server to be queried in ginga_config.py. Here is an example for defining three cone search catalogs for guide stars:

def pre_gui_config(ginga):
    from ginga.util.catalog import AstroPyCatalogServer

    # Add Cone Search services
    catalogs = [
        ('The HST Guide Star Catalog, Version 1.2 (Lasker+ 1996) 1',
         'GSC_1.2'),
        ('The PMM USNO-A1.0 Catalogue (Monet 1997) 1', 'USNO_A1'),
        ('The USNO-A2.0 Catalogue (Monet+ 1998) 1', 'USNO_A2'),
    ]
    bank = ginga.get_ServerBank()
    for longname, shortname in catalogs:
        obj = AstroPyCatalogServer(
            ginga.logger, longname, shortname, '', shortname)
        bank.addCatalogServer(obj)

def post_gui_config(ginga):
    pass

Then, start Ginga and then start the Catalogs local plugin from the channel you want to perform searchs on. You will see the catalogs listed in a drop-down menu on the plugin GUI.

Draw a shape on the displayed image and adjust search parameters as desired. When you are ready, press on the button to perform the search. When search results are available, they will be displayed on the image and also listed in a table on the plugin GUI. You can click on either the table or the image to highlight selection.

It is customizable using ~/.ginga/plugin_Catalogs.cfg, where ~ is your HOME directory:

#
# Catalogs plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Catalogs.cfg"

draw_type = 'circle'
select_color = 'skyblue'
color_outline = 'aquamarine'
click_radius = 10
Mosaic

Plugin to create image mosaic.

Plugin Type: Local

Mosaic is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

Warning

This can be very memory intensive.

This plugin is used to automatically create a mosaic in the channel using images provided by the user (e.g., using FBrowser). The position of an image on the mosaic is determined by its WCS without distortion correction. This is meant as a quick-look tool, not a replacement for image drizzling that takes account of image distortion, etc. The mosaic only exists in memory but you can save it out to a FITS file using SaveImage.

When a mosaic falls out of memory, it is no longer accessible in Ginga. To avoid this, you must configure your session such that your Ginga data cache is sufficiently large (see “Customizing Ginga” in the manual).

To create a new mosaic, set the FOV and drag files onto the display window. Images must have a working WCS.

It is customizable using ~/.ginga/plugin_Mosaic.cfg, where ~ is your HOME directory:

#
# Mosaic plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Mosaic.cfg"

# annotate images with their names
annotate_images = False

# default FOV for new mosaics
fov_deg = 0.2

# Try to match backgrounds
match_bg = False

# Number of pixels to trim from edges
trim_px = 0

# Merge (coadd pixels) instead of overlapping tiles
merge = False

# Number of threads to devote to opening images
num_threads = 4

# dropping a new file or files starts a new mosaic
drop_creates_new_mosaic = False

# Set to True when you want to mosaic image HDUs in a file
mosaic_hdus = False

# Limit on skew between X and Y axis after warping tile acceptable for mosaic
skew_limit = 0.1

# Allow the mosaic image to expand if new tiles are added that
# aren't in the region
allow_expand = True

# When expanding an image, pad on a side by this many deg
expand_pad_deg = 0.01

# Maximum delta from center of image (in deg) beyond which new images
# are assumed to start a new mosaic. Set to None if you never want this
# bahavior
max_center_deg_delta = 2.0

# Allow mosaic images to create thumbnail entries
make_thumbs = False

# Reuse existing mosaic for new mosaic (faster)
reuse_image = False
Drawing

A plugin for drawing canvas forms (overlaid graphics).

Plugin Type: Local

Drawing is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

This plugin can be used to draw many different shapes on the image display. When it is in “draw” mode, select a shape from the drop-down menu, adjust the shape’s parameters (if needed), and draw on the image by using left mouse button. You can choose to draw in pixel or WCS space.

To move or edit an existing shape, set the plugin on “edit” or “move” mode, respectively.

To save the drawn shape(s) as mask image, click the “Create Mask” button and you will see a new mask image created in Ginga. Then, use SaveImage plugin to save it out as single-extension FITS. Note that the mask will take the size of the displayed image. Therefore, to create masks for different image dimensions, you need to repeat the steps multiple times.

FBrowser

A plugin for browsing the local filesystem and loading files.

Plugin Type: Global or Local

FBrowser is a hybrid global/local plugin, which means it can be invoked in either fashion. If invoked as a local plugin then it is associated with a channel, and an instance can be opened for each channel. It can also be opened as a global plugin.

Usage

Navigate the directory tree until you come to the location files you want to load. You can double click a file to load it into the associated channel, or drag a file into a channel viewer window to load it into any channel viewer.

Multiple files can be selected by holding down Ctrl (Command on Mac), or Shift-clicking to select a contiguous range of files.

You may also enter full path to the desired image(s) in the text box as /my/path/to/image.fits, /my/path/to/image.fits[ext], /my/path/to/image*.fits, or /my/path/to/image*.fits[ext].

Because it is a local plugin, FBrowser will remember its last directory if closed and then restarted.

It is customizable using ~/.ginga/plugin_FBrowser.cfg, where ~ is your HOME directory:

#
# FBrowser plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_FBrowser.cfg"

# Set to a specific directory to choose a starting point for file exploration.
# If None is given, it defaults to your HOME.
home_path = None

# This controls whether the plugin scans the FITS headers to create the
# listing (slow for large numbers of files)
scan_fits_headers = False

# If the number of files in the listing is greater than this, don't do
# a scan on the headers
scan_limit = 100

# if scan_fits_headers is True, then the keywords provides a map between
# attributes and FITS header keywords to fetch from the header
keywords = [('Object', 'OBJECT'), ('Date', 'DATE-OBS'), ('Time UT', 'UT')]

# columns lists the column headers and attributes to show in the listing.
# If you want to include FITS keywords, be sure to include the attributes
# defined in the keywords preference (i.e., 'Time UT', 'Object')
columns = [('Type', 'icon'), ('Name', 'name'), ('Size', 'st_size_str'), ('Mode', 'st_mode_oct'), ('Last Changed', 'st_mtime_str')]

# If True, color every other row in alternating shades to improve
# readability of long tables
color_alternate_rows = True

# Maximum number of rows that will turn off auto column resizing (for speed)
max_rows_for_col_resize = 5000
Compose

A plugin for composing RGB images from constituent monochrome images.

Plugin Type: Local

Compose is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

Start the Compose plugin from the “Operations” menu – the tab should show up under “Dialogs”.

  1. Select the kind of composition you want to make from the “Compose Type” drop down: “RGB” for composing three monochrome images into a color image, “Alpha” to compose a series of images as layers with different alpha values for each layer.
  2. Press “New Image” to start composing a new image.

*For RGB composition*

  1. Drag your three constituent images that will make up the R, G, and B planes to the “Preview” window – drag them in the order R (red), G (green), and B (blue). Alternatively, you can load the images into the channel viewer one by one and after each one pressing “Insert from Channel” (similarly, do these in the order of R, G, and B).

In the plugin GUI, the R, G, and B images should show up as three slider controls in the “Layers” area of the plugin, and the Preview should show a low resolution version of how the composite image looks with the sliders set.

Composing an RGB image

Composing an RGB Image.

  1. Play with the alpha levels of each layer using the sliders in the Compose plugin; as you adjust a slider the preview image should update.
  2. When you see something you like, you can save it to a file using the “Save As” button (use “jpeg” or “png” as the file extension), or insert it into the channel using the “Save to Channel” button.

*For Alpha composition*

For Alpha-type composition the images are just combined in the order shown in the stack, with Layer 0 being the bottom layer, and successive layers stacked on top. Each layer’s alpha level is adjustible by a slider in the same manner as discussed above.

Alpha-composing an image

Alpha-composing an image.

  1. Drag your N constituent images that will make up the layers to the “Preview” window, or load the images into the channel viewer one by one and after each one pressing “Insert from Channel” (the first image will be at the bottom of the stack–layer 0).
  2. Play with the alpha levels of each layer using the sliders in the Compose plugin; as you adjust a slider the preview image should update.
  3. When you see something you like, you can save it to a file using the “Save As” button (use “fits” as the file extension), or insert it into the channel using the “Save to Channel” button.

*General Notes*

  • The preview window is just a ginga widget, so all the usual bindings apply; you can set color maps, cut levels, etc. with the mouse and key bindings.
PlotTable
PlotTable display

A plugin to display basic plot for any two selected columns in a table.

Plugin Type: Local

PlotTable is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

PlotTable is a plugin designed to plot any two selected columns for a given FITS table HDU (can be accessed via MultiDim). For masked columns, masked data is not shown (even if only one of the (X, Y) pair is masked). It is meant as a way to quickly look at table data and not for detailed scientific analysis.

It is customizable using ~/.ginga/plugin_PlotTable.cfg, where ~ is your HOME directory:

#
# PlotTable plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_PlotTable.cfg"

# matplotlib options for plotted line
linewidth = 1
linestyle = '-'
linecolor = 'blue'

# matplotlib options for markers
markersize = 6
markerwidth = 0.5
markerstyle = 'o'
markercolor = 'red'

# Show markers (can also be set in GUI)
show_marker = True

# Table column numbers to plot (can also be set in GUI).
# 0 = row indices, not the first table column
x_index = 1
y_index = 2

# Output file suffix (as accepted by matplotlib)
file_suffix = '.png'
Pipeline

Simple data reduction pipeline plugin for Ginga.

Note

This plugin is available but not loaded into Ginga reference viewer by default because it is experimental.

Plugin Type: Local

Pipeline is a local plugin, which means it is associated with a channel. An instance can be opened for each channel.

Usage

It is customizable using ~/.ginga/plugin_Pipeline.cfg, where ~ is your HOME directory:

#
# Pipeline plugin preferences file
#
# Place this in file under ~/.ginga with the name "plugin_Pipeline.cfg"

num_threads = 4
ScreenShot
ScreenShot plugin

Capture PNG or JPEG images of the channel viewer image.

Usage

  1. Select the RGB graphics type for the snap from the “Type” combo box.
  2. Press “Snap” when you have the channel image the way you want to capture it.

A copy of the RGB image will be loaded into the ScreenShot viewer. You can pan and zoom within the ScreenShot viewer like a normal Ginga viewer to examine detail (e.g., see the magnified difference between JPEG and PNG formats).

  1. Repeat (1) and (2) until you have the image you want.
  2. Enter a valid path for a new file into the “Folder” text box.
  3. Enter a valid name for a new file into the “Name” text box. There is no need to add the file extension; it will be added, if needed.
  4. Press the “Save” button. The file will be saved where you specified.

Notes

  • PNG offers less artifacts for overlaid graphics, but files are larger than JPEG.
  • The “Center” button will center the snap image; “Fit” will set the zoom to fit it to the window; and “Clear” will clear the image.
  • Press “1” in the screenshot viewer to zoom to 100% pixels.

Customizing Ginga

One of the primary guiding concepts behind the Ginga project is to provide convenient ways to build custom viewers. The reference viewer embodies this concept through the use of a flexible layout engine and the use of plugins to implement all the major user interface features. By modifying or replacing the layout and adding, subclassing or removing plugins you can completely change the look, feel and operation of the reference viewer.

This chapter explains how you can customize the Ginga reference viewer in various ways, as a user or a developer.

Configuration Options

Ginga examines a configuration directory on startup to check for any configuration files or customization of the default behavior.

Note

The configuration area is determined first by examining the environment variable GINGA_HOME. If that is not set, then $HOME/.ginga (Mac OS X, Linux) or $HOMEDRIVE:$HOMEPATH\\.ginga (Windows) will be used.

Examples of the types of configuration files with comments describing the effects of the parameters can be found in .../ginga/examples/configs. Many of the plugins have their own configuration file, with preferences that are only changed via that file. You can copy an example configuration file to your Ginga settings area and change the settings to your liking.

Usually it is sufficient to simply close the plugin and open it again to pick up any settings changes, but some changes may require a viewer restart to take effect.

Channels also use configuration files to store many different settings for the channel viewer windows. When a channel is created, the reference viewer looks to see if there is a configuration file for that channel in the configuration area; if so, the settings therein are used to configure it. If not, the settings for the generic startup channel “Image” are used to configure the new channel. The “Preferences” plugin can be used to set many of the channel settings. If you set these for the “Image” channel and use the “Save” button, other channels will inherit them. You can also manually copy the example file from .../ginga/examples/configs/channel_Image.cfg to your configuration area and edit it if you prefer.

Saving the workspace layout between sessions

By default, Ginga will will write its window size, position and some layout information to a “layout” file in the configuration directory when the program is closed. Upon a subsequent startup Ginga will attempt to restore the window to the saved configuration. If this behavior is not desired you can add the option save_layout = False to your general.cfg file in the Ginga configuration directory.

There is a sample general.cfg file in .../ginga/examples/configs.

Invoking the program with the --norestore option also prevents it from reading the saved layout file. This may be needed in some cases when the layout changes in an incompatible way between when the program was last stopped and when it was started again.

Rebinding Controls

One configuration file that many users will be interested in is the one controlling how keyboard and mouse/touch bindings are assigned. This is handled by the configuration file bindings.cfg. Several examples are stored in .../ginga/examples/bindings, including an example for users familiar with the ds9 mouse controls, and an example for users using a touchpad without a mouse (pinch zoom and scroll panning). Simply copy the appropriate file to your Ginga settings area as bindings.cfg.

Customizing the Reference Viewer During Initialization

The reference viewer can be customized during viewer initialization using a module called ginga_config, which can be anywhere in the user’s Python import path, including in the Ginga configuration folder described above (e.g. $HOME/.ginga/ginga_config.py).

Specifically, this file will be imported and two methods will be run if defined: pre_gui_config(ginga_shell) and post_gui_config(ginga_shell). The parameter to each function is the main viewer shell. These functions can be used to define a different viewer layout, add or remove plugins, add menu entries, add custom image or star catalogs, etc. We will refer back to these functions in the sections below.

Workspace configuration

Ginga has a flexible table-driven layout scheme for dynamically creating workspaces and mapping the available plugins to workspaces. By changing a couple of tables via ginga_config.pre_gui_config() you can change the way Ginga looks and presents its content.

If you examine the module ginga.rv.main you will find a layout table called default_layout:

default_layout = ['seq', {},
                   ['vbox', dict(name='top', width=1400, height=700),
                    dict(row=['hbox', dict(name='menu')],
                         stretch=0),
                    dict(row=['hpanel', dict(name='hpnl'),
                     ['ws', dict(name='left', wstype='tabs',
                                 width=300, height=-1, group=2),
                      # (tabname, layout), ...
                      [("Info", ['vpanel', {},
                                 ['ws', dict(name='uleft', wstype='stack',
                                             height=250, group=3)],
                                 ['ws', dict(name='lleft', wstype='tabs',
                                             height=330, group=3)],
                                 ]
                        )]],
                     ['vbox', dict(name='main', width=600),
                      dict(row=['ws', dict(name='channels', wstype='tabs',
                                           group=1, use_toolbar=True)],
                           stretch=1),
                      dict(row=['ws', dict(name='cbar', wstype='stack',
                                           group=99)], stretch=0),
                      dict(row=['ws', dict(name='readout', wstype='stack',
                                           group=99)], stretch=0),
                      dict(row=['ws', dict(name='operations', wstype='stack',
                                           group=99)], stretch=0),
                      ],
                     ['ws', dict(name='right', wstype='tabs',
                                 width=400, height=-1, group=2),
                      # (tabname, layout), ...
                      [("Dialogs", ['ws', dict(name='dialogs', wstype='tabs',
                                               group=2)
                                    ]
                        )]
                      ],
                     ], stretch=1),
                    dict(row=['ws', dict(name='toolbar', wstype='stack',
                                         height=40, group=2)],
                         stretch=0),
                    dict(row=['hbox', dict(name='status')], stretch=0),
                    ]]

This rather arcane-looking table defines the precise layout of the reference viewer shell, including how many workspaces it will have, their characteristics, how they are organized, and their names.

The key point in this section is that you can modify this table or replace it entirely with one of your own design and set it in the pre_gui_config() method described above:

my_layout = [
              ...
             ]

def pre_gui_config(ginga_shell):
    ...

    ginga_shell.set_layout(my_layout)

If done in the pre_gui_config() method (as shown) the new layout will be the one that is used when the GUI is constructed.

Format of the Layout Table

The table consists of a nested list of sublists, tuples and/or dictionaries. The first item in a sublist indicates the type of the container to be constructed. The following types are available:

  • seq: defines a sequence of top-level windows to be created
  • hpanel: a horizontal panel of containers, with handles to size them
  • vpanel: a vertical panel of containers, with handles to size them
  • hbox: a horizontal panel of containers of fixed size
  • vbox: a vertical panel of containers of fixed size
  • ws: a workspace that allows a plugin or a channel viewer to be loaded into it. A workspace can be configured in four ways: as a tabbed notebook (wstype="tabs"), as a stack (wstype="stack"), as an MDI (Multiple Document Interface, wstype="mdi") or a grid (wstype="grid").
  • widget: a preconstructed widget passed in.

In every case the second item in the sublist is a dictionary that provides some optional parameters that modify the characteristics of the container. If there is no need to override the default parameters the dictionary can simply be empty. The optional third and following items are specifications for nested content.

All types of containers honor the following parameters:

  • width: can specify a desired width in pixels for the container.
  • height: can specify a desired height in pixels for the container.
  • name: specifies a mapping of a name to the created container widget. The name is important especially for workspaces, as they may be referred to as an output destination when registering plugins.

Note

In the above example, we define a top-level window consisting of a vbox (named “top”) with 4 layers: a hbox (“menu”), hpanel (“hpnl”), a workspace (“toolbar”) and another hbox (“status”). The main horizontal panel of three containers: a workspace (“left”) with a width of 300 pixels, a vbox (“main”, 700 pixels) and a workspace (“right”, 400 pixels). The “left” workspace is pre-populated with an “Info” tab containing a vertical panel of two workspaces: “uleft” and “lleft” with heights of 300 and 430 pixels, respectively. The “right” workspace is pre-populated with a “Dialogs” tab containing an empty workspace. The “main” vbox is configured with three rows of workspaces: “channels”, “cbar” and “readout”.

Ginga uses some container names in special ways. For example, Ginga looks for a “channels” workspace as the default workspace for creating channels, and the “dialogs” workspace is where most local plugins are instantiated (when activated), by default. These two names should at least be defined somewhere in default_layout.

Auto-Start Plugins

Not all plugins provided by Ginga are automatically started up by default. A plugin can be started automatically in post_gui_config() using the start_global_plugin() or start_local_plugin() methods, as appropriate:

def post_gui_config(ginga_shell):
    # Auto start global plugins
    ginga_shell.start_global_plugin('Zoom')
    ginga_shell.start_global_plugin('Header')

    # Auto start local plugin
    ginga_shell.add_channel('Image')
    ginga_shell.start_local_plugin('Image', 'Histogram', None)

Alternately, you can also start plugins via the command line interface using --plugins and -modules for local and global plugins, respectively. To load multiple plugins at once, use a comma-separated list. For example:

ginga --plugins=MyLocalPlugin,Imexam --modules=MyGlobalPlugin
Adding Plugins

A plugin can be added to the reference viewer in pre_gui_config() using the add_plugin() method with a specification (“spec”) for the plugin:

from ginga.misc.Bunch import Bunch

def pre_gui_config(ginga_shell):
    ...

    spec = Bunch(module='DQCheck', klass='DQCheck', workspace='dialogs',
                 category='Utils', ptype='local')
    ginga_shell.add_plugin(spec)

The above call would try to load a local plugin called “DQCheck” from a module called “DQCheck”. When invoked from the Operations menu it would occupy a spot in the “dialogs” workspace (see layout discussion above).

Other keywords that can be used in a spec:

  • Global plugins use ptype='global'.
  • If a plugin should be hidden from the menus (e.g. it is started under program control, not by the user), specify hidden=True.
  • If the plugin should be started when the program starts, specify start=True.
  • To use a different name in the menu for starting the plugin, specify menu="Custom Name".
  • To use a different name in the tab that is showing the plugin GUI, specify tab="Tab Name".
  • To prevent a control icon from appearing in the Operations plugin manager tray specify optray=False.
Disabling Plugins

Both local and global plugins can be disabled (thus, not shown in the reference viewer) using the --disable-plugins option in the command line interface. To remove multiple plugins at once, use a comma-separated list. For example:

ginga --disable-plugins=Zoom,Compose

Alternately, plugins can also be disabled via general.cfg configuration file. For example:

disable_plugins = "Zoom,Compose"

Some plugins, like Operations, when disabled, may result in inconvenient GUI experience.

Making a Custom Startup Script

You can make a custom startup script to make the same reference viewer configuration available without relying on the ginga_config module in a personal settings area. To do this we make use of the main module:

import sys
from ginga.rv.main import ReferenceViewer
from optparse import OptionParser

my_layout = [ ... ]

plugins = [ ... ]

if __name__ == "__main__":
    viewer = ReferenceViewer(layout=my_layout)
    # add plugins
    for spec in plugins:
        viewer.add_plugin(spec)

    # Parse command line options with optparse module
    usage = "usage: %prog [options] cmd [args]"
    optprs = OptionParser(usage=usage)
    viewer.add_default_options(optprs)

    (options, args) = optprs.parse_args(sys_argv[1:])

    viewer.main(options, args)

Developing with Ginga

Developers interested in using Ginga in their project will probably follow one of two logical development paths:

  • using Ginga toolkit classes in a program of their own design, or
  • starting with the full-featured reference viewer that comes with Ginga and customizing it for some special purpose, typically by modifying one of the plugins or writing a new plugin.

The first approach is probably best for when the developer has a custom application in mind, needs a minimal but powerful viewer or wants to develop an entirely new full-featured viewer. Developers interested in this direction should head over to the chapter on the viewer object (see Using the Basic Ginga Viewer Object in Python Programs).

The second approach is probably best for end users or developers that are mostly satisfied with the reference viewer as a general purpose tool and want to add some specific enhancements or functionality. Because the reference viewer is based on a flexible plugin architecture this is fairly straightforward to do.

Writing plugins for the reference viewer

The philosophy behind the design of the reference viewer distributed with the Ginga is that it is simply a flexible layout shell for instantiating instances of the Ginga view widgets described in the earlier section. All of the other important pieces of a modern FITS viewer–a panning widget, information panels, zoom widget, analysis panes–are implemented as plugins: encapsulated modules that interface with the viewing shell using a standardized API. This makes it easy to customize and to add, change or remove functionality in a very modular, flexible way.

The Ginga viewer divides the application window GUI into containers that hold either viewing widgets or plugins. The view widgets are called “channels” in the viewer nomenclature, and are a means of organizing images in the viewer, functioning much like “frames” in other viewers. A channel has a name and maintains its own history of images that have cycled through it. The user can create new channels as needed. For example, they might use different channels for different kinds of images: camera vs. spectrograph, or channels organized by CCD, or by target, or raw data vs. quick look, etc. In the default layout, the channel tabs are in the large middle pane, while the plugins occupy the left and right panes. Other layouts are possible, by simply changing a table used in the startup script.

Ginga distinguishes between two types of plugin: global and local. Global plugins are used where the functionality is generally enabled during the entire session with the viewer and where the plugin is active no matter which channel is currently under interaction with the user. Examples of global plugins include a panning view (a small, bird’s-eye view of the image that shows a panning rectangle and allows graphical positioning of the pan region), a zoomed view (that shows an enlarged cutout of the area currently under the cursor), informational displays about world coordinates, FITS headers, thumbnails, etc. Figure Two global plugins: Pan (top) and Info (bottom), shown sharing a tab. shows an example of two global plugins occupying a notebook tab.

_images/global_plugin1.png

Two global plugins: Pan (top) and Info (bottom), shown sharing a tab.

Local plugins are used for modal operations with images in specific channels. For example, the Pick plugin is used to perform stellar evaluation of objects, finding the center of the object and giving informational readings of the exact celestial coordinates, image quality, etc. The Pick plugin is only visible while the user has it open, and does not capture the mouse actions unless the channel it is operating on is selected. Thus one can have two different Pick operations going on concurrently on two different channels, for example, or a Pick operation in a camera channel, and a Cuts (line cuts) operation on a spectrograph channel. Figure The Pick local plugin, shown occupying a tab. shows an example of the Pick local plugin occupying a notebook tab.

_images/local_plugin1.png

The Pick local plugin, shown occupying a tab.

Anatomy of a Local Ginga Plugin

Let’s take a look at a local plugin to understand the API for interfacing to the Ginga shell. In Listing 2, we show a stub for a local plugin.

from ginga import GingaPlugin

class MyPlugin(GingaPlugin.LocalPlugin):

    def __init__(self, fv, fitsimage):
        super(MyPlugin, self).__init__(fv, fitsimage)

    def build_gui(self, container):
        pass

    def start(self):
        pass

    def stop(self):
        pass

    def pause(self):
        pass

    def resume(self):
        pass

    def redo(self):
        pass

    def __str__(self):
        return 'myplugin'
A little more fleshed out example: MyLocalPlugin

This is a skeleton for a local plugin. It is also good example of something that actually runs and can be copied as a template for a local plugin. This plugin is distributed with the Ginga package and can be loaded and invoked from a terminal:

$ ginga –plugins=MyLocalPlugin –loglevel=20 –log=/tmp/ginga.log

The plugin will be accessible via the “Operation” button in the Plugin Manager bar.

from ginga import GingaPlugin
from ginga.misc import Widgets

# import any other modules you want here--it's a python world!

class MyLocalPlugin(GingaPlugin.LocalPlugin):

    def __init__(self, fv, fitsimage):
        """
        This method is called when the plugin is loaded for the  first
        time.  ``fv`` is a reference to the Ginga (reference viewer) shell
        and ``fitsimage`` is a reference to the specific ImageViewCanvas
        object associated with the channel on which the plugin is being
        invoked.
        You need to call the superclass initializer and then do any local
        initialization.
        """
        super(MyLocalPlugin, self).__init__(fv, fitsimage)

        # your local state and initialization code goes here

    def build_gui(self, container):
        """
        This method is called when the plugin is invoked.  It builds the
        GUI used by the plugin into the widget layout passed as
        ``container``.
        This method may be called many times as the plugin is opened and
        closed for modal operations.  The method may be omitted if there
        is no GUI for the plugin.

        This specific example uses the GUI widget set agnostic wrappers
        to build the GUI, but you can also just as easily use explicit
        toolkit calls here if you only want to support one widget set.
        """
        top = Widgets.VBox()
        top.set_border_width(4)

        # this is a little trick for making plugins that work either in
        # a vertical or horizontal orientation.  It returns a box container,
        # a scroll widget and an orientation ('vertical', 'horizontal')
        vbox, sw, orientation = Widgets.get_oriented_box(container)
        vbox.set_border_width(4)
        vbox.set_spacing(2)

        # Take a text widget to show some instructions
        self.msgFont = self.fv.getFont("sansFont", 12)
        tw = Widgets.TextArea(wrap=True, editable=False)
        tw.set_font(self.msgFont)
        self.tw = tw

        # Frame for instructions and add the text widget with another
        # blank widget to stretch as needed to fill emp
        fr = Widgets.Frame("Instructions")
        vbox2 = Widgets.VBox()
        vbox2.add_widget(tw)
        vbox2.add_widget(Widgets.Label(''), stretch=1)
        fr.set_widget(vbox2)
        vbox.add_widget(fr, stretch=0)

        # Add a spacer to stretch the rest of the way to the end of the
        # plugin space
        spacer = Widgets.Label('')
        vbox.add_widget(spacer, stretch=1)

        # scroll bars will allow lots of content to be accessed
        top.add_widget(sw, stretch=1)

        # A button box that is always visible at the bottom
        btns = Widgets.HBox()
        btns.set_spacing(3)

        # Add a close button for the convenience of the user
        btn = Widgets.Button("Close")
        btn.add_callback('activated', lambda w: self.close())
        btns.add_widget(btn, stretch=0)
        btns.add_widget(Widgets.Label(''), stretch=1)
        top.add_widget(btns, stretch=0)

        # Add our GUI to the container
        container.add_widget(top, stretch=1)
        # NOTE: if you are building a GUI using a specific widget toolkit
        # (e.g. Qt) GUI calls, you need to extract the widget or layout
        # from the non-toolkit specific container wrapper and call on that
        # to pack your widget, e.g.:
        #cw = container.get_widget()
        #cw.addWidget(widget, stretch=1)

    def close(self):
        """
        Example close method.  You can use this method and attach it as a
        callback to a button that you place in your GUI to close the plugin
        as a convenience to the user.
        """
        chname = self.fv.get_channel_name(self.fitsimage)
        self.fv.stop_local_plugin(chname, str(self))
        return True

    def start(self):
        """
        This method is called just after ``build_gui()`` when the plugin
        is invoked.  This method may be called many times as the plugin is
        opened and closed for modal operations.  This method may be omitted
        in many cases.
        """
        self.tw.set_text("""This plugin doesn't do anything interesting.""")
        self.resume()

    def pause(self):
        """
        This method is called when the plugin loses focus.
        It should take any actions necessary to stop handling user
        interaction events that were initiated in ``start()`` or
        ``resume()``.
        This method may be called many times as the plugin is focused
        or defocused.  It may be omitted if there is no user event handling
        to disable.
        """
        pass

    def resume(self):
        """
        This method is called when the plugin gets focus.
        It should take any actions necessary to start handling user
        interaction events for the operations that it does.
        This method may be called many times as the plugin is focused or
        defocused.  The method may be omitted if there is no user event
        handling to enable.
        """
        pass

    def stop(self):
        """
        This method is called when the plugin is stopped.
        It should perform any special clean up necessary to terminate
        the operation.  The GUI will be destroyed by the plugin manager
        so there is no need for the stop method to do that.
        This method may be called many  times as the plugin is opened and
        closed for modal operations, and may be omitted if there is no
        special cleanup required when stopping.
        """
        pass

    def redo(self):
        """
        This method is called when the plugin is active and a new
        image is loaded into the associated channel.  It can optionally
        redo the current operation on the new image.  This method may be
        called many times as new images are loaded while the plugin is
        active.  This method may be omitted.
        """
        pass

    def __str__(self):
        """
        This method should be provided and should return the lower case
        name of the plugin.
        """
        return 'mylocalplugin'

The instance variables “fv” and “fitsimage” will be assigned by the superclass initializer to self.fv and self.fitsimage–these are the reference viewer “shell” and the ginga display object respectively. To interact with the viewer you will be calling methods on one or both of these objects.

The best way to get a feel for these APIs is to look at the source of one of the many plugins distributed with Ginga. Most of them are not very long or complex. Also, a plugin can include any Python packages or modules that it wants and programming one is essentially similar to writing any other Python program.

Launching and Debugging Your Plugin

The easiest way to start out is to create a plugins directory under your ginga configuration area. In a terminal:

$ mkdir $HOME/.ginga/plugins

Put your plugin in there (a good one to start with is to modify the MyLocalPlugin example that comes with Ginga):

$ cd …/ginga/examples/reference-viewer $ cp MyLocalPlugin.py $HOME/.ginga/plugins/MyPlugin.py

To load it when the reference viewer starts (and add some logging to stderr as well as to a file):

$ ginga –plugins=MyPlugin –loglevel=20 –stderr –log=/tmp/ginga.log

To start the plugin from within the reference viewer, use the Plugin Manager bar just below the color and readout bars. Use the “Operation” menu to select your plugin and it should be launched in the right panel.

If you don’t see the name of your plugin in the Operation menu, then there was probably an error trying to load it. Examine the log and search for the name of your plugin–you should find some error message associated with it.

If you select your plugin from the menu, but it doesn’t launch a GUI, there may be a problem or error in the plugin file. Again, examine the log and search for the name of your plugin–you should find some error message associated with it. It may help for you to add some debugging messages to your plugin (either using self.logger.debug(“…”) or simple print statements to stdout) to gauge the progress of building the gui and plugin starting.

If the plugin launches, but encounters an error building the GUI, it should show some error messages (and probably a stack trace) in placeholders in the right panel in the container where it tried to build the GUI or possibly under the Errors tab.

Note

Ginga has a feature for quickly reloading plugins to facilitate rapid debugging cycles. If it is not already running, start the “Command” plugin from the “Plugins” menu in the menu bar. If your plugin launched (but has some error), make sure you have closed your plugin by right clicking (or Control + click on Mac touchpad) on the small box representing your plugin in the Plugin Manager bar and selecting “Stop”. In the Command plugin, use the command “reload_local <plugin_name>”–this will reload the python module representing your plugin and you should be able to immediately restart it using the Plugin Manager bar as described above (if the plugin is of the global plugin variety, use the command “reload_global” instead).

If you have edited third party modules that are included in the plugin, this will not be enough to pick up those changes.

A more complex example: The Ruler Plugin

Finally, in Listing 3 we show a completed plugin for Ruler. The purpose of this plugin to draw triangulation (distance measurement) rulers on the image. For reference, you may want to refer to the ruler shown in The Ruler local plugin GUI, shown occupying a tab..

_images/ruler_plugin.png

The Ruler local plugin GUI, shown occupying a tab.

#
# Ruler.py -- Ruler plugin for Ginga reference viewer
#
from ginga import GingaPlugin
from ginga.gw import Widgets

class Ruler(GingaPlugin.LocalPlugin):

    def __init__(self, fv, fitsimage):
        # superclass defines some variables for us, like logger
        super(Ruler, self).__init__(fv, fitsimage)

        self.rulecolor = 'green'
        self.layertag = 'ruler-canvas'
        self.ruletag = None

        self.dc = fv.getDrawClasses()
        canvas = self.dc.DrawingCanvas()
        canvas.enable_draw(True)
        canvas.enable_edit(True)
        canvas.set_drawtype('ruler', color='cyan')
        canvas.set_callback('draw-event', self.wcsruler)
        canvas.set_callback('draw-down', self.clear)
        canvas.set_callback('edit-event', self.edit_cb)
        canvas.set_draw_mode('draw')
        canvas.set_surface(self.fitsimage)
        canvas.register_for_cursor_drawing(self.fitsimage)
        canvas.name = 'Ruler-canvas'
        self.canvas = canvas

        self.w = None
        self.unittypes = ('arcmin', 'degrees', 'pixels')
        self.units = 'arcmin'

    def build_gui(self, container):
        top = Widgets.VBox()
        top.set_border_width(4)

        vbox, sw, orientation = Widgets.get_oriented_box(container)
        vbox.set_border_width(4)
        vbox.set_spacing(2)

        self.msgFont = self.fv.getFont("sansFont", 12)
        tw = Widgets.TextArea(wrap=True, editable=False)
        tw.set_font(self.msgFont)
        self.tw = tw

        fr = Widgets.Expander("Instructions")
        fr.set_widget(tw)
        vbox.add_widget(fr, stretch=0)

        fr = Widgets.Frame("Ruler")

        captions = (('Units:', 'label', 'Units', 'combobox'),
                    )
        w, b = Widgets.build_info(captions, orientation=orientation)
        self.w = b

        combobox = b.units
        for name in self.unittypes:
            combobox.append_text(name)
        index = self.unittypes.index(self.units)
        combobox.set_index(index)
        combobox.add_callback('activated', lambda w, idx: self.set_units())

        fr.set_widget(w)
        vbox.add_widget(fr, stretch=0)

        mode = self.canvas.get_draw_mode()
        hbox = Widgets.HBox()
        btn1 = Widgets.RadioButton("Draw")
        btn1.set_state(mode == 'draw')
        btn1.add_callback('activated', lambda w, val: self.set_mode_cb('draw', val))
        btn1.set_tooltip("Choose this to draw a ruler")
        self.w.btn_draw = btn1
        hbox.add_widget(btn1)

        btn2 = Widgets.RadioButton("Edit", group=btn1)
        btn2.set_state(mode == 'edit')
        btn2.add_callback('activated', lambda w, val: self.set_mode_cb('edit', val))
        btn2.set_tooltip("Choose this to edit a ruler")
        self.w.btn_edit = btn2
        hbox.add_widget(btn2)

        hbox.add_widget(Widgets.Label(''), stretch=1)
        vbox.add_widget(hbox, stretch=0)

        spacer = Widgets.Label('')
        vbox.add_widget(spacer, stretch=1)

        top.add_widget(sw, stretch=1)

        btns = Widgets.HBox()
        btns.set_spacing(3)

        btn = Widgets.Button("Close")
        btn.add_callback('activated', lambda w: self.close())
        btns.add_widget(btn, stretch=0)
        btns.add_widget(Widgets.Label(''), stretch=1)
        top.add_widget(btns, stretch=0)

        container.add_widget(top, stretch=1)

    def set_units(self):
        index = self.w.units.get_index()
        units = self.unittypes[index]
        self.canvas.set_drawtype('ruler', color='cyan', units=units)

        if self.ruletag is not None:
            obj = self.canvas.getObjectByTag(self.ruletag)
            if obj.kind == 'ruler':
                obj.units = units
                self.canvas.redraw(whence=3)
        return True

    def close(self):
        chname = self.fv.get_channelName(self.fitsimage)
        self.fv.stop_local_plugin(chname, str(self))
        return True

    def instructions(self):
        self.tw.set_text("""Draw (or redraw) a line with the cursor.

Display the Zoom tab at the same time to precisely see detail while drawing.""")

    def start(self):
        self.instructions()
        # start ruler drawing operation
        p_canvas = self.fitsimage.get_canvas()
        if not p_canvas.has_object(self.canvas):
            p_canvas.add(self.canvas, tag=self.layertag)

        self.canvas.delete_all_objects()
        self.resume()

    def pause(self):
        self.canvas.ui_setActive(False)

    def resume(self):
        self.canvas.ui_setActive(True)
        self.fv.showStatus("Draw a ruler with the right mouse button")

    def stop(self):
        # remove the canvas from the image
        p_canvas = self.fitsimage.get_canvas()
        try:
            p_canvas.delete_object_by_tag(self.layertag)
        except:
            pass
        self.canvas.ui_setActive(False)
        self.fv.showStatus("")

    def redo(self):
        obj = self.canvas.get_object_by_tag(self.ruletag)
        if obj.kind != 'ruler':
            return True
        # redraw updates ruler measurements
        self.canvas.redraw(whence=3)

    def clear(self, canvas, button, data_x, data_y):
        self.canvas.delete_all_objects()
        self.ruletag = None
        return False

    def wcsruler(self, surface, tag):
        obj = self.canvas.get_object_by_tag(tag)
        if obj.kind != 'ruler':
            return True
        # remove the old ruler
        try:
            self.canvas.delete_object_by_tag(self.ruletag)
        except:
            pass

        # change some characteristics of the drawn image and
        # save as the new ruler
        self.ruletag = tag
        obj.color = self.rulecolor
        obj.cap = 'ball'
        self.canvas.redraw(whence=3)

    def edit_cb(self, canvas, obj):
        self.redo()
        return True

    def edit_select_ruler(self):
        if self.ruletag is not None:
            obj = self.canvas.get_object_by_tag(self.ruletag)
            self.canvas.edit_select(obj)
        else:
            self.canvas.clear_selected()
        self.canvas.update_canvas()

    def set_mode_cb(self, mode, tf):
        if tf:
            self.canvas.set_draw_mode(mode)
            if mode == 'edit':
                self.edit_select_ruler()
        return True

    def __str__(self):
        return 'ruler'

#END

This plugin shows a standard design pattern typical to local plugins. Often one is wanting to draw or plot something on top of the image below. The ImageViewCanvas widget used by Ginga allows this to be done very cleanly and conveniently by adding a DrawingCanvas object to the image and drawing on that. Canvases can be layered on top of each other in a manner analogous to “layers” in an image editing program. Since each local plugin maintains it’s own canvas, it is very easy to encapsulate the logic for drawing on and dealing with the objects associated with that plugin. We use this technique in the Ruler plugin. When the plugin is loaded (refer to __init__() method), it creates a canvas, enables drawing on it, sets the draw type and registers a callback for drawing events. When start() is called it adds that canvas to the widget. When stop() is called it removes the canvas from the widget (but does not destroy the canvas). pause() disables user interaction on the canvas and resume() reenables that interaction. redo() simply redraws the ruler with new measurements taken from any new image that may have been loaded. In the __init__() method you will notice a setSurface() call that associates this canvas with a ImageView-based widget–this is the key for the canvas to utilize WCS information for correct plotting. All the other methods shown are support methods for doing the ruler drawing operation and interacting with the plugin GUI.

Writing a Global Plugin

The last example was focused on writing a local plugin. Global plugins employ a nearly identical API to that shown in Listing 2, except that the constructor does not take a fitsimage parameter. pause() and resume() can safely be omitted. Like local plugins, build_gui() can be omitted if there is no GUI associated with the plugin.

A template: MyGlobalPlugin

This is a skeleton for a global plugin, and serves as a decent example of something that can be copied as a template for a global plugin. This plugin is distributed with the Ginga package and can be loaded and invoked from a terminal:

$ ginga –modules=MyGlobalPlugin –loglevel=20 –log=/tmp/ginga.log

The plugin will be started at program startup and can be seen in the “MyGlobalPlugin” tab in the right panel. Watch the status message as you create new channels, delete channels or load images into channels.

from ginga import GingaPlugin
from ginga.misc import Widgets

# import any other modules you want here--it's a python world!

class MyGlobalPlugin(GingaPlugin.GlobalPlugin):

    def __init__(self, fv):
        """
        This method is called when the plugin is loaded for the  first
        time.  ``fv`` is a reference to the Ginga (reference viewer) shell.

        You need to call the superclass initializer and then do any local
        initialization.
        """
        super(MyGlobalPlugin, self).__init__(fv)

        # Your initialization here

        # Create some variables to keep track of what is happening
        # with which channel
        self.active = None

        # Subscribe to some interesting callbacks that will inform us
        # of channel events.  You may not need these depending on what
        # your plugin does
        fv.set_callback('add-channel', self.add_channel)
        fv.set_callback('delete-channel', self.delete_channel)
        fv.set_callback('active-image', self.focus_cb)

    def build_gui(self, container):
        """
        This method is called when the plugin is invoked.  It builds the
        GUI used by the plugin into the widget layout passed as
        ``container``.
        This method could be called several times if the plugin is opened
        and closed.  The method may be omitted if there is no GUI for the
        plugin.

        This specific example uses the GUI widget set agnostic wrappers
        to build the GUI, but you can also just as easily use explicit
        toolkit calls here if you only want to support one widget set.
        """
        top = Widgets.VBox()
        top.set_border_width(4)

        # this is a little trick for making plugins that work either in
        # a vertical or horizontal orientation.  It returns a box container,
        # a scroll widget and an orientation ('vertical', 'horizontal')
        vbox, sw, orientation = Widgets.get_oriented_box(container)
        vbox.set_border_width(4)
        vbox.set_spacing(2)

        # Take a text widget to show some instructions
        self.msgFont = self.fv.getFont("sansFont", 12)
        tw = Widgets.TextArea(wrap=True, editable=False)
        tw.set_font(self.msgFont)
        self.tw = tw

        # Frame for instructions and add the text widget with another
        # blank widget to stretch as needed to fill emp
        fr = Widgets.Frame("Status")
        vbox2 = Widgets.VBox()
        vbox2.add_widget(tw)
        vbox2.add_widget(Widgets.Label(''), stretch=1)
        fr.set_widget(vbox2)
        vbox.add_widget(fr, stretch=0)

        # Add a spacer to stretch the rest of the way to the end of the
        # plugin space
        spacer = Widgets.Label('')
        vbox.add_widget(spacer, stretch=1)

        # scroll bars will allow lots of content to be accessed
        top.add_widget(sw, stretch=1)

        # A button box that is always visible at the bottom
        btns = Widgets.HBox()
        btns.set_spacing(3)

        # Add a close button for the convenience of the user
        btn = Widgets.Button("Close")
        btn.add_callback('activated', lambda w: self.close())
        btns.add_widget(btn, stretch=0)
        btns.add_widget(Widgets.Label(''), stretch=1)
        top.add_widget(btns, stretch=0)

        # Add our GUI to the container
        container.add_widget(top, stretch=1)
        # NOTE: if you are building a GUI using a specific widget toolkit
        # (e.g. Qt) GUI calls, you need to extract the widget or layout
        # from the non-toolkit specific container wrapper and call on that
        # to pack your widget, e.g.:
        #cw = container.get_widget()
        #cw.addWidget(widget, stretch=1)

    def get_channel_info(self, fitsimage):
        chname = self.fv.get_channelName(fitsimage)
        chinfo = self.fv.get_channelInfo(chname)
        return chinfo

    def set_info(self, text):
        self.tw.set_text(text)

    # CALLBACKS

    def add_channel(self, viewer, chinfo):
        """
        Callback from the reference viewer shell when a channel is added.
        """
        self.set_info("Channel '%s' has been added" % (
                chinfo.name))
        # Register for new image callbacks on this channel's canvas
        fitsimage = chinfo.fitsimage
        fitsimage.set_callback('image-set', self.new_image_cb)

    def delete_channel(self, viewer, chinfo):
        """
        Callback from the reference viewer shell when a channel is deleted.
        """
        self.set_info("Channel '%s' has been deleted" % (
                chinfo.name))
        return True

    def focus_cb(self, viewer, fitsimage):
        """
        Callback from the reference viewer shell when the focus changes
        between channels.
        """
        chinfo = self.get_channel_info(fitsimage)
        chname = chinfo.name

        if self.active != chname:
            # focus has shifted to a different channel than our idea
            # of the active one
            self.active = chname
            self.set_info("Focus is now in channel '%s'" % (
                self.active))
        return True

    def new_image_cb(self, fitsimage, image):
        """
        Callback from the reference viewer shell when a new image has
        been added to a channel.
        """
        chinfo = self.get_channel_info(fitsimage)
        chname = chinfo.name

        # Only update our GUI if the activity is in the focused
        # channel
        if self.active == chname:
            imname = image.get('name', 'NONAME')
            self.set_info("A new image '%s' has been added to channel %s" % (
                imname, chname))
        return True

    def start(self):
        """
        This method is called just after ``build_gui()`` when the plugin
        is invoked.  This method could be called more than once if the
        plugin is opened and closed.  This method may be omitted
        in many cases.
        """
        pass

    def stop(self):
        """
        This method is called when the plugin is stopped.
        It should perform any special clean up necessary to terminate
        the operation.  This method could be called more than once if
        the plugin is opened and closed, and may be omitted if there is no
        special cleanup required when stopping.
        """
        pass

    def close(self):
        self.fv.stop_global_plugin(str(self))
        return True

    def __str__(self):
        """
        This method should be provided and should return the lower case
        name of the plugin.
        """
        return 'myglobalplugin'
Writing Separately Installable Plugins

If you want to distribute your plugin(s) as a separately installable package and have Ginga discover them when it starts up, you can use the Ginga Plugin Template to write your own package that installs plugins.

You can include as many plugins in your package as you want. You write your plugins in exactly the same way as described above, and they can be either global or local. For details, clone the repo at the link above and follow the directions in the README.

Using the Basic Ginga Viewer Object in Python Programs

The core design principle of the Ginga project is to make it possible to easily build powerful image viewers in Python with many possible GUI toolkits.

This chapter is for developers who want to use only the Ginga rendering class in a program of their own design (not customizing the reference viewer).

Using the basic rendering class in new programs

Ginga basically follows the Model-View-Controller (MVC) design pattern, that is described in more detail in the chapter on internals (see Ginga Internals). The “view” classes are rooted in the base class ImageView. Ginga supports backends for different widget sets through various subclasses of this class.

Typically, a developer picks a GUI toolkit that has a supported backend (Gtk 2/3, Qt 4/5, Tk, matplotlib, HTML5 canvas) and writes a GUI program using that widget set with the typical Python toolkit bindings and API. Where they want a image view pane they instantiate the appropriate subclass of ImageView, and using the get_widget() call extract the native widget and insert it into the GUI layout. A reference should also be kept to the view object, as this is typically what you will be calling methods on to control the viewer.

Ginga does not create any additional GUI components beyond the image pane itself, however it does provide a standard set of keyboard and mouse bindings on the host widget that can be enabled, disabled or changed. The user interface bindings are configurable via a pluggable Bindings class which constitutes the “controller” part of the MVC design. There are a plethora of callbacks that can be registered, allowing the user to create their own custom user interface for manipulating the view. Of course, the developer can add many different GUI widgets from the selected toolkit to supplement or replace these built in controls.

_images/barebonesviewer_qt.png

A simple, “bare bones” FITS viewer written in Qt.

Listing 1 shows a code listing for a simple graphical FITS viewer built using the subclass ImageViewCanvas from the module ImageViewCanvasQt (screenshot in Figure A simple, “bare bones” FITS viewer written in Qt.) written in around 100 or so lines of Python. It creates a window containing an image view and two buttons. This example will open FITS files dragged and dropped on the image window or via a dialog popped up when clicking the “Open File” button.

#
# example1_qt.py -- Simple FITS viewer using the Ginga toolkit and Qt widgets.
#
import sys, os
import logging

from ginga import AstroImage
from ginga.misc import log
from ginga.qtw.QtHelp import QtGui, QtCore
from ginga.qtw.ImageViewCanvasQt import ImageViewCanvas


class FitsViewer(QtGui.QMainWindow):

    def __init__(self, logger):
        super(FitsViewer, self).__init__()
        self.logger = logger

        fi = ImageViewCanvas(self.logger, render='widget')
        fi.enable_autocuts('on')
        fi.set_autocut_params('zscale')
        fi.enable_autozoom('on')
        fi.set_callback('drag-drop', self.drop_file)
        fi.set_bg(0.2, 0.2, 0.2)
        fi.ui_setActive(True)
        fi.enable_draw(False)
        self.fitsimage = fi

        bd = fi.get_bindings()
        bd.enable_all(True)

        w = fi.get_widget()
        w.resize(512, 512)

        vbox = QtGui.QVBoxLayout()
        vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2))
        vbox.setSpacing(1)
        vbox.addWidget(w, stretch=1)

        hbox = QtGui.QHBoxLayout()
        hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2))

        wopen = QtGui.QPushButton("Open File")
        wopen.clicked.connect(self.open_file)
        wquit = QtGui.QPushButton("Quit")
        wquit.clicked.connect(self.quit)

        hbox.addStretch(1)
        for w in (wopen, wquit):
            hbox.addWidget(w, stretch=0)

        hw = QtGui.QWidget()
        hw.setLayout(hbox)
        vbox.addWidget(hw, stretch=0)

        vw = QtGui.QWidget()
        self.setCentralWidget(vw)
        vw.setLayout(vbox)

    def load_file(self, filepath):
        image = AstroImage.AstroImage(logger=self.logger)
        image.load_file(filepath)
        self.fitsimage.set_image(image)
        self.setWindowTitle(filepath)

    def open_file(self):
        res = QtGui.QFileDialog.getOpenFileName(self, "Open FITS file",
                                                ".", "FITS files (*.fits)")
        if isinstance(res, tuple):
            fileName = res[0]
        else:
            fileName = str(res)
        if len(fileName) != 0:
            self.load_file(fileName)

    def drop_file(self, fitsimage, paths):
        fileName = paths[0]
        self.load_file(fileName)

    def quit(self, *args):
        self.logger.info("Attempting to shut down the application...")
        self.deleteLater()


def main(options, args):

    app = QtGui.QApplication(sys.argv)

    # ginga needs a logger.
    # If you don't want to log anything you can create a null logger by
    # using null=True in this call instead of log_stderr=True
    logger = log.get_logger("example1", log_stderr=True)

    w = FitsViewer(logger)
    w.resize(524, 540)
    w.show()
    app.setActiveWindow(w)
    w.raise_()
    w.activateWindow()

    if len(args) > 0:
        w.load_file(args[0])

    app.exec_()

if __name__ == '__main__':
    main(None, sys.argv[1:])

Looking at the constructor for this particular viewer, you can see where we create a ImageViewCanvas object. On this object we enable automatic cut levels (using the ‘zscale’ algorithm), configure it to auto zoom the image to fit the window and set a callback function for files dropped on the window. We extract the user-interface bindings with get_bindings(), and on this object enable standard user interactive controls for all the possible key and mouse operations. We then extract the platform-specific widget (Qt-based, in this case) using get_widget() and pack it into a Qt container along with a couple of buttons to complete the viewer.

Scanning down the code a bit, we can see that whether by dragging and dropping or via the click to open, we ultimately call the load_file() method to get the data into the viewer. As shown, load_file creates an AstroImage object (the “model” part of our MVC design). It then passes this object to the viewer via the set_image() method. AstroImage objects have methods for ingesting data via a file path, an astropy.io.fits HDU or a bare Numpy data array.

Many of these sorts of examples for all supported backends are contained in the examples directory in the source distribution.

For a list of many methods provided by the viewer object, click on the module index link at the top of this chapter and then click on the link for ImageViewBase.

Graphics plotting with Ginga
_images/example2_screenshot.png

An example of a ImageViewCanvas widget with graphical overlay.

An ImageViewCanvas actually combines a view with a canvas object (in particular a DrawingCanvas object). You can get more detail about canvases and the objects they support (see Ginga Canvas Graphics). A variety of graphical shapes are available, and plotted objects scale, transform and rotate seamlessly with the viewer.

Rendering into Matplotlib Figures

Ginga can also render directly into a Matplotlib Figure, which opens up possibilities for overplotting beyond the limited capabilities of the Ginga canvas items. See the examples under “examples/matplotlib” for ideas, particularly “example4_mpl.py”.

Rendering into HTML5 canvases

Ginga can render onto HTML5 canvases displayed in a web browser. This opens up interesting possibilities for server-based remote viewing tools. See the examples under “examples/pg”, particularly “example2_pg.py”.

Writing widget toolkit independent code

You can write code that allows the widget set to be abstracted by Ginga’s widget wrappers. This is the same technique used to allow the reference viewer to switch between supported toolkits using the “-t” command line option. Currently only Qt (4/5), Gtk (2/3), and HTML5 (to a more limited degree) are supported, and there are some limitations compared to developing using a native toolkit directly. Nevertheless, the ability to target different platforms just by changing a command line option is a very interesting proposition.

See the examples under “examples/gw”, particularly “example2.py”.

Ginga Internals

This chapter explains the secret inner workings of Ginga and its classes so that you can subclass them and use them in your own applications.

Introduction

Ginga uses a version of the Model-View-Controller design pattern. The MVC pattern spells out a division of responsibilities and encapsulation where the Model provides various ways to access and interface to the data, the View provides ways to display the data and the Controller provides the methods and user interface hooks for controlling the view.

The Model
_images/class_structure_astroimage.png

Hierarchy of Ginga AstroImage class

The Model classes are rooted in the base class BaseImage. The basic interface to the data is expected to be a Numpy-like array object that is obtained via the get_data() method on the model. It also provides methods for obtaining scaled, cutouts and transformed views of the data, and methods for getting and setting key-value like metadata.

There are two subclasses defined on BaseImage: RGBImage and AstroImage. RGBImage is used for displaying 3 channel RGB type images such as JPEG, TIFF, PNG, etc. AstroImage is the subclass used to represent astronomical images and its organization is shown in Figure Hierarchy of Ginga AstroImage class. It has two delegate objects devoted to handling World Coordinate System transformations and file IO. There is also a mixin class, LayerImage that can be used to create layered images with alpha compositing on each layer.

New models can be created, subclassing from BaseImage or AstroImage. As long as the model duck types like a BaseImage it can be loaded into a view object with the set_image() method. AstroImage provides convenience methods for accessing WCS information that may be necessary when using the model in canvas subclasses of a View that allow graphics drawing.

The View
_images/class_structure_viewer.png

Class structure of Ginga basic widget viewer

Figure Class structure of Ginga basic widget viewer shows the class inheritance of the ImageViewZoom class, which is a typical end class to use in a program if one is not planning to do any graphical overplotting. The figure key indicates the base class verses the widget specific classes.

The View classes are rooted in the base class ImageView, which handles image display, scaling (zooming), panning, manual cut levels, auto cut levels, color mapping, transformations, and rotation. The ImageView is quite powerful compared to base classes in most inheritance designs, as it actually renders the view all the way out to RGB image planes in the appropriate sizes for the widget target window. Ginga supports “backends” for different widget sets (Gtk, Qt, Tk, etc.) through various subclasses of this base class, which do the actual painting of the resulting RGB image into a widget in the native widget set.

In this example, ImageViewXYZ is a class that renders to a native widget in the “XYZ” toolkit. ImageViewEvent adds event handlers for various pointing and keyboard events, but without connecting them to any particular handling scheme. Finally, ImageViewZoom provides a concrete implementation of event handling by connecting the handlers in the ImageViewEvent class with the logic in the BindingMapper and Bindings delegate objects as will as some logic in the UIMixin class. This event handling scheme is described in more detail in the section on the Controller. With this layered class construction, it is possible to minimize the widget specific code and reuse a large amount of code across widget sets and platforms. Because the vast majority of work is done in the base class, and the outer classes simply inherit the widget-specific ones and mix in the others, it is a fairly simple matter to port the basic Ginga functionality to a new widget set. All that is required is that the new widget set have some kind of native widget that supports painting an RGB image (like a canvas or image widget) and a way to register for user interaction events on that widget.

The Controller

The control interface is a combination of methods on the view object and a pluggable Bindings class which handles the mapping of user input events such as mouse, gesture and keystrokes into commands on the view. There are many callback functions that can be registered, allowing the user to create their own custom user interface for manipulating the view.

Graphics on Ginga
_images/class_structure_drawingcanvas.png

Class structure of Ginga DrawingCanvas class.

Ginga’s graphics are all rendered from objects placed on a DrawingCanvas. All objects that can be put on a DrawingCanvas are rooted in the CanvasObject type (including DrawingCanvas itself).

Miscellaneous Topics
I want to use my own World Coordinate System!

No problem. Ginga encapsulates the WCS behind a pluggable object used in the AstroImage class. Your WCS should implement this abstract class:

def MyWCS(object):
    def __init__(self, logger):
        self.logger = logger

    def get_keyword(self, key):
        return self.header[key]

    def get_keywords(self, *args):
        return map(lambda key: self.header[key], args)

    def load_header(self, header, fobj=None):
        pass

    def pixtoradec(self, idxs, coords='data'):
        # calculate ra_deg, dec_deg
        return (ra_deg, dec_deg)

    def radectopix(self, ra_deg, dec_deg, coords='data', naxispath=None):
        # calculate x, y
        return (x, y)

    def pixtosystem(self, idxs, system=None, coords='data'):
        return (deg1, deg2)

    def datapt_to_wcspt(self, datapt, coords='data', naxispath=None):
        return [[ra_deg_0, dec_deg_0], [ra_deg_1, dec_deg_1], ...,
                [ra_deg_n, dec_deg_n]]

    def wcspt_to_datapt(self, wcspt, coords='data', naxispath=None):
        return [[x0, y0], [x1, y1], ..., [xn, yn]]

To use your WCS with Ginga create your images like this:

from ginga.AstroImage import AstroImage
AstroImage.set_wcsClass(MyWCS)
...

image = AstroImage()
...
view.set_image(image)

or you can override the WCS on a case-by-case basis:

from ginga.AstroImage import AstroImage
...

image = AstroImage(wcsclass=MyWCS)
...
view.set_image(image)

You could also subclass AstroImage or BaseImage and implement your own WCS handling. There are certain methods in AstroImage used for graphics plotting and plugins, however, so these would need to be supported if you expect the same functionality.

I want to use my own file storage format, not FITS!

No problem. Ginga encapsulates the io behind a pluggable object used in the AstroImage class. You should implement this abstract class:

class MyIOHandler(object):
    def __init__(self, logger):
        self.logger = logger

    def register_type(self, name, klass):
        self.factory_dict[name.lower()] = klass

    def load_file(self, filespec, numhdu=None, dstobj=None, **kwdargs):
        # create object of the appropriate type, usually
        # an AstroImage or AstroTable, by looking up the correct
        # class in self.factory_dict, under the keys 'image' or
        # 'table'
        return dstobj

    def save_as_file(self, path, data, header, **kwdargs):
        pass

The save_as_file method is optional if you will never need to save a modified file from Ginga. To use your io handler with Ginga create your images like this:

from ginga.AstroImage import AstroImage
AstroImage.set_ioClass(MyIOHandler)
...

image = AstroImage()
image.load_file(path)
...
view.set_image(image)

or you can override the io handler on a case-by-case basis:

from ginga.AstroImage import AstroImage
...

image = AstroImage(ioclass=MyIOHandler)
image.load_file(path)
...
view.set_image(image)

You could also subclass AstroImage or BaseImage and implement your own I/O handling.

Note

Both naxispath and numhdu are valid keyword arguments to the load_file() method.

You probably want to treat numhdu as a kind of index into your file, similarly to the meaning within a FITS file (although you are free also to ignore it!).

If the user passes a valid numhdu (whatever that means to your load_file method) you simply return that value that they passed as the middle element of the return tuple. If they passed None (default), then you return the index you used to access the data area that you loaded.

You probably want to treat naxispath as any kind of path that you would need to take to navigate through your kind of data area selected by numhdu (above). This is usually used to describe the path through a data cube of N-dimensionality to reach a 2D slice.

If the user passes a valid naxispath (whatever that means to your load_file method) you simply return that value that they passed. If they passed None (default), then you return whatever path you used to access the data slice that you returned.

Porting Ginga to a New Widget Set

[TBD]

Optimizing Ginga’s Performance

There are several ways to optimize the performance of certain aspects of Ginga’s operation.

OpenCL Acceleration

Ginga includes support for OpenCL accelerated array operations for some operations (e.g. rotation). This support is not enabled by default.

To enable OpenCL support, install the pyopencl module, e.g.:

$ pip install pyopencl

If you are building your own program using a ginga viewer widget, simply enable the support by:

from ginga import trcalc
trcalc.use('opencl')

If you are using the reference viewer, you can add the command line option --opencl to enable support.

Alternatively, you can add the following line to your Ginga general options configuration file ($HOME/.ginga/general.cfg):

use_opencl = True

Note

pyopencl may prompt you if it can’t figure out which device is the obvious choice to use as for hardware acceleration. If so, you can set the PYOPENCL_CTX variable to prevent being prompted in the future.

Example of being prompted by pyopencl package:

$ ginga
NVIDIA: no NVIDIA devices found
Choose platform:
[0] <pyopencl.Platform 'Intel(R) OpenCL' at 0x2d95fd0>
[1] <pyopencl.Platform 'Clover' at 0x7f13f3ffcac0>
Choice [0]:
Set the environment variable PYOPENCL_CTX='' to avoid
being asked again.

OpenCv Acceleration

Ginga includes support for OpenCv accelerated operations (e.g. rotation and rescaling). This support is not enabled by default.

To enable OpenCv support, install the python opencv module (you can find it here).

If you are building your own program using a ginga viewer widget, simply enable the support by:

from ginga import trcalc
trcalc.use('opencv')

If you are using the reference viewer, you can add the command line option --opencv to enable support.

Alternatively, you can add the following line to your Ginga general options configuration file ($HOME/.ginga/general.cfg):

use_opencv = True

numexpr Acceleration

Ginga can use the numexpr package to speed up rotations. However, this is only used if the OpenCL and OpenCv optimizations are not being used and the performance gain is not nearly as dramatic as with the latter.

To enable numexpr acceleration, simply install the package, e.g.:

$ pip install numexpr

It will be automatically detected and used when appropriate.

Reference/API

ginga.canvas.CanvasMixin Module

Classes
CanvasMixin() A CanvasMixin is combined with the CompoundMixin to make a tag-addressible canvas-like interface.

ginga.canvas.CanvasObject Module

Classes
CanvasObjectBase(**kwdargs) This is the abstract base class for a CanvasObject.

ginga.canvas.CompoundMixin Module

Classes
CompoundMixin() A CompoundMixin is a mixin class that makes an object that is an aggregation of other objects.

ginga.canvas.coordmap Module

Classes
NativeMapper(viewer) A coordinate mapper that maps to the viewer’s canvas in the viewer’s canvas coordinates.
WindowMapper(viewer) A coordinate mapper that maps to the viewer in ‘window’ coordinates.
CartesianMapper(viewer) A coordinate mapper that maps to the viewer in Cartesian coordinates that do not scale (unlike DataMapper).
DataMapper(viewer) A coordinate mapper that maps to the viewer in data coordinates.
OffsetMapper(viewer, refobj) A coordinate mapper that maps to the viewer in data coordinates that are offsets relative to some other reference object.
WCSMapper(viewer) A coordinate mapper that maps to the viewer in WCS coordinates.

ginga.canvas.DrawingMixin Module

Classes
DrawingMixin() The DrawingMixin is a mixin class that adds drawing capability for some of the basic CanvasObject-derived types.

ginga.canvas.types.layer Module

Classes
CompoundObject(*objects, **kwdargs) Compound object on a ImageViewCanvas.
Canvas(*objects, **kwdargs) Class to handle canvas in Ginga.
DrawingCanvas(**kwdargs) Drawing canvas.
Class Inheritance Diagram

Inheritance diagram of ginga.canvas.types.layer.CompoundObject, ginga.canvas.types.layer.Canvas, ginga.canvas.types.layer.DrawingCanvas

ginga.ImageView Module

This module handles image viewers.

Classes
ImageViewBase([logger, rgbmap, settings]) An abstract base class for displaying images represented by Numpy data arrays.

ginga.rv.main Module

This module handles the main reference viewer.

Classes
ReferenceViewer([layout]) This class exists solely to be able to customize the reference viewer startup.

ginga.util.wcsmod Package

We are fortunate to have several possible choices for a python WCS package compatible with Ginga: astlib, kapteyn, starlink and astropy. kapteyn and astropy wrap Mark Calabretta’s “WCSLIB”, astLib wraps Jessica Mink’s “wcstools”, and I’m not sure what starlink uses (their own?).

Note that astlib requires pyfits (or astropy) in order to create a WCS object from a FITS header.

To force the use of one, do:

from ginga.util import wcsmod
wcsmod.use('kapteyn')

before you load any images. Otherwise Ginga will try to pick one for you.

Note that you can register custom WCS types using:

from ginga.util.wcsmod.common import register_wcs
register_wcs('mywcs', MyWCSClass, list_of_coord_types)

Look at the implemented WCS wrappers for details.

ginga.util.wcs Module

This module handles calculations based on world coordinate system.

Functions
hmsToDeg(h, m, s) Convert RA hours, minutes, seconds into an angle in degrees.
dmsToDeg(sign, deg, min, sec) Convert dec sign, degrees, minutes, seconds into a signed angle in degrees.
decTimeToDeg(sign_sym, deg, min, sec) Convert dec sign, degrees, minutes, seconds into a signed angle in degrees.
degToHms(ra) Converts the ra (in degrees) to HMS three tuple.
degToDms(dec[, isLatitude]) Convert the dec, in degrees, to an (sign,D,M,S) tuple.
arcsecToDeg(arcsec) Convert numeric arcseconds (aka DMS seconds) to degrees of arc.
hmsStrToDeg(ra) Convert a string representation of RA into a float in degrees.
dmsStrToDeg(dec) Convert a string representation of DEC into a float in degrees.
raDegToString(ra_deg[, format])
decDegToString(dec_deg[, format])
trans_coeff(eq, x, y, z) This function is provided by MOKA2 Development Team (1996.xx.xx) and used in SOSS system.
eqToEq2000(ra_deg, dec_deg, eq) Convert Eq to Eq 2000.
get_xy_rotation_and_scale(header) CREDIT: See IDL code at http://www.astro.washington.edu/docs/idl/cgi-bin/getpro/library32.html?GETROT
get_rotation_and_scale(header[, skew_threshold]) Calculate rotation and CDELT.
get_relative_orientation(image, ref_image) Computes the relative orientation and scale of an image to a reference image.
simple_wcs(px_x, px_y, ra_deg, dec_deg, …) Calculate a set of WCS keywords for a 2D simple instrument FITS file with a ‘standard’ RA/DEC pixel projection.
deg2fmt(ra_deg, dec_deg, format) Format coordinates.
dispos(dra0, decd0, dra, decd) Compute distance and position angle solving a spherical triangle (no approximations).
deltaStarsRaDecDeg1(ra1_deg, dec1_deg, …) Spherical triangulation.
deltaStarsRaDecDeg2(ra1_deg, dec1_deg, …)
get_starsep_RaDecDeg(ra1_deg, dec1_deg, …) Calculate separation.
add_offset_radec(ra_deg, dec_deg, …) Algorithm to compute RA/Dec from RA/Dec base position plus tangent plane offsets.
get_RaDecOffsets(ra1_deg, dec1_deg, ra2_deg, …) Calculate offset.
lon_to_deg(lon) Convert longitude to degrees.
lat_to_deg(lat) Convert latitude to degrees.

Some training videos are available in the downloads page on Github.

Be sure to also check out the Ginga wiki.

Bug Reports

Please file an issue with the issue tracker on Github.

Ginga has a logging facility, and it would be most helpful if you can invoke Ginga with the logging options to capture any logged errors:

$ ginga --loglevel=20 --log=ginga.log

If the difficulty is with non-display or non-working World Coordinate System (WCS) for a particular image file please be ready to supply the file for our aid in debugging.

Developer Info

In the source code examples/* directories, see example{1,2}_gtk.py (Gtk), example{1,2}_qt.py (Qt), example{1,2}_tk.py (Tk) or example{1,2,3,4,5}_mpl.py (Matplotlib). There is more information for developers in the The Ginga Viewer and Toolkit Manual.

See also the Module Index for a complete list of the available modules.

Etymology

“Ginga” is the romanized spelling of the Japanese word “銀河” (Hiragana: ぎんが), meaning “galaxy” (in general) and, more familiarly, the Milky Way. This viewer was written by software engineers at Subaru Telescope, National Astronomical Observatory of Japan—thus the connection.

Pronunciation

Ginga the viewer may be pronounced “ging-ga” (proper Japanese) or “jing-ga” (perhaps easier for Westerners). The latter pronunciation has meaning in the Brazilian dance/martial art Capoeira: a fundamental rocking or back and forth swinging motion. Pronunciation as “jin-ja” is considered poor form.