Dashboards

Dashboards are the backdrops on which all controls and charts are bundled together. Since they act as the unifying component of the visualization and controls, dashboards can also be intentionally linked to create dependencies between controls. Controls may also be used to set a visualization to a predefined state, or act as a trigger point for ChartWrapper events.

In general, a visualization with dashboard, controls, and events will always follow a pattern similar to the following outline:

<html>
<head>
<script>
function visualization{

// Listen for an error event to happen
google.visualization.events.addListener(chart/dashboard, 'error/ready/select',run_on_error);

// Load the Wrapper libraries
google.load


// Data creation, linking methods don't change
var data = google.visualization.DataTable

// Create some controls
var ctrl = new google.visualization.ControlWrapper


// Create a chart
var chart = new google.visualization.ChartWrapper

// Bundle controls and charts together on a dashboard. Draw the visualization.
google.visualization.Dashboard
bind( )

draw(data)
}

// Run this function when addListener "hears" the eventfunction run_on_error{

}
</script>
</head>
.
.
.
</html>

Now that it's possible to create "triggers" to listen for events in the dashboard, it is useful to harness the triggering ability through the user interface. With the Visualization API, the API controls as well as standard JavaScript interactivity, such as onload and onclick, are accepted methods to initiate chart events from the user interface.

Controls

The purpose of ControlWrapper controls is to allow the viewer to manipulate the chart data into their own desired visualization using on-screen graphical methods. Controls do not alter the dataset itself, but instead provide a filtered view only. This method is desirable to both developer and user as it presents anyone viewing the chart to customize the visualization to their needs sans concern of damaging the visualization or data by doing so.

There are several kinds of filters available:

  • StringFilter
  • NumberRangeFilter
  • CategoryFilter
  • ChartRangeFilter

StringFilter

StringFilter control is essentially a search filter for the data table. The user enters strings of characters as search queries into a field, and the visualization dynamically displays the results of the search. The StringFilter control is defined using the ControlWrapper method:

varMyFilter = google.visualization.ControlWrapper({
    'controlType': 'StringFilter',
    'containerId': 'control1',
    'options': {
      'filterColumnLabel': 'your_column_name'
    }
  });

The following chart example presents the same 2010 Chicago Census data that has been a continuing resource throughout this book. However, in this case, only the data for the male population is used. In the example, users may enter a sequence of numbers in the search field, and the chart view is reduced to only those entries where the sequence of numbers exists in the Male column.

StringFilter

The preceding data for age groups of males is loaded into the visualization with the arrayToDataTable function. Of course, an alternative method would be to use a data source method as described in Chapter 6, Data Manipulation and Sources, such as a Spreadsheet URL or JSON feed. If a data source method is chosen, remember that the ChartWrapper function used for charts with controls provides the data source linkage methods within ChartWrapper. The following data array is created in the example chart's script.

    ['Age', 'Male'],
    ['Under 5 years',    94100],
    ['5 to 9 years',     84122],
    ['10 to 14 years',   83274],
    ['15 to 19 years',   91528],
    ['20 to 24 years',   108407],
    ['25 to 29 years',   134931],
    ['30 to 34 years',   119828],
    ['35 to 39 years',   100651],
    ['40 to 44 years',   89957],
    ['45 to 49 years',   85645],
    ['50 to 54 years',   80838],
    ['55 to 59 years',   68441]

As mentioned earlier in the chapter, when building dashboards, the control elements and chart must be defined first. To define the control for the StringFilter, use the ControlWrapper class to create the object with the StringFilter control being the controlType. Also, define which <div id> element you wish to use as a container. The containerID option sets the <div id>, anchoring the control to the HTML page. Control has a variety of variables that can be set at the time of declaration, most of them being optional. However, for the StringFilter control in this instance, a column index or label is required in order for the control to know on which column to apply the search. This is accomplished by the addition of the filterColumnLabel option which provides the the filter's definition. In the example, the filter is set to search on the Male column.

  // Define a StringFilter control for the 'Male Population' column
  var stringFilter = new google.visualization.ControlWrapper({
    'controlType': 'StringFilter',
    'containerId': 'control1',
    'options': {
      'filterColumnLabel': 'Male'
    }
  });

Now that the search filter has been defined, the chart itself must be configured. In this example, a table visualization is the end result. To build the table and make it compatible with the controls just defined, use the ChartWrapper class. When defining ChartWrapper, configure chartType, the <div id> container HTML element, in addition to other formatting.

  // Define a table visualization
  var table = new google.visualization.ChartWrapper({
   'chartType': 'Table',
    'containerId': 'mydivid',
    'options': {'height': '13em', 'width': '20em'}
  });

To complete the dashboard, the ControlWrapper and ChartWrapper components must be assigned to the dashboard component. This is accomplished through the bind function. The semantics for bind are to first state the control to be bound in parentheses; with the data object it is to be bound to as the second input variable. The bind function may also be used in series to create dependent controls that manipulate the same visualization. Dependent controls are a topic covered later in this chapter.

  // Create the dashboard.
  var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard')).
    // Configure the string filter to affect the table contents
    bind(stringFilter, table).
    // Draw the dashboard
    draw(data);

For reference, the following code example for a StringFilter control is presented in its entirety, including the HTML framework.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
   <title>
    Google Visualization API Sample
   </title>
   <script type="text/javascript" src="http://www.google.com/jsapi"></script>
   <script type="text/javascript">
     google.load('visualization', '1.1', {packages: ['controls']});
    </script>
    <script type="text/javascript">
     function drawVisualization() {
        // Prepare the data.
       var data = google.visualization.arrayToDataTable([
                ['Age', 'Male'],
                ['Under 5 years',    94100],
                ['5 to 9 years',     84122],
                ['10 to 14 years',   83274],
                ['15 to 19 years',   91528],
                ['20 to 24 years',   108407],
                ['25 to 29 years',   134931],
                ['30 to 34 years',   119828],
                ['35 to 39 years',   100651],
                ['40 to 44 years',   89957],
                ['45 to 49 years',   85645],
                ['50 to 54 years',   80838],
                ['55 to 59 years',   68441]
        ]);
      
       // Define a StringFilter control for the 'Male Population' column
       var stringFilter = new google.visualization.ControlWrapper({
          'controlType': 'StringFilter',
          'containerId': 'control1',
          'options': {
            'filterColumnLabel': 'Male'
          }
        });
      
        // Define a table visualization
        var table = new google.visualization.ChartWrapper({
          'chartType': 'Table',
          'containerId': 'chart1',
          'options': {'height': '13em', 'width': '20em'}
        });
      
        // Create the dashboard.
        var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard')).
          // Configure the string filter to affect the table contents
          bind(stringFilter, table).
          // Draw the dashboard
          draw(data);
      }
      
      google.setOnLoadCallback(drawVisualization);
    </script>
  </head>
  <body style="font-family: Arial;border: 0 none;">
    <div id="dashboard">
      <table>
        <tr style='vertical-align: top'>
          <td style='width: 300px; font-size: 0.9em;'>
            <div id="control1"></div>
            <div id="control2"></div>
            <div id="control3"></div>
          </td>
          <td style='width: 600px'>
            <div style="float: left;" id="chart1"></div>
          </td>
        </tr>
      </table>
    </div>
  </body>
</html>

Predictability of a control

Before publishing a visualization with controls, it is important to understand how the control actually affects the data view. This may be common sense, but can be an easily overlooked step. Often it may be assumed a filter will behave a certain way, when in reality the actual behavior is quite different. In the following example, the number "1" is entered into the search field. The resulting filter of data returns all entries in the Male column that begins with the integer 1. An incorrect interpretation of this filter functionality may have been to search the column for the number 1 as it appears anywhere, even numerous times, in the entry.

Predictability of a control

Similarly, searching for 10 returns only the population numbers that start with 10. Entries that contain other sequences or alternative string locations, such as 180 or 2010 are not among the results.

Predictability of a control

At this point, it can be assumed searching for the string 108 will only return the exact sequence of the integer one, followed by the integer zero, followed by the integer eight, which is in fact, the result.

Predictability of a control

At the time of this publication, the Visualization API does not support using the generally accepted notation of language processing searches, such as wildcards and ranges that do not improve results. At this time, it can then be deduced that the StringFilter is literally just that, a simple string filter. In this case, the filter may sometimes behave as a search-style control, but is actually not designed for typical search functionality.

Overall, adding controls to a chart is fairly simple. Issues primarily arise when expectations of a certain functionality do not coincide with actual functionality.

Tip

Know how ControlWrapper controls interact with specific charts and data. Test control functionality to be sure that the visualization result is as expected and intended.

NumberRangeFilter

A NumberRangeFilter control is a bar-shaped slider with handles at each end of the bar. The individual viewing the chart is able to manipulate the handles in order to dynamically view a specific range of data on the visualization.

NumberRangeFilter

A NumberRangeFilter is built in the same manner as a StringFilter. First, the control object for the filter is defined. Notice much of the code is exactly the same, with the exception of the controlType setting. To create a NumberRangeFilter, create the same object as with StringFilter but substitute NumberRangeFilter as the controlType.

// Define a slider control for the 'Male Population' column
  var slider = new google.visualization.ControlWrapper({
    'controlType': 'NumberRangeFilter',
    'containerId': 'control1',
    'options': {
      'filterColumnLabel': 'Male',
      'ui': {'labelStacking': 'vertical'}
    }
  });

Once again, as with StringFilter, create the chart component for the NumberRangeFilter.

var piechart = new google.visualization.ChartWrapper({
'chartType': 'PieChart',
 'containerId': 'chart1',
 'options': {
   'width': 700,
   'height': 300,
   'legend': 'bottom',
'chartArea': {'left': 15, 'top': 15, 'right': 0, 'bottom': 0},
      'pieSliceText': 'value'
   }
});

Finally, finalize the drawing of the chart by attaching the control to the visualization dashboard component with bind.

// Create the dashboard.
new google.visualization.Dashboard(document.getElementById('dashboard')).
    // Configure the slider to affect the piechart
    bind(slider, piechart).
    // Draw the dashboard
    draw(data);

CategoryFilter

A CategoryFilter control is a drop-down menu where selecting an item from the drop-down filters the view of the visualization based on that selected item. CategoryFilter has several customization options, such as allowing multiple selections at a time, or user-typed selections. The following example shows a category filter that sets the chart view by selected age group.

CategoryFilter

To illustrate the power of visualization when using a category filter, note in the preceding figure, the Under 5 years and 20 to 24 years categories make chart data appear relatively close in value. However, when a third, 25 to 29 years category is added, values of data are not as close as first suggested.

CategoryFilter

Using CategoryFilter controls allow users to target specific regions of data without losing the perspective of the entire dataset. The CategoryFilter control is created in a similar manner to other controls. As with any other visualization, create or import data first.

function drawVisualization() {
  // Prepare the data.
  var data = google.visualization.arrayToDataTable([
    ['Age Group', 'Male', 'Female'],
    ['Under 5 years', 94100, 91787],
    ['10 to 14 years', 84122, 81955],
    ['15 to 19 years', 83274, 81192],
    ['20 to 24 years', 91528, 91405],
    ['25 to 29 years', 108407, 114620],
    ['30 to 24 years', 134931, 141208]
  ]);

Then, a variable is defined to provide the age selector control. The control creation also defines an initial state for the chart.

  // Define a category picker for the Age Group column.
  var agePicker = new google.visualization.ControlWrapper({
    'controlType': 'CategoryFilter',
    'containerId': 'control1',
    'options': {
      'filterColumnLabel': 'Age Group',
      'ui': {
        'allowTyping': false,
        'allowMultiple': true,
        'selectedValuesLayout': 'belowStacked'
      }
    },
    // Define an initial state, i.e. a set of age groups to be initially selected.
    'state': {'selectedValues': ['Under 5 years', '20 to 24 years']}
  });

Following the control creation, the bar chart visualization must be defined. The label options for the chart are included as part of the options definitions.

  // Define a bar chart with ChartWrapper.
  var barChart = new google.visualization.ChartWrapper({
    'chartType': 'BarChart',
    'containerId': 'chart1',
    'options': {
      'colors': ['orange', 'purple'],
      'title': ['2010 Chicago Census by Gender & Age Group'],
      'hAxis':{'title': "Population"},
      'vAxis':{'title': "Age Group"},
      'width': 550,
      'height': 350
    }
  });

Finally, the dashboard is created and the bind function links the selection control and chart together.

  // Create the dashboard.
  var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard')).
    // Configure the age picker to affect the chart
    bind(agePicker, barChart).
    // Draw the dashboard
    draw(data);
}

ChartRangeFilter

Similar to the NumberRangeFilter control that filters a data view based on a column's range of values, the ChartRangeFilter control filters a view based on a time period.

ChartRangeFilter involves time-based data, which requires extra discussion. Given this need, it is better categorized as part of the Time-based charts section in Chapter 8, Advanced Charts. The following graphic is a ChartRangeFilter control filtering the main chart view data that is linked to a time period in roughly February 2012.

ChartRangeFilter

Controls with dependencies

A series of controls may be linked together, such that the subsequent control relies on the previous control's value. Outside of the Visualization API, this is often referred to as a cascading list of values. This technique is particularly useful with charts that require a selection of data to be systematically pared down from larger categories. A control that filters by country may then become a dependency of another control that filters by state, city, or county. The state filter will automatically receive the filtered results of the country control as its selection options. In this way, it is possible to view data at various levels of granularity by using multiple controls in conjunction.

To illustrate, this is a simple bar graph that has been created from the age group population data of Chicago from 2000, 2005, and 2010. One of the controls on the far-left side has a dependency on the other. When the Year is selected, the graph is populated with that particular year's population for the selected year. To further filter the display, one or more Age Groups may be selected for the given year.

Controls with dependencies

To change the selected data to another year, simply select the Year drop-down and pick a different option. The data displayed will automatically adjust to the Age Group filters already selected. The following dependency example is in its entirety. On initial load, the Year option has been preset to 2010. Setting of the initial state takes place as part of the control declaration itself.

function drawVisualization() {
  // Prepare the data
  var data = google.visualization.arrayToDataTable([
    ['Year', 'Age Group', 'Population'],
    ['2000', 'Under 5 yrs', 776733],
    ['2005', 'Under 5 yrs', 8175173],
    ['2010', 'Under 5 yrs', 21372],
    ['2000', '5 to 9 yrs', 3694820],
    ['2005', '5 to 9 yrs', 70708],
    ['2010', '5 to 9 yrs', 857592],
    ['2000', '6 to 10 yrs', 2193031],
    ['2005', '6 to 10 yrs', 852395],
    ['2010', '6 to 10 yrs', 348556]
  ]);
  var yearPicker = new google.visualization.ControlWrapper({
    'controlType': 'CategoryFilter',
    'containerId': 'control2',
    'options': {
      'filterColumnLabel': 'Year',
      'ui': {
        'labelStacking': 'vertical',
        'allowTyping': false,
        'allowMultiple': false
      }
    },
    'state': {'selectedValues': ['2010']}
  });
  var agePicker = new google.visualization.ControlWrapper({
    'controlType': 'CategoryFilter',
    'containerId': 'control3',
    'options': {
      'filterColumnLabel': 'Age Group',
      'ui': {
        'labelStacking': 'vertical',
        'allowTyping': false,
        'allowMultiple': true
      }
    }
  }); 
  
  // Define a bar chart to show 'Population' data
  var barChart = new google.visualization.ChartWrapper({
    'chartType': 'BarChart',
    'containerId': 'chart1',
    'options': {
      'title': ['2000 & 2010 Chicago Census by Gender & Age Group (incl. 2005 estimate)'],
      'width': 800,
      'height': 300,
      'chartArea': {top: 50, right: 50, bottom: 50}
    },
    // Configure the barchart to use columns 1 (age group) and 2 (population)
    'view': {'columns': [1, 2]}
  });

  // Create the dashboard.
  new google.visualization.Dashboard(document.getElementById('dashboard')).
    // Configure the controls so that:
    // - the 'Year' selection drives the 'Age Group' one,
    // - and the 'Age Group' output drives the chart

    bind(yearPicker, agePicker).
    bind(agePicker, barChart).
    // Draw the dashboard
    draw(data);
}

Working with dependent controls may take some trial and error to make them function as desired.

Tip

Troubleshooting

When using the ChartArea option in defining a chart, be careful to not make area values too small so that title and axis labels are accidentally cropped out of the viewable area. If titles or axis labels do not appear as expected, try increasing the chart area values.

Programmatic control

The purpose of providing programmatic control through the Visualization API is to allow the developer to dynamically set chart attributes through various external sources. Programmatic control is therefore nothing more than the assignment of available chart attributes through the user interface, or other mechanism capable of triggering an event. Just as the Google Visualization API uses events to enable dynamic activity within itself, JavaScript events such as onclick() or onload() also allow web page events to trigger Visualization API customization.

The following example illustrates the combination of event triggers designed as buttons, which then set visualization option configurations. The buttons are ultimately just presets for the visualized chart. To filter the pie chart to a view of only the 50 to 54 and 55 to 59 years age group ranges, the user would select the Select 50 to 54 + 55 to 59 years button.

Programmatic control

The resulting visualization not only alters the pie chart view, but is also programmed so that the slider configuration changes as well. The button press event is in actuality, linked only to the slider control. In turn, the chart depends on the slider configuration. In this manner, a chain of dependencies is achieved, although the slider can still be manipulated independently of the preset button.

Programmatic control

Similarly, when the Select 90K – 12K population button is pressed, the slider values are set, which subsequently alters the chart visualization itself.

Programmatic control

Global variables

To code the preceding example, there is one key difference to recognize as part of creating a programmatic control for a chart. As with previous examples, the function to execute upon triggering the event is organized as a function outside of the main visualization function. The slider and pie chart variables happen to be used in both the functions. However, if these variables are only known to the main visualization function, the execution of the dashboardReady code will result in an error when the button event is triggered. This occurrence results in the following Uncaught ReferenceError: slider is not defined error message when debugging the code:

Global variables

The slider in the error is referring to the use of the slider object in the dashboardReady function, not the main drawVisualization function. The slider object is known to the drawVisualization function, but not to the dashboardReady function, as they are completely separate functions and slider is defined in drawVisualization only. To solve this issue and introduce consistency of variables, a variable that is known to the entire scripted application is required. This type of variable is called a Global variable. To create a global variable, simply create it outside of either function.

<script>

var slider;
varpiechart;

functiondrawVisualization () { … }
…
</script>

The declaration of the variable must still be inside the <script> tags, but outside of all JavaScript functions in order to be considered global to the application. The slider example declares the global variables, slider and piechart, at the very beginning of the API script. In this way, both slider and piechart can be referenced in any function in the API script. The entire HTML code for the programmatic control example is explained by section here. The first section loads the appropriate libraries.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>
      Google Visualization API Sample
    </title>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load('visualization', '1.1', {packages: ['controls']});
    </script>
    <script type="text/javascript">

Next, the global slider and piechart variables are declared. The dataset is created as a DataTable, and the slider and piechart variables are configured.

      // Define the slider and pie chart variables as global variables.
      var slider;
      var piechart;
      
      function drawVisualization() {
        // Prepare the data
        var data = google.visualization.arrayToDataTable([
             ['Age', 'Male'],
             ['Under 5 years',    94100],
             ['5 to 9 years',     84122],
             ['10 to 14 years',   83274],
             ['15 to 19 years',   91528],
             ['20 to 24 years',   108407],
             ['25 to 29 years',   134931],
             ['30 to 34 years',   119828],
             ['35 to 39 years',   100651],
             ['40 to 44 years',   89957],
             ['45 to 49 years',   85645],
             ['50 to 54 years',   80838],
             ['55 to 59 years',   68441]
        ]);
      
      // Define a slider control for the 'Male Population' column
      slider = new google.visualization.ControlWrapper({
        'controlType': 'NumberRangeFilter',
        'containerId': 'control1',
        'options': {
        'filterColumnLabel': 'Male',
        'ui': {'labelStacking': 'vertical'}
        }
      });       
        
      // Define a pie chart
      piechart = new google.visualization.ChartWrapper({
        'chartType': 'PieChart',
        'containerId': 'chart1',
        'options': {
          'width': 700,
          'height': 400,
          'legend': 'side',
          'chartArea': {'left': 15, 'top': 15, 'right': 0, 'bottom': 10},
          'pieSliceText': 'value'
        }
      });

At this point, the dashboard is defined. Also, the event that listens for the chart to finish rendering is created. The final step is to bind the slider and piechart controls to the dashboard and draw the chart.

    // Create the dashboard
    var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard'));
        
    // Register a listener to be notified once the dashboard is ready to accept presets.
    google.visualization.events.addListener(dashboard, 'ready', dashboardReady);
        
    // Configure the slider to affect the piechart, bind to the // dashboard
    dashboard.bind(slider, piechart).draw(data);
      
 }

Outside of the visualization function, the dashboardReady function sets the state values for the range slider and preset buttons.

function dashboardReady() {
  // The dashboard is ready to accept interaction. Configure the buttons to programmatically affect the dashboard when clicked.
  // This button selects the range that happens to be the 50-54 and 55-59 year age groups
  document.getElementById('rangeButton').onclick = function() {
    slider.setState({'lowValue': 68441, 'highValue': 80838});
    slider.draw();
  };

  // This button selects population numbers between 90K to 120K
  document.getElementById('rangeButton2').onclick = function() {
    slider.setState({'lowValue': 90000, 'highValue': 120000});
    slider.draw();
  };
       
}

The final section of code sets the containers for the slider, buttons, and chart.

      google.setOnLoadCallback(drawVisualization);
    </script>
  </head>
  <body style="font-family: Arial;border: 0 none;">
    <div id="dashboard">
 <table>
        <tr style='vertical-align: top'>
          <td style='width: 300px; font-size: 0.9em;'>
            <div id="control1"></div>                       
            <div id="buttons">
              <button style="margin: 2em" id="rangeButton">Select 50 to 54 + 55 to 59 years</button><br /> 
              <button style="margin: 2em" id="rangeButton2">Select 90K - 120K population</button><br />
            </div>
          </td>
          <td style='width: 600px'>
            <div style="float: left;" id="chart1"></div>
          </td>
        </tr>
      </table>
    </div>
  </body>
</html>

Dashboards and controls can at first appear to be complicated given the length of code required. However, breaking down the code into functional components reveals the methodical, but simple approach to dashboard construction.

Note

Dashboard and control documentation is available at https://developers.google.com/chart/interactive/docs/gallery/controls.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset