In today's blog post, we'll show how to use two different components to visualize the same data set, using consistent coloring for the data items and cross component highlighting. This helps with achieving one of the primary best practices related to using multiple data visualizations, which is that all components should consistently represent the data and that they should behave as a cohesive dashboard rather than a set of independent components. For those of you who attended OpenWorld this year, this post may look familiar as the code sample is very similar to what we showed in the Data Visualization session.

assocViews.png

 

We'll build upon the code sample from How to Create Colorful Bar Charts, which shows how to create a bar chart using the JET attribute group handler for coloring. If you're not familiar with the oj.ColorAttributeGroupHandler, it's a good idea to start with that post first. There are three main concepts shown in the code sample:

  • Consistent Coloring via ColorAttributeGroupHandler: We'll use the same ColorAttributeGroupHandler from How to Create Colorful Bar Charts to assign colors to both components.
  • Hover Behavior across Components: We'll turn on hoverBehavior on the components and take advantage of Knockout's Two-Way Binding to keep the highlightedCategories synchronized across components. For more details on the two-way binding, please see Two-Way Data Binding JET Components with Knockout.
  • Data Item Categories to Support Cross Component Interactivity: We'll specify custom categories on the data items, since the default categories may not produce the expected result across all data sets and components.

 

JS Data: In How to Create Colorful Bar Charts, we only showed data for teams with more than one championship. Since we are displaying the data in a treemap, which displays parts of a whole, we are introducing an additional item representing the 8 teams that have won only one championship to avoid distorting the data.

var DATA = [
  {city: "Boston", team: "Celtics", conference: "East", count: 17},
  {city: "Los Angeles", team: "Lakers", conference: "West", count: 16},
  {city: "Chicago", team: "Bulls", conference: "East", count: 6},
  {city: "San Antonio", team: "Spurs", conference: "West", count: 5},
  {city: "Golden State", team: "Warriors", conference: "West", count: 4},
  {city: "Philadelphia", team: "76ers", conference: "East", count: 3},
  {city: "Detroit", team: "Pistons", conference: "East", count: 3},
  {city: "Miami", team: "Heat", conference: "East", count: 3},
  {city: "New York", team: "Knicks", conference: "East", count: 2},
  {city: "Houston", team: "Rockets", conference: "West", count: 2},
  {city: "Other", team: "Other", conference: "Other", count: 8}
];
    

 

HTML: Declares a ojChart and ojTreemap component. The data will be set up in the JS view model. Highlighting is enabled by setting hoverBehavior to dim, which allows the component to initiate the highlighting. The highlightedCategories attributes are bound to the same observableArray, causing the highlighting to be synchronized.

<div data-bind="ojComponent: {
  component: 'ojChart',
  hoverBehavior: 'dim', highlightedCategories: highlightedCategories,
  series: chartSeries, groups: chartGroups,
  title: {text: 'Number of NBA Championships', halign: 'center'}
}" style="width:600px;height:300px;">
</div>

<div data-bind="ojComponent: {
  component: 'ojTreemap',
  hoverBehavior: 'dim', highlightedCategories: highlightedCategories,
  nodes: treemapNodes
}" style="width:600px;height:300px;border:none;">
</div>
    

 

JS: Defines the data used by the components, uses ColorAttributeGroupHandler to assign consistent colors between components, and assigns a custom array of categories to each data item. By default, each component creates a default array of categories for each data item (series name for chart, id of the node and its ancestors for treemap). It's necessary to assign a custom list of categories here since the series name does not match the item name (the team name) on the chart.

function ViewModel() {
  var self = this;

  // AttributeGroupHandler used for maintaining consistent coloring across components.
  var colorHandler = new oj.ColorAttributeGroupHandler({Other: '#888888'});

  // Observable arrays for syncing highlight state across components.
  self.highlightedCategories = ko.observableArray();

  // Create data for a chart with 1 series and multiple groups.
  self.chartGroups = [];
  self.chartSeries = [{items: []}];
  for(var i=0; i<DATA.length; i++) {
    var item = DATA[i];

    self.chartGroups.push(item.team);
    self.chartSeries[0].items.push({
      value: item.count,
      categories: [item.team],
      color: colorHandler.getValue(item.team)
    });
  }

  // Create data for a treemap
  self.treemapNodes = [];
  for(var i=0; i<DATA.length; i++) {
    var item = DATA[i];

    self.treemapNodes.push({
      label: item.team,
      value: item.count,
      categories: [item.team],
      color: colorHandler.getValue(item.team)
    });
  }
}
    

 

Tip: There is a bug in JET 1.1.2 where the default treemap and sunburst categories are not computed correctly if there are multiple nodes at the root layer (like in this sample). Once this is fixed, we could use the default categories from the treemap here.

 

For more information on our associated views highlighting feature, please see the highlighting demo in the JET cookbook. For more information on the JET Data Visualizations and an overview of the chart component, please see Introduction to JET Data Visualization and Charting.