Creating a Custom Visualization with Scala and Java script

You can create visualizations using the Custom Operator SDK, the common JavaScript libraries D3, Plotly, and Dojo.

Work through this example to create a custom visualization. When you are comfortable with the workflow, customize the example to create your own custom visualization.
Before you begin Review the section on Custom Operators.

Install the Installing the Custom Sample Operator for your Version.

The following two files, located in the SDK, are required for the Javascript visualization.

  • JavascriptVisualization.js- stored in /src/main/resources/javascript/
  • JavascriptVisualization.scala - stored in /src/main/scala/com.alpine.plugin.samples/advanced/JavascriptVisualization.scala

    Procedure
  1. Rename JavascriptVisualization with the preferred name of your operator.

    For example, to create an operator called "MyCoolOperator," use the filenames MyCoolOperator.js and MyCoolOperator.scala.

  2. Review the following Scala sample code.
    class JavascriptVisualizationRuntime extends SparkRuntime[HdfsTabularDataset, IONone] {
     
    [...]
     override def createVisualResults(context: SparkExecutionContext,
                                       input: HdfsTabularDataset,
                                       output: IONone,
                                       params: OperatorParameters,
                                       listener: OperatorListener): VisualModel = {
        val dataset = context.visualModelHelper.createTabularDatasetVisualization(input)
        val tabularModel = dataset.asInstanceOf[TabularVisualModel]
     
        val columnName = params.getTabularDatasetSelectedColumn(JavascriptVisualizationUtil.COLUMN_TO_ANALYZE)._2
        val i = tabularModel.columnDefs.indexWhere(columnDef => columnDef.columnName == columnName)
     
        val compositeVisualModel = new CompositeVisualModel()
        if (i != -1) {
          val valuesSet = tabularModel.content.map(row => row(i))
          compositeVisualModel.addVisualModel("Data Cloud",
            new JavascriptVisualModel("execute", Option.apply(valuesSet)))
        } else {
          compositeVisualModel.addVisualModel("Data Cloud",
            new JavascriptVisualModel("execute", Option.apply("No results")))
        }
        compositeVisualModel.addVisualModel("Hello World",
          new JavascriptVisualModel("simpleFunction", Option.apply("")))
        compositeVisualModel
      }
    • JavascriptVisualizationRuntime extends SparkRuntime.
    • The example overrides createVisualResults to insert custom code. For your customization, keep the parameters as defined.
    • CompositeVisualModel() is the core of the example, creating and defining the visualization. CompositeVisualModel means that you can have several "tabs" in the output. This example creates a visualization with two tabs: one with a "word cloud" and one with simple text that says "Hello World."
    • Within CompositeVisualModel, the example creates a JavascriptVisualModel using the following structure.
      case class JavascriptVisualModel(
                functionName:String,
                data: Option[Any]) extends VisualModel
    • The JavaScript code executes the function simpleFunction.
    • The example returns CompositeVisualModel.

    Before editing the example JavaScript code, check the signature class of the operator to ensure that the metadata includes useJavascript=True. JavaScript code does not run without this setting.

3. In the JavaScript file, define the functions called from the Scala code.

The following example code demonstrates using JavaScript for the word cloud example.
define([
    "dojo/dom-construct",
    "dojo/dom-geometry"
], function(domConstruct, domGeo) {
    return {
        /**
         * @param outpane The enclosing html <div> in which the Javascript code should place elements into
         * @param visualData Data specified by the custom operator in createVisualResults() when creating the JavascriptVisualModel
         */
        execute: function(outpane, visualData) {
            var geo = domGeo.position(outpane);
            var canvas = domConstruct.create('canvas', {width: geo.w, height: geo.h}, outpane);
            var context = canvas.getContext('2d');
              // Trivial visualization example - all elements in visualData (an array) are randomly positioned in the canvas with random colors
            for (var i = 0; i < visualData.length; i++) {
                context.fillStyle = 'rgb('+Math.floor(Math.random() * 255)+','+Math.floor(Math.random() *
                    255)+','+ Math.floor(Math.random() * 255)+')';
                context.fillText(visualData[i], 100 + (Math.random() * (geo.w - 200)), 100 + (Math.random() * (geo.h - 200)));
            }
        },
        simpleFunction: function(outpane, visualData) {
            var span = domConstruct.create('span', {}, outpane);
            span.innerHTML = "Hello World"
        }
    };
});
Result 
  • The execute function creates the word cloud and uses the JavaScript built-in canvas technology.
  • The function simpleFunction outputs "Hello World" as text.