How to Create Interactive JavaScript Charts from Custom Data Sets
Charts are a great way of visualizing complex data quickly and effectively. Whether you want to identify a trend, highlight a relationship, or make a comparison, charts help you communicate with your audience in a precise and meaningful manner.
In my previous article — Getting Started with AnyChart: 10 Practical Examples — I introduced the AnyChart library and demonstrated how it is a great fit for your data visualization needs. Today, I want to dig a little deeper and look at AnyChart’s data mapping features which allow you to create beautiful charts from custom data sets with a minimum of fuss.
I also want to look at the many ways you can customize AnyChart to suit your requirements, as well as how you can change the look and feel of AnyChart charts by using themes. There are currently 17 out-of-the-box themes to choose from, or you can create your own. And if you’ve not got the best eye for design, why not buy our book to get a leg up.
As the Head of R&D at AnyChart, I could spend all day talking about this library, but now it’s time to get down to business.
Data Mapping in AnyChart
To facilitate the integration of custom data sources into charting applications, AnyChart has special objects called data sets. These objects act as intermediate containers for data. When data is stored in data sets, AnyChart can track changes to it, analyze it, and work with this data in a more robust and effective manner. In short: interactive JavaScript charts have never been easier!
No matter if you have an array of objects, an array of arrays, or a .csv
file, you can use data sets to:
- ensure full and explicit control over the series created
- define which column is an argument (x-axis)
- define which columns hold values for which series
- filter data
- sort data
Basics of Data Mapping
The best way to learn how data mapping works in AnyChart is to look at an example. Let’s imagine an array with the following custom data set:
var rawData = [
["A", 5, 4, 5, 8, 1, "bad"],
["B", 7, 1, 7, 9, 2, "good"],
["C", 9, 3, 5, 4, 3, "normal"],
["D", 1, 4, 9, 2, 4, "bad"]
];
There’s nothing too wild going on here — this kind of custom data structure is common in a lot of existing applications. But now you want to use this array in AnyChart. With many other charting libraries you would be forced to transform the data to a format that the library can work with. Well, with AnyChart things are a lot simpler — just look what we can do. First, load the array into a data set:
var rawData = [
["A", 5, 4, 5, 8, 1, "bad"],
["B", 7, 1, 7, 9, 2, "good"],
["C", 9, 3, 5, 4, 3, "normal"],
["D", 1, 4, 9, 2, 4, "bad"]
];
var dataSet = anychart.data.set(rawData);
And then, once the data has been loaded into the data set, the real magic begins: you can now create so called views. These are data sets derived from other data sets.
var rawData = [
["A", 5, 4, 5, 8, 1, "bad"],
["B", 7, 1, 7, 9, 2, "good"],
["C", 9, 3, 5, 4, 3, "normal"],
["D", 1, 4, 9, 2, 4, "bad"]
];
var dataSet = anychart.data.set(rawData);
var view1 = dataSet.mapAs({x: 0, value: 1});
var view2 = dataSet.mapAs({x: 0, value: 2});
var view3 = dataSet.mapAs({x: 0, high: 3, low: 4});
var view4 = dataSet.mapAs({x: 0, value: 5, meta: 6});
You’ll notice that when defining a view, you determine which columns from the original array are included and what names these columns get. You can then use them to create whichever kind of charts you like. For example, here’s how to create a pie chart from the custom data in the 5th column.
Note: AnyChart needs only x
and value
fields to create a pie chart, but the views also contain a meta
field with the data from the 6th column. You can map any number of optional fields and use them as you like. For example, these fields can contain additional data to be shown as labels or as tooltips:
anychart.onDocumentLoad(function() {
var rawData = [
["A", 5, 4, 5, 8, 3, "Bad"],
["B", 7, 1, 7, 9, 5, "Good"],
["C", 9, 3, 5, 4, 4, "Normal"],
["D", 1, 4, 9, 2, 3, "Bad"]
];
var dataSet = anychart.data.set(rawData);
var view4 = dataSet.mapAs({x: 0, value: 5, meta: 6});
// create chart
var chart = anychart.pie(view4);
chart.title("AnyChart: Pie Chart from Custom Data Set");
chart.labels().format("{%meta}: {%Value}");
chart.container("container").draw();
});
And this is what we end up with:
See the Pen AnyChart Pie Chart from Data Set by SitePoint (@SitePoint) on CodePen.
Note: You can find all of the demos in this article as a CodePen collection.
Multi-Series Combination Chart with Custom Data Set
Now, let’s see how we can use the same custom data to create a combination chart with line and range area charts on the same plot. This section is going to be very short since now you know what views are. All you need to do is choose the proper views and create the necessary series explicitly:
anychart.onDocumentLoad(function() {
var rawData = [
["A", 5, 4, 5, 8, 3, "Bad"],
["B", 7, 1, 7, 9, 5, "Good"],
["C", 9, 3, 5, 4, 4, "Normal"],
["D", 1, 4, 9, 2, 3, "Bad"]
];
var dataSet = anychart.data.set(rawData);
var view1 = dataSet.mapAs({x: 0, value: 1});
var view2 = dataSet.mapAs({x: 0, value: 2});
var view3 = dataSet.mapAs({x: 0, high: 3, low: 4});
// create chart
var chart = anychart.line();
// create two line series
chart.line(view1).name("EUR");
chart.line(view2).name("USD");
// create range area series
chart.line(view2).name("Trend");
// set title and draw chart
chart.title("AnyChart: Combined Chart from Data Set");
chart.container("container").draw();
});
This is what it looks like:
See the Pen AnyChart Combined Chart from Data Set by SitePoint (@SitePoint) on CodePen.
Live Data Streaming and Filtering
And now, to showcase the beauty of views and data sets. For this we’ll create a column chart and a multi-line chart, live stream data into a data set, and accept only certain values into the column chart. Sound complicated? It isn’t really!
anychart.onDocumentLoad(function() {
var rawData = [
["A", 5, 4, 2, 6, 3, "Bad"],
["B", 7, 2, 1, 9, 5, "Good"],
["C", 8, 3, 2, 9, 4, "Normal"],
["D", 1, 4, 1, 4, 3, "Bad"]
];
dataSet = anychart.data.set(rawData);
var view1 = dataSet.mapAs({ x: 0, value: 1 });
var view2 = dataSet.mapAs({ x: 0, value: 2 });
var view3 = dataSet.mapAs({ x: 0, value: 3 });
var view4 = dataSet.mapAs({ x: 0, value: 4 });
var view5 = dataSet.mapAs({ x: 0, value: 5 });
// create chart
var chart1 = anychart.line();
// create several line series
chart1.line(view1).name("EUR");
chart1.line(view2).name("USD");
chart1.line(view3).name("YEN");
chart1.line(view4).name("CNY");
// create column chart
// based on filtered view
// that accepts values of less than 5 only
var chart2 = anychart.column(
view5.filter("value", function(v) {
return v < 5;
})
);
// set title and draw multi-line chart
chart1.title("Line: Streaming from Data Set");
chart1.legend(true);
chart1.container("lineContainer").draw();
// set title and draw column chart
chart2.title("Column: Filtering Stream");
chart2.container("columnContainer").draw();
});
// streaming function
var streamId;
function stream() {
if (streamId === undefined) {
streamId = setInterval(function() {
addValue();
}, 1000);
} else {
clearInterval(streamId);
streamId = undefined;
}
}
// function to add new value and remove first one
function addValue() {
// generate next letter/symbol as argument
var x = String.fromCharCode(
dataSet.row(dataSet.getRowsCount() - 1)[0].charCodeAt(0) + 1
);
// append row of random values to data set
dataSet.append([
x,
Math.random() * 10,
Math.random() * 10,
Math.random() * 10,
Math.random() * 10,
Math.random() * 10
]);
// remove first row
dataSet.remove(0);
}
You see that we’ve created a custom data set and five derived views. Four of them are used as is to create lines, but when creating our column chart, we apply the filtering function and let only values of less than 5 into the view. Then we stream data by adding and removing rows from the main data set, and all the views automatically receive data and charts are updated — no coding is needed to implement this!
See the Pen AnyChart Streaming and Filtering by SitePoint (@SitePoint) on CodePen.
This is just the tip of the iceberg as far as data mapping goes! You can do the same with arrays of objects and CSV data, and you can sort, search, listen to changes, go through values, as well as change existing rows. There are also special views for hierarchical data utilized in Tree Maps and Gantt Charts, and such views can be searched and traversed.
Customizing Chart Visualization
AnyChart is extremely versatile when it comes to chart customization. You can change line styles, fill colors, use gradient fill or image fill on almost any element. Colors can be set using String constants, HEX or RGB notation, or a function that returns one of these values. The library also offers a number of built-in patterns, as well as an option to create patterns of your own.
Themes
The easiest way to change the look and feel of AnyChart charts is to change the theme.
In fact, you can create your own theme or use one of those that already come with the library. There are currently 17 out-of-the-box themes available in AnyChart: Coffee, Dark Blue, Dark Earth, Dark Glamour, Dark Provence, Dark Turquoise, Default Theme, Light Blue, Light Earth, Light Glamour, Light Provence, Light Turquoise, Monochrome, Morning, Pastel, Sea, Wines. The files for these themes can be obtained from the Themes Section at AnyChart CDN.
You can reference them like so:
<script src="https://cdn.anychart.com/js/latest/anychart-bundle.min.js"></script>
<script src="https://cdn.anychart.com/themes/latest/coffee.min.js"></script>
And activate the theme with just one line:
anychart.theme(anychart.themes.coffee);
Let’s use the basic chart from the previous article by way of an example.
anychart.onDocumentLoad(function() {
// set theme referenced in scripts section from
// https://cdn.anychart.com/themes/latest/coffee.min.js
anychart.theme(anychart.themes.coffee);
// create chart and set data
var chart = anychart.column([
["Winter", 2],
["Spring", 7],
["Summer", 6],
["Fall", 10]
]);
// set chart title
chart.title("AnyChart Coffee Theme");
// set chart container and draw
chart.container("container").draw();
});
Now the look and feel of that chart is completely different.
See the Pen AnyChart Coffee Theme by SitePoint (@SitePoint) on CodePen.
Note: you can browse through all the themes and see how they work with different chart types and series on the AnyChart Themes Demo Page. Please refer to the AnyChart Documentation to learn how to create your own themes and read about other options.
Coloring
As you have seen, it’s quite trivial to color elements in the AnyChart charting library. But there’s more! It is also possible to color shapes with solid colors with opacity, use radial and linear gradients, and make lines dashed. You can apply colors by their web constant names, HEX codes, or RGB, RGBA, HSL, HSLA values — just as you can in CSS.
To showcase all of this in one powerful sample, I want to highlight another option along the way — namely that you can color elements using your own custom functions. This may come in handy in many data visualization situations, for example when you want to set a custom color depending on the value of the element. Let’s test this out on a Pareto chart. AnyChart can build this chart from raw data and calculate everything it needs.
anychart.onDocumentReady(function() {
// create Pareto chart
var chart = anychart.pareto([
{x: "Defect 1", value: 19},
{x: "Defect 2", value: 9},
{x: "Defect 3", value: 28},
{x: "Defect 4", value: 87},
{x: "Defect 5", value: 14},
]);
// set chart title
chart.title("Pareto Chart: Conditional coloring");
// set container id and draw
chart.container("container").draw();
});
But say we want to highlight the elements that have relative frequency of less than 10%. All we need to do in this case is to add some coloring functions:
// Get Pareto column series
// and configure fill and stroke
var column = chart.getSeriesAt(0);
column.fill(function () {
if (this.rf < 10) {
return '#E24B26 0.5'
} else {
return this.sourceColor;
}
});
column.stroke(function () {
if (this.rf < 10) {
return {color: anychart.color.darken('#E24B26'), dash:"5 5"};
} else {
return this.sourceColor;
}
});
As is shown in the example, we can access the coloring function context with the help of the this
keyword, then we create a condition and output whichever color or line setting we need. We use a simple HEX string with opacity for the color: '#E24B26 0.5'
. For the line, we calculate a darker color using AnyChart’s special color transformation function and also set an appropriate dash parameter: {color: anychart.color.darken('#E24B26'), dash:"5 5"}
.
Here’s what we end up with:
See the Pen AnyChart Conditional Colour Sample by SitePoint (@SitePoint) on CodePen.
Default Pattern Fill
The AnyChart JavaScript charting library also provides a very flexible way to work with pattern (hatch) fills. To start with, you have 32 pattern fill types. They can be arranged into your own custom pallets, and you can directly set which one to use for a certain series, element, etc. Here’s what the code for a monochrome pie chart might look like:
anychart.onDocumentReady(function() {
// create a Pie chart and set data
chart = anychart.pie([
["Apple", 2],
["Banana", 2],
["Orange", 2],
["Grape", 2],
["Pineapple", 2],
["Strawberry", 2],
["Pear", 2],
["Peach", 2]
]);
// configure chart using chaining calls to shorten sample
chart.hatchFill(true).fill("white").stroke("Black");
chart
.labels()
.background()
.enabled(true)
.fill("Black 1")
.cornerType("Round")
.corners("10%");
// draw a chart
chart.container("container").draw();
});
The only thing we did to enable the pattern fill is chart.hatchFill(true)
.
See the Pen AnyChart Default Pattern Fill Sample by SitePoint (@SitePoint) on CodePen.
Custom Pattern Fill
AnyChart gets its ability to use custom patterns from the underlying GraphicsJS library. I introduced this library and showcased some really cool drawing samples in my article here on SitePoint: Introducing GraphicsJS, a Powerful Lightweight Graphics Library. The fact that AnyChart is powered by GraphicsJS allows for some really amazing results, but a picture is worth a thousand words, so let’s proceed to the next example.
We’ll create patterns using one old font that used to be rather popular among geologists – Interdex. I remember one of AnyChart customers asking us how to use this in his project, and he was very happy to learn just how easy it was.
First, if you want to use a font that is not present on your system, you need to create a web font and properly reference it in the CSS file. A sample of such file for our Interdex font can be found on the AnyChart CDN. We need to reference it along with the font management library being used and the AnyChart charting library:
<link rel="stylesheet" type="text/css" href="https://cdn.anychart.com/fonts/interdex/interdex.css"/>
<script src="https://cdn.anychart.com/js/latest/anychart-bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fontfaceobserver/2.0.7/fontfaceobserver.js"></script>
After that, we can proceed with the coding:
var fontLoad = new FontFaceObserver("Conv_interdex");
// create chart when font is loaded using
// https://cdnjs.cloudflare.com/ajax/libs/fontfaceobserver/2.0.7/fontfaceobserver.js
fontLoad.load().then(function() {
anychart.onDocumentReady(function() {
// enable hatch fill by default and make chart monochrome
anychart.theme({
chart: {
defaultSeriesSettings: {
base: {
hatchFill: true,
fill: "White",
hoverFill: "White",
stroke: "Black"
}
}
}
});
// create a stage, it is needed to create a custom pattern fill
stage = anychart.graphics.create("container");
// create a column chart and set title
chart = anychart.column();
chart.title("AnyChart Custom Pattern");
// set the data
chart.data([
["Jan", 1000, 1200, 1500, 1000, 1200, 1500],
["Feb", 1200, 1500, 1600, 1200, 1500, 1600],
["Mar", 1800, 1600, 1700, 1800, 1600, 1700],
["Apr", 1100, 1300, 1600, 1100, 1300, 1600],
["May", 1900, 1900, 1500, 1900, 1900, 1500]
]);
// set custom hatch palette
// it can be populated with any number of patterns
chart.hatchFillPalette([
getPattern("A"),
getPattern("N"),
getPattern("Y"),
getPattern("C")
]);
// set container and draw chart
chart.container(stage).draw();
});
});
// function to create patterns
function getPattern(letter) {
var size = 40;
// create a text object
var text = anychart.graphics
.text()
.htmlText(
"<span " +
"style='font-family:Conv_interdex;font-size:" +
size +
";'>" +
letter +
"</span>"
);
// create a pattern object
var pattern = stage.pattern(text.getBounds());
// add text to a pattern
pattern.addChild(text);
return pattern;
}
I’ve included all the explanations in the comments, but just to sum up – you can create custom patterns, arrange them in custom pattern palettes, which you can then apply to an entire chart. If you’re paying attention, you’ll notice that we’ve made use of the AnyChart themes mechanism to set defaults.
Here’s the end result. Lovely, I’m sure you’ll agree…
See the Pen AnyChart Custom Pattern Sample by SitePoint (@SitePoint) on CodePen.
Custom Series
And the final sample in this article is for those who want even more flexibility and customization. While AnyChart strives to provide an ever-increasing number of chart types out of the box, data visualization is an enormous field, and each project has different requirements. In order to make (and keep) everyone as happy as possible and provide a way to create the visualizations of their choice, AnyChart open-sourced the JavaScript drawing library of GraphicsJS and also opened the source of the AnyChart JavaScript charting library itself.
But if you really, really want to go with 100% custom drawing, you’ll have to do a lot of work if you decide to fork the source code. For example, customizing might be a pain, and you could potentially have problems merging future versions if AnyChart doesn’t accept your pull request.
Luckily, there is a third option. With most of AnyChart’s basic chart types, you can override the rendering function and change the appearance of chart elements, while keeping all of the other things AnyChart provides.
Below you will find a code sample that shows how to transform a widely used range column chart (which is supported in the AnyChart charting library), into a less common cherry chart (which isn’t). The main thing to bare in mind when you override AnyChart’s rendering function, is that this function calculates everything from values supplied to a series, and your own (custom) series should be created out of a series with the same number of values.
anychart.onDocumentReady(function() {
// create a chart
var chart = anychart.cartesian();
chart.xAxis().title("Month");
chart.yAxis().title("Cherry price");
// create a data set
var data = [
{ x: "Apr", low: 29, high: 37 },
{ x: "May" },
{ x: "Jun", low: 29, high: 47 },
{ x: "Jul", low: 12, high: 27 },
{ x: "Aug", low: 20, high: 33, color: "#ff0000" },
{ x: "Sep", low: 35, high: 44 },
{ x: "Oct", low: 20, high: 31 },
{ x: "Nov", low: 44, high: 51 }
];
// create a range column series
var series = chart.rangeColumn(data);
// set a meta field to use as a cherry size
// series.meta("cherry", 50);
// set a meta field to use as a stem thickness
// series.meta("stem", 1);
// optional: configurable select fill
series.selectFill("white");
// call a custom function that changes series rendering
cherryChartRendering(series);
// set container id for the chart and initiate chart drawing
chart.container("container").draw();
});
// custom function to change range column series rendering to
// cherry chart with a special value line markers
function cherryChartRendering(series) {
// cherry fill color
series.fill(function() {
// check if color is set for the point and use it or series color
color = this.iterator.get("color") || this.sourceColor;
return anychart.color.lighten(color, 0.25);
});
// cherry stroke color
series.stroke(function() {
// check if color is set for the point and use it or series color
color = this.iterator.get("color") || this.sourceColor;
return anychart.color.darken(color, 0.1);
});
// set rendering settings
series.rendering()// set point function to drawing
.point(drawer);
}
// custom drawer function to draw a cherry chart
function drawer() {
// if value is missing - skip drawing
if (this.missing) return;
// get cherry size or set default
var cherry = this.series.meta("cherry") || this.categoryWidth / 15;
// get stem thickness or set default
var stem = this.series.meta("stem") || this.categoryWidth / 50;
// get shapes group
var shapes = this.shapes || this.getShapesGroup(this.pointState);
// calculate the left value of the x-axis
var leftX = this.x - stem / 2;
// calculate the right value of the x-axis
var rightX = leftX + stem / 2;
shapes["path"]
// resets all 'path' operations
.clear()
// draw bulb
.moveTo(leftX, this.low - cherry)
.lineTo(leftX, this.high)
.lineTo(rightX, this.high)
.lineTo(rightX, this.low - cherry)
.arcToByEndPoint(leftX, this.low - cherry, cherry, cherry, true, true)
// close by connecting the last point with the first
.close();
}
Here’s what we end up with:
See the Pen AnyChart Cherry Chart Custom Rendering Function by SitePoint (@SitePoint) on CodePen.
Conclusion
I hope you’ve found this look at AnyChart’s more advanced functionality useful and that this has given you plenty ideas and inspiration for your own data vizualizations.
If you’ve not tried AnyChart yet, I urge you to give it a go. Our latest release (version 7.14.0) added eight new chart types, five new technical indicators, Google Spreadsheet data loader, marquee select and zoom, text wrap and other cool new features.
And if you’re using AnyChart in your projects and have any comments or questions regarding the library, I’d love to hear these in the comments below.