The JS9 Public API provides a JavaScript programming interface for interacting with JS9. Obviously, all of JS9 JavaScript code is available to you within a web page, but the public API is designed to stable and well-documented for users and web designers. It also will provide the basis for planned language bindings (python, perhaps C/Fortran).
In general, the public API routines act on the current image being displayed in the default JS9 display (i.e., the HTML div element that defines the JS9 display). Since most web pages will have only a single JS9 display, this behavior is usually what you want. It parallels DS9's behavior in which XPA commands act on the currently displayed image. For example, to change the colormap of the current image, use:
JS9.SetColormap("cool");
However, for cases where multiple JS9 displays are defined on a single page, you can specify the specific display to process by adding an display object argument to the calling sequence with a single display property:
{display: [display_id]}where [display_id] is the id of the target JS9 display (i.e. the id of the HTML div element). For example, if two JS9 displays with ids "JS9" and "myJS9", respectively, are present on a single web page, you can set the colormap of the second one this way:
JS9.SetColormap("cool", {display: "myJS9"})Note that this display object contains only the display property and always is specified as the final argument in a call.
For image-based API routines (not display-based routines with names ending in Display, e.g., JS9.ResizeDisplay or JS9.BlendDisplay), the display property can specify an image handle or image id instead of a JS9 display id. When the image handle in question points to the currently displayed image, this alternate usage is nothing more than a trivial optimization. Thus, to call a routine such as JS9.WCSToPix() or JS9.PixtoWCS():
var im = JS9.GetImage({display: "myJS9"}); for(i=0; i<1000; i++){ x = ... y = ... wcs = JS9.PixtoWCS(x, y, {display: im}); console.log("%s %s -> %s %s", x, y, wcs.ra, wcs.dec); }However, the image handle does not need to point to the currently displayed image. When it does not, the public routine will act on the image associated with the image handle, not the current image. In particular, you can use JS9.LookupImage() to get the image handle of any image, and then act on that image. For example, if two images, foo1.fits and foo2.fits, are loaded into a JS9 display, and foo1.fits is currently being displayed, you can close foo2.fits this way:
var im = JS9.LookupImage("foo2.fits"); if( im ){ JS9.CloseImage({display: im}); }
The optional display object argument generally is not mentioned in the routines below, but it is always available.
Choose from the following sections:
JS9.Load(url, opts)
where:
Load a FITS file (or even a PNG/JPEG file) into JS9. You also can pass an in-memory buffer containing a FITS file, a blob containing a FITS file, or a string containing a base64-encoded FITS file. Finally, you can pass a generic data object containing the following properties:
However, in the case where an image already is loaded, JS9.Load() does not reload the image into a new display: this would initiate another (often time-consuming) download, resulting in two identical images. Instead, behavior is dependent on the value of the refresh property passed in opts (or, if that is not set, by the JS9.globalOpts.reloadRefresh property), as follows:
To override default image parameters, pass the image opts argument:
JS9.Load("png/m13.png", {scale:"linear", colormap:"sls"});You can also pass a regions property to add regions:
JS9.Load("./fits/casa.fits", {regions:'ICRS; box(23:23:40.340, +58:47:04.059, 29.5", 29.5", 0)'});
If an onload callback function is specified in opts, it will be called after the image is loaded:
JS9.Load("fits/3c273.fits", {scale: "linear", onload: func});The image handle is passed as the first argument to the callback.
To load an image into a specified display, pass the display object as the last argument:
JS9.Load("fits/3c273.fits", {scale: "linear"}, {display: "myJS9"});
See Displaying Your Data for further discussion of how to use this routine.
JS9.LoadWindow(url, opts, type, html, winopts)
where:
The type argument determines whether to create a light-weight window ("light", which is the default) or a new, separate window ("new").
By default, the created window will contain a Menubar above a JS9 Display area and a Colorbar below:
<div class='JS9Menubar' id='[id]Menubar'></div> <div class='JS9' id='[id]'></div> <div style="margin-top: 2px;"> <div class='JS9Colorbar' id='[id]Colorbar'></div> <div>You can use the html argument to supply different web page elements for the window. Furthermore, if you create a light window, a default set of DynamicDrive dhtmlwindow parameters will be used to make the window the correct size for the default html:
"width=512px,height=542px,center=1,resize=1,scrolling=1"You can supply your own parameters for the new dhtmlwindow using the winOpts argument. See: DynamicDrive for more information about their light-weight window.
To create a new light window without loading an image, use:
JS9.LoadWindow(null, null, "light");
See js9create.html for examples of how to use this routine.
JS9.LoadProxy(url, opts)
where:
Load a FITS, PNG, or JPEG file specified by an arbitrary URL into JS9 using the JS9 back-end helper as a proxy server.
For security reasons, JavaScript contained in one web page can access data in another web page only if both web pages have the same origin (i.e., basically coming from the same host). This policy is called the Same Origin Policy. This means that JS9 cannot load a image files (i.e., FITS, PNG, or JPG) from an arbitrary URL without using special techniques.
One such technique is Cross-Origin Resource Sharing, by which the second server grants permission to access its image data. Dropbox is CORS-enabled, so that image files can be loaded directly into JS9. But obviously this requires that explicit permission be granted by the other server.
A second technique is to use a proxy server: the URL is not loaded directly into JS9, but instead is copied back to the server from which JS9 itself was loaded. The file is then retrieved by JS9 from this server so that the "same origin" rules are not violated.
The JS9 Node.js back-end helper can be configured to support proxy server mode by setting the JS9.globalOpts.loadProxy property. In addition, the back-end server must be configured to support temporary working directories for each loaded page by setting the JS9.globalOpts.workDir property. If the back-end server is thus configured as a proxy server, JS9 will support the JS9.LoadProxy() call and allow you to load FITS, PNG, and JPG files from arbitrary URLs. JS9 also will display a open link via proxy menu option in the File menu.
The JS9.LoadProxy() call takes a URL as its first argument. This URL will be retrieved using curl or wget and stored on the back-end server in a directory specifically tied to the web page. (The directory and its contents will be deleted when the page is unloaded.) JS9 then will load the file from this directory. Note that since the file resides on the back-end server, all back-end analysis defined on that server is available.
To override default image parameters, pass the image opts argument:
JS9.LoadProxy("http://hea-www.cfa.harvard.edu/~eric/coma.fits", {scale:"linear", colormap:"sls"});'
If an onload callback function is specified in opts, it will be called after the image is loaded:
JS9.LoadProxy("http://hea-www.cfa.harvard.edu/~eric/coma.fits", {scale: "linear", onload: func});'The image handle is passed as the first argument to the callback.
To load an image into a specified display, pass the display object as the last argument:
JS9.LoadProxy("http://hea-www.cfa.harvard.edu/~eric/coma.fits", {scale: "linear"}, {display: "myJS9"});'
Note again that not all back-end servers support the proxy functionality. The main JS9 web site does support proxy service, and can be used to view images from arbitrary URLs.
JS9.Preload(url1, opts1, url2, opts2, ... url2, optsn)
where:
It is worth emphasizing that JS9.Preload() should not be called until the web page is fully loaded, since JS9 itself is not fully initialized until then. It is for this reason that JS9.Preload() generally is called using an onload routine tied to the web page body.
You can load URLs outside the current web page domain if you are running a JS9 helper which has enabled the server side Proxy Load capability. See Server-side Analysis Tasks for more information.
status = JS9.GetStatus(id, type)
where:
A status of "complete" means that the image is fully processed. Other statuses include:
tfits = "foo.fits" hdul = fits.open(tfits) ... j = JS9() j.Load(hdul, tfits) while j.GetStatus(tfits, "load") != "complete": time.sleep(0.1) j.SetZoom(2)
status = JS9.GetLoadStatus(id)
where:
A status of "complete" means that the image is fully loaded. Other statuses include:
tfits = "foo.fits" hdul = fits.open(tfits) ... j = JS9() j.Load(hdul, tfits) while j.GetLoadStatus(tfits) != "complete": time.sleep(0.1) j.SetZoom(2)
im = JS9.GetImage()
returns:
The routine returns the image handle associated with the current image.
The returned image handle can be passed in the display object. This is marginally more efficient than the default behavior, which is to determine the current image for each call.
im = JS9.LookupImage(id)
where:
returns:
The JS9.LookupImage() routine takes a string id as input and returns the image handle of the image having that id (or null). The id is the same as is found in the File menu list of displayed images. This routine is similar to the standard JS9.GetImage() routine, but returns an image by name, regardless of whether it is currently being displayed.
You can use this routine, for example, so close an image that is not currently being displayed. If two images, foo1.fits and foo2.fits, are loaded into a JS9 display, and foo1.fits is currently being displayed, you can close foo2.fits this way:
var im = JS9.LookupImage("foo2.fits"); if( im ){ JS9.CloseImage({display: im}); }
imdata = JS9.GetImageData(dflag)
where:
returns:
The image data object contains the following information:
If dflag is the string "array", a JavaScript array is returned. This is not a reference to the real data and will utilize additional memory, but the values can be manipulated safely.
If dflag is the string "base64", a base64-encoded string is returned. Early on, this seems to be the fastest method of transferring data via socket.io an external process such as Python. Currently, the "array" method should generally be used (this is now the default for the pyjs9 interface to Python).
The file value can be a FITS file or a representation PNG file. The fits value will be the path of the FITS file associated with this image. For a presentation PNG file, the path generally will be relative to the JS9 install directory. For a normal FITS file, the path usually is an absolute path to the FITS file.
The header object contains FITS header keywords. Note that all HISTORY and COMMENT keywords have two underscores and a numeric value appended, in order to make them unique within the object.
If you are calling JS9.GetImageData() from an external process (via the msg protocol), you almost certainly want to set dflag to "array". Doing so will serialize the data as an array instead of as an object, saving a considerable amount of transfer data.
Given a FITS-standard 1-indexed image pixel x,y, you can find the data value at that location using:
val = obj.data[Math.floor(y-0.5) * obj.width + Math.floor(x-0.5)];Note the need to integerize the x and y values: JavaScript arrays are objects and so floating point array indices do not get truncated automatically as in C. They will return null values.
imarr = JS9.GetDisplayData()
returns:
The JS9.GetDisplayData() routine returns an array of image data objects, one for each images loaded into the specified display. That is, it returns the same type of information as JS9.GetImageData(), but does so for each image associated with the display, not just the current image.
JS9.DisplayImage(step)
where:
The default step is "primary", which displays the image without recalculating color data, scaled data, etc. This generally is what you want, unless you have explicitly changed parameter(s) used in a prior step.
JS9.RefreshImage(input, opts)
where:
If the input argument is null, the current image file is reloaded, assuming its file path (or URL) is known. For security reasons, browsers do not expose the path of files loaded via Drag and Drop or Open Local File. On a local web page, you can safely use the File -> set this image file's path menu option to enter the image path here for subsequent reloading (or analysis).
When passing an object as input, the required image property containing the image data can be a javascript array or a typed data array. It also can contain a base64-encoded string containing an array. This latter can be useful when calling JS9.RefreshImage() via HTTP.
Ordinarily, when refreshing an image, there is no need to specify the optional axis, bitpix, or header properties. But note that you actually can change these values on the fly, and JS9 will process the new data correctly. Also, if you do not pass dmin or dmax, they will be calculated by JS9.
Note that you can pass a blob containing a complete FITS image to this routine. The blob will be passed to the underlying FITS-handler before being displayed. Thus, processing time is slightly greater than if you just pass the image data directly.
The second optional argument can be an object containing the following:
# preferred method JS9.RefreshImage(blob, {onrefresh: xrefresh}); # for backwards compatibility JS9.RefreshImage(blob, xrefresh); # both call this function function xrefresh(im){ ... };
Advanced use: it is possible to load several images into an instance of JS9 and then refresh any of them regardless of which image is currently displayed. To do this, you pass the display property in a trailing object, with the id of the image to refresh. For example, if foo1.fits and foo2.fits are loaded and foo2.fits is currently displayed:
# refresh foo2.fits using foo2.fits as the new image JS9.RefreshImage(); # refresh foo2.fits using foo3.fits as the new image JS9.RefreshImage("foo3.fits"); # refresh foo1.fits (even though its not currently displayed) # it will be currently displayed once this operation is complete JS9.RefreshImage({display:"foo1.fits"}); # refresh foo1.fits using foo4.fits as the new image JS9.RefreshImage("foo4.fits", {display:"foo1.fits"}); # warning: this refreshes foo2.fits using foo1.fits as the new image, # rather than refreshing foo1.fits!! JS9.RefreshImage("foo1.fits");
The main difference between JS9.RefreshImage() and JS9.Load() is that the former updates the data in the currently displayed image, while the latter adds a completely new image to the display.
JS9.DisplaySection(opts)
where:
The bin directives are:
All properties are optional: if a property is not specified,
the routine will use
the center of the file, with dimensions and binning
specified by JS9.globalOpts.table and JS9.globalOpts.image objects.
the image's current settings. This allows you to set up the section once,
and then repeatedly change a property such as the center or filter,
without having to specify the other properties.
For example, if an image has dimensions 4096 x 4096, then specifying:
Note that setting xcen,ycen to 0,0 will specify the file center.
By default, the new section replaces the data in the currently displayed image. You can display the section as a separate image in the current display by supplying an opts object with the separate property set to true. For example:
JS9.DisplaySection({ ... separate: true});will display the new section separately from the original file, allowing blinking, image blending, etc. between the two "files".
You also can display the section as a separate image in a different display by supplying a string value to the opts.separate property. The string value takes two forms:
# separate into a new display, same image id JS9.DisplaySection({ ... separate: "myJS9"}); # separate into a new display, and with a new image id JS9.DisplaySection({ ... separate: "myJS9:newsection.fits"});Both of these commands will display the new section "myJS9" display. The first will retain the original image id, while the second will use "newsection.fits" as the image id. Alternatively, you can display the section by refreshing the image in a different display by supplying a string value to the opts.refresh property. Again, the string value takes two forms:
# refresh image in a new display, same image id JS9.DisplaySection({ ... refresh: "myJS9"}); # refresh the new display, and change to a new image id JS9.DisplaySection({ ... refresh: "myJS9:newsection.fits"});If no image is currently loaded in the specified display, the first call to this routine using the refresh property will create a new image in that display. Subsequent calls will refresh that image.
Table filtering allows you to select rows from an FITS binary table (e.g., an X-ray event list) by checking each row against an expression involving the columns in the table. When a table is filtered, only valid rows satisfying these expressions are used to make the image.
A filter expression consists of an arithmetic or logical operation involving one or more column values from a table. Columns can be compared to other columns or to numeric constants. Standard JavaScript math functions can be applied to columns. JavaScript (or C) semantics are used when constructing expressions, with the usual precedence and associativity rules holding sway:
Operator Associativity -------- ------------- () left to right ! (bitwise not) - (unary minus) right to left * / left to right + - left to right < <= > >= left to right == != left to right & (bitwise and) left to right ^ (bitwise exclusive or) left to right | (bitwise inclusive or) left to right && (logical and) left to right || (logical or) left to right = right to leftFor example, if energy and pha are columns in a table, then the following are valid expressions:
pha > 1 energy == pha pha > 1 && energy ≤ 2 max(pha,energy) ≥ 2.5
NB: JS9 uses cfitsio by default (you can, but should not, use the deprecated fitsy.js), and therefore follows cfitsio filtering conventions, which are documented here.
JS9.DisplayExtension(extid, opts)
where:
The optional opts object can contain:
See the FITS Primer for more information about HDUs and multi-extension FITS.
JS9.DisplaySlice(slice, opts)
where:
The slice parameter can either be the numeric value of the slice in the third (or fourth) image dimension (starting with 1) or it can be a slice description string: a combination of asterisks (or commas) and a numeric value defines the slice axis. Thus, for example, in a 1024 x 1024 x 16 cube, you can display the sixth slice along the third axis in one of two ways:
JS9.DisplaySlice(6);or:
# sixth slice along third axis JS9.DisplaySlice("*:*:6"); # comma separators also can be used JS9.DisplaySlice("*,*,6");If the image was organized as 16 x 1024 x 1024, you would use the string description:
JS9.DisplaySlice("6:*:*");
By default, the new slice replaces the data in the currently displayed image. You can display the slice as a separate image in the current display by supplying an opts object with the separate property set to true. For example:
JS9.DisplaySlice("6:*:*", {separate: true});will display the sixth slice of the first image dimension separately from the original file, allowing blinking, image blending, etc. between the two "files". Note that the new id and filename are adjusted to be the original file's values with the cfitsio image section [6:6:*:*] appended.
If the first argument is "all", then all slices will be loaded into JS9 separately.
JS9.BlendImage(blendMode, opacity)
Calling sequences:
JS9.BlendImage() # return current blend params JS9.BlendImage(true||false) # turn on/off blending JS9.BlendImage(mode, opacity) # set blend mode and/or opacity
where:
JS9 allows you to use these modes to blend images together. If you load two images of the same object into JS9, you can use the JS9.ReprojectData() routine to align them by WCS. You then can blend one image into the other by specifying a blend mode and an optional opacity. For example, if chandra.fits and spitzer.fits are two aligned images of the same object, and chandra.fits is currently being displayed, you can blend spitzer into chandra using the "screen" blend and opacity 0.9 mode this way:
JS9.BlendImage("screen", 0.9);After the spitzer image is blended, both images will be displayed as part of the chandra.fits display. However, changing the colormap, scale, contrast, or bias will only affect the current chandra image, not the blended spitzer part. In this way, you can continue to manipulate the current image and the image blending will update automatically.
Also note that the spitzer image is still available separately for display and manipulation. You can switch to displaying spitzer and change colormap, scale, bias, contrast, etc. But since the images are now blended, changes to spitzer will be reflected in the spitzer part of the blended chandra display. Thus, if you change the colormap on the display of spitzer, and change back to chandra, the blended chandra image will utilize the new colormap.
This linkage is maintained during zoom and pan operations. If you display the blended chandra image and then zoom or pan it, both images will be updated correctly to maintain alignment. But note that this means when you go back to the spitzer display, its zoom and/or pan values will have been updated. In this way, the spitzer image always is correctly linked to the blended version. The JS9.BlendImage() call accepts a variable number of arguments to perform a variety of functions:
mode = JS9.BlendDisplay(true|false)
returns:
If the first argument is "reset", the blend mode for all images in this display will be set to false, along with the display's blend mode. This is useful if you have loaded/blended a number of images, and want to load/blend another set of images.
If the first argument is "list", an array is returned containing the image id's of all images that have blend mode turned on for this display. This is useful for changing the blend modes of all active images at once.
JS9.SyncImages(ops, images, opts)
Calling sequences:
JS9.SyncImages([ops], [images], [opts]) # set up synchronization JS9.SyncImages(true||false) # turn on/off synchronization
where:
When the JS9.SyncImages() call is invoked, the current image is configured to synchronize the specified images. In addition, if the reciprocate property is set in the opts object (see below), the other images are also configured to synchronize one another (as well as the current image). Once configuration is complete, a sync command is executed immediately. If the current image already displays one or more regions, these will be created in the target images.
The operations that can be specified for sync'ing are: "colormap", "pan", "regions", "scale", "wcs", "zoom", and "contrastbias". If no array is specified, the default array in JS9.globalOpts.syncOps is used.
Images to synchronize can be specified as an array of image handles or image ids. If no array is specified, all currently displayed images are sync'ed.
The optional opts object can contain:
Examples:
# the current image will sync all operations for all images # this will happen reciprocally, so that changing any image syncs the others JS9.SyncImages() # the current image will sync the specified ops for foo1.fits, foo2.fits: JS9.SyncImages(["scale", "colormap"], ["foo1.fits", "foo2.fits"]) # the current image will sync two images with default ops, # but the two images themselves will not sync images reciprocally JS9.SyncImages(null, ["foo1.fits", "foo2.fits"], {reciprocate: false});
Note that if the pan operation syncs two images having differently sized fields of view, the smaller image will stop panning when it reaches its edge, rather than displaying a blank field.
You can turn on/off syncing for a given image by specifying a single boolean argument:
# turn off sync'ing temporarily JS9.SyncImages(false);This is different from unsync'ing in that you can turn sync'ing back on without having to re-sync the images.
JS9.UnsyncImages(ops, images, opts)
Calling sequence:
JS9.UnsyncImages([ops], [images], [opts]) # clear synchronization
where:
The operations that can be specified for unsync'ing are: "colormap", "pan", "regions", "scale", "wcs", "zoom", and "contrastbias". If no array is specified, the default array in JS9.globalOpts.syncOps is used. Thus, you can turn off sync'ing for specified operations, while leaving others to be sync'ed.
Images to be unsync'ed can be specified as an array of image handles or image ids. If no array is specified, all currently displayed images are unsync'ed.
The optional opts object can contain:
Examples:
# this image will no longer sync on scale for foo1.fits and foo2.fits, # and they also will stop sync'ing JS9.UnsyncImages(["scale"], ["foo1.fits", "foo2.fits"]) # this image will still sync foo1.fits and foo2.fits, but # foo1.fits and foo2.fits will no longer sync this image: JS9.UnsyncImages(null, ["foo1.fits", "foo2.fits"], {reverse: true, reciprocal: false})
JS9.CloseImage(opts)
where:
Each loaded image claims a non-trivial amount of memory from a finite amount of browser heap space. For example, the default 32-bit version of Google Chrome has a memory limit of approximately 500Mb. If you are finished viewing an image, closing it tells the browser that the image's memory can be freed. In principle, this is can help reduce overall memory usage as successive images are loaded and discarded. Note, however, that closing an image only provides a hint to the browser, since this sort of garbage collection is not directly accessible to JavaScript programming and happens when it happens.
The optional first argument is an opts object (or a JSON-formatted string) containing:
cmap = JS9.GetColormap()
returns:
JS9.SetColormap(colormap, [contrast, bias])
where:
JS9.SaveColormap(fname, cmapArray)
Calling sequences:
JS9.SaveColormap() # save current colormap to "js9.cmap" JS9.SaveColormap(fname) # save current colormap to fname JS9.SaveColormap(cmapArray) # save array of colormaps to "js9.cmap" JS9.SaveColormap(fname, cmapArray) # save array of colormaps to fname
where:
# save the current colormap in js9.cmap JS9.SaveColormap() # save the current colormap in foo.cmap JS9.SaveColormap("foo.cmap") # save the foo1 and foo2 colormaps in js9.cmap JS9.SaveColormap(["foo1", "foo2"]) # save the user-defined foo1 and foo2 colormaps in foo.cmap JS9.SaveColormap("foo.cmap", ["foo1", "foo2"])
The colormaps are saved in JSON format. Multiple saved colormaps will be stored in a JSON array, while a single saved colormap will be saved at the top level.
Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.
JS9.AddColormap(name, aa|rr,gg,bb|obj|json, opts)
where:
JS9.AddColormap("i8", [[0,0,0], [0,1,0], [0,0,1], [0,1,1], [1,0,0], [1,1,0], [1,0,1], [1,1,1]]));Here, the colormap is divided into 8 sections having the following colors: black, green, blue, cyan (green + blue), red, yellow (red + green), purple (red + blue), and white. A colormap such as sls also utilizes an array of RGB triplets, but it has 200 entries, leading to much more gradual transitions between colors.
The second colormap format consists three arrays of vertices defining the change in intensity of red, green, and blue, respectively. For each of these three color triplets, the first coordinate of each vertex is the x-distance along the colormap axis (scaled from 0 to 1) and the second coordinate is the y-intensity of the color. Colors are interpolated between the vertices. For example, consider the following:
JS9.AddColormap("red", [[0,0],[1,1]], [[0,0], [0,0]], [[0,0],[0,0]]); JS9.AddColormap("blue", [[0,0],[0,0]], [[0,0], [0,0]], [[0,0],[1,1]]); JS9.AddColormap("purple", [[0,0],[1,1]], [[0,0], [0,0]], [[0,0],[1,1]]);In the red (blue) colormap, the red (blue) array contains two vertices, whose color ranges from no intensity (0) to full intensity (1) over the whole range of the colormap (0 to 1). The same holds true for the purple colormap, except that both red and blue change from zero to full intensity.
For a more complicated example, consider the a colormap, which is defined as:
JS9.AddColormap("a", [[0,0], [0.25,0], [0.5,1], [1,1]], [[0,0], [0.25,1], [0.5,0], [0.77,0], [1,1]], [[0,0], [0.125,0], [0.5, 1], [0.64,0.5], [0.77, 0], [1,0]]);Here we see that red is absent for the first quarter of the colormap, then gradually increases to full intensity by the half mark, after which it stays at full intensity to the end. Green ramps up to full intensity in the first quarter, then drops to zero by the half and stays that way until a bit more than three-quarters along, after which it gradually increases again. Blue starts off at no intensity for an eighth, then gradually increases to full intensity by the half-way mark, decreasing gradually to zero by the three-quarter mark. The result is that you see, for example, green at the beginning and yellow (red + green) at the end, with some purple (red + blue) in the middle of the colormap.
As a convenience, you also can pass an object or JSON string containing the colormap definition:
# RGB color triplets for the I8 colormap in a "colors" property {"name":"i8","colors":[[0,0,0],[0,1,0],[0,0,1],[0,1,1],[1,0,0],[1,1,0],[1,0,1],[1,1,1]]} # all 3 vertex arrays for the purple colormap in one "vertices" property {"name":"purple","vertices":[[[0,0],[1,1]],[[0,0],[0,0]],[[0,0],[1,1]]]}
The colormap will be added to the toplevel of the Colormap menu, unless you pass a final opts argument that sets the toplevel property to false:
JS9.AddColormap("cyan", [[0,0],[0,0]], [[0,0],[1,1]], [[0,0],[1,1]], {toplevel:false});Finally, note that JS9.AddColormap() adds its new colormap to all JS9 displays on the given page.
JS9.LoadColormap(filename, opts)
where:
# RGB color format { "name": "purplish", "colors": [ [0.196, 0.196, 0.196], [0.475, 0, 0.608], [0, 0, 0.785], [0.373, 0.655, 0.925], [0, 0.596, 0], [0, 0.965, 0], [1, 1, 0], [1, 0.694, 0], [1, 0, 0] ] } # vertex format { "name": "aips0", "vertices": [ [ [0.203, 0], [0.236, 0.245], [0.282, 0.5], [0.342, 0.706], [0.411, 0.882], [0.497, 1] ], [ [0.394, 0], [0.411, 0.196], [0.464, 0.48], [0.526, 0.696], [0.593, 0.882], [0.673, 1], [0.94, 1], [0.94, 0] ], [ [0.091, 0], [0.091, 0.373], [0.262, 1], [0.94, 1], [0.94, 0] ] ] }
The colormap will be added to the toplevel of the Colormap menu, unless you pass a final opts argument that sets the toplevel property to false:
JS9.LoadColormap("secondary.cmap", {toplevel:false});As with JS9.AddColormap(), the new colormap will be available in all displays.
JS9.GetRGBMode()
returns:
JS9.SetRGBMode(mode, [imobj])
where:
The JS9.SetRGBMode() call turns on or off RGB mode. The boolean mode argument specifies whether to activate or de-activate RGB mode. The optional imobj object specifies (already-loaded) images to assign to the three colormaps:
If no arguments are specified, the current RGB mode is toggled;
scale = JS9.GetScale()
returns:
JS9.SetScale(scale, smin, smax)
where:
zoom = JS9.GetZoom()
returns:
JS9.SetZoom(zoom)
where:
ipos = JS9.GetPan()
returns:
JS9.SetPan(x, y)
where:
Set the current pan position using image coordinates. Note that you can use JS9.WCSToPix() and JS9.PixToWCS() to convert between image and WCS coordinates.
An object can also be supplied with a position specified in image, physical, or WCS coordinates:JS9.SetPan({wcs: "23:23:28.895 +58:49:43.50 ICRS"});will set the pan position to the specified RA and Dec using the ICRS system. Note that the WCS string above is returned by the Edit menu's "copy wcs pos" option (i.e., the "/" keystroke).
Finally, if you pass the string "mouse" as the sole argument, the image is panned to the current mouse position. This is especially useful in conjunction with keyboard shortcuts (where currently the "m" key uses this routine to pan to the current mouse position.)
By default, panning is unconstrained: you can pan the image so that some (or even all) of the display does not contain image data (e.g., if you pan an image to point 0,0, the image origin will be the center of the display and only the upper right quadrant will contain data.) If you want to avoid blank areas in the display, set the JS9.globalOpts.panWithinDisplay property to true. Site authors can change this property in js9prefs.js, while users can change this via the Global tab of the Preferences plugin.
JS9.AlignPanZoom(im)
where:
This routine changes the pan and zoom of the current image to match a target image, assuming both have WCS info available. The image is panned to the RA, Dec at the center of the target image's display. The zoom is also matched. The pixel size (as specified by the FITS CDELT1 parameter) will be taken into account when zooming, but not the image rotation or flip. This routine is faster than JS9.ReprojectData() for aligning reasonably similar images.
No attempt is make to keep the images aligned after the call. This allows you to make adjustments to the current and/or target images and then re-align as needed.
JS9.SetFlip(flip)
where:
flip = JS9.GetFlip()
returns:
JS9.SetRot90(flip)
where:
rot = JS9.GetRot90()
returns:
val = JS9.GetParam(param)
where:
returns:
Return the value of an image parameter. The available parameters are listed below in the JS9.SetParam() section.
In the value of param is "all", the entire param object is returned.
ovalue = JS9.SetParam(param, value)
where:
returns:
In addition, you can set the internal values associated with core functionality ("colormap", "pan", "regions", "scale", "wcs", or "zoom") and the corresponding core function will be called. The core parameters that can be set in this way are:
The routine returns the previous value of the parameter, which can be useful when temporarily turning off a function. For example:
oval = JS9.SetParam("xeqonchange", false); .... processing ... JS9.SetParam("xeqonchange", oval);will temporarily disable execution of the previously defined regions onload callback, resetting it to the old value after processing is complete.
If param is "all" and the second argument is an object, this object is merged into the current param object. This allows you to save the params from one image and restore them to another. If the object contains internal core parameters (see above), the corresponding core function will be called.
If param is "disable", the specified value (or array of values) is added to the disable array for this image, thereby disabling core functionality. The resulting disable array is returned. Thus, for example:
JS9.SetParam("disable", ["zoom", "pan"]);will disable zoom and pan functionality for this image. Note that disabling regions means that you cannot create new regions, but you can still change and even remove existing regions.
If param is "enable", the specified value (or array of values) is removed to the disable array for this image, thereby enabling core functionality. The resulting disable array is returned.
dpos = JS9.EventToDisplayPos(evt)
where:
ipos = JS9.DisplayToImagePos(dpos)
where:
dpos = JS9.ImageToDisplayPos(ipos)
where:
ipos = JS9.LogicalToImagePos(lpos, lcs)
where:
This routine will convert from logical to image coordinates. By default, the current logical coordinate system is used. You can specify a different logical coordinate system (assuming the appropriate keywords have been defined).
lpos = JS9.ImageToLogicalPos(ipos, lcs)
where:
This routine will convert from image to logical coordinates. By default, the current logical coordinate system is used. You can specify a different logical coordinate system (assuming the appropriate keywords have been defined).
valpos = JS9.GetValPos(ipos, display)
where:
JS9.SetValPos(mode)
where:
inherit = JS9.GetImageInherit()
returns:
JS9.SetImageInherit(mode)
where:
wcsobj = JS9.GetWCS()
returns:
Get information about the current WCS, including:
JS9.SetWCS(which)
where:
The which argument can be one of the following:
unitsstr = JS9.GetWCSUnits()
returns:
JS9.SetWCSUnits(unitsstr)
where:
sysstr = JS9.GetWCSSys()
returns:
JS9.SetWCSSys(sysstr)
where:
wcsobj = JS9.PixToWCS(x, y)
where:
The returned WCS object contains the following properties:
pixobj = JS9.WCSToPix(ra, dec)
where:
JS9.DisplayMessage(which, text)
where:
JS9.DisplayCoordGrid(mode, opts)
where:
If no arguments are supplied, the routine returns true if the coordinate grid is currently being displayed, false otherwise. A boolean first argument specifies whether to display the coordinate grid or not.
The optional second argument is an opts object (or a JSON-formatted string) containing properties to override the default JS9.Grid.opts properties. These properties include:
JS9's label placement algorithm puts labels close to the intersection of RA and Dec lines. A number of properties can be useful in cases where this simple algorithm is not sufficient: the raAngle and decAngle properties allow you to rotate the labels with respect to the grid lines. The four label[RA,Dec]Off[x,y] properties allow you to move the label with respect to the grid lines. The raSkip and decSkip properties allow you to skip labelling the first available lines within the display. It can be useful, for example, on a rotated image, when the labels are placed in a corner.
The degPrec and sexaPrec properties specify the precision for degree values and sexagesimal values, respectively. Higher precision will use more digits and take more space along each line.
A number of properties are (more or less) internal but might be of use: the reduceDims property will reduce the raLines and decLines properties by the ratio of image dimensions if one dimension is smaller than the other. This can prevent crowding in the smaller dimension. The stride property specifies the length of each line segment that together make up a grid line. A smaller stride might make the grid lines smoother in some cases, at the price of more processing time. The cover property determines whether the grid is drawn over the entire image or just the displayed part of the image. At the moment, drawing lines over the displayed part of the image seems to be sufficient.
Note that you can specify global site-wide values for all these parameters (overriding the JS9.Grid.opts defaults) by supplying them in a grid object within the globalOpts object in the js9prefs.js file.
Example: display a coordinate grid, specifying the line color:
JS9.DisplayCoordGrid(true, {lineColor: "pink"});
JS9.CountsInRegions(sregion, bregion, opts)
where:
The regcnts program has been compiled into JS9 using Emscripten. Using this routine, it can be run on the FITS file stored in memory for the currently displayed image. The first two arguments specify the source region(s) and background region(s), respectively. You can pass a standard region specifier as the source or background region:
JS9.CountsInRegions('ICRS; circle(23:23:18.76, +58:47:27.25, 31.8")');If the string "$sregions" ("$bregions") is specified, the source (background) regions are taken from the currently displayed image. You also can specify a region selector using any of the following:
# all regions JS9.CountsInRegions('all'); # selected regions JS9.CountsInRegions('selected'); # regions tagged with the "foo" tag JS9.CountsInRegions('foo');Note that if you pass a region selector and no regions are returned, the routine will throw an error.
In keeping with how desktop regcnts works, if no argument or null or a null string is specified as the source region, the entire field is used as the source region. If no argument or null or a null string is explicitly specified as a background region, no regions are used for the background. In particular, if you pass only the source region argument, or pass only the source region and opts arguments, no background region is used. To recap:
# use entire field, no background JS9.CountsInRegions([opts]) JS9.CountsInRegions("field"||null||""[, opts]) # use displayed source and displayed background JS9.CountsInRegions("$sregions", "$bregions"[, opts]) # use displayed source, no background JS9.CountsInRegions("$sregions"[, opts]) # use displayed source and specified background JS9.CountsInRegions("$sregions", bregions[, opts]) # use specified source, no background JS9.CountsInRegions(sregions[, opts]) # use specified source and specified background JS9.CountsInRegions(sregions, bregions[, opts]) # use specified source and displayed background JS9.CountsInRegions(sregions, "$bregions"[, opts]) # use entire field and specified background JS9.CountsInRegions("field"||null||"", bregions[, opts]) # use entire field and displayed background JS9.CountsInRegions("field"||null||"", "$bregions"[, opts])The third argument allows you to specify options to regcnts:
# display results in a light window JS9.CountsInRegions({lightwin: true}) # return JSON using maximum precision in output JS9.CountsInRegions({cmdswitches: "-j -G"})Results are also returned as a text string.
The regcnts code is memory (and cpu) intensive. In the desktop environment, this is not typically a problem, but the memory-constrained browser environment can present a challenge for large images and binary tables. To avoid running out of memory (and for large images, to speed up processing considerably), the JS9.CountsInRegions() routine will bin the image to reduce its size, unless the reduce option is explicitly set to false. The binned image size can be specified by the dim option, defaulting to the global value of the image dimension options. When a file is binned in this manner, the returned resolution value (e.g., arcsec/pixel) will reflect the applied binning. Note that the number of photons found inside a binned and unbinned region differ slightly, due to the difference in the pixel boundaries in the two cases.
The Counts in Regions option of the Analysis -> Client-side Analysis menu runs regcnts on the source and background regions of the currently displayed image. The results are displayed in a light window.
Finally, note that the main JS9 web site also offers regcnts as a server-based analysis program in the Analysis menu. The displayed source and background regions are passed to the server for processing. Because this version runs the desktop program, it runs on the original file and does no binning to reduce the image size (which, by the way, could lengthen the processing time). But the server-side task also can be useful for large file support, which involves displaying a small representation file associated with a much larger parent file stored on the server. In this case, you often want to run the analysis on the larger (original) file.
JS9.RadialProfile(sregion, bregion, opts)
where:
The third argument allows you to specify options to the counts routine, as well as the following options for the radial profile plot:
JS9.CountsInRegions(sregions, bregions, {cmdswitches: "-j -r"})The return value is the id of the light window containing the plot.
JS9.RawDataLayer(opts, func)
where:
To create a new raw data layer (or edit an existing layer), call the JS9.RawDataLayer() with two arguments: layer opts (or layer name) and a function. The layer opts object can have the following properties:
The pixel modifying function should have the following calling sequence:
func(oraw, nraw, opts)where:
Note that the nraw object will contain the raw data for this layer, if it already exists. Otherwise, it will contain a copy of the from data.
For example, the following routine creates a new "clip" layer and clips the original raw data at the specified nmax level:
im.rawData({rawid: "clip", nmax: n}, function (oraw, nraw, opts){ var i, len; opts = opts || {}; if( opts.nmax === undefined ){ opts.nmax = 0; } len = nraw.width * nraw.height; for(i=0; i<len; i++){ if( oraw.data[i] < opts.nmax ){ nraw.data[i] = 0; } else { nraw.data[i] = oraw.data[i]; } } return true; });When clipping, the nraw pixel values are taken from the oraw values, so that you can clip to a value of 100, then clip to a value of 50, and get the right result. This is different from the following example "add" layer, which adds a constant value to the existing data:
im.rawData({rawid: "add", val: n}, function (oraw, nraw, opts){ var i, len; opts = opts || {}; if( opts.val === undefined ){ opts.val = 1; } len = nraw.width * nraw.height; for(i=0; i<len; i++){ nraw.data[i] += opts.val; } return true; });Here, the operation is performed on the existing "add" layer each time, so that the addition is cumulative.
The oraw and nraw objects contain a subset of the properties returned by JS9.GetImageData():
To switch to a layer, call JS9.RawDataLayer() with a single argument, the layer name:
JS9.RawDataLayer("raw0") # switch to original data JS9.RawDataLayer("clip") # switch to clipped data JS9.RawDataLayer("add") # switch to add dataTo get the currently displayed layer, call the routine with no arguments:
JS9.RawDataLayer() # returns "clip"
JS9.GaussBlurData(sigma, opts)
where:
See JS9.RawDataLayer() for more information about raw data layers.
JS9.ImarithData(op, arg1, opts)
where:
JS9.ImarithData("max", "foo.fits");will make a new data layer of the currently displayed image, where each pixel is the larger value from that image and the foo.fits image (which can be in any display).
This routine creates a new raw data layer called "imarith" containing the results of the operation. Successive calls to this routine are cumulative, so that you can build up a more complex operation from simple ones. For example:
# foo.fits is displayed in the "myJS9" display var myim = JS9.GetImage({display: "myJS9"}); JS9.ImarithData("max", myim); JS9.ImarithData("add", 2.718);will make a new data layer where each pixel is the larger value from the two images, after which an approximation of the irrational number e is added to each pixel.
The special reset operation deletes the "imarith" raw data layer, allowing you to start afresh.
The bitpix value of the new "imarith" layer is chosen as follows:
Finally, note that the two images must have the same dimensions. We might be able to remove this restriction in the future, although it is unclear how one lines up images of different dimensions.
See JS9.RawDataLayer() for more information about raw data layers.
JS9.ShiftData(x, y, opts)
where:
See JS9.RawDataLayer() for more information about raw data layers.
JS9.ReprojectData(wcsim, opts)
where:
mProjectPP performs a plane-to-plane transform on the input image, and is an adaptation of the Mopex algorithm and developed in collaboration with the Spitzer Space Telescope. It provides a speed increase of approximately a factor of 30 over the general-purpose mProject. However, mProjectPP is only suitable for projections which can be approximated by tangent-plane projections (TAN, SIN, ZEA, STG, ARC), and is therefore not suited for images covering large portions of the sky. Also note that it does not directly support changes in coordinate system (i.e., equatorial to galactic coordinates), though these changes can be facilitated by the use of an alternate header.These Montage programs have been compiled into JS9 using Emscripten.
The wcsim argument is an image id, image filename, or image object pointing to the WCS image. This is the image whose WCS will be used for the reprojection. Alternatively, if the wcsim argument is set to "all", the WCS from the currently displayed image will be used to reproject all other images in the display.
The opts object can contain the following reproject-specific properties:
{cmdswitches: "-d 1 -z .75"}will set the mProjectPP debugging and the drizzle factor, resulting in a command line that looks like this:
mProjectPP -d 1 -z .75 -s statusfile in.fits out.fits template.hdrSee the mProjectPP documentation for more information about command switches.
Reprojection is an intensive process which can take a considerable amount of memory and processing time. It also (at least currently) requires that the full reprojected image be displayed (so that the reprojected image can be properly aligned with the WCS image used in making the reprojection). We therefore restrict the WCS image size to be less than or equal to JS9.globalOpts.image.xdim by JS9.globalOpts.image.ydim. If the WCS image exceeds this size, an error is thrown.
See JS9.RawDataLayer() for more information about raw data layers.
JS9.RotateData(angle, opts)
where:
The optional opts object is passed directly to the JS9.ReprojectData() routine. See JS9.ReprojectData() above for more information.
JS9.FilterRGBImage(filter, args)
where:
The JS9.FilterRGBImage() routine supports a number of image processing routines, which are listed below. To call one of them using JS9.FilterRGBImage(), supply the filter name, followed by any filter-specific arguments, e.g.:
JS9.FilterRGBImage("luminance", {display: "myJS9"}); JS9.FilterRGBImage("duotone", "g", {display: "myJS9"}); JS9.FilterRGBImage("convolve", [-1,-1,-1,-1,8,-1,-1,-1,-1]);You can, of course, use the default arguments where applicable.
Note that the standard JS9 colormaps, scale, contrast and bias selections are applied to the raw data to regenerate the RGB image. Thus, if you use any of the image processing techniques listed below and then change colormap, contrast, bias, or scale, you will undo the applied image processing. This is a good way to reset the displayed image. The same thing can be accomplished programmatically by specifying "reset" as the filter name:
JS9.FilterRGBImage("reset", {display: "myJS9"});
The following simple image processing filters are available:
The following image convolutions are available:
With no arguments, the routine returns an array of available filters:
JS9.FilterRGBImage() ["convolve", "luminance", ..., "blur", "emboss", "lighten", "darken"]
JS9.SaveSession(session, opts)
where:
This routine saves session information related to the currently displayed image or all images in the specified display. The first argument can be a filename or an options object. If a filename is specified, the second argument can be the options object.
The opts options object supports a mode property whose value can be "display" (save all images in the specified display) or "image" (save the currently displayed image. If this property is not specified, the default is to save all images in the display.
If no filename is specified, the default filename depends on the save mode. If mode is "display", the default filename takes the form js9-[date].ses, e.g., "js9-2018-01-09.ses". If mode is "image", the default filename is [im.id].ses, e.g., "casa.fits.ses".
Saved information (filename, scaling, colormap, contrast/bias, zoom, regions, catalogs, etc) is stored in a JSON-formatted text file. You can subsequently load this file into JS9 to restore the image session. Don't forget that the file is saved by the browser in whatever location you have set up for downloads.
The session file is a text file and can be edited, subject to the usual rules of JSON formatting. For example, you can change the colormap, scaling, etc. after the fact.
The session file contains a file property near the top that specifies the location of the image. A local file usually will contain an absolute path or a path relative to the web page being displayed. However, if the image was originally opened using drag-and-drop, no pathname information is available, in accordance with standard web security protocols. In this case, you must edit the session file to supply the path (either absolute or relative to the web page) before re-loading the session.
JS9.LoadSession(session)
where:
Restore an image session by loading a JSON-formatted session file. The image itself is retrieved and loaded, and all of the saved parameters and graphics (scale, colormap, regions, catalogs etc) are applied to the display.
The pathname of the session file should either be absolute or should be relative to the web page.
The session file contains a file property near the top that specifies the location of the image. For browser-based JS9, a local file usually will contain an absolute path or a path relative to the web page being displayed.
On the desktop, session files and the associated data files often are moved around or used with different web pages, breaking the connection between the web page and the image path. To deal with this problem, the JS9.desktoplOpts.sessionPath variable is provided:
If the image was originally opened using drag-and-drop, no pathname information is available, in accordance with standard web security protocols. In this case, you may have to edit the session file to supply the path (either absolute or relative) before re-loading the session.
Note that the raw data file itself is not saved (only its pathname), so you must have access to that file in order to restore a session. However, the data file need not be in the same location as it was originally: you can adjust the path of the data file by editing the file property as needed.
Spatial regions of interest are a crucial part of astronomical data analysis. The regions layer is a special case of the more generalized Shape layers, automatically created by JS9 to support the options in the Regions menu, as well as local and server-side data analysis using regions. As such, these region routines are just a thin layer on top of the Shape routines, calling the equivalent Shape routine with "region" as the first argument.
Note that the JS9.GetRegions(), JS9.ChangeRegions(), JS9.RemoveRegions() calls all take a regions specification as the second argument, which can be any of the following (in order of precedence):
id = JS9.AddRegions(rarr, opts)
where:
# example 1: circular region in the center of the field JS9.AddRegions("circle"); # example 2: red circular region in the center of the field JS9.AddRegions("circle", {color: "red"}); # example 3: red circular region with dashed lines JS9.AddRegions("circle", {color: "red", strokeDashArray: [3,1]}); # example 4: regions using an object in first arg JS9.AddRegions({shape: "circle", color: "red", strokeDashArray: [3,1]}) # example 5: multiple regions using an array specification in first arg JS9.AddRegions([{shape: "circle", color: "red", strokeDashArray: [3,1]}, {shape: "box", color: "green", strokeDashArray: [6,1]}]) # example 6: js9 region syntax: properties in the second arg object JS9.AddRegions('ellipse(23:23:22.179, +58:48:10.542, 40", 20", 60)', {text: "ellipse test", color: "violet", tags: "json tag, another tag", textOpts: {color: "yellow", fontSize: 16, fontStyle: "italic", fontWeight: "bold"}}); # example 7: js9 region syntax: JSON properties in the first arg string JS9.AddRegions('ellipse(23:23:22.179, +58:48:10.542, 40", 20", 60) {"color": "violet", "text": "ellipse test", "textOpts": {"color": "yellow", "fontSize": 16, "fontStyle": "italic", "fontWeight": "bold"}} # json tag, another tag'); # example 8: ds9 region syntax: comment properties in the first arg string JS9.AddRegions('box(23:23:35.486, +58:50:03.146, 40", 20", 30) # width=4 text={box test} dash=1 color=red rotate=0 tag="test tag"') # example 9: create a region at the specified RA and Dec using ICRS # Note that the WCS string is returned by the Edit menu's "copy wcs pos" # option (i.e., the "/" keystroke.) JS9.AddRegions("circle", {wcs: "23:23:28.895 +58:49:43.50 ICRS"});In sum, you can specify a region using:
Examples 6 and 7 also show the text property, which allows you to associate a text string with a non-text region. JS9 will create a separate text region as a child of the original region. You can move this child text region around relative to the original region, change its angle, etc. The child will then maintain its new position relative to the original region as the latter is moved, resized, etc. You also can double-click on the text child to bring up its configuration dialog box and change its color, font, size, text string, etc.
rarr = JS9.GetRegions(regions, opts)
where:
If the regions argument is not specified, it defaults to "all". You can specify regions using any of the following:
Each returned region object contains the following properties:
The image position x, y can be used to access the image data returned by the JS9.GetImageData() routine:
obj = JS9.GetImageData(); xreg = JS9.GetRegions("selected")[0]; val = obj.data[Math.floor(xreg.y-0.5) * obj.width + Math.floor(xreg.x-0.5)];
Note the need to integerize the x and y values: JavaScript arrays are objects and so floating point array indices do not get truncated automatically as in C. They will return null values.
In opts.format is set to "text", the regions are returned as a string in standard regions format, using semi-colon delimiters:
JS9.GetRegions("all", {format: "text"}) "ICRS; box(23:23:40.340, +58:47:04.059, 29.513978\", 29.513974\", 0.000000) # background,include; ellipse(23:23:28.069, +58:48:40.540, 14.756998\", 15.756998\") # source,include"
JS9.ChangeRegions(regions, opts)
where:
The opts object can contain the parameters described in the JS9.AddRegions() section. However, you cannot (yet) change the shape itself (e.g., from "box" to "circle"). See js9onchange.html for examples of how to use this routine.
JS9.CopyRegions(to, regions)
where:
If the regions argument is not specified, it defaults to "all". You can specify a region selector using any of the following:
JS9.RemoveRegions(regions)
where:
If JS9.globalOpts.resetEmptyShapeId is set to true (default is false), the region id counter will be reset to 0 whenever all the regions are removed.
JS9.UnremoveRegions()
If you accidentally remove one or more regions, you can use restore them using this call. JS9 maintains a stack of removed regions (of size JS9.globalOpts.unremoveReg, current default is 100). Each time one or more regions is removed, they are stored as a single entry on this stack. The UnremoveRegions call pops the last entry off the stack and calls AddRegions.
JS9.SaveRegions(filename, which, layer)
where:
Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.
If the which argument is not specified, it defaults to "all". You can specify "selected" to return information about the selected regions, or a tag value to save regions having that tag.
If the layer argument is not specified, it defaults to "regions", i.e., the usual regions layer. You can specify a different layer, e.g., if you want to save a catalog layer as a region file (since JS9.SaveCatalog() will save the data in table format instead of as regions).
The layer argument can also be an object or a JSON-formatted string containing these properties:
Note that if the output type is set to svg, the default filename will be "js9.svg" instead of "js9.reg". Similarly, if a filename is specified that ends in ".svg", the type will be set to svg.
JS9.ToggleRegionTags(which, t1, t2)
where:
JS9.ToggleRegionTags("selected", "source", "background");will change a background region into a source/ region or vice-versa, depending on the state of the region, while:
JS9.ToggleRegionTags("selected", "include", "exclude");will toggle between include and exclude.
JS9.LoadRegions(filename, opts)
where:
The opts property specifies global options that are applied to all regions in the file. They will be over-ridden by individual region properties attached to a given region. For example, if a region file named "foo.reg" contains the following regions:
# Region file format: JS9 version 1.0 image circle(512.0, 512.0, 40) {"color": "red"} box(512.0, 512.0, 40, 40) annulus(512.0, 512.0, 0.0, 3.0, 12.0, 18.0, 27.0)then a command such as:
JS9.LoadRegions("foo.reg", {color: "blue"});will create a red circle, a blue box, and a blue annulus.
The opts object also can include an onload property containing a function to be called when the load is complete. The image handle is passed as an argument to this function.
If the same region file is loaded more than once, behavior is determined by the JS9.globalOpts.reloadRefreshReg property. If set to true (the default), all previous regions loaded from the file are removed (regardless of their current position, size, etc.) If set to false, the new regions are added to the previous ones. Site authors can change this property in js9prefs.js, while users can change this via the Global tab of the Preferences plugin.
JS9 supports individual layers for drawing 2D graphics. The regions layer is a special case of a shape layer, created automatically by JS9. The Catalog plugin creates a separate layer for each catalog. You can define your own shape layer using the NewShapeLayer() call and then add geometric shapes to it.
Note that the JS9.GetShapes(), JS9.ChangeShapes(), JS9.RemoveShapes() calls all take a shape specification as the second argument, which can be any of the following (in order of precedence):
lid = JS9.NewShapeLayer(layer, opts)
where:
The opts parameter allows you to specify default options for the new layer. Although this argument is optional, you generally will want to set default values for various properties utilized by your new shape layer. See JS9.Regions.opts in js9.js for example of the default options for the regions layer. This is a good set of options to pass if you want region-like behavior in your new layer.
The JS9.Catalogs.opts object is also supplied as a possible baseline object for new shape layers. It differs from the JS9.Regions.opts in a few important ways:
Starting with the JS9.Catalogs.opts object as a default, you can make the new layer interactive in a few different ways. The first way is to set the movable property in the opts object to true. This will permit individual shapes to be moved, rotated, resized and deleted. Shapes also will be movable and resizable as a group.
The second way is to supply one or more event callbacks as properties to the opts object:
opts.onmouseover = function(im, xreg, evt){ console.log("mouseover: %s %s", im.id, xreg.data.tag); }; opts.onmousedown = function(im, xreg, evt){ console.log("mousedown: %s %s", im.id, xreg.data.tag);Note that the shapes are still not movable unless you also set the movable property.
In addition to firing callbacks on events for individual shapes, you can set the ongroupcreate property in the opts object to a function that will fire when two or more objects are selected into a group (which is done using the Command key on a Mac, or Control key everywhere else):
opts.ongroupcreate = function(im, xreg, evt){ var i, nshape, xcen, ycen; var xtot=0, ytot=0; nshape = xreg.length; for(i=0; i<nshape; i++){ xtot += xreg[i].x; ytot += xreg[i].y; } xcen = xtot / nshape; ycen = ytot / nshape; console.log("average pos for %s objects: %s,%s", nshape, xcen, ycen); }
The final way to make a shape layer interactive is to specify a tooltip to display when hovering over objects in this shape layer. This is done by assigning a tooltip format string to the tooltip property of the opts object. This string can contain HTML directives, and it also can contain references to properties in the im, xreg, and evt objects. When the mouse hovers over an object, a tooltip string is generated by macro-expanding the values for these properties. The generated tooltip string is displayed as the inner HTML of the tooltip. When the mouse leaves the object, the tooltip is hidden.
For example, consider the following tooltip string:
opts.tooltip = "<b>id: $im.id</b><br>pos: $xreg.x $xreg.y<br><i>$xreg.data.tag</i>";Note how properties of the im and xreg objects are specified with a "$" prefix. When the mouse hovers over an object, the generated tooltip will display current image id in bold, followed by that object's x,y pixel position, followed by a user tag property passed in the data object when the shape was added. As a convenience, $data can be used as a shorthand for $xreg.data.
JS9.ShowShapeLayer(layer, mode)
where:
JS9.ToggleShapeLayers()
While JS9.ShowShapeLayer() allows you to display or hide a single shape layer, this routine will toggle display of all active layers in the current image. An active layer is one that has not been turned off using the Shape Layers plugin or JS9.ShowShapeLayer().
The routine remembers which layers were active at the moment when layers are hidden and restores only those layers in the next toggle. Thus, if you have two layers, "regions" and "catalog1", and the "catalog1" layer has previously been turned off, calling this routine repeatedly will turn on and off the "regions" layer only.
JS9.ActiveShapeLayer(layer)
where:
If no arguments are supplied, the JS9.ActiveShapeLayer() routine returns the currently active layer. Specify the name of a layer as the first argument to make it active. Note that the specified layer must be visible.
This routine forms the basis for the Shape Layer plugin, which provides a graphical way to make a layer active (by moving it to the top of the layer stack).
JS9.AddShapes(layer, sarr, opts)
where:
JS9.RemoveShapes(layer, shapes)
where:
If JS9.globalOpts.resetEmptyShapeId is set to true (default is false), the shape id counter will be reset to 0 whenever all the shapes are removed.
JS9.GetShapes(layer, shapes)
where:
Each returned shape object contains the following properties:
JS9.ChangeShapes(layer, shapes, opts)
where:
If the shapes argument is not specified, it defaults to "all". You can specify a selector using any of the following:
JS9.LoadCatalog(layer, table, opts)
where:
Two examples of catalog files are shown below:
ra dec magj magh magk ----------- ------------ ------ ---- ---- 23:22:56.003 58:44:45.429 15.612 15.103 14.9 23:22:56.230 58:45:32.011 13.723 13.174 12.981 23:22:56.319 58:45:08.954 14.212 13.119 12.723 ... # # VizieR Astronomical Server vizier.u-strasbg.fr # ... #Coosys J2000: eq_FK5 J2000 # ... #Title: 2MASS All-Sky Catalog of Point Sources (Cutri+ 2003) # ... #Column _RAJ2000 (A12) [ucd=pos.eq.ra] #Column _DEJ2000 (A12) [ucd=pos.eq.dec] #Column RAJ2000 (F10.6) [ucd=pos.eq.ra;meta.main] #Column DEJ2000 (F10.6) [ucd=pos.eq.dec;meta.main] #Column 2MASS (a17) [ucd=meta.id;meta.main] # ... #Column Aflg (I1) [ucd=meta.code] _RAJ2000 _DEJ2000 RAJ2000 DEJ2000 2MASS Jmag e_Jmag Hmag e_Hmag Kmag e_Kmag Qflg Rflg Bflg Cflg Xflg Aflg ------------ ------------ ---------- ---------- ----------------- ------ ------ ------ ------ ------ ------ --- --- --- --- - - 23 22 56.002 +58 44 45.43 350.733342 +58.745953 23225600+5844454 15.612 0.064 15.103 0.078 14.900 0.121 AAB 222 111 ccc 0 0 23 22 59.647 +58 44 56.84 350.748531 +58.749123 23225964+5844568 15.580 0.063 14.922 0.072 14.506 0.079 AAA 222 111 c00 0 0 23 22 56.981 +58 44 44.61 350.737422 +58.745724 23225698+5844446 14.920 0.049 14.292 0.049 14.002 0.055 AAA 222 111 ccc 0 0 ...Notice that both files have a tab-delimited header, followed by a tab-delimited line of dashes, followed by tab-delimited data rows. This file format is sometimes called "tsv" or "tab-separated values". A very useful astronomical package for manipulating tables is Starbase, written by John Roll.
The JS9.LoadCatalog() routine will read a file in this format, processing the data rows by converting the RA and Dec values into image position values that will be displayed as shapes in a new catalog layer.
The first argument to the JS9.LoadCatalog() routine is the name of the shape layer that will contain the objects in the catalog. Specifying the name of an existing layer is valid: previous shapes in that layer will be removed.
The second argument is either a blob or a string containing the table data described above. Blobs are the result of loading a local file into the browser (e.g., the load catalog menu option), while strings result from a remote XHR call (e.g., the Archives and Catalogs plugin). Alternatively, the second string argument can be a file name or URL to load. File names are distinguished from strings containing a table in that the latter must contain at least one tab.
The third argument is an optional object used to specify parameters, including:
The opts object also can include an onload property containing a function to be called when the load is complete. The image handle is passed as an argument to this function.
Note the second (Vizier) example table above does not actually have a columns called "RA" and "Dec". Instead, it has "_RAJ2000", "_DEJ2000", "RAJ2000", and "DEJ2000" columns. In order to pick RA and Dec column, a heuristic is used based on the values contained in the JS9.globalOpts.catalogs.ras and JS9.globalOpts.catalogs.decs arrays:
ras: ["RA", "_RAJ2000", "RAJ2000"] decs: ["Dec", "_DEJ2000", "DEJ2000"]These defaults make it easy to process simple catalogs and Vizier catalogs.
Once the RA and Dec columns are specified, the RA and Dec values from each row are converted into image positions, and JS9 shapes are generated to be displayed in the new catalog layer. The WCS system used to convert RA and Dec into image coordinates can be specified using the opts.wcssys or JS9.globalOpts.catalogs.wcssys properties.
The RA and Dec of the catalog object are always saved in the data object of each generated shape, for use in the tooltip string. In addition, if opts.save (or the default: JS9.globalOpts.catalogs.save) property is not false, all of the catalog object properties will also be save in the data object for use in the tooltip string, e.g.:
opts.tooltip = "$xreg.data.ra $xreg.data.dec $xreg.data.Qflg $xreg.data.Rflg"in the above VizieR example. Caveat: any "." (dot) in any catalog property name will be converted to "_" (underscore) automatically. For a more detailed discussion of tooltips, please see JS9.NewShapeLayer().
When catalog layer has been created, you can use the Shape Layers plugin to toggle its visibility and also to change its position in the layer stack.
JS9.SaveCatalog(filename, which)
where:
Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.
If the which argument is not specified, the catalog associated with the current active layer will be saved. In either case, the layer to save must actually be a catalog created from a tab-delimited file (or URL) of catalog objects (not, for example, the regions layer).
JS9 supports the following configurable mouse and touch actions:
Users can change the action assignments using the MouseTouch plugin, which displays the current mapping between mouse/touch gesture and its action. Simply drag and drop an action to a different gesture in order to change the mapping. You also can toggle the scroll/pinch to zoom capability by clicking its button.
Web page developers can extend the available mouse and touch actions beyond the defaults contained in the Mouse Touch plugin. To add a new action, first write a function with the following calling sequence:
gestureFunc(im, ipos, evt)where:
JS9.MouseTouch.Actions["all contrast/bias"] = function(im, ipos, evt){ var i, myim; for(i=0; i<JS9.displays.length; i++){ myim = JS9.displays[i].image; if( myim ){ JS9.MouseTouch.Actions["change contrast/bias"](myim, ipos, evt); } } };At this point, the Mouse Touch Plugin will display the new function in its list of available actions. Users can move it into one of the defined gestures to activate it.
Of course, you can add the new action to the JS9.globalOpts.mouseActions and/or JS9.globalOpts.touchActions arrays to make it active immediately:
JS9.globalOpts.mouseActions[1] = "all contrast/bias"; JS9.globalOpts.touchActions[1] = "all contrast/bias";Here, we have replaced the one-button mouse move and two-button touch move actions (whose defaults are to "change contrast/bias") with our new action.
JS9.GetAnalysis()
The JS9.GetAnalysis() routine returns an array of analysis task definitions, each containing the following information:
JS9.RunAnalysis(name, parr, func)
where:
http://api.jquery.com/serializeArray/
The func() routine is a callback function to process the returned results from the analysis task. The calling sequence is:
func(stdout, stderr, errcode, aobj)where:
If no func callback is specified, the default processing will display "text" in a new light window. If the return type is "plot", the results are assumed to be in flot format and will be plotted.
Instead of passing a callback function each time, you can set the global property JS9.globalOpts.analysisFunc to a function having the same signature:
func(stdout, stderr, errcode, aobj)The specified function will be called for each execution of JS9.RunAnalysis
In addition, you can change the target of the analysis results display from a light window to your own div element by setting the global property JS9.globalOpts.analysisDiv to the id of your new target div. The div must have CSS height and width properties if you are going to plot results.
JS9.SubmitAnalysis(el, name, func)
where:
The func callback and global options are the same as for JS9.RunAnalysis() above.
JS9.CreateMosaic(which, opts)
where:
Because the browser environment is memory-limited, there are some restrictions on generating mosaics in JS9. The FITS files must be well-behaved, i.e., they must have WCS projections which can be approximated by tangent-plane projections (TAN, SIN, ZEA, STG, ARC). This precludes creating mosaics from images covering large portions of the sky. For large sky areas, please use Montage itself on your desktop to create a mosaic. A simplified js9mosaic script is included in the JS9 distribution or, for more control, use the Montage programs directly. Of course, in either case, you must install Montage.
The which parameter determine which images are used in the mosaic:
In order to keep the size of the resulting mosaic within memory limits, JS9 reduces the size of each image before adding them all together The options parameter determines how the reduction is performed:
The resulting mosaic will be loaded into the specified JS9 display as a separate image. Because the mosaic is separate from the original image(s), you can view each of the latter individually (or view each image extension of a single image using the Extensions plugin). Internal analysis can be performed on the mosaic (e.g., ImExam functions) but, of course, no external analysis tasks will be available.
dobj = JS9.LookupDisplay(dname, mustExist)
where:
If dname is specified but does not exist, an error is thrown unless the mustExist parameter is explicitly set to false (i.e., the default is that the id must exist).
JS9.ResizeDisplay(dname, width, height, opts)
where:
If the first argument is full, the display is resized to match the browser window.innerWidth and window.innerHeight variables, which are the width and height (in pixels) of the browser window viewport. You can then scroll the window so that the image fills the entire browser window. Alternatively, if the first argument is reset, the display is resized to match its original size.
The opts object can contain the following properties:
If no arguments are passed to this routine, it returns an object containing the current display width and height. Otherwise, the display object is returned.
You can supply a display name as the first argument, or the display object:
JS9.ResizeDisplay("myJS9", 350, 400);or:
JS9.ResizeDisplay(350, 400, {display: "myJS9"});
JS9.MoveToDisplay(dname)
where:
JS9.MoveToDisplay("myJS9", {display: "JS9"});will move the current image displayed in the "JS9" display window to the "myJS9" window.
Note that the new JS9 display must already exist. New displays can be created with the JS9.LoadWindow() public access routine or the File:new JS9 light window menu option.
JS9.GatherDisplay(dname, opts)
where:
This routine move all images in other displays to this display. You can supply a display name or the display object:
JS9.GatherDisplay("myJS9");or:
JS9.GatherDisplay({display: "myJS9"});You can supply an opts object containing the properties:
JS9.SeparateDisplay(dname, opts)
where:
JS9.SeparateDisplay("myJS9");or:
JS9.SeparateDisplay({display: "myJS9"});You also can supply an opts object containing the properties:
Note that you can supply the opts object without supplying the display parameter, e.g:
JS9.SeparateDisplay({layout: "horizontal"});will separate images from the default "JS9" display in a horizontal layout.
By default, the ids of the successive JS9 displays will consist of the original display id, followed by the string "_sep", followed by an increasing integer (not necessarily starting at 1). If you pass the idbase property in the opts object, the id of each successive display will be the specified base id followed by an increasing integer that does start from 1. In the latter case, it is your responsibility to ensure that the new ids to not conflict with existing ids.
JS9.CenterDisplay(dname)
where:
This routine scrolls this display to the center of the viewport. You can supply a display name or the display object:
JS9.CenterDisplay("myJS9");or:
JS9.CenterDisplay({display: "myJS9"});
JS9.RenameDisplay(oid, nid)
Calling sequences:
JS9.RenameDisplay(nid) # change default id (usually "JS9") to nid JS9.RenameDisplay(oid, nid) # change oid to nid
where:
This routine is used by the Desktop version of JS9 to implement the --title (and --renameid) switch(es), which change the id of the JS9 display(s) to the specified id(s). Once an id has been renamed, external communication (via the js9 script or pyjs9) should target the new id instead of the original id.
The original id is still available internally, so Javascript public API calls on the web page itself can target either the original or the new id using the {display: "id"} syntax.
JS9.CloseDisplay(dname)
where:
This routine closes all images in the specified display. You can supply a display name as the first argument or the display object:
JS9.CloseDisplay("myJS9");or:
JS9.CloseDisplay({display: "myJS9"});
JS9.Print(opts)
where:
Print the currently displayed image. A new window is displayed containing the image, along with regions and other graphical layers (the 2D graphics having been converted to a re-scalable format). The standard Print dialog box also is displayed and can be used to print this new window. Dismiss both windows when you are finished.
By default, if a colorbar is active on the page, it will be placed beneath the image. You can pass the colorbar: false option in the opts object to avoid printing the active colorbar.
JS9.WindowPrint(opts)
where:
The JS9 desktop application that utilizes Electron.js has the ability to print the whole application window. When executed, the system print dialog box is displayed (unless the silent the option is passed in opts) and the window will be printed according to your print configuration.
The first argument allows you to specify the following options:
JS9.WindowToPDF(filename, opts)
where:
The JS9 desktop application that utilizes Electron.js has the ability to save the whole application window to a PDF file. The first argument specifies the name of the PDF file.
The second argument allows you to specify the following options:
JS9.SaveDir(dirname)
where:
The savedir directory can be specified on the desktop command line using the --savedir switch:
js9 -a --savedir $HOME/tmp ~/data/casa.fitsBut you can use this routine to set or change the save directory at any time:
js9 SaveDir "$HOME/tmp"Future downloads for this desktop session will then be saved (without use of a dialog box) to the specified directory.
It's worth remembering that relative paths are taken relative to the directory in which the JS9 app was started, not the current directory in which you are running the js9 SaveDir command. To avoid confusion, it is recommended that you supply a full path.
JS9.SaveFITS(filename)
where:
Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.
JS9.SavePNG(filename, opts)
where:
The opts object can specify the following properties:
Also by default, SavePNG() will save the RGB pixels from the display. This means, for example, that a blended set of images will save the blended pixels. If you want to save the RGB pixels from one of the images in a blended image, you can specify the source property to the image. For example, in the js9blend.html demo, you can save the RGB pixels of the Chandra image by specifying use of the "image" source and specifying the image's id in the display parameter:
JS9.SavePNG("chandra.png", {source:"image"}, {display:"chandra.fits"});
Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.
JS9.SaveJPEG(filename, opts)
where:
The opts object can specify the following properties:
Also by default, SaveJPEG() will save the RGB pixels from the display. This means, for example, that a blended set of images will save the blended pixels. If you want to save the RGB pixels from one of the images in a blended image, you can specify the source property to the image. For example, in the js9blend.html demo, you can save the RGB pixels of the Chandra image by specifying use of the "image" source and specifying the image's id in the display parameter:
JS9.SaveJPEG("chandra.png", {source:"image"}, {display:"chandra.fits"});
If encoder quality parameter is not specified, a suitable default is used. On FireFox (at least), this default values is 0.95 (I think).
Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.
JS9.UploadFITSFile()
Upload the currently displayed FITS file to the proxy server, so that back-end analysis can be performed. This routine requires that a Node.js-based JS9 helper is running and that the helper has enabled the loadProxy property and set up a workDir directory in which to store the FITS file.
JS9.GetFITSHeader(nlflag)
where:
Note that the JS9.GetImageData() routine also returns the FITS header, but as an object whose properties contain the header values. For example, obj.SIMPLE will usually have a value of true, obj.BITPIX will have contain the bits/pixel, etc. This object is more useful for programming tasks, but does not contain the FITS comments associated with each header card.
JS9.DisplayHelp(name)
where:
JS9.DisplayPlugin(name)
where:
You can supply the full class and plugin name or just the name, using exact case or lower case, e.g.:
As with plugins in the View and Analysis menus, this routine does nothing if the plugin is explicitly defined on the web page.
This routine is useful if you are building a web interface that supports the JS9 menu functions.
JS9.LightWindow(id, type, content, title, opts)
where:
The content shown inside the window depends on the content parameter:
The opts parameter specifies options for the light window, such as its size. This parameter consists of a string with comma-separated keywords, e.g.:
"width=830px,height=400px,center=1,resize=1,scrolling=1"The opts keywords, defined in the Dynamic Drive documentation, are: width, height, left, top, center, resize, and scrolling. The JS9.lightOpts.dhtml object defines oft-used lightwin configurations, and the JS9.lightOpts.dhtml.textWin property is used as the default for this call. You can utilize these properties in your own call to JS9.LightWindow() or make up your own configuration string.
As an extension to the Dynamic Drive light window support, JS9 adds the ability to double-click the title bar in order to close the window.
JS9.OpenFileMenu()
Calling this routine brings up the browser's file dialog box. When a FITS file is selected, if will be loaded into the JS9 display.
This routine is useful if you are building a web interface that supports the JS9 menu functions.
JS9.OpenRegionsMenu()
Calling this routine brings up the browser file menu. When a region file is selected, if will be loaded into the JS9 display.
This routine is useful if you are building a web interface that supports the JS9 menu functions.
JS9.OpenColormapMenu()
Calling this routine brings up the browser file menu. When a JSON-format colormap file is selected, it will be loaded into the JS9 display. The colormap file can take one of two forms (without the comments):
# RGB color triplets for the I8 colormap in a "colors" property {"name":"i8","colors":[[0,0,0],[0,1,0],[0,0,1],[0,1,1],[1,0,0],[1,1,0],[1,0,1],[1,1,1]]} # all 3 vertex arrays for the purple colormap in one "vertices" property {"name":"purple","vertices":[[[0,0],[1,1]],[[0,0],[0,0]],[[0,0],[1,1]]]}This routine is useful if you are building a web interface that supports the JS9 menu functions. See JS9.AddColormap() for more information about colormap formats.
val = JS9.GetToolbar(type)
where:
JS9.SetToolbar(arg1, arg2)
where:
Examples of tool objects:
{ "name": "linear", "tip": "linear scale", "image": "images/toolbar/dax_images/lin.png", "cmd": "SetScale", "args": ["linear"] }, { "name": "histeq", "tip": "histogram equalization", "cmd": "SetScale", "args": ["histeq"] }, { "name": "annulus", "tip": "annulus region", "image": "images/toolbar/dax_images/annulus.png", "cmd": "AddRegions", "args": ["annulus"] }, { "name": "remove", "tip": "remove selected region", "image": "images/toolbar/dax_images/erase.png", "cmd": "RemoveRegions", "args": ["selected"] }, { "name": "zoom1", "tip": "zoom 1", "image": "images/toolbar/dax_images/mag_one.png", "cmd": "SetZoom", "args": [1] }, { "name": "magnifier", "tip": "toggle magnifier display", "image": "images/toolbar/dax_images/mag.png", "cmd": "DisplayPlugin", "args": ["JS9Magnifier"] }Each time a tool is added to the list of available tools, the active Toolbar plugins will be re-initialized to display that tool. By default, the new tool not be added to the top-level list: you must also edit the JS9.globalOpts.toolBar array to add the name of the tool. If this is done after you add the tool, remember to re-initialize active toolbars by calling:
JS9.SetToolbar("init");
rpath = JS9.InstallDir(file)
where:
JS9.Send(msg, obj, cb)
where:
Communication with the back-end is usually done behind the scenes and need not concern users or application programmers. However, if you write your own socket.io-based server, you might want to add project-specific messages to your implementation. For example, a Perl-based or Python-based server might add its own special messages that execute Perl or Python commands within the server in response to JS9 messages. In this case, you can use JS9.Send() to send a message to these message handlers.
The msg name is the name of the message, as defined by the server. By convention, an object is usually passed to the message handler. JS9 will add a dataPath property to this object to indicate the current list of directories in which to search for data. All other properties are specific to the message being handled. You can pass a null instead of an object and JS9.Send() will generate a temporary object to hold the dataPath.
The cb function will be called if the message sends an acknowledgment. The arguments passed to this function call by the server are specific to the message being handled.
For example, you can send a message to the back-end server to retrieve the list of available analysis tasks and then display this list using the call:
JS9.Send("getAnalysis", null, function(s){alert(s)});The "getAnalysis" message passes no parameters to the server. The server returns a list of available analysis tasks in JSON format.
JS9.AddDivs(id1, id2, ...)
where:
The routine will accept a list of JS9 display divs to initialize. If all you are doing is adding one or more plugins to an existing display, leave the argument list empty.
For example, to add a new JS9 display and menubar at the end of a web page and load an image into that display:
var html = "<div class='JS9Menubar' id='myJS9Menubar'></div><div class='JS9' id='myJS9'></div>"; // jquery append to end of page $(html).appendTo($("body")); // create the new JS9 display, with associated plugins JS9.AddDivs("myJS9"); // just a standard load to that display JS9.Load("foo.fits", {scale: "log"}, {display: "myJS9"});You can use JS9.LoadWindow() to load images into a light-weight or completely new window. To do this with your own routine, you should call JS9.AddDivs() after the window has been created. You can use the jQuery arrive wrapper that implements support for the MutationObserver:
// once the window exists containing the div id, we can finish the set up $("#window").arrive("#"+id, {onceOnly: true}, function(){ finishUp(); }); // (make-believe) create light win routine, where id is the window div id myCreateLightWindow(id, html, title, opts);
JS9.InstantiatePlugins()
Normally, JS9 will instantiate all of its plugins automatically once the page is loaded and ready: internally, jQuery $(document).ready() calls JS9.init(). However, module loaders such as Require.js can load scripts asynchronously and cause jQuery $(document).ready() to fire before all JS9 scripts are available. The JS9.RegisterPlugin() routine should deal properly with this situation. But just in case ... the JS9.InstantiatePlugins() will perform the plugin instantiation explicitly.
In you find you need to call this routine in order make your in-page plugins display properly, please let us know the circumstances.
NB: The routines in this section are prototypes and therefore are subject to change. Feel free to contact us to discuss your needs so that we can gain a better understanding of what is required in these cases.
JS9.LoadAuxFile(name, func)
where:
It sometimes is desirable to process auxiliary files when an image is first loaded. Examples include overlaying an image mask on an image, and pre-loading regions from a region file. The JS9.LoadAuxFile prototypes this sort of functionality.
Auxiliary files are defined in the js9Prefs.json file by means of the JS9.auxfiles array containing one or more auxfile objects. Each auxfile specification has the following properties:
"auxFiles": [{"type": "mask", "name": "sciencemasks", "image": "casa.*.png", "url": "../myauxfiles/casa-mask.png"}, {"type": "regions", "name": "scienceregions", "image": "casa.*.png", "url": "../myauxfiles/casa.reg"}],Here, a mask auxfile and a regions auxfile are defined for Cas-A dataset(s). These auxfiles are brought into play as follows:
// run this routine after loading each image function onImageLoad(im){ JS9.LoadAuxFile("sciencemasks", function(im, aux){ // if we succeed in loading the mask, set up the onchange callback im.onregionschange = regionOnChange; // view the image through the mask data im.maskData = aux.im.raw.data; // I mean now! im.displayImage("all"); }); JS9.LoadAuxFile("scienceregions"); } // tell JS9 about the onload callback JS9.imageOpts.onload = onImageLoad;An onImageLoad function is defined that will try to load auxfiles of types "sciencemasks" and "scienceregions". This routine is set to be called whenever a new image is loaded.
On image load, when JS9.LoadAuxFile() is called, it looks in the list of known auxfiles for an entry that matches both the class name and the image name. If found (in the example above, for Cas-A datasets), the associated auxfile URL is loaded and type-specific processing is performed:
As should be clear from the description above, considerable "black magic" currently is involved when processing auxiliary files. Visibility is required into the inner properties of the image object. Please contact us if you want to work with auxiliary files, so that we can continue to think about what is required for their support.
The JS9 Public API is meant to be stable and well-documented. If we are forced to make an incompatible change to the API, it will be documented here.
Prior to JS9 version 2.1, JS9.DisplaySection() always used the center of the file, along with dimensions and binning specified by the JS9.globalOpts.table and JS9.globalOpts.image objects, if these properties were not explicitly specified. This was just wrong: it meant that you could not set up a section and then repeated change the filter or position without re-specifying the current section parameters. We therefore changed the default behavior so that unspecified properties take on the current values. To use the original defaults, simply specify 0 for xcen and ycen, and use the globalOpts values for dimensions and binning.
The routines JS9.OpenFileMenu() and JS9.OpenRegionsMenu() required a display argument, instead of utilizing the standard optional display object. This mistake has been corrected, with the result that both routines now target the default display, as expected, if no display is passed.
The public Set routines (JS9.SetZoom(), JS9.SetColormap(), etc) were returning a boolean true when successful. This has been changed to "OK", to make it clear that the return value is a status value, not a boolean data value.
Due to an oversight, the signature of the callback function supplied to JS9.RunAnalysis() (and its derivative function, JS9.SubmitAnalysis()) was missing the errcode argument. To correct this mistake, the signature was changed from:
func(stdout, stderr, aobj)to:
func(stdout, stderr, errcode, aobj)See js9onchange.html for an example of using this callback function.