Skip to content

API Reference

Peter Griggs edited this page Mar 29, 2021 · 76 revisions

Kyrix offers a concise set of declarative primitives for creating scalable visualizations. This wiki serves as an API reference. Users should refer to our tutorial wiki for more details on the concepts and their relationships in the Kyrix declarative model.

Project

πŸ”— Project(name, config_file) <>

Constructs a project object, which holds all information about an application. Details on the arguments:

  • name: the name of the project
  • config_file: path to the config file. Normally, if you use our docker image and the compile script, config_file should be ../../../config.txt.

πŸ”— project.addView(view) <>

Adds a view to a project.

πŸ”— project.addCanvas(canvas) <>

Adds a canvas to a project.

πŸ”— project.addJump(jump) <>

Adds a jump to a project.

πŸ”— project.addSSV(ssv, args) <>

Adds a Scalable Scatterplot Visualization (SSV) to the project. ssv is a JSON object with specifications of the SSV in the declarative grammar offered by Kyrix-S. Details of the grammar can be found in the documentation of Kyrix-S. args, which is optional, is an object with two optional fields: view and pyramid. view is a view object. If view is not specified, this method creates a new view with the initial canvas being the first zoom level of the SSV. Specifying a view serves as an indication that no new view needs to be created. pyramid is an array of canvases. If pyramid is specified, this method adds new layers to each canvas in the array, resulting in pyramid.length zoom levels in the SSV. If pyramid is not specified, this methods adds a set of new canvases into the project. The number of canvases added is specified in ssv.

This method returns an object with two fields view and pyramid. view is either the new view created or args.view. pyramid is either the set of new canvases created or args.pyramid. This returned object can be useful in doing a variety of things. For example, more layers can be added to canvases in pyramid. One can also pass this returned object as args in another addSSV() to overlay multiple SSVs.

πŸ”— project.addUSMap(usmap, args) <>

Adds a US choropleth map to the project. usmap is a JSON object defining the choropleth map based on the template USMap API. args, which is optional, is an object with two optional fields: view and pyramid. view is a view object. If view is not specified, this method creates a new view with the initial canvas being the state-level map. Specifying a view serves as an indication that no new view needs to be created. pyramid is an array of canvases with at most two canvases (one for the state map, one for the county map). If pyramid is specified, this method adds new layers to each canvas in the array. If pyramid is not specified, this methods adds a set of new canvases into the project. The number of canvases added is either 1 or 2 depending on whether county is specified in usmap.

This method returns an object with two fields view and pyramid. view is either the new view created or args.view. pyramid is either the set of new canvases created or args.pyramid. This returned object can be useful in doing a variety of things. For example, more layers can be added to canvases in pyramid.

πŸ”— project.addStaticAggregation(staticAggregation, args) <>

Adds a static aggregation (a treemap, a circle pack, a bar chart or a pie chart) to the project. staticAggregation is a JSON object defining the static aggregation based on the template Static Aggregation API. args, which is optional, is an object with two optional fields: view and canvas. view is a view object. If view is not specified, this method creates a new view with the initial canvas showing the static aggregation. Specifying a view serves as an indication that no new view needs to be created. canvas is a canvas object. If canvas is specified, this method adds new layers to the canvas. If canvas is not specified, this methods adds a new canvas into the project.

This method returns an object with two fields view and canvas. view is either the new view created or args.view. canvas is either the new canvas created or args.canvas. This returned object can be useful in doing a variety of things. For example, more layers can be added in canvas.

πŸ”— project.addRenderingParams(rendering_params) <>

Specifies rendering parameters that can be accessed by rendering functions and transform functions. rendering_params should be a JS object mapping names of parameters to numbers, strings or functions (nested objects are not supported). Note that the name of a function must have _func as a suffix. An example is here. In general, the name of a rendering parameter can be any that is allowed by Javascript. When the application has SSVs authored with Kyrix-S, however, names like ssv0, ssv1, ssv2 will be reserved. So be sure not to use them.

πŸ”— project.addStyles(css_filepath) <>

Specifies a separate CSS file for the project. Note that this works when correct selector properties (classes, ids) are applied in rendering functions. Simple usage: p.addStyles("project.css"). An example is here.

πŸ”— project.saveProject() <>

Serializes a project into a JSON string, saves it in the database and sends it to the backend. If the backend is not running, Kyrix compiler will prompt an error that can be ignored. Note that after this function is called, Kyrix will create (if not existed) a database and a project table to store the serialized definitions of projects. The database name is specified in the config file (kyrix by default in docker containers).

πŸ”— project.setInitialStates(view, initial_canvas, initial_viewport_x, initial_viewport_y, initial_predicates) <>

Sets the initial states of a view object, including an initial canvas (initial_canvas) to show in the view when the app is first loaded, the canvas coordinates (initial_viewport_x and initial_viewport_y) of the top left-hand corner of the view, and a predicate object (initial_predicates) used to filter the transform data of the layers on the initial canvas. The predicates should be specified as a JS object mapping layers to binary AND/OR/EQ expression trees. Consider the following example:

p.setInitialStates(leftView, employeeCanvas, 300, 400, {"layer0" : {"==" : ["age", 30]}});

which enables the visualization user to first see in the leftView a canvas showing employees with age 30. The canvas coordinates of the top lefthand corner of the viewport is at (300, 400). Kyrix compiler will prompt error if this describe a viewport that is (partially) outside the initial canvas.

πŸ”— project.setFetchingScheme(fetchingScheme, deltaBox) <>

Sets the scheme of data fetching for all layers in the project. fetchingScheme can be either dbox (dynamic boxes) or tiling (using tiles). If specified as dbox, you can optionally specify whether to use deltaBox. If deltaBox is set to true, performance gain should be observed but the renderer of any layer must be able to render a subset of all data in the viewport.

By default, all layers use dbox and have deltaBox=true, which should work the best in most cases. In some cases, using tiling or deltaBox=false might be desirable. For example, when rendering a heatmap layer, the renderer must accept all data items in the viewport to be able to render a heatmap, thus requiring either tiling or deltaBox=false.

Alternatively, you can configure the fetching scheme of a layer using Layer.setFetchingScheme.

View

πŸ”— View(id, width, height) <>

Constructs a view object. id is the identifier of this view. Two views cannot have the same id. width and height are the size of this view in number of pixels. Note that for each view, Kyrix's front-end reserves a surrounding padding area for rendering axes. The size of the padding is 70 pixels. Therefore, the real width/height of the view is width+140/height+140.

Canvas

πŸ”— Canvas(id, w, h, w_string, h_string) <>

Constructs a canvas object. This constructor is passed in the identifier, width and height of the canvas (in number of pixels). The width (or height) can also be specified as a SQL query (w_string and h_string) to the database. For either dimension, if the size of the canvas is larger than the viewport size, panning is automatically enabled in that dimension. See an example here.

πŸ”— canvas.addLayer(layer) <>

Adds a layer to a canvas. Layers in a canvas are numbered from 0 in the order they are added.

πŸ”— canvas.addAxes(axes) <>

Adds axes to the canvas. Note that this is for creating axes that will be dynamically updated as the viewport changes. Static axes can be created using static layers.

axes is a JS function being passed in a parameter args, which is a JS object with some useful info about the view that the canvas is displayed in:

Parameter Description
canvasId The id of the current canvas.
canvasW The width of the current canvas.
canvasH The height of the current canvas.
pyramidLevel The zoom level of the current canvas (0-based).
viewportW The width of the current view, excluding padding.
viewportH The height of the current view, excluding padding.
predicates An array of predicate objects applied on the canvas.
tileW The width of a tile (for tiling fetching scheme).
tileH The height of a tile (for tiling fetching scheme).
viewId The id of the current view.
renderingParams The rendering parameters of the current project.

and returns an array of axis objects. An axis object is a JS object containing a couple fields:

  • dim, required, indicates the dimension (either x or y);
  • axis, required, is a D3 axis object indicating the orientation of the axis;
  • scale, required, is a D3 scale object specifying the mapping from the axis domain to the "visual canvas range", e.g., [0, args.canvasW/args.canvasH];
  • translate, required, is the amount of translation of the axis relative to the top lefthand corner of the view;
  • styling, optional, is a custom function that styles axis elements. It's passed in a <g> where the axis is drawn.

Axes will be rendered in the order they are in the returned array. An example is here.

Transform

πŸ”— Transform(query, db, transform_func, schema, separable) <>

Constructs a transform object. Details on the arguments:

  • query: the SQL query to fetch raw data;
  • db: the DB name that query is run in.
  • tranform_func: a function that transforms the SQL query results into desired format. It is passed in a row in the SQL query results, the width & height of the canvas, and the rendering parameters, and returns a transformed row. Currently, you need to specify a new JS array ret at the beginning of the function body and return Java.to(ret ,"java.lang.String[]"). An example is here. This function can be specified as an empty string, which indicates that raw query results do not need to be "cooked" in anyway.
  • schema: an array of strings representing the names of the fields of the transformed records. If transform_func is an empty string, this array can be an empty array. The names will then be inferred from the SQL query result metadata. For updatable layers, this value should be an object that maps strings -> functions (see section below for more details).
  • separable: a boolean representing whether tranform_func takes as input one row (separable) or all rows (non-separable) in the SQL query result. Right now the system only supports separable cases, so this argument has no effect.

Note that a null value in the query result is converted to an empty string before being passed into transform_func. To avoid unexpected behaviors, make sure to clean up null values in the database beforehand.

Alternatively, users should clean/transform their data outside Kyrix if it's more convenient.

Transform for Updatable Layer

To enable updates on a layer, a transform object must be instantiated with a schema is that is an object itself mapping the field names to reverse functions for each field. A reverse function for a field has a uniform function signature function (oldRow, width, height) where the parameter oldRow contains the already transformed fields, and width/height are the dimensions of the transform's layer. Each reverse function must return a new transformed row, which is used to update the base and index table of the current layer. See (https://github.com/tracyhenry/Kyrix/blob/31b5d24cf471c052b49124b4a6a45c3070c31c19/compiler/examples/nba/transforms.js#L25) for an example using the NBA visualization. All fields listed in the schema object are processed by the Kyrix compiler and added to the update menu for that layer, and any fields not listed don't allow updates.

Layer

πŸ”— Layer(transform, is_static) <>

Constructs a layer object. transform is a transform object, which is used as the data source for rendering this layer. For static layers, transform can be specified as null. is_static is a boolean representing whether this layer is static. If is_static=false, the layer is a called a dynamic layer. Static layers do not change when the user pans or zooms. Dynamic layers respond to user actions, and trigger dynamic data fetching.

πŸ”— Layer.addPlacement(placement) <>

Associates a placement function with a dynamic layer (do not call this function for static layers). This placement function calculates a bounding box for each row in the transform result of this layer, and should be specified as a JS object with four fields: centroid_x, centroid_y, width and height. Each of these fields can be either a constant (e.g. con:1000) or a column from the data transform result (e.g. col:x). To specify bounding boxes that span the entire canvas, a shortcut is to specify any of the fields as full. Some examples are here.

πŸ”— Layer.addRenderingFunc(rendering) <>

Associates a rendering function with a layer. This rendering function is passed in the following:

  • svg: an HTML SVG element which the rendering function attaches visual marks to;
  • data: a JS array containing a set of data rows. Each row is a JS object mapping field names (specified in/generated by the data transform of this layer) to data values. These are all rows whose bounding boxes (specified in the placement function) intersect with the current viewport. So they are only a subset of all data on the current canvas. Note that any original data field is typed string by default. So make sure to cast it to number format before assigning them to numeric visual properties. Two generated data fields cx and cy exist for each row, which are the centroid coordinates of that row.
  • args: a JS object containing some useful info about the current view that the layer is displayed in. In addition to everything shown in the table in Canvas.addAxes, there are also viewportX/viewportY, which are the current viewport coordinates (top left-hand corner), and the id of the layer layerId.

This rendering function should create SVG elements based on data rows, and does not return anything. There are several constraints on this function:

  • It should create a <g> element at the beginning;
  • To enable data-driven jumps, you should use D3's data joins to bind data to visual elements.
  • Do not modify data in any way.
  • The renderer should not register any mouse-dragging related event listeners such as dragstart or d3.zoom. Mouse movement event listeners (e.g. mouseover or mouseout) used to show things upon hover are fine.
  • To make an SVG element stay size-invariant during a literal zoom (see Jumps), you need to add a class kyrix-retainsizezoom to it. Points of interests (e.g. restaurants) on Google Maps are an example of where this is useful. If this class does not exist on an SVG element, this element will be scaled during a literal zoom. Background maps are an example.

An example is here.

πŸ”— Layer.addTooltip(tooltipColumns, tooltipAliases) <>

Enables the user to see a tooltip of data fields when hovering over a visual mark on this layer. tooltipColumns is an array of data fields to be displayed. tooltipAliases, an optional array of strings, allows the fields to be displayed differently than the original database field name. For example, whentooltipColumns=["studentName", "courseId"], setting tooltipAliases=["Name of student", "Course ID"] would make the tooltip more readable. If tooltipAliases is present, it must have the same number of elements as tooltipColumns.

Enabling tooltip requires that data is bound to visual marks. A common mistake is often made when using data generated by some D3 APIs (e.g. d3-treemap). The data items generated often have the meaningful data fields stored in a nested data field, i.e. data.data. You need to flat them out as the outermost fields to make this addTooltip API work.

πŸ”— Layer.setFetchingScheme(fetchingScheme, deltaBox) <>

Sets the scheme of data fetching for this layer. fetchingScheme can be either dbox (dynamic boxes) or tiling (using tiles). If specified as dbox, you can optionally specify whether to use deltaBox. If deltaBox is set to true, performance gain should be observed but the renderer of this layer must be able to render a subset of all data in the viewport. See also Project.setFetchingScheme.

Jump

πŸ”— Jump(sourceCanvas, destCanvas, type, optional_args) <>

Creates a jump of type type from sourceCanvas to destCanvas. type can be one of following (you can click on the a GIF to see the code for that example):

literal_zoom_in or literal_zoom_out. Similar to Google Maps, the user can spin the mouse wheel or click on a zoom button to zoom in/out, and use mouse dragging to pan (note that for literal zooms, sourceCanvas and destCanvas must have at least one dynamic layer):

semantic_zoom. Zoom-like transition to connect two canvases with different coordinate systems. Zooming-back is automatically enabled for a semantic zoom:

geometric_semantic_zoom. A mix of a literal zoom and a semantic zoom. Similar to a literal zoom, for two canvases connected by a geometric semantic zoom, one canvas is simply a higher-resolution version of the other (e.g. state-level and county-level crime rates). Similar to a semantic zoom, it allows the user to click on a object and zoom into the viewport centered at that object. Zooming-back is automatically enabled for a geometric semantic zoom:

load. Loads a canvas in a view:

highlight. Coordinated highlighting between two views. See the GIF immediately above.

slide. Slide transition to connect two canvases with possibly different coordinates:


For literal zooms, optional_args is not needed. Kyrix will automatically enable double-click-based literal zooming. For the rest of the jump types, several additional parameters need to be provided in optional_args. Despite having sharp differences in looks, these jump types actually have one thing in common: they are all triggered by clicking on a visual object in one canvas, and then another canvas gets updated in some way (e.g. being zoomed into, being loaded).

More specifically, optional_args is a JS object containing several data-driven functions and variables. All data-driven functions are passed in an input row, which is the data bound to the visual object got clicked, as well as a JS object args containing useful info about the current view (see the table in Canvas.addAxes). More details:

  • selector: returns a boolean indicating whether visual objects to which row is bound to can trigger this jump. This function is required for all jump types except literal zooms. Generally, if row is null, this function should return false to avoid making things like axes labels/ticks trigger a jump or become clickable.

  • predicate: returns a set of predicates (JS objects that describe an AND/OR/EQ binary expression tree) in a JS object. Similar to project.setInitialStates, each predicate is used to select data of the one layer on destCanvas. Note that for highlight, this selection is done in the frontend and highlights all selected objects (and dims non-selected objects). For other jump types, this filtering is done in the backend (i.e. non-selected data is not passed to frontend).

    Also note that predicates of the current canvas can be retrieved from args.predicates, some of which can be included in the returned predicates to enable predicate chaining.

  • viewport: returns the viewport location after the jump, required for semantic_zoom, geometric_semantic_zoom and load. To specify a constant viewport, return a JS object with one property constant mapping to an array of two numbers, which are respectively the x and y coordinates of the top lefthand corner of the viewport (in the coordinate system set up by destCanvas).

  • name: returns the name of this jump. This name is shown in the popover menu after the visualization user clicks on a visual object. This argument if optional: the default name for a jump is the ID of destCanvas.

  • sourceView and destView: two view objects used to indicate that view coordination only happens when sourceCanvas is in sourceView and destCanvas is in destView.

  • noPrefix: if set to true, there will be no automatic prefix like "ZOOM IN" or "LOAD SOME VIEW with" attached to a jump option. By default this is set to false.

  • slideDirection: a number in [0, 360) indicating the direction of the slide jump. By default the sliding direction is 0, i.e., sliding towards east.

  • slideSuperman: if set to true, the sliding animation will have a superman flying. By default this is set to false.

Some examples can be found here.