I was delighted to help plan the SAP BizViz Hackathon in Palo Alto on Sep 10-12th, 2015. It’s a successful event with talented participations that helped form excellent teams. After this event, I was very inspired to improve my first Lumira extension. That I had made almost 2 month ago when I just joined SAP, Palo Alto.

This extension covers a project management scenario in which costs and values are displayed over various project phases, for different project types. It has a bunch of different sizes of bubbles split to 8 pipelines, each of them represents one phase of the project development. We are all familiar with normal bubble charts, but this one is a bit special. The common bubble chart includes Y-axis (measure), X-axis (dimension), bubble size (dimension) and bubble color (dimension). In the Pipeline Bubble Chart, the x-axis contain a series of discrete values, which represent the stages and sub-stages instead of a continuous linear scale for each bubble. I split all of the data points into one of eight pipelines based on its “stage” value.

/wp-content/uploads/2015/10/skitch_concept_810349.jpg

Concept of extension

v1Result.jpg

/wp-content/uploads/2015/10/v2_1_810348.png

New in Version 2:

  • Mouse hover animation for bubbles and stages
  • 3 lines tool-tip
  • Bubble generating animation
  • Allow access to different data sets
  • Hierarchical sorted bubbles-smallest on the top
  • Color improvement

1. Processing the data

The trick here is to map the data with d3.nest() function. Grouping a data base on their stage and sub-stage is key to splitting the data into smaller groups. Oftentimes, I prefer to use d3 functions instead of JavaScript as a loop to break apart the data by a categorical variable, because it provides an easy and more effective solution when grouping data into a hierarchical tree structure in here. The leaf nodes of the tree can be sorted by value, while the internal nodes can be sorted by key. An optional rollup function will collapse the elements in each leaf node using a summary function. I also use the .sortKeys() function with stageSeq array to sort each level by particular sequence, and you can also use a simple d3.ascending or d3.descending for this purpose.

/wp-content/uploads/2015/10/d3nest_811338.png


2. Multiple Dimension Error in Web IDE & Lumira


In the first version, the project is hard to code for a particular data set. In the second version, I extend the input filed to one measure and two dimensions with a clear name to remind the user to put a special column to correspond to the input fields. I use bracket notation to access data array dynamically with dimension/measure names variable.

DynamicColumnName.png


However, I find that it brings a weird problem that there are more than one dimension as input field. I only have around 200 rows of data in .csv, but I got more than 4000 objects in data variables in render function. I talked with a senior colleague and discovered that there is a bug in the current version of Web IDE and Lumira. Each duplicated data object contains “null” value property. My first solution is to use a filter to remove null elements, but it has the potential downside error to lose useful data elements. After a series of debugging, I make sure that the bug is eliminated and move one of the variables to the second measure input field, and only keep one dimension.

DataError.png

data_Solution.png

  • Side topic: How can you rename your dimension and measure without creating a new project
  • Find flow.js in the same folder with render.js, double click and open it in Web IDE. Find code in /*Feeds Definition*/ section like below:

var ds1 = {

                                      “id”: “sap.vix.ext.pipelinebubbledata.PlotModule.DS1”,

                                      “name”: “Stage, Bubble Color & Tooltip”,

                                      “type”: “Dimension”,

                                      “min”: 0, //minimum number of data container

                                      “max”: 2, //maximum number of data container

                                      “aaIndex”: 1

                       };                      

                       element.addFeed(ds1);

                       var ms1 = {

                                      “id”: “sap.vix.ext.pipelinebubbledata.PlotModule.MS1”,

                                      “name”: “Bubble Height”,

                                      “type”: “Measure”,

                                      “min”: 0, //minimum number of measures

                                      “max”:  2, //maximum number of measures

                                      “mgIndex”: 1

                       };

                       element.addFeed(ms1);

3. Draw rectangle for stage, and circle for bubble


I use d3.nest() twice to group all elements based on their stage and sub-stage property, and draw two rows of stage rectangle based on the item key. This particular Pipeline chart need append <rect>(svg) or <div>(html) to build the bottom stage part, but both solutions have their disadvantages. The first, <rect>( http://www.w3schools.com/svg/svg_rect.asp) in <svg>, which is a predefined shape element that can be used to draw rectangles. Those <rect> form the Main Stage(light blue) and Sub-Stage(dark blue) rectangle in the chart. The weakness of this solution is that when user filters data in Lumira Compose Room, it will remove both bubbles and stages in the same time.

The second idea is to use <div> to build stages. But SVG defines vector-based graphics in XML format, and cannot embed HTML elements into graphics directly. The best solution is to append foreignObject element which allows inclusion of a foreign XML namespace for has its graphical content drawn by a different user agent. The included foreign graphical content is subject to SVG transformations and composition.

4. Create tooltips


Next step is create tooltips for a bubble to show more detailed data for each of them.


var tipcontent = tooltip.append(“g”).attr(“class”, “label_detail”);

tipcontent.append(“text”).attr(“class”, “project”);

// bubble elements on mouseover event

bubble.on(‘mouseover’, function(d) {

              d3.select(this).attr(‘opacity’, 0.8).attr(“font-size”, “1.4em”).attr(“font-weight”, “bold”);

              var position = d3.select(this).attr(“transform”).split(“,”);

              tooltip.attr(“transform”, “translate(” + (parseFloat(position[0].split(“(“)[1]) + subStageWidth/3) + “,” + (parseFloat(position[1]) – 40) +”)”).style(“opacity”, 1);

              tooltip.select(‘.label’) .attr(“x”, 0).attr(“width”, 130).attr(“y”,0) .attr(“height”, 50). attr(“rx”, 2).attr(“ry”, 2).attr(“opacity”, .7);

               tipcontent.select(‘.project’).attr(“font-size”, “1.2em”) .attr(“dy”,”1.4em”) .attr(“x”, 10).text(d.project);

})

5. Customize color and stage sequence

If the user wants to customize colors for bubbles or sequences for stages, they can decompress the extension zip file, find

bundles-> sap-> vix-> ext-> pipelinesbubbledata -> sap_vix_ext_pipelinebubbledata -> js -> render.js.

The following image shows the three variables “stageSeq”, “subStageSeq” and buColor to set up your own color and stage sequence.

ColorSetup.png


6. Best practice

The extension in Lumira shares CSS with other extensions. Therefore, it is necessary to use unique CSS class/id to avoid conflict between different extensions. More detail in here.

Download extension and .lum file in Github

Special Credit

Thanks so much for my friend and colleague Sandra Moerch-Petersen to help me review this blog.

To report this post you need to login first.

1 Comment

You must be Logged on to comment or reply to a post.

Leave a Reply