27 min read

In this article by Miguel Gaspar the author of the book Learning Pentaho CTools you will learn about the Charts Component Library in detail. The Charts Components Library is not really a Pentaho plugin, but instead is a Chart library that Webdetails created some years ago and that Pentaho started to use on the Analyzer visualizations. It allows a great level of customization by changing the properties that are applied to the charts and perfectly integrates with CDF, CDE, and CDA.

(For more resources related to this topic, see here.)

The dashboards that Webdetails creates make use of the CCC charts, usually with a great level of customization. Customizing them is a way to make them fancy and really good-looking, and even more importantly, it is a way to create a visualization that best fits the customer/end user’s needs. We really should be focused on having the best visualizations for the end user, and CCC is one of the best ways to achieve this, but do this this you need to have a very deep knowledge of the library, and know how to get amazing results.

I think I could write an entire book just about CCC, and in this article I will only be able to cover a small part of what I like, but I will try to focus on the basics and give you some tips and tricks that could make a difference.I’ll be happy if I can give you some directions that you follow, and then you can keep searching and learning about CCC. An important part of CCC is understanding some properties such as the series in rows or the crosstab mode, because that is where people usually struggle at the start.

When you can’t find a property to change some styling/functionality/behavior of the charts, you might find a way to extend the options by using something called extension points, so we will also cover them. I also find the interaction within the dashboard to be an important feature.So we will look at how to use it, and you will see that it’s very simple.

In this article,you will learn how to:

  • Understand the properties needed to adapt the chart to your data source results
  • Use the properties of a CCC chart
  • Create a CCC chat by using the JavaScript library
  • Make use of internationalization of CCC charts
  • See how to handle clicks on charts
  • Scale the base axis
  • Customize the tooltips

Some background on CCC

CCC is built on top of Protovis, a JavaScript library that allows you to produce visualizations just based on simple marks such as bars, dots, and lines, among others, which are created through dynamic properties based on the data to be represented. You can get more information on this at: http://mbostock.github.io/protovis/.

If you want to extend the charts with some elements that are not available you can, but it would be useful to have an idea about how Protovis works.CCC has a great website, which is available at http://www.webdetails.pt/ctools/ccc/, where you can see some samples including the source code. On the page, you can edit the code, change some properties, and click the apply button. If the code is valid, you will see your chart update.As well as that, it provides documentation for almost all of the properties and options that CCC makes available.

Making use of the CCC library in a CDF dashboard

As CCC is a chart library, you can use it as you would use it on any other webpage, by using it like the samples on CCC webpages. But CDF also provides components that you can implement to use a CCC chart on a dashboard and fully integrate with the life cycle of the dashboard. To use a CCC chart on CDF dashboard, the HTML that is invoked from the XCDF file would look like the following(as we already covered how to build a CDF dashboard, I will not focus on that, and will mainly focus on the JavaScript code):

<div class="row">

<div class="col-xs-12">

<div id="chart"/>

</div>

</div>

<script language="javascript" type="text/javascript">

  require(['cdf/Dashboard.Bootstrap',

'cdf/components/CccBarChartComponent'],

function(Dashboard, CccBarChartComponent) {

    var dashboard = new Dashboard();

    var chart = new CccBarChartComponent({

        type: "cccBarChart",

        name: "cccChart",

        executeAtStart: true,

        htmlObject: "chart",

        chartDefinition: {

            height: 200,

            path: "/public/…/queries.cda",

            dataAccessId: "totalSalesQuery",

            crosstabMode: true,

            seriesInRows: false,

timeSeries: false

            plotFrameVisible: false,

            compatVersion: 2

        }

    });

    dashboard.addComponent(chart);

    dashboard.init();

  });

</script>

The most important thing here is the use of the CCC chart component that we have covered as an example in which we have covered it’s a bar chart. We can see by the object that we are instantiating CccBarChartComponent as also by the type that is cccBarChart.

The previous dashboard will execute the query specified as dataAccessId of the CDA file set on the property path, and render the chart on the dashboard. We are also saying that its data comes from the query in the crosstab mode, but the base axis should not be atimeSeries. There are series in the columns, but don’t worry about this as we’ll be covering it later.

The existing CCC components that you are able to use out of the box inside CDF dashboards are as follows. Don’t forget that CCC has plenty of charts, so the sample images that you will see in the following table are just one example of the type of charts you can achieve.

CCC Component

Chart Type

Sample Chart

CccAreaChartComponent

cccAreaChart

 

CccBarChartComponent

cccBarChart

http://www.webdetails.pt/ctools/ccc/#type=bar

CccBoxplotChartComponent

cccBoxplotChart

http://www.webdetails.pt/ctools/ccc/#type=boxplot

CccBulletChartComponent

cccBulletChart

http://www.webdetails.pt/ctools/ccc/#type=bullet

CccDotChartComponent

cccDotChart

http://www.webdetails.pt/ctools/ccc/#type=dot

CccHeatGridChartComponent

cccHeatGridChart

http://www.webdetails.pt/ctools/ccc/#type=heatgrid

CccLineChartComponent

cccLineChart

http://www.webdetails.pt/ctools/ccc/#type=line

CccMetricDotChartComponent

cccMetricDotChart

http://www.webdetails.pt/ctools/ccc/#type=metricdot

CccMetricLineChartComponent

cccMetricLineChart

 

CccNormalizedBarChartComponent

cccNormalizedBarChart

 

CccParCoordChartComponent

cccParCoordChart

 

CccPieChartComponent

cccPieChart

http://www.webdetails.pt/ctools/ccc/#type=pie

CccStackedAreaChartComponent

cccStackedAreaChart

http://www.webdetails.pt/ctools/ccc/#type=stackedarea

CccStackedDotChartComponent

cccStackedDotChart

 

CccStackedLineChartComponent

cccStackedLineChart

http://www.webdetails.pt/ctools/ccc/#type=stackedline

CccSunburstChartComponent

cccSunburstChart

http://www.webdetails.pt/ctools/ccc/#type=sunburst

CccTreemapAreaChartComponent

cccTreemapAreaChart

http://www.webdetails.pt/ctools/ccc/#type=treemap

CccWaterfallAreaChartComponent

cccWaterfallAreaChart

http://www.webdetails.pt/ctools/ccc/#type=waterfall

In the sample code, you will find a property calledcompatMode that hasa value of 2 set. This will make CCC work as a revamped version that delivers more options, a lot of improvements, and makes it easier to use.

Mandatory and desirable properties

Among otherssuch as name, datasource, and htmlObject, there are other properties of the charts that are mandatory. The height is really important, because if you don’t set the height of the chart, you will not fit the chart in the dashboard. The height should also be specified in pixels.

If you don’t set the width of the component, or to be more precise, then the chart will grab the width of the element where it’s being rendered it will grab the width of the HTML element with the name specified in the htmlObject property.

The seriesInRows, crosstabMode, and timeseriesproperties are optional, but depending on the kind of chart you are generating, you might want to specify them. The use of these properties becomes clear if we can also see the output of the queries we are executing. We need to get deeper into the properties that are related to the data mapping to visual elements.

Mapping data

We need to be aware of the way that data mapping is done in the chart.You can understand how it works if you can imagine data input as a table. CCC can receive the data as two different structures: relational and crosstab. If CCC receives data as crosstab,it will translate it to a relational structure. You can see this in the following examples.

Crosstab

The following table is an example of the crosstab data structure:

Column Data 1

Column Data 2

Row Data 1

Measure Data 1.1

Measure Data 1.2

Row Data 2

Measure Data 2.1

Measure Data 2.2

Creating crosstab queries

To create a crosstab query, usually you can do this with the group when using SQL, or just use MDX, which allows us to easily specify a set for the columns and for the rows.

Just by looking at the previous and following examples, you should be able to understand that in the crosstab structure (the previous), columns and rows are part of the result set, while in the relational format (the following), column headers or headers are not part of the result set, but are part of the metadata that is returned from the query.

The relationalformat is as follows:

Column

Row

Value

Column Data 1

Row Data 1

Measure Data 1.1

Column Data 2

Row Data 1

Measure Data 2.1

Column Data 1

Row Data 2

Measure Data 1.2

Column Data 2

Row Data 2

Measure Data 2.1

 

The preceding two data structures represent the options when setting the properties crosstabMode and seriesInRows.

The crosstabMode property

To better understand these concepts, we will make use of a real example. This property, crosstabMode, is easy to understand when comparing the two that represents the results of two queries.

Non-crosstab (Relational):

Markets

Sales

APAC

1281705

EMEA

50028224

Japan

503957

NA

3852061

Crosstab:

Markets

2003

2004

2005

APAC

3529

5938

3411

EMEA

16711

23630

9237

Japan

2851

1692

380

NA

13348

18157

6447

 

In the previous tables, you can see that on the left-handside you can find the values of sales from each of the territories. The only relevant information relative to the values presented in only one variable, territories. We can say that we are able to get all the information just by looking at the rows, where we can see a direct connection between markets and the sales value.

In the table presented on the right, you will find a value for each territory/year, meaning that the values presented, and in the sample provided in the matrix, are dependent on two variables, which are the territory in the rows and the years in the columns. Here we need both the rows andthe columns to know what each one of the values represents. Relevant information can be found in the rows and the columns, so this a crosstab. The crosstabs display the joint distribution of two or more variables, and are usually represented in the form of a contingency table in a matrix.

When the result of a query is dependent only on one variable, then you should set the crosstabModeproperty to false. When it is dependent on 2 or more variables, you should set the crosstabMode property to false, otherwise CCC will just use the first two columns like in the non-crosstab example.

The seriesInRows property

Now let’s use the same examplewhere we have a crosstab:

The previous image shows two charts: the one on the left is a crosstab with the series in the rows, and the one on the right is also crosstab but the series are not in the rows (the series are in the columns).When the crosstab is set to true, it means that the measure column title can be translated as a series or a category,and that’s determined by the property seriesInRows. If this property is set to true, then it will read the series from the rows, otherwise it will read the series from the columns.

If the crosstab is set to false, the community chart component is expecting a row to correspond exactly to one data point, and two or three columns can be returned. When three columns are returned, they can be a category, series and dataor series, category and data and that’s determined by the seriesInRows property. When set to true, CCC will expect the structure to have three columns such as category, series, and data. When it is set to false, it will expect them to be series, category, and data.

A simple table should give you a quicker reference, so here goes:

crosstabMode

seriesInRows

Description

true

true

The column titles will act as category values while the series values are represented as data points of the first column.

true

false

The column titles will act as series value while the category/category values are represented as data points of the first column.

false

true

The column titles will act as category values while the series values are represented as data points of the first column.

false

false

The column titles will act as category values while the series values are represented as data points of the first column.

The timeSeries and timeSeriesFormat properties

The timeSeries property defines whether the data to be represented by the chart is discrete or continuous. If we want to present some values over time, then the timeSeries property should be set to true. When we set the chart to be timeSeries, we also need to set another property to tell CCC how it should interpret the dates that come from the query.Check out the following image for timeSeries and timeSeriesFormat:

The result of one of the queries has the year and the abbreviated month name separate by , like 2015-Nov. For the chart to understand it as a date, we need to specify the format by setting the property timeSeriesFomart, which in our example would be %Y-%b, where %Y is the year is represented by four digits, and %b is the abbreviated month name.

The format should be specified using the Protovis format that follows the same format as strftime in the C programming language, aside from some unsupported options. To find out what options are available, you should take a look at the documentation, which you will find at: https://mbostock.github.io/protovis/jsdoc/symbols/pv.Format.date.html.

Making use of CCC inCDE

There are a lot of properties that will use a default value, and you can find out aboutthem by looking at the documentation or inspecting the code that is generated by CDE when you use the charts components. By looking at the console log of your browser, you should also able to understand and get some information about the properties being used by default and/or see whether you are using a property that does not fit your needs.

The use of CCC charts in CDE is simpler, just because you may not need to code. I am only saying may because to achieve quicker results, you may apply some code and make it easier to share properties among different charts or type of charts. To use a CCC chart, you just need to select the property that you need to change and set its value by using the dropdown or by just setting the value:

The previous image shows a group of properties with the respective values on the right side.

One of the best ways to start to get used to the CCC properties is to use the CCC page available as part of the Webdetails page: http://www.webdetails.pt/ctools/ccc. There you will find samples and the properties that are being used for each of the charts. You can use the dropdown to select different kinds of charts from all those that are available inside CCC. You also have the ability to change the properties and update the chart to check the result immediately.

What I usually do, as it’s easier and faster, is to change the properties here and check the results and then apply the necessary values for each of the properties in the CCC charts inside the dashboards. In the following samples, you will also find documentation about the properties, see where the properties are separated by sections of the chart, and after that you will find the extension points.

On the site, when you click on a property/option, you will be redirected to another page where you will find the documentation and how to use it.

Changing properties in the preExecution or postFetch

We are able to change the properties for the charts, as with any other component. Inside the preExecution, this, refers to the component itself, so we will have access to the chart’s main object, which we can also manipulate and add, remove, and change options.

For instance, you can apply the following code:

function() {

   var cdProps = {

        dotsVisible: true,

        plotFrame_strokeStyle: '#bbbbbb',

        colors: ['#005CA7', '#FFC20F', '#333333', '#68AC2D']

    };

    $.extend(true, this.chartDefinition, cdProps);

}

What we are doing is creating an object with all the properties that we want to add or change for the chart, and then extending the chartDefinitions (where the properties or options are). This is what we are doing with the JQuery function, extending.

Use the CCC website and make your life easier

This way to apply options makes it easier to set the properties. Just change or add the properties that you need, test it, and when you’re happy with the result, you just need to copy them into the object that will extend/overwrite the chart options. Just keep in mind that the properties you change directly in the editor will be overwritten by the ones defined in the preExecution, if they match each other of course.

Why is this important? It’s because not all the properties that you can apply to CCC are exposed in CDE, so you can use the preExecution to use or set those properties.

Handling the click event

One important thing about the charts is that they allow interaction. CCC provides a way to handle some events in the chart and click is one of those events. To have it working, we need to change two properties: clickable, which needs to be set to true, and clickAction where we need to write a function with the code to be executed when a click happens. The function receives one argument that usually is referred to as a scene. The scene is an object that has a lot of information about the context where the event happened. From the object you will have access to vars, another object where we can find the series and the categories where the clicked happened.

We can use the function to get the series/categories being clicked and perform a fireChange that can trigger updates on other components:

function(scene) {

    var series =  "Series:"+scene.atoms.series.label;

    var category =  "Category:"+scene.vars.category.label;

    var value = "Value:"+scene.vars.value.label;

    Logger.log(category+"&"+value);

    Logger.log(series);

}

In the previous code example, you can find the function to handle the click action for a CCC chart. When the click happens, the code is executed, and a variable with the click series is taken from scene.atoms.series.label. As well as this, the categories clickedscene.vars.category.label and the value that crosses the same series/category in scene.vars.value.value. This is valid for a crosstab, but you will not find the series when it’s non-crosstab.

You can think of a scene as describing one instance of visual representation. It is generally local to each panel or section of the chart and it’s represented by a group of variables that are organized hierarchically. Depending on the scene, it may contain one or many datums. And you must be asking what a hell is a datum? A datum represents a row, so it contains values for multiple columns.

We also can see from the example that we are referring to atoms, which hold at least a value, a label, and a key of a column. To get a better understanding of what I am talking about, you should perform a breakpoint anywhere in the code of the previous function and explore the object scene.

In the previous example, you would be able to access to the category, series labels, and value, as you can see in the following table:

 

Corosstab

Non-crosstab

Value

scene.vars.value.label

or

scene.getValue();

scene.vars.value.label

or

scene.getValue();

Category

scene.vars.category.label

or

scene.getCategoryLabel();

scene.vars.category.label

or

scene.getCategoryLabel();

Series

scene.atoms.series.label

or

scene.getSeriesLabel()

 

For instance, if you add the previous function code to a chart that is a crosstab where the categories are the years and the series are the territories, if you click on the chart, the output would be something like:

[info] WD: Category:2004 & Value:23630

[info] WD: Series:EMEA

This means that you clicked on the year 2004 for the EMEA. EMEA sales for the year 2004 were 23,630.

If you replace the Logger functions withfireChangeas follows, you will be able to make use of the label/value of the clicked category to render other components and some details about them:

this.dashboard.fireChange("parameter", scene.vars.category.label);

Internationalization of CCCCharts

We already saw that all the values coming from the database should not need to be translated. There are some ways in Pentaho to do this, but we may still need to set the title of a chart, where the title should be also internationalized. Another case is when you have dates where the month is represented by numbers in the base axis, but you want to display the month’s abbreviated name. This name could be also translated to different languages, which is not hard.

For the title, sub-title, and legend, the way to do it is using the instructions on how to set properties on preExecution.First, you will need to define the properties files for the internationalization and set the properties/translations:

var cd = this.chartDefinition;

cd.title =  this.dashboard.i18nSupport.prop('BOTTOMCHART.TITLE');

To change the title of the chart based on the language defined, we will need to define a function, but we can’t use the property on the chart because that will only allow you to define a string, so you will not be able to use a JavaScript instruction to get the text. If you set the previous example code on the preExecution of the chart then, you will be able to.

It may also make sense to change not only the titles, but for instance also internationalize the month names. If you are getting data like 2004-02, this may correspond to a time series format as %Y-%m. If that’s the case and you want to display the abbreviated month name, then you may use the baseAxisTickFormatter and the dateFormat function from the dashboard utilities, also known as Utils. The code to write inside the preExecution would be like:

var cd = this.chartDefinition;

cd.baseAxisTickFormatter = function(label) {

  return Utils.dateFormat(moment(label, 'YYYY-mmm'), 'MMM/YYYY');

};

The preceding code uses the baseAxisTickFormatter, which allows you to write a function that receives an argument, identified on the code as a label, because it will store the label for each one of the base axis ticks. We are using the dateFormatmethod and moment to format and return the year followed by the abbreviated month name.

You can get information about the language defined and being used by running the following instruction

moment.locale();

If you need to, you can change the language.

Format a basis axis label based on the scale

When you are working with a time series chart, you may want to set a different format for the base axis labels. Let’s suppose you want to have a chart that is listening to a time selector. If you select one year old data to be displayed on the chart, certainly you are not interested in seeing the minutes on the date label. However, if you want to display the last hour, the ticks of the base axis need to be presented in minutes.

There is an extension point we can use to get a conditional format based on the scale of the base axis. The extension point is baseAxisScale_tickFormatter, and it can be used like in the code as follows:

baseAxisScale_tickFormatter: function(value, dateTickPrecision) {

switch(dateTickPrecision) {

casepvc.time.intervals.y:

return format_date_year_tick(value);

             break;

casepvc.time.intervals.m:

return format_date_month_tick(value);

             break;

 

         casepvc.time.intervals.H:

return format_date_hour_tick(value);

             break;

         default:

             return format_date_default_tick(value);

 

}

}

It accepts a function with two arguments: the value to be formatted and the tick precision, and should return the formatted label to be presented on each label of the base axis.

The previous code shows howthe function is used. You can see a switch that based on the base axis scale will do a different format, calling a function. The functions in the code are not pre-defined—we need to write the functions or code to create the formatting. One example of a function to format the date is that we could use the utils dateFormat function to return the formatted value to the chart.

The following table shows the intervals that can be used when verifying which time intervals are being displayed on the chart:

Interval

Description

Number representing the interval

y

Year

31536e6

m

Month

2592e6

d30

30 days

2592e6

d7

7 days

6048e5

d

Day

864e5

H

Hour

36e5

m

Minute

6e4

s

Second

1e3

ms

Milliseconds

1

Customizing tooltips

CCC provides the ability to change the tooltip format that comes by default, and can be changed using the tooltipFormat property. We can change it, making it look likethe following image, on the right side. You can also compare it to the one on the left, which is the default one:

The tooltip default format might change depending on the chart type, but also on some options that you apply to the chart, mainly crosstabMode and seriesInRows. The property accepts a function that receives one argument, the scene, which will be a similar structure as already covered for the click event. You should return the HTML to be showed on the dashboard when we hover the chart.

In the previous image,you will see on the chart on the left side the defiant tooltip, and on the right a different tooltip. That’s because the following code was applied:

tooltipFormat: function(scene){

  var year = scene.atoms.series.label;

  var territory = scene.atoms.category.value;

  var sales = Utils.numberFormat(scene.vars.value.value, "#.00A");

  var html = '<html>' +

<div>Sales for '+year+' at '+territory+':'+sales+'</div>' +

'</html>';

  return html;

}

The code is pretty self-explanatory. First we are setting some variables such as year, territory, and the sales values, which we need to present inside the tooltip. Like in the click event, we are getting the labels/value from the scene, which might depend on the properties we set for the chart. For the sales, we are also abbreviating it, using two decimal places. And last, we build the HTML to be displayed when we hover over the chart.

You can also change the base axis tooltip

Like we are doing to the tooltip when hovering over the values represented in the chart, we can also baseAxisTooltip, just don’t forget that the baseAxisTooltipVisible must be set to true (the value by default). Getting the values to show will pretty similar.

It can get more complex, though not much more, when we also want for instance, to display the total value of sales for one year or for the territory. Based on that, we could also present the percentage relative to the total. We should use the property as explained earlier.

The previous image is one example of how we can customize a tooltip. In this case, we are showing the value but also the percentage that represents the hovered over territory (as the percentage/all the years) and also for the hovered over year (where we show the percentage/all the territories):

tooltipFormat: function(scene){

  var year = scene.getSeriesLabel();

  var territory = scene.getCategoryLabel();

  var value = scene.getValue();

  var sales = Utils.numberFormat(value, "#.00A");

  var totals = {};

  _.each(scene.chart().data._datums, function(element) {

    var value = element.atoms.value.value;

    totals[element.atoms.category.label] =     

      (totals[element.atoms.category.label]||0)+value;

    totals[element.atoms.series.label] =

      (totals[element.atoms.series.label]||0)+value;

  });

  var categoryPerc = Utils.numberFormat(value/totals[territory], "0.0%");

  var seriesPerc = Utils.numberFormat(value/totals[year], "0.0%");

  var html =  '<html>' +

'<div class="value">'+sales+'</div>' +

'<div class="dValue">Sales for '+territory+' in '+year+'</div>' +

'<div class="bar">'+

'<div class="pPerc">'+categoryPerc+' of '+territory+'</div>'+

'<div class="partialBar" style="width:'+cPerc+'"></div>'+

'</div>' +

'<div class="bar">'+

'<div class="pPerc">'+seriesPerc+' of '+year+'</div>'+

'<div class="partialBar" style="width:'+seriesPerc+'"></div>'+

'</div>' +

'</html>';

  return html;

}

The first lines of the code are pretty similar except that we are using scene.getSeriesLabel() in place of scene.atoms.series.label. They do the same, so it’s only different ways to get the values/labels. Then the total calculations that are calculated by iterating in all the elements of scene.chart().data._datums, which return the logical/relational table, a combination of the territory, years, and value. The last part is just to build the HTML with all the values and labels that we already got from the scene.

There are multiple ways to get the values you need, for instance to customize the tooltip, you just need to explore the hierarchical structure of the scene and get used to it.

The image that you are seeing also presents a different style, and that should be done using CSS. You can add CSS for your dashboard and change the style of the tooltip, not just the format.

Styling tooltips

When we want to style a tooltip, we may want to use the developer’s tools to check the classes or names and CSS properties already applied, but it’s hard because the popup does not stay still. We can change the tooltipDelayOut property and increase its default value from 80 to 1000 or more, depending on the time you need.

When you want to apply some styles to the tooltips for a particular chart you can do by setting a CSS class on the tooltip. For that you should use the propertytooltipClassName and set the class name to be added and latter user on the CSS.

Summary

In this article,we provided a quick overview of how to use CCC in CDF and CDE dashboards and showed you what kinds of charts are available. We covered some of the base options as well as some advanced option that you might use to get a more customized visualization.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here