Data

While many of the articles touch data topic in some specific way, we've created this one to give a broader view of the data concepts in amCharts 4.

Structure of data

Array of data items

Absolutely all data in amCharts 4 takes the same shape - it's an array of objects.

Each object in the array represents a single data point.

Each key in the object (data point) holds a value which can be used for series, axes, or simply displayed in labels or tooltips.

Here's a basic data (taken from our XY Chart article):

[{
  "country": "Lithuania",
  "research": 501.9,
  "marketing": 250,
  "sales": 199
}, {
  "country": "Czech Republic",
  "research": 301.9,
  "marketing": 222,
  "sales": 251
}, {
  "country": "Ireland",
  "research": 201.1,
  "marketing": 170,
  "sales": 199
}, {
  "country": "Germany",
  "research": 165.8,
  "marketing": 122,
  "sales": 90
}, {
  "country": "Australia",
  "research": 139.9,
  "marketing": 99,
  "sales": 252
}, {
  "country": "Austria",
  "research": 128.3,
  "marketing": 85,
  "sales": 84
}, {
  "country": "UK",
  "research": 99,
  "marketing": 93,
  "sales": 142
}, {
  "country": "Belgium",
  "research": 60,
  "marketing": 50,
  "sales": 55
}, {
  "country": "The Netherlands",
  "research": 50,
  "marketing": 42,
  "sales": 25
}]

For example, a Category axis will build a category out of each data point, taking category labels out of "country" field.

A "Research" series, will draw values for its data points from "research" fields.

How do they know which fields to use? We'll explain shortly.

Order of data items

In most of the cases order of data items is not important. However, there are some chart setups where you should take care of how data items are ordered. Let's discuss those.

If you have a series, that is not connected by lines, you should be good to go. The chart will intelligently place the data item in the correct category/value/date on corresponding Axis, even if they come in no particular order.

Columns are shown in correct order

However, if you have a Series that connects data items in some way, like a LineSeries, the order of data items becomes important.

Even if the data item itself will be placed correctly, the line connecting them will follow the order in data: connecting first data item, with the second, then to third, etc.

Naturally, if they are in any other than consecutive order, the line will zig-zag back an forth like this:

Data items are in correct place, but the line seems buggy

There are two ways to solve this.

First, and most obvious one is to get your source data in order.

Second, is to pre-sort your data using a custom function, or an Adapter. The following will fix the issue:

chart.adapter.add("data", function(data) {
  data.sort(function(a, b) {
    return (new Date(a.date)) - (new Date(b.date));
  });
  return data;
});
chart.adapter.add("data", function(data) {
  data.sort(function(a, b) {
    return (new Date(a.date)) - (new Date(b.date));
  });
  return data;
});
{
  // ...
  "adapter": {
    "data": function(a, b) {
        return (new Date(a.date)) - (new Date(b.date));
      });
      return data;
    }
  }
}

That'll fix our chart:

See the Pen amCharts 4: date axis with out-of-order items by amCharts (@amcharts) on CodePen.24419

NOTE The actual code will depend per type and structure of your data. Update accordingly.

Binding data

As we already mentioned, there's a way to bind specific values in data to the elements that will use them, such as Category axis, or Column series.

Let's explore ways on how data can be accessed and used from different places.

Data fields

Some specific data users such as, say, Column series need specific data to be able to make sense.

For a Pie chart series, it might be numeric value and a title to name its slices.

For a series in an XY Chart, it needs to know at least two dimensional values, so it can plot data points on a two-dimensional plot.

Therefore each Series has a pre-defined list of "data fields", as defined in its dataFields property.

Look up each specific series in our class reference to find out the type of the data fields available for each specific series.

Here's how dataFields looks like for Pie series.

Pie series data fields

You can see that dataFields for Pie series is defined by IPieSeriesDataFields interface. Go ahead, click on it.

Pie series data fields in class reference

Now we know precisely which data fields are available for Pie series, and can set up dataFields:

pieSeries.dataFields.value = "research";
pieSeries.dataFields.category = "country";
pieSeries.dataFields.value = "research";
pieSeries.dataFields.category = "country";
{
  // ...
  "series": [{
    "type": "PieSeries",
    "dataFields": {
      "value": "research",
      "category": "country"
    }
  }]
}

There you go, we just told our Pie series to get its "category" (slice title) from "country" fields in data, and its values for slices from "research".

MORE INFO For more chart-specific Series configurations, data fields details, and examples, visit our other articles in "Chart types" section.

SUMMING UP To sum it up, data fields hold data that is needed by chart elements. Those fields hold data in specific format. They are pre-processed by the chart, aggregated, calculated, and otherwise given great care.

Property fields

We already know data fields, that hold chart data in specific format.

Now, let's look at their cousins - property fields.

Property fields are a way to tie chart element's properties to data.

Those fields are not pre-processed like data fields. They're just a way to bind a property to a field in data.

For example, we may bind a column fill color in a Column series to a color field in data, so we set individual colors for each column through data.

Here's how it would look code-wise:

series.columns.template.propertyFields.fill = "color";
series.columns.template.propertyFields.stroke = "color";
series.columns.template.propertyFields.fill = "color";
series.columns.template.propertyFields.stroke = "color";
{
  // ...
  "series": [{
    "type": "ColumnSeries",
    // ...
    "columns": {
      "propertyFields": {
        "fill": "color",
        "stroke": "color"
      }
    }
  }]
}

Here's a live example, that shows the use of both data and property fields:

See the Pen amCharts V4: Data (1) by amCharts (@amcharts) on CodePen.24419

SUMMING UP Property fields are used to bind raw values in data to various properties in the chart elements.

Just to drive point home, here's how we would use property fields to color sections of a Line series:

series.propertyFields.fill = "color";
series.propertyFields.stroke = "color";
series.propertyFields.fill = "color";
series.propertyFields.stroke = "color";
{
  // ...
  "series": [{
    "type": "LineSeries",
    // ...
    "propertyFields": {
      "fill": "color",
      "stroke": "color"
    }
  }]
}

NOTE Notice how we are setting propertyFields directly on series. Line series is a bit different from other types of series in that it will automatically create segments based on the need. Not necessarily for each data point, which is the case with Column series.

See the Pen amCharts 4: Line series with alternating fills by amCharts (@amcharts) on CodePen.24419

Config field

Both data fields and property fields we just learned about are good to binding a single value to a single property.

But what if you would like to bind a whole lot of values, including ones for sub-elements?

For that we have a configField setting.

It means basically this: "this field in data may hold a config object that needs to be applied for the particular element tied to the data point".

Config fields can be multi-level, meaning that we can set not just element's properties, but also those of its sub-elements.

Take a look here:

chart.data = [{
  "country": "Lithuania",
  "litres": 501.9,
  "config": {
    "isActive": true,
    "stroke": am4core.color("#3787ac"),
    "filters": [{
      "type": "DropShadowFilter"
    }]
  }
}, {
  "country": "Czech Republic",
  "litres": 301.9
}, {
  "country": "Ireland",
  "litres": 201.1
}, {
  "country": "Germany",
  "litres": 165.8
}, {
  "country": "Australia",
  "litres": 139.9
}, {
  "country": "Austria",
  "litres": 128.3
}];

// ...

pieSeries.slices.template.configField = "config";
chart.data = [{
  "country": "Lithuania",
  "litres": 501.9,
  "config": {
    "isActive": true,
    "stroke": am4core.color("#3787ac"),
    "filters": [{
      "type": "DropShadowFilter"
    }]
  }
}, {
  "country": "Czech Republic",
  "litres": 301.9
}, {
  "country": "Ireland",
  "litres": 201.1
}, {
  "country": "Germany",
  "litres": 165.8
}, {
  "country": "Australia",
  "litres": 139.9
}, {
  "country": "Austria",
  "litres": 128.3
}];

// ...

pieSeries.slices.template.configField = "config";
{
  // ...
  "data": [{
    "country": "Lithuania",
    "litres": 501.9,
    "config": {
      "isActive": true,
      "stroke": "#3787ac",
      "filters": [{
        "type": "DropShadowFilter"
      }]
    }
  }, {
    "country": "Czech Republic",
    "litres": 301.9
  }, {
    "country": "Ireland",
    "litres": 201.1
  }, {
    "country": "Germany",
    "litres": 165.8
  }, {
    "country": "Australia",
    "litres": 139.9
  }, {
    "country": "Austria",
    "litres": 128.3
  }],
  // ...
  "series": [{
    "type": "PieSeries",
    // ...
    "slices": {
      "configField": "config"
    }
  }]
}

The above will not only set stroke for the first slice in our Pie chart, but will also set its isActive to make it pre-pulled as well as add Drop Shadow filter.

Here's how this looks in a live demo:

See the Pen amCharts 4: Using configField by amCharts (@amcharts) on CodePen.24419

Text placeholders

Placeholders in on-screen text

Various labels and tooltips in amCharts 4 can also directly refer to data values, using text placeholders.

For example, a tooltipText property of the columns in Column series, can refer directly to any value in data either by its data field name or by how its called in data:

series.columns.template.tooltipText = "{category}:\n[bold]{value}[/b]";
series.columns.template.tooltipText = "{category}:\n[bold]{value}[/b]";
{
  // ...
  "series": [{
    "type": "ColumnSeries",
    // ...
    "columns": {
      // ...
      "tooltipText": "{category}:\n[bold]{value}[/b]"
    }
  }]
}

Go ahead, hover over any of the columns in the below chart and see how our code transformed into information in tooltip:

See the Pen amCharts V4: Data (2) by amCharts (@amcharts) on CodePen.24419

MORE INFO Please refer to our article "Formatting Strings" on more info and details on how these work.

Placeholders in URLs

Labels and tooltips are not the only place where you can use placeholders to bind to data. You can also use them in element's url property.

For example, if we a column series and want to run a Google search on the category of the clicked column, we could do something like this:

series.columns.template.url = "https://www.google.com/search?q={category.urlEncode()}";
series.columns.template.url = "https://www.google.com/search?q={category.urlEncode()}";
{
  // ...
  "series": [{
    // ...
    "columns": {
      "url": "https://www.google.com/search?q={category.urlEncode()}"
    }
  }]
}

IMPORTANT Notice the urlEncode() call next to the category reference? It's important, because it will make sure our strings are encoded properly to be included in the URLs.

Setting data

There are a number of ways to set data to a chart. Let's look at them.

Chart-wide data

Probably the most common way is to simply set chart's data property.

That's it. You don't need to do anything else. Just set your data as any other chart's property:

chart.data = [ ... ];
chart.data = [ ... ];
{
  // ...
  "data": [ ... ]
}

Series-specific data

Each Series on a chart can draw data from chart, or they can have own data.

To set data directly to some series, you set series' data property:

series.data = [ ... ];
series.data = [ ... ];
{
  // ...
  "series": [{
    "type": "ColumnSeries",
    "data": [ ... ]
  }]
}

This might come in handy of you have a lot of series, with seemingly different data, and do not want to plop it all together. Or, you have separate data sources for each series.

Here's a Radar chart example that has three series, all with their own data sets:

See the Pen amCharts V4: Radar chart (Scatter plot) by amCharts (@amcharts) on CodePen.24419

Dynamic updates

Replacing whole data set

To replace the whole data with a new set you simply assign it to chart's data property.

No further actions are necessary. The chart will automatically take in the new data and update everything.

Incremental updates

Sometimes replacing a the whole data set just because you added a new data point does not make a sense - it would be a tremendous waste of computer resources.

For that amCharts 4 implements incremental loading.

To add new data point, or several data points, to already existing data set, you use chart's addData(datapoint(s), remove) method.

As the first parameter, you pass in a data point (or an array of data points) to add to your existing data set.

Optional second parameter tells how many data points to remove from the begining of the data set.

This allows creating live-data charts, without going through the motion of updating whole data sets.

Here's a cool one:

See the Pen amCharts V4: Live data by amCharts (@amcharts) on CodePen.24419

Manipulating existing data points

You can also manipulate and change data in data array.

However, the chart itself won't detect such direct changes.

To take in the changes, you will need to call chart's method invalidateData() or invalidateRawData().

chart.data[1]["research"] = 123;
chart.invalidateData();
chart.data[1]["research"] = 123;
chart.invalidateData();

Now, let's explain the difference between the two, seemingly similar functions that update the data.

If we use invalidateData() the chart will re-evaluate all of the data. It will completely disregard current data set and treat the updated data as a new set of data. This will trigger chart redraw.

invalidateRawData() is more subtle. It will assume that data items remain the same, with only their numeric values changed. This will not trigger complete re-parsing of data and redraw, but the chart will rather transition to new values of existing data items. Depending on whether you have animations enabled, this transition will be either instantaneous or will smoothly animate to new values.

Using "dummy data"

Each and every element in amCharts 4 has a property dummyData.

Think of it as a storage container for any arbitrary data you want to associate with that object.

Technically, in JavaScript you would be able to create any properties on any object. That would not fly in TypeScript applications though, since TypeScript enforces type check. Hence a built-in property to store your data.

dummyData is not used by the charts. It can be used by any custom code you create, such as events, adapters, and even referenced to by text formatters.

Using in adapters

Whenever an adapter is applied to some value, its handler function receives reference to the object itself. This means that you will also be able to access dummyData for it as well, which might be used in the functionality of the function.

The following example shows how you can set arbitrary data to chart's series, which later on is used to modify series' name using name adapter:

let series = chart.series.push(new am4charts.ColumnSeries());
// ...
series.dummyData = {
  name: "First series"
};
series.adapter.add("name", function(name, target) {
  return target.dummyData.name;
});
var series = chart.series.push(new am4charts.ColumnSeries());
// ...
series.dummyData = {
  name: "First series"
};
series.adapter.add("name", function(name, target) {
  return target.dummyData.name;
});
{
  // ...
  "series": [{
    "type": "ColumnSeries",
    // ...
    "dummyData": {
      "name": "First series
    },
    "adapter": {
      "name": function(name, target) {
        return target.dummyData.name;
      }
    }
  }]
}

Here's an example in action:

See the Pen amCharts 4: dummyData (1) by amCharts (@amcharts) on CodePen.24419

Referring to dummy data in text

We can refer to dummy data in text as well.

For example, in a tooltipText template:

series.tooltipText = "{dummyData.name} -- {dummyData.note}";
series.tooltipText = "{dummyData.name} -- {dummyData.note}";
{
  // ...
  "series": [{
    "type": "ColumnSeries",
    // ...
    "tooltipText": "{dummyData.name} -- {dummyData.note}"
  }]
}

We can even use references within text formatting blocks, e.g. "Quick [bold brown]brown {dummyData.perp}[/] jumps over lazy [bold {dummyData.victim_color}]{dummyData.victim}[/].";

BTW, here's a working example with the above:

See the Pen amCharts 4: text formatting by amCharts (@amcharts) on CodePen.24419

Dummy data in data points

Finally, you may want to include your dummy data in your real data.

That's where "property fields" may come in handy. Remember we've learned about them earlier in this article.

chart.data = [{
  "category": "Research",
  "value": 450,
  "breakdown": {
    "personnel": 250,
    "equipment": 150,
    "other": 50
  }
}, {
  "category": "Marketing",
  "value": 1200,
  "breakdown": {
    "personnel": 600,
    "equipment": 400,
    "other": 200
  }
}, {
  "category": "Distribution",
  "value": 1850,
  "breakdown": {
    "personnel": 1200,
    "equipment": 600,
    "other": 50
  }
}];

// ...

let series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueY = "value";
series.dataFields.categoryX = "category";
series.columns.template.propertyFields.dummyData = "breakdown";
series.columns.template.tooltipText = "[bold]{category}[/]\nPersonnel: {dummyData.personnel}\nEquipment: {dummyData.equipment}\nOther: {dummyData.other}";
chart.data = [{
  "category": "Research",
  "value": 450,
  "breakdown": {
    "personnel": 250,
    "equipment": 150,
    "other": 50
  }
}, {
  "category": "Marketing",
  "value": 1200,
  "breakdown": {
    "personnel": 600,
    "equipment": 400,
    "other": 200
  }
}, {
  "category": "Distribution",
  "value": 1850,
  "breakdown": {
    "personnel": 1200,
    "equipment": 600,
    "other": 50
  }
}];

// ...

var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueY = "value";
series.dataFields.categoryX = "category";
series.columns.template.propertyFields.dummyData = "breakdown";
series.columns.template.tooltipText = "[bold]{category}[/]\nPersonnel: {dummyData.personnel}\nEquipment: {dummyData.equipment}\nOther: {dummyData.other}";
{
  // ...
  "data": [{
    "category": "Research",
    "value": 450,
    "breakdown": {
      "personnel": 250,
      "equipment": 150,
      "other": 50
    }
  }, {
    "category": "Marketing",
    "value": 1200,
    "breakdown": {
      "personnel": 600,
      "equipment": 400,
      "other": 200
    }
  }, {
    "category": "Distribution",
    "value": 1850,
    "breakdown": {
      "personnel": 1200,
      "equipment": 600,
      "other": 50
    }
  }],
  // ...
  "series": [{
    "type": "ColumnSeries",
    // ...
    "columns": {
      "propertyFields": {
        "dummyData": "breakdown"
      },
      "tooltipText": "[bold]{category}[/]\nPersonnel: {dummyData.personnel}\nEquipment: {dummyData.equipment}\nOther: {dummyData.other}"
    }
  }]
}

See the Pen amCharts 4: using dummyData (3) by amCharts (@amcharts) on CodePen.24419

Loading external data

A chart, besides numerous ways to set in-line data, has also built-in facilities to load data from external resources in CSV or JSON formats.

Please refer to "Loading external data" article for further details.

Related demos