So I have this code that I'm using for a class, but whenever I run it, nothing shows in the browser and instead under the Console I get an error that says that data.sort is not a function.
Here is the code in its entirety.
// Use d3 to read the JSON file.
// The data from the JSON file is arbitrarily named importedData as the argument.
d3.json("data/data.json").then((importedData) => {
// console.log(importedData);
var data = importedData;
// Sort the data array by using the greekSearchResults value.
data.sort(function(a, b) {
return parseFloat(b.greekSearchResults) - parseFloat(a.greekSearchResults);
});
// Slice the first 10 objects for plotting.
data = data.slice(0, 10);
// Reverse the array because of the Plotly defaults.
data = data.reverse();
// Trace1 for the Greek data.
var trace1 = {
x: data.map(row => row.greekSearchResults),
y: data.map(row => row.greekName),
text: data.map(row => row.greekName),
name: "Greek",
type: "bar",
orientation: "h"
};
// Data
var chartData = [trace1];
// Apply the group bar mode to the layout.
var layout = {
title: "Greek gods search results",
margin: {
l: 100,
r: 100,
t: 100,
b: 100
}
};
// Render the plot to the div tag with the id of "plot".
Plotly.newPlot("plot", chartData, layout);
});
sort is an array method. my guess is that the importedData variable isn't an array, hence you get that error. if you wish to use it, make sure to create an array from the data response.
sort - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
I know that I can set depth of all bars in Highcharts using depth property in column property of plotOptions likes the following code:
plotOptions: {
column : {
depth: 30
}
}
Or
# in R
hc_plotOptions(column = list(
depth = 30
)
The questions is how can I set different depth for each bar group in a bar chart (not one depth for all)? Solution can be in R (Highcharter) or in JS?
In core code the depth property is always taken from the series object options. Every group consists of the points with the same x values.
These 2 solutions came to my mind:
1. Modify the core code so that depth values are taken from points' configuration instead:
(function(H) {
(...)
H.seriesTypes.column.prototype.translate3dShapes = function() {
(...)
point.shapeType = 'cuboid';
shapeArgs.z = z;
shapeArgs.depth = point.options.depth; // changed from: shapeArgs.depth = depth;
shapeArgs.insidePlotArea = true;
(...)
};
})(Highcharts);
Series options:
series: [{
data: [{y: 5, depth: 50}, {y: 2, depth: 100}]
}, {
data: [{y: 13, depth: 50}, {y: 1, depth: 100}]
}]
Live demo: http://jsfiddle.net/kkulig/3pkon2Lp/
Docs page about overwriting core functions: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts
2. Create a separate series for every point.
depth property can be applied to a series so the modification of the core wouldn't be necessary. Every series is shown in legend by default so series will have to be properly connected using linkedTo property (so that the user doesn't see as many series as points).
Points can be modified before passing them to the chart constructor or dynamically handled in chart.events.load.
Live demo: http://jsfiddle.net/kkulig/37sot3am/
load: function() {
var chart = this,
newSeries = [],
merge = Highcharts.merge,
depths = [10, 100]; // depth values for subsequent x values
for (var i = chart.series.length - 1; i >= 0; i--) {
var s = chart.series[i];
s.data.forEach(function(p, i) {
// merge point options
var pointOptions = [merge(p.options, {
// x value doesn't have to appear in options so it needs to be added manually
x: p.x
})];
// merge series options
var options = merge(s.options, {
data: pointOptions,
depth: depths[i]
});
// mimic original series structure in the legend
if (i) {
options.linkedTo = ":previous"
}
newSeries.push(options);
});
s.remove(true);
}
newSeries.forEach((s) => chart.addSeries(s));
}
API reference:
https://api.highcharts.com/highcharts/plotOptions.series.linkedTo
I'm trying to find the X values of the first and second elements in a node array, such as this one:
nodes = [{
x: xvalue,
y: getY(xvalue)
}, {
x: xvalue2,
y: getY(xvalue2)
}];
I thought it would be something like:
nodes[0].x;
or:
d3.select(".nodes").something
but I'm not really sure and I can't find anything about it online.
I read the guide->updating after initial drawing part at https://github.com/markmarkoh/datamaps but updating doesn't work using string values (it works fine using fillKey property instead). I read this closed issue too: markmarkoh/datamaps#118 but nothing.
This is my code:
v
ar map = new Datamap({
element: document.getElementById('world'),
geographyConfig: {
dataUrl: 'world-topo-min.json',
borderColor: 'black'
},
scope: 'countries',
fills: {
defaultFill: 'rgb(255,255,255)',
someKey: '#08306b'
},
data: {
'108': {fillKey: 'someKey'}
},
setProjection: function(element) {
var projection = d3.geo.mercator()
.center([30, 34.4444])
.scale(170)
.translate([element.offsetWidth / 2 , element.offsetHeight/2]);
var path = d3.geo.path().projection(projection);
return {path: path, projection: projection};
}
});map.updateChoropleth({'57': {fillKey:'someKey'},'116': '#08306b'});
Country identificated by id=57 is ok, country 116 doesn't change
I pull data from a PHP-array like this:
myarray=[[57,32],[116,12]]
Country 57 has value 32, country 116 has value 12 and so on.
I ignore myarray right now because I want to solve updatechoropleth issue first
Obviously, I'm going to create a linear scale to put right colors into countries path but this is another thing.
Help me please
Thank you guys!
I want to add a series to a highchart scatterplot where I am naming each point in the series. I create a chart in the following way:
var chart; // globally available
makeCharts = function(){
chart = new Highcharts.Chart({
chart: {
renderTo: 'container1',
type: 'scatter'
},
series: [{
name: 'a',
data: [{
'id': 'point1',
'x': 1,
'y': 2
}, {
'id': 'point2',
'x': 2,
'y': 5
}]
}]
});
}
I would like to be able to update the points on the chart using something like:
chart.series[0].setData([{id:['point3', 'point4', 'point5'], y:[0,1,2], x:[1,2,3]}])
but this is not correct. Is it possible to update a chart using this approach where each point has an ID?
EDIT:
Just to clarify, I would like to be able to pass the arrays directly, rather than adding the data point by point using addPoint(). I could loop through an array and use addPoint() doing something like this:
id:['point3', 'point4', 'point5'];
y:[0,1,2];
x:[1,2,3];
for (i=0; i<x.length; i++)
{
chart.series[0].addPoint({
x: x[[i],
y: y[i],
id: id[i]
});
}
However, this is very slow. It's much quicker to add data using the following approach:
chart.series[0].setData([[1,0],[2,1],[3,2]]);
I have found that I can add data like this:
chart.series[0].setData([[1,0, 'point3'],[2,1, 'point4'],[3,2, 'point5']]);
but then the only way that I can access the id when the point is selected, is through this.point.config[2]. With the following approach I am unable to use chart.get('pointID') to identify a point as I did not set the ID. I want to be able to identify the point using just the ID.
Well broadly speaking there are two ways in which you can modify the chart data dynamically
Series.setData() Use this approach when you want to completely replace the existing data with some new data
Series.addPoint() Use this approach when you want to add a subset of the points dynamically. This method is not just for adding one point at a time, if you read the documentation carefully again you will find that this method takes a boolean redraw argument, and the argument detail is as following
redraw: Boolean
Defaults to true. Whether to redraw the chart after
the point is added. When adding more than one point, it is highly
recommended that the redraw option beset to false, and instead
chart.redraw() is explicitly called after the adding of points is
finished.
In your case, since you want to add a few points dynamically, but retaining the existing points, you should go with approach 2. But you need to use it inside a loop, with the redraw being set to false (hence solving the problem of being slow) and then after the loop, call the redraw method explicitly
Code
var id = ['point3', 'point4', 'point5'],
y = [0, 1, 2],
x = [1, 2, 3];
for (var i = 0; i < x.length; i++) {
chart.series[0].addPoint({
x: x[i],
y: y[i],
id: id[i]
},false);
}
chart.redraw();
Adding multiple points dynamically | Highcharts and Highstock # jsFiddle
Try using series.addPoint.
chart.series[0].addPoint({
x: 0,
y: 0,
id: 'anything'
});
But if you need to set data for series, use
chart.series[0].setData([{
x: 0,
y: 0,
id: 'anything'
},{
x: 2,
y: 2,
id: 'another'
}]);
As soon as you can pass your data like this:
chart.series[0].setData([[1,0, 'point3'],[2,1, 'point4'],[3,2, 'point5']]);
(as you stated in question), I can suggest you to use a little hack.
We'll need to add another statement to method applyOptions of Highcharts.Point prototype.
if (typeof options[0] === 'number' && options[2] && typeof options[2] === 'string') this.id = options[2];
Here you can see it in action.