Notes on how to use dn.js

Tutorials and documentation


More detailed guidance follows here on each of the charts available in dn.js, our roadmap for development and some hints and useful functions included in dn.js for data exploration and more. Do also check out the other examples or download dn.js from GitHub and read the quick start guide. In each of the sections on this page, there are quick examples and code snippets relating to each dn.js chart using (fictitious!) meal delivery data from 2018 and 2019 for selected cities in the UK. The code is available in a JSFiddle. Here below is the summary of the data shown, and the reset button.
Summary
Total deliveries shown:
Average rating (5 is best):
 

How to load data using d3.js and how to use dn.js for data exploration?


dn.js expects an array of objects, with each object's parameters corresponding to data variables that can be converted into charts. At it's simplest this could be a structure like the following, where we have one variable "AA" with an associated count:
    // A list of data objects
    let dataList = [
        { AA: 1234, Count: 10 },
        { AA: 5678, Count: 20 },
        ...
    ];
This is equivalent to a flat file data structure and it has its origins in the first uses of dn.js for visualising multi-dimensional survey data. A typical approach to loading data would be:
  1. Store the core data attributes in a comma separated values (csv) file.
  2. Load this file from a cloud location (GitHub, Dropbox etc) using d3.csv.
  3. Parse the data and ensure numeric fields are well typed.
  4. Append any additional data - for example nested data that would be superfluous to store in the csv file.
It's worth spending some time on refining the data loading as it's normally possible to simplify and reduce the data provided in a csv, which often substantially reduces the time taken to download and parse a dataset. There is always a tradeoff between minimising the data downloaded and then the processing required on the clientside to regenerate the full dataset. Bear in mind too that while mobile devices continue to improve, they have less data crunching power than a desktop computer (for now!).
Here is the data loading code snippet for the example charts on this page:
    // Load the data using d3.csv
    d3.csv(urlData).then(function (data) {

        // Build the lookup lists for Food and location (dn is our DN object)
        lookupListFood = dn.BuildLookupList(data, "Food", 100);
        lookupListLocation = dn.BuildLookupList(data, "Location", 200);

        // Apply the latitude and longitude to the lookup table to support the map
        lookupListLocation.map(d => {
            let obj = dn.GetObjInList(ListCentroids, "ID", d.Title);

            let lat = 0;
            let long = 0;
            if (dn.IsDefined(obj)) {
                lat = obj.Latitude;
                long = obj.Longitude;
            }
            d.Latitude = lat;
            d.Longitude = long;
        });

        // Loop through and ensure that the raw data is numeric and set the codes for the food and location data
        data.map(d => {
            d.Count = +d.Count;
            d.FO = dn.GetObjInList(lookupListFood, "Title", d.Food).ID;
            d.RA = +d.RA;
            d.DA = +(d.Date.replace(/-/g, "")).substring(0, 6);  // We convert the dates to be YYYYMM
            d.DL = d.DA; // For the line charts
            d.LO = dn.GetObjInList(lookupListLocation, "Title", d.Location).ID;
            return d;
        });

        // Create the lookups for the dates
        lookupListDate = dn.GetYearMonthDescriptionList(dn.Unique(data.map(d => d.DA)));

        // Continue to create the chart group and the charts...
    });
Note that in this example, the csv does not contain the normalised numeric keys for the food and location variables; we create these on-the-fly using the dn.BuildLookupList function and then apply these codes as the elements of new data variables in our dataset using the dn.GetObjInList function. For larger datasets consider using hashes to lookup the values - dn.js has a useful dn.HashArray function for this purpose.
This leads onto data exploration - we'd recommend using R or another statistical language for analysing your datasets before visualising them; that said, it's possible to quickly create some views of the variables in a dataset to help you to better understand it. Here for example is the summary output from dn.DescribeDataset:
    // Lets have a quick look at our data ...
    // we use dn.DescribeDataset(divIDToAppendSummaryTo, datasetObject, maxNumRows)
    dn.DescribeDataset("DataExplorationSummary1", data, 10);
This summarises the head of our dataset, so we can better understand and verify the variables contained in it.
Similarly, the function dn.DescribeVariable, describes a specific variable - here for example is the summary output for four variables from our example dataset:
    // Lets have a quick look at four of the variables
    // we use dn.DescribeVariable(divIDToAppendSummaryTo, datasetObject, variableName, expectedDataType)
    dn.DescribeVariable("DataExplorationSummary2", data, "Count", "Number");
    dn.DescribeVariable("DataExplorationSummary2", data, "Date", "Date");
    dn.DescribeVariable("DataExplorationSummary2", data, "Food", "String");
    dn.DescribeVariable("DataExplorationSummary2", data, "Location", "String");
Thirdly, here is the output from dn.DescribeElement which summarises the element counts for a specific variable:
    // And lets get a summary of the elements within the Food variable
    // we use dn.DescribeElement(divIDToAppendSummaryTo, datasetObject, variableName, variableToCount)
    dn.DescribeElement("DataExplorationSummary3", data, "Food", "Count");
All three of these functions are useful for exploring source data from external sources and for checking that your source data is being loaded correctly.
 

How does the DNChartGroup data processing work?


DNChartGroup handles most of the data processing. It stores our dataset and has two primary purposes:
  1. Filtering - whenever a user selects a specific chart element (like a bar or pie segment), DNChartGroup filters the dataset based on all of the user's selection from all charts.
  2. Summarising - DNChartGroup then produces simple summary outputs for each data variable that is presented in a chart - analagous to a SQL GroupBy function. Most charts require simple data summaries, but Sankey diagrams require a more involved structure with nodes and links. DNChartGroup produces the appropriate data summaries for each chart.
By default, DNChartGroup will consider the data to be "flow" data - i.e. each row of data is independent and it makes sense to summarise all data rows cumulatively. Good examples of flow data are arrivals of population groups, or the count of specific events occurring.
DNChartGroup also handles the following types of data:
  • Stock data - is the opposite of flow data!
    • Stock data has a specific dimension, normally time, that cannot be summarised. For example the number of people living in a country each year - it does not make sense to add the totals for 2018 and 2019 together! In DNChartGroup, stock data is termed data with a "single option" dimension, to avoid confusion with data about stock markets! Data with a single option dimension is best visualised on column charts and this refugee population visualisation is a good example.
    • When setting up a chart group, add the two lines of code below (SingleOptionDimension-01 and SingleOptionDimension-02). These set a specific variable in the dataset to be the single option dimension, as well as the default element to select (typically the latest element in the variable). The second line then filters the dataset to only include rows for the default single option element's value.
  • Nested data
    • It's pretty common - for example, geographic data (regions, countries, administrative units etc.) are naturally nested. By default, DNChartGroup will handle these as other variables. It is also possible to redraw all the charts when a nested value is selected. This is useful when exploring a nested element with small counts as these might not be apparent in the default view.
    • In DNChartGroup, these dimensions are called pivot dimensions and to set these, we simply add a list of the data variables to treat as pivot dimensions (see the pivot-01 line below).
  • Dynamic summarisation of data
    • When either single option or pivot dimensions are used, there is also the potential to dynamically summarise other variables when these values are set. This is particularly useful for variables that are nested (for example countries in regions). To maintain useability most bar charts would be limited to 10-20 elements and with dynamically generated data, we can summarise additional elements in an "other" category. A good example are the countries or origin and asylum / residence on the refugee population visualisation.
    • To add these we need to add the two "Dynamic" snippets in the code example below. The first sets the variables that should be calculated dynamically and the second generates these variables. Dynamic variables in DNChartGroups are considered to have a source and target data variable, summarise the numeric values in the given column, display a given maximum number of values, and have a specific identifier for the dynamically generated "other" category.
Note that in the following code snippet, the order is critical!
    // Create the chart group
    let chartGroup = new DNChartGroup(data);
                
    //--SingleOptionDimension-01-- Setup the data visualisation as STOCK figures: Set the stock dimension to be Years, and specify that the default year is the latest year ...
    chartGroup.SetSingleOptionDimension("YE", latestYear);

    //--Pivot-01-- Set the pivot dimensions
    chartGroup.SetPivotDimensions(["GR", "ER", "PT"]);

    //--Dynamic-01-- Set up the dynamically generated data
    let sMaxNumToVis = dn.defaultSankeyMaxNumToVisualise;
    chartGroup.AddDynamicallyGeneratedDataVariable("CO", "CP", "Count", sMaxNumToVis, ListCO[ListCO.length - 1].ID);
    chartGroup.AddDynamicallyGeneratedDataVariable("CR", "CS", "Count", sMaxNumToVis, ListCR[ListCR.length - 1].ID);

    //--SingleOptionDimension-02-- Then filter the data based on the selected stock dimension (years).
    chartGroup.SetFilteredData(
        chartGroup.GetFilteredData(null));

    //--Dynamic-02-- then lets dynamically generate the data (this has to happen after the filtering by the single option).  The sankey diagram in particular is dependent on this.
    chartGroup.DynamicallyGenerateData();

    // Then continue to visualise the data...
 

Common attributes for all charts


A typical way of drawing a DNChart is to use the chart name function (e.g. BarChart, SankeyChart etc.). These functions take a list of attributes, many of which are consistent between charts. Here is an example for bar charts and in the following sections an example is given for each type of chart.
    // Draw a bar chart
    new DNChart().BarChart("AA", "DataVisDivID", chartGroup, 10, 20, 300, 400, 10, "CCSClass", true, 30, "", lookupList, "Chart title", true);
The generic attributes, that are common to all charts are as follows:
  • Chart ID - always the first parameter, this should be a two character identifier and should correspond to the name of the data variable in the dataset to be used. E.g. in the example given on this page the meal delivery rating data is variable "RA", so the rating chart has the ID "RA" too.
  • Chart Type - currently this is set implicitly by the type of chart being added. Exposing this will help make dn.js and options for doing this are currently being explored.
  • Chart wrapper div ID - the ID of the div that will contain this specific chart. Not all charts need to belong to the same div - as on this page, the charts are distributed within the narrative.
  • Chart group object - the DNChartGroup object that contains the data and will conduct most of the data processing and links between charts.
  • Extents - the usual left, top, width and height specified as four integers.
  • Chart title - The title of the chart to be displayed. All charts are created with a wrapper styled with ChartBox, and the chart title styled with ChartTitle. These styles can be overidden.
  • Lookup list of element names - dn.js expects the data variables to be numeric to ensure optimal efficiency in processing the data. Most data elements in a variable are usually better explained as text (e.g. 1002 versus UKR versus Ukraine!), and this lookup list contains the unique list of the IDs associated with each element of the data variable used to produce this chart and the textual descriptions for each of these. These lookup lists are lists of objects of the form [{ID:123, Title:"XYZ"},...].
  • Whether or not to draw the chart immediately - in most cases, it makes sense to draw the chart immediately (set DoDraw===true), however, if customised data is to be passed to the chart or additional parameters need to be set specific to this chart, set this to false and then call Draw{MyChartName}() once the processing is completed.
 

Bar chart


    // Draw a bar chart
    new DNChart().BarChart("AA", "DataVisDivID", chartGroup, 10, 20, 300, 400, 70, "CCSClass", true, 30, "", lookupList, "Chart title", true); 
In addition to the list of attributes common to all charts, bar charts require the following additional attributes:
  • Legend offset - the horizontal distance (in pixels) between the left hand edge of the chart and the y-axis. This is useful when element names are particularly long (or short).
  • CSS class - an easy way to override the default classes used by each type of chart. If set, this classname will be used instead.
  • Sort by value - if true, the chart is sorted in descending order by the value of the column to sum. Otherwise the elements are sorted by the numeric element ID.
  • Maximum number of elements - the default is zero, with all elements displayed. For data with lots of unique elements, setting this to a value will truncate the number of elements shown. Note that if a variable is a dynamic dimension, an addition "Other" category is added containing the total for all the elements that have been truncated..
  • Column to sum - This is the name of the variable that is summarised when folding the data for specific charts. The default is "Count".
  • Legend maximum character length - The number of characters that can be displayed in the legend before being truncated with "...". Use in combination with the legend offset above to create more space. The default for bar charts is 25.
 

Pie chart


    // Draw a pie chart
    new DNChart().PieChart("BB", "DataVisDivID", chartGroup, 10, 20, 300, 400, 65, colourRange, null, "Chart title", true);
In addition to the list of attributes common to all charts, pie charts require the following additional attributes:
  • Colour range - an array of html colour codes (see ColourBrewer.js for examples). The array should be the same length or longer as the number of unique elements for a given variable. The colours will be applied in the order given to the unique elements in the lookup list. E.g. the first element in the lookup list will be associated with the first colour in the colour range list.
  • Legend offset - shuffles the legend left (or right if negative) the given number of pixels. Useful for adjusting if the element names are particularly long (or short).
  • Legend maximum character length - The number of characters that can be displayed in the legend before being truncated with "...". Use in combination with the legend offset above to create more space. The default for pie charts is 29.
 

Line chart


    // Draw a line chart
    new DNChart().LineChart("CC", "DataVisDivID", chartGroup, 10, 20, 300, 400, "CssClass", lookupList, "Chart title", true);  
In addition to the list of attributes common to all charts, line charts require the following additional attributes:
  • CSS class - an easy way to override the default classes used by each type of chart. If set, this classname will be used instead.
 

Column chart


    // Draw a column chart
    new DNChart().ColumnChart("DD", "DataVisDivID", chartGroup, 10, 20, 300, 400, 10, "CssClass", false, 0, null, lookupList, "Chart title", true, true);
In addition to the list of attributes common to all charts, column charts require the following additional attributes:
  • Legend offset - the horizontal distance (in pixels) between the left hand edge of the chart and the y-axis. This is useful when element names are particularly long (or short).
  • CSS class - an easy way to override the default classes used by each type of chart. If set, this classname will be used instead.
  • Sort by value - if true, the chart is sorted in descending order by the value of the column to sum. Otherwise the elements are sorted by the numeric element ID.
  • Maximum number of elements - the default is zero, with all elements displayed. For data with lots of unique elements, setting this to a value will truncate the number of elements shown. Note that if a variable is a dynamic dimension, an addition "Other" category is added containing the total for all the elements that have been truncated..
  • Column to sum - This is the name of the variable that is summarised when folding the data for specific charts. The default is "Count".
  • Legend maximum character length - The number of characters that can be displayed in the legend before being truncated with "...". Use in combination with the legend offset above to create more space. The default for column charts is 25.
  • Show slider - Whether or not to show the slider underneath the column chart. This widget lets users summarise multiple neighbouring columns and animate the data series (which will update all the other charts as well). To show the slider, the CCSliderWrapper class should with position:absolute.
 

Sankey diagram


    // Draw a Sankey
    new DNChart().SankeyChart("EE", "DataVisDivID", chartGroup, 10, 20, 300, 400, true, colourRangeSource, colourRangeTarget, sourcelookupList, targetlookupList, "AA", "BB", "Chart title", true); 
In addition to the list of attributes common to all charts, dn.js sankey diagrams are unique in having two input dimensions. They require the following additional attributes:
  • Chart ID and source and target data variable IDs - Sankey diagrams have the usual two character chart ID, but also require the identifiers for the source and target variables as well. By convention, these should also be two character identifiers and should correspond to the names of the source and target data variables in the dataset to be used. E.g. in the example given on this page the meal delivery rating data is variable "RA", so the rating chart has the ID "RA" too.
  • Lookup list of element names for the source and target variables - dn.js expects the data variables to be numeric to ensure optimal efficiency in processing the data. Most data elements in a variable are usually better explained as text (e.g. 1002 versus UKR versus Ukraine!), and these lookup list contain the unique list of the IDs associated with each element of the source and target data variables used to produce this chart and the textual descriptions for each of these. These lookup lists are lists of objects of the form [{ID:123, Title:"XYZ"},...].
  • Colour ranges for the source and target variables - two arrays of html colour codes (see ColourBrewer.js for examples). The arrays should be the same length or longer as the number of unique elements for eachgiven variable. The colours will be applied in the order given to the unique elements in the lookup list. E.g. the first element in the lookup list will be associated with the first colour in the colour range list and this will be applied to the associated node in the diagram.
  • Sort by value - if true, the chart is sorted in descending order by the value of the column to sum. Otherwise the elements are sorted by the numeric element ID.
 

Map

    // The location lookup list with centroids of our cities
    let ListLocationLookupWithCentroids = [
        { ID: 200, Title: "London", Longitude: -0.118092, Latitude: 51.509865 },
        { ID: 201, Title:  "Edinburgh", Longitude: -3.188267, Latitude: 55.953251 },
        { ID: 202, Title: "Bath", Longitude: -2.360000, Latitude: 51.380001 },
        { ID: 203, Title: "Cambridge", Longitude: 0.119167, Latitude: 52.205276 },
        { ID: 204, Title: "York", Longitude: -1.080278, Latitude: 53.958332 }
    ]; 

    // The tile URL and access token (e.g. from MapBox or OpenStreetMap)
    dn.mapTileURL = "ADD YOUR MAP TILE URL";
    dn.mapTileAccessToken = "ADD YOUR MAP TILE ACCESS TOKEN";

    // The map centroid
    dn.defaultMapCentroid = [54.7, -4.2];
    dn.defaultMapZoomLevel = 5;
 
    // Draw a Map
    new DNChart().Map("FF", null, "DataVisDivID", chartGroup, 10, 20, 300, 400, ListLocationLookupWithCentroids, null, "Chart title", dn.defaultMapCentroid, dn.defaultMapZoomLevel, true); 
                                     
In addition to the list of attributes common to all charts, maps require the following additional attributes:
  • Zoom level - the default level of zoom for the map. It is expressed as a integer and typically 3-4 is useful for regional maps; 5-6 for country level and more for specific locations.
  • Centroid - the default location to centre the map. It is expressed as an array in decimal degrees: [latitude, longitude].
  • IMPORTANT - maps require also the latitude and longitude of the locations specified by each element in the data variable in decimal degrees format. For maps, the latitude and longitude should be incorporated in the lookup lists, which are lists of objects of the form [{ID:123, Title:"XYZ", Latitude:12.333, Longitude:-20.2},...]. The example above is the simplest approach to achieving this and there are many ways to do this dynamically instead.
  • Tile URL and access token - these should be set prior to creating the map.
Not currently implemented:
  • Additional Chart ID for a second geographic level - When implemented, would allow nested chart identifiers (for e.g. locations and sub locations).
  • A lookup list of element names for the second geographic level - dn.js expects the data variables to be numeric to ensure optimal efficiency in processing the data. Most data elements in a variable are usually better explained as text (e.g. 1002 versus UKR versus Ukraine!), and these lookup list contain the unique list of the IDs associated with each element of the source and target data variables used to produce this chart and the textual descriptions for each of these.
 

How to create responsive dn.js visualisations?


Most modern websites use CSS and / or JavaScript to alter the flow and volume of the content presented based on the available screen real estate. While a pure CSS option would be ideal, it is tricky to do with visualisations like these using Scalable Vector Graphics (SVG).
Our suggested approach is to decide on a series of templates for different ranges of screen sizes. In each template it's then possible to ensure that the most important data summaries are shown first (i.e. near the top). As well as with supporting mobile devices, it is also useful to reshape the visualisation if the user resizes their browser. The stock ticker chart example is a good example of how a responsive approach can be applied - try changing the width of your browser to see how it resizes. The pseudo code for the DrawResponsively method is provided below.
    // the DimensionsChartObjects chart object dimensions of the form "ChartID": [X,Y,W,H]
    var DCO = {};
                
    // Lets draw the ticker chart responsively
    function DrawResponsively() {

        //--00-- Get the width and height of the browser (stored in Site.js)
        let { docWidth, docHeight } = dn.WidthAndHeight();

        if (docWidth > 800) {               
            // Desktop version
            DCO["TC"] = [0, 0, 600, 600];
        } else {                                
            // Mobile version
            DCO["TC"] = [0, 0, docWidth - 20, 400];
        }

        // Now go ahead and call Visualise data to redraw the chart using the dimensions set in the DCO object ...    
        // e.g. to get the x coordinate: DCO["TC"][0]
        DoVisualisation();
    }
The refugee population visualisation is another example of this approach, with five different templates for different browser widths.

How to store filter selections in the page's URL history?


When exploring data using an interactive visualisation, at some moments you have a Eureka moment and you want to share the current view with a colleague. Normally, when your colleague views the same page, nothing is selected and they need to reapply the filters that you had applied. DNURLEditor solves this by enabling a shareable link to be created that includes all the filters that you have been applied. Check out how it works in the refugee population visualisation.
To set it up, we add three short blocks of code; firstly at the global level we instantiate our DNURLEditor and create a list of the chartIDs that we want to monitor. The DNURLEditor will only check for these specific parameters. We also take a snapshot of the URL provided which we will check to see if any specific parameters have been requested.
    //--01-- Lets declare our DNURLEditor here too
    var urlEditor = new DNURLEditor();
    var urlEditorChartIDs = ["YE", "GR", "CR", "CP", "ER", "CS", "PT"];
    // And lets take a snapshot of the initial URL
    let initialURL = new URL(window.location.href);
Secondly, when creating the chart group, also assign our DNURLEditor to the chart group. This ensures that whenever the user filters one or more charts, the page's URL will update to reflect this.
    //--02-- Define the chart group and set the URL editor
    chartGroup = new DNChartGroup(rawJSData);
    chartGroup.urlEditor = urlEditor;
Thirdly, in Visualise data, AFTER the charts have been drawn, append the following lines. These ensure that the currently selected filters are applied to the charts and to the data.
     // If this is the initial load, lets apply any filters provided in the URL
    if (dn.IsDefined(initialURL) && initialURL !== "") {
        // Apply the URL filters (if any were provided)
        urlChartID = urlEditor.URLApplyFilters(urlEditorChartIDs, initialURL, chartGroup, true);
        
        // clear the initialURL so it does not get reapplied
        initialURL = null;
      
        // We always need to reapply the filter for the initial load.  This redraws the charts, and updates everything that's needed)
        chartGroup.ApplyFilter(urlChartID, false, true, true);
    }
 

How to work with big data?


As you've probably seen by now, dn.js can handle fairly big datasets. As noted in the roadmap, we are exploring asynchronous options to pull the chart summary data from a server to the client. In the meantime, JSZip is a really useful JavaScript library for unzipping datasets. The great thing about clean CSV files is that they can be substantially compressed by zipping them.
JSZIP requires two javascript files as noted in the prerequisites section, JSZip handles the unzipping and JSZipUtils handles downloading the binary data. Here is an example of how to use it:
    // Extract the csv from a zip file and parse it
    JSZipUtils.getBinaryContent(urlZipped, function (err, data) {
        if (err) {
            console.error("dn.js - Unzipping the file " + urlZipped + " failed.  Check the internet connection.");
        } else {

            //--02--Our JSZip object
            let unzipper = new JSZip();

            unzipper.loadAsync(data).then(function () {

                //--03--Load--- Extract our file
                unzipper.file(zippedFileName).async("string").then(function (rawData) {

                    //--04--Load--- Parse our data with D3
                    let data = d3.csvParse(rawData);

                    //--05--Load--- Process the data ...
                    ProcessData(data);
                });
            });
        }
    });

    // Or lets get the unzipped version
    d3.csv(urlUnzipped).then(function (data) {
        ProcessData(data);
    });
Using JSZip, the initial load of pages is definitely faster once the unzipped csv files increase to more than 1MB. However, bear in mind that even when the file is cached locally, the unzipping runs each time the page is loaded. For page reloads therefore, the unzipped version remains faster. A smarter approach might be to unzip the file once and then store it in the local storage (it's not guaranteed but there is normally up to around 10MB per origin domain available).
 

Roadmap for development of dn.js


There are already a few important development items underway and do let us know if there is something you urgently require. Bear in mind that dn.js is never going to include every type of chart out there - the library would simply become too huge and unmanageable. So far, we've tried to identify the charts that are most commonly used, or like the Sankey diagrams and maps, that are really useful but woefully underused. A useful reference guide showing the universe of charts out there and the recommended uses for each is the Financial Times Visual Vocabulary.
For dn.js, extensibility is therefore the key - we've designed the code so far so that it is relatively easy to add a new type of chart. In that way the core library remains relatively compact and once the extensibility is implemented, different users will be able to plugin their own charting extensions. This is probably the key element from the list below and it's underway (as of Jan 2020). Here's the full current list:
  1. Extensibility - as noted above this is the priority area. We are currently testing approaches to achieving this, and once we have a tested, working solution, we'll document how to do it here. Timeline - will be included in dn.js in spring 2020.
  2. TreeMaps - are another underused but visually compelling chart. We've developed a working prototype, as used in the stock market example. The approach is similar to the Sankey diagrams in that while the visual code is relatively simple, the complexity is in structuring the data correctly. Timeline - will be included in dn.js in summer 2020 and TreeMaps are a contender as a plugin to the core library.
  3. Ticker charts - help bring e.g. stock data to life as in this stock tracker chart example. They are variants of line charts and will be included as an optional plugin in summer 2020.
  4. Multivariate bar or column charts - are great for visualing multiple elements of a variable in a relatively compact format. Check out these colourful examples of protection rates of refugees in Europe. Most probably, these will be included in the core libary in spring 2020.
  5. Scale changes on bar, line and column charts - when multiple filters are applied, the selected data can quickly reduce leading to almost entirely blank columns. For some comparisons, this scale insensitivity is useful, but it makes sense to add a toggle button, most probably for each chart, to let the user decide whether the chart's range should adapt dynamically depending on the data selected. To be included in summer 2020.
  6. Asynchronous loading of summary data for charts - the JSZip package helps with larger datasets ranging from 100,000 to a few million records. For larger datasets asyncronous loading of the summary data for each charts is needed to maintain acceptable performance. This obviously requires a server architecture to process the requests for summary data and given that the current library is a pure client side library, it's likely that the asynchronous capabilities will be bundled into a plugin. Timeline - autumn 2020.
  7. A whizzy loading animation - while not so obviously important as the items listed above, perceptions matter, particularly loading times. An attractive and fun loading animation (not a swirling circle!), would help fill the few seconds it takes to load larger datasets. This could take the form of one single animation, or could be a small simple animation in each chart block (e.g. a small simple bar chart for the space where a bar chart will load). Timeline - spring 2020.
  8. Further streamline the codebase - it is our intention to ensure that the core dn.js library does not exceed 45-50kb when minified (currently its around 38kb). Given all the useful items noted above, refactoring existing code will be essential. One area that would simplify the creation of charts, is to use an options object to store the parameters that need to be customised. Another would be to convert inner loops to use more efficient hash lookups where possible.
Please do get in touch if there are specific areas you would like use to explore - we'd be thrilled to hear from you! And in the meantime, have fun using dn.js!