Protobi has a wide array of charts readily available to choose from in the chart type dialog. If none of the charts meet your specific needs, you can create your own custom charts using JavaScript and CSS. 

In this article, we review how the TargetSorter works and look at the process of adding a custom chart to your project.

TargetSorter components

The TargetSorter is a custom, sortable table that consists of four components. 

1. Banner group

The banner groups in the TargetSorter typically include all the project banners you want to cut your data by. The banners make up the rows of the table. You add banner groups by adding them as children of the TargetSorter. 

2. Banner point and sample size

Every data point within each banner will appear under the banner points section of the TargetSorter. This section also shows the sample size for each banner point. 

3. Target values and frequencies

This section represents the crosstab on the TargetSorter. Each value from the crosstab element is represented by a column. The numbers represent the value frequency per banner point. Press on the headers to sort by a target value.

4. Groups picker

The groups picker shows every banner group that is included in the TargetSorter. Select the banner groups that you want to hide by pressing on them. Hidden groups will show with the strikethrough text format. To unhide them, press again.

Sort by a target value

Press on the target values to sort the frequencies in descending order. This allows you to better understand which banner groups/points are associated with high frequency. 

Hide rows to bring groups of interest to the top

Press on the groups under the picker to hide/unhide banner rows. 

Set up a custom chart

1. Create a new element 

Press on the + sign to add a new element. Protobi will prompt you to create a new key for the element. 

2. From the JSON editor, set the chartType to "BasicElement". 

The BasicElement chartType is used for custom charts. It's not an option in the chartType dialog, so we add the chartType manually in the JSON editor.

 

3. Edit the HTML content editor by selecting the element and using the shortcut SHIFT+X+C.

You can write HTML, Markdown or Embedded JavaScript Templating in the content editor to create a custom chart. 

Embedded JavaScript Templating lets us embed JavaScript code in a template language that is used to generate HTML. You can insert dynamic data with Embedded JavaScript Templating, but with HTML you can only insert static text. See examples from Create custom charts

Add the TargetSorter to your project

Specify children

Add child elements under properties.* Set the banner groups you want to include in the TargetSorter as children in your custom element. The children can be single elements, or groups. In this example, we use banners which includes many elements (Gender, Age, Education, etc). 

*Note: Not every custom chart has children. Some might use the field attribute as the source of data like in this simple example with just one data point

Add the crosstab

The crosstab becomes the target values columns. In this TargetSorter we use “PARTY ID & IDEOLOGY”. 

Insert content and style

In the content editor (SHIFT+X+C) add the following Embedded JavaScript Templating code. See the comments within the code that describe what each block does. You can edit this example to fit your needs, or reach out to support@protobi.com and we will work with you to create a custom chart for your project. 

Content

<%
console.log("render banner sorter")
    var self = this
    showMargin  = true
    
// initial setup 
if (!model.get('col')) model.set('col', ['COUNTRY'])
if (!model.get('children')) model.set('children', ['banners'])

// get settings we'll refer to several times
var showMissing = true
var showOverall = getShowOverall()
var showFormat = getShowFormat()
var chartOptions = getChartOptions()
var margin = chartOptions.margin;
let showBasis = model.get('showBasis') !== false

var byDims = getCrosstabDimensions()
var byDim = byDims[0]  // right now only use first banner

var width = chartOptions.width-20  || 800
var innerWidth = width - (margin.r||200)

var kids = getVisibleChildren(model)  // exclude if hidden:true

// if kids is one group, e.g. "banners", expand the group
if (kids.length==1 && isGroup(kids[0])) kids = getVisibleChildren(kids[0])

// get one crosstab per kid
this.data = kids.reduce(function(acc,kid,arr) { 
    acc[kid.get('key')] = tabular.getCrosstab(byDim, kid, model.get('filter'), {showOverall: false})
    return acc
}, {})
    
// get marginal distribution of the banner variable
var marg = tabular.getMarginal(byDim, 'current', model.get('filter'))
var byDimFormat = byDim.get('format')
var byKeys = marg.getKeys().filter(k=>!isNA(k))
var titleColWidth = margin.l / 2
let numDataColumns = byKeys.length + 1
var dataColWidth 
if (showBasis) {
   dataColWidth = (innerWidth - margin.l -25 - 40) / byKeys.length 
}
else {
    dataColWidth = (innerWidth - margin.l-25) / byKeys.length 
}


// assemble a data structure we can sort and render
var i=0
var entries = _.flatten( kids
    .filter(kid=>!model.getDeep(['excluded', kid.get('key')]))
    .map(function(kid, kidIdx) {
    
        var xtab = self.data[kid.get('key')]
        var xkeys = xtab.columnKeys.map(x=>x[0])
        return xkeys.map(function(xKey, xKeyIdx) { 
            return {
                row: i,
                dim: kid, 
                rowKey: xKey,
                xtab: xtab,
                basis: xtab.getBasis(xKey, showMissing),
                bannerLabel: kid.getDisplayKey(),
                pointLabel: toDisplayString(xKey, kid.get('format'), kid),
                vals: byKeys.reduce(function(acc, byKey, arr) {
                    acc[byKey] = xtab.getRowPercent(xKey, byKey, showMissing)
                    return acc
                }, {})
            }
        }) 
    })
)
var orderby = model.get('orderby')
if (orderby) {
    entries = _.sortBy(entries, function(entry) {
        return _.get(entry, orderby)
    }).reverse()
}

listenTo(viewModel, 'change:showFormat', renderBody)

%>

 
 

The following CSS belongs in the style attribute within chartOptions. You can copy + paste the entire block into the JSON of your custom element. CSS describes how the HTML elements are to be displayed. You can use CSS to change the font, color, size, or spacing of the chart content. 

Style

"chartOptions": {
    "style": "
        .banner-sorter style {
            display: block; 
            border: 1px dashed grey; 
            white-space: pre;
            border: 2px solid grey;
            margin: 2px;
            border-radius: 5px;
            border-collapse: collapse;
            box-sizing: border-box;  
        }
        .banner-sorter table  {
            border: 2px solid grey !important;
            border-radius: 5px;
            table-layout: fixed;
            margin: 2px;
        }
       .banner-sorter table thead {
            display: block;
            ÷background: #ccc;
           }
       .banner-sorter table tbody {
            display: block;
            overflow-y: auto;
            height: 1600px;
            } .banner-sorter table tr:hover {
        background: #eee
        }
        .banner-sorter table th {
           padding: 5px 10px;
            box-sizing: border-box  !important;
            background: #ccc;
            vertical-align: top;
         }
       .banner-sorter table td {
           padding: 2px 10px  !important; 
           box-sizing: border-box !important;
         }
         .banner-sorter table.selector td:hover {
        background-color: #DEF;
        }
    .banner-sorter table.selector td.excluded {
        background-color: #EEE;
        text-decoration: line-through

    }
.banner-sorter table.selector td.excluded:hover {
    background-color: #CCC;
    }

table.groups td.excluded {background-color: #FC0}
"}</code></pre></div>
 
 

 

Learn more

See the links below for more information on HTML, Markdown and Lodash Javascript which is a more concise and maintainable form of JavaScript.

Helpful articles: