How To Use Highmaps Data In JSON Not Labeled 'value' - javascript

I have a data set that contains many fields. I have no control over the creation of this JSON. Sample:
data = [
{
'maparea':'3704000063',
'relatedsource':null,
'empcount':'198390',
'response':'78',
'mean':'61663.00',
},
...
]
The chart code is:
Highcharts.mapChart('container', {
chart: {
map: geojson
},
title: {
text: 'GeoJSON in Highmaps'
},
mapNavigation: {
enabled: true,
buttonOptions: {
verticalAlign: 'bottom'
}
},
colorAxis: {
tickPixelInterval: 100
},
series: [{
data: data,
keys: ['maparea', 'relatedsource', 'empcount', 'response', 'mean'],
joinBy: ['fips', 'maparea'],
name: 'Random data',
states: {
hover: {
color: '#a4edba'
}
},
dataLabels: {
enabled: true,
format: '{point.properties.postal}'
}
}]
});
The geoJSON uses fips to label the areas (in this case counties in NC). The map shows the state and county elements. However, no data is used to plot. This is because the HighMaps code is expecting a value element to be present in the data I think.
Is there a way to tell HighMaps what element in the data set to use to shade the choropleth?

I don't see any option to map your unique data shape to the expected keys in the data according to the docs. Per your comment this is possible with an array, but it doesn't seem to be possible with an object.
However, it's pretty simple to just remap your object to the required shape. The code below gives a partial example.
let dataMapped = data.map(obj => {
var median = Number(obj.median);
return Object.assign(obj, { name: obj.maparea, value: median });
});
And then use dataMapped as the value for your data.
There might be a more elegant way to do this in ES6 with object spread and avoid the Object.assign I am using to merge the old object with new attributes, but I don't have time to research that at the moment.

Related

How to create a threshold in Observable Plot in JavaScript / TypeScript

I am trying to create a grouped bar chart using Observable's Plot.plot in JavaScript (code is in TypeScript).
The problem is that the x-axis is showing each specific date, however I want the dates to show dynamic months or weeks, not specific dates.
This is the code:
const chart = Plot.plot({
x: { axis: null, domain: ["Add", "Remove"], },
y: { tickFormat: "s", label: "↑ Access Requests", grid: true },
color: {
legend: true,
type: "categorical",
domain: ["Add", "Remove"],
range: redGreenColorRange,
},
style: {
background: "transparent",
},
width: 1350,
caption: "in 2 week increments",
facet: {
data: groupedAddRemove,
label: "Created Date",
x: "createdDate",
// thresholds: d3.utcWeeks,
// ^ this doesn't work, but a similar structure has worked in other projects I've seen
},
marks: [
Plot.barY(groupedAddRemove, {
x: "type",
y: "count",
fill: "type",
}),
Plot.ruleY([0]),
],
});
and this is what it looks like:
I want the x-axis marks to show a dynamic version of Months, like:
My data structure either could show the "Date" as a string, or a TypeScript typeof Date object
data structure with date with a type of string
data structure with date with a type of Date
This is the data structure type:
The 'groupedAddRemove' is an array of this type
( AddRemoveBarChartType[] )
type AddRemoveBarChartType = {
createdDate: Date;
count: number;
type: "Add" | "Remove";
};
the "Type" can either be "Add" or "Remove". I had a boolean for this value previously, but the "Add" and "Remove" fit better to automatically have the legend say "Add" and "Remove". It could be changed back to a boolean if there is a better way to display it that way.
The data could be changed in other ways too, if that will simplify things. I am also open to using a D3.js implementation instead of Plot.plot.
I'm very new to Observable Plot.plot so any help is appreciated, thank you!

HighStock: chart gets broken when navigator touches right border

I'm developing an web application that handles and shows large amounts of live data from some devices. To visualise the data I decided to use HighStock. It seems to work well on most of the data:
However, when the bottom navigator touches right border, the picture becomes quite different:
The timeline is almost the same, but the number of points is different, also vertical scale is different... What is this happening? How to fix it?
My code looks this way:
const ch1 = Highcharts.stockChart('chart1', {
rangeSelector: {
selected: 1,
inputEnabled: false,
buttonTheme: {visibility: 'hidden'},
labelStyle: {visibility: 'hidden'},
},
title: {
text: 'Metrics',
},
series: [{
name: 'Sensor 1', data: [],
}, {
name: 'Sensor 2', data: [],
}, {
name: 'Sensor 3', data: [],
}]
});
// a,b,c gets values from the server
// They are arrays of pairs of timestamp & value
ch1.series[0].setData(a);
ch1.series[1].setData(b);
ch1.series[2].setData(c);
// tm_min & tm_max are dynamically calculated using the data
ch1.xAxis[0].setExtremes(tm_min, tm_max);
Update: Here is an example with 2% of my data – try to do the same as shown above.
I found the solution. The issue is caused by your data and xAxis.ordinal that is enabled by default in Highstock. Your data has many empty points on the right side of the chart and because of ordinal, the empty space was not rendered, yet dataGrouping grouped data differently.
Check this here https://jsfiddle.net/BlackLabel/x1tgqbw6/ (disabled ordinal):
xAxis: {
ordinal: true
}
So, the solution is to disable xAxis.ordinal or generate your data without null points:
https://jsfiddle.net/BlackLabel/ex054oy8/
API reference:
https://api.highcharts.com/highstock/xAxis.ordinal

Chart.js chart in vue.js component does not update

I´m developing a visualization module for some crypto portfolios with vue.js and chart.js but am currently stuck with this:
Empty chart is displayed but non of the values are rendered.
Since the values are dynamically loaded after the chart is initialized I believe that the chart is not updating itself properly (even though I call .update()), but no errors are displayed whatsoever.
I wrapped the chart.js rendering in a vue component:
Vue.component('portfolioValues', {
template: '<canvas width="400" height="200"></canvas>',
data: function() {
return {
portfolio_value: [],
portfolio_labels: [],
chart: null,
}
},
methods: {
load_portfolio_value_local: function() {
values = [];
labels = []
local_data.forEach(element => {
values.push(element.total_usd);
labels.push(moment(element.timestamp, 'X'));
});
this.portfolio_value = values;
this.portfolio_labels = labels;
this.chart.update();
},
render_chart: function() {
this.chart = new Chart(this.$el, {
type: 'line',
data: {
labels: this.portfolio_labels,
datasets: [{
label: "Portfolio Value",
data: this.portfolio_value,
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
distribution: 'linear',
}]
}
}
});
}
},
mounted: function() {
this.render_chart();
this.load_portfolio_value_local();
}
});
For demonstration purposes I just added some data locally, looks like this:
local_data = [{
"timestamp": 1515102737,
"total_btc": 0.102627448096786,
"total_usd": 1539.41274772627
}, {
"timestamp": 1515102871,
"total_btc": 0.102636926127186,
"total_usd": 1538.52649627725
}, {
"timestamp": 1515103588,
"total_btc": 0.102627448096786,
"total_usd": 1532.33042753311
}
]
Here is the full demo code: https://codepen.io/perelin/pen/mppbxV
Any ideas why no data gets rendered? thx!
The problem you have here is how vuejs handles its data.
If you use it like that:
local_data.forEach(element => {
this.portfolio_value.push(element.total_usd);
this.portfolio_labels.push(moment(element.timestamp, 'X'));
});
this.chart.update();
The chart will update. But by re-initializing the arrays you work against vuejs.
TL;DR
If you want to re-initialize an object, you could assign the array to the object:
Object.assign(this.portfolio_value, values);
Object.assign(this.portfolio_labels, labels);
That way, the linking stays working.

How to construct HighCharts data series to match returned Json via ajax call

I'm trying to construct an Highchart with a JSON returned from my .NET controller. The data is formatted in the following way (in the controller):
var data = new
{
sentiment = new[]
{
new { value = "Positive", data = positiveScore.ToString() },
new { value = "Negative", data = negativeScore.ToString() },
new { value = "Neutral", data = neutralScore.ToString() }
}
};
return Json(data, JsonRequestBehavior.AllowGet);
The data I'm receiving is the following:
My Highchart is constructed in the following way:
function sentimentAnalysisData(data)
//$(document).ready(function ()
{
var chart = new Highcharts.Chart({
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie',
renderTo: 'highchart'
},
title: {
text: 'Sentiment Analysis'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %',
style: {
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
}
}
}
},
series: [{data}]
//});
})
};
The data parameter passed to my function is actually the data you can see in the image I provided. I had a GET request via an ajax call, where I retrieved the data, then, in the "on success" callback I'm calling this function which will construct the chart.
My problem is the following: the Highchart is generated, I can see it on my front end, but since my data is passed in a wrong way to the series field, the chart body is actually empty, with no data to show. I've tried to generate it on the way, I also tried to loop through the object, parse it in two arrays and use those arrays (one for the description string and one for value) but I'm missing something. Any helpful thoughts?
I was able to solve my problem in the following way:
I changed the way I constructed my JSON in order to match the pie chart structure in which I had a name and a value part (the name part must be noted as "name", and the value as "y")
var data = new[]
{
new { name = "Positive", y = positiveScore },
new { name = "Negative", y = negativeScore },
new { name = "Neutral" , y = neutralScore }
};
return Json(data, JsonRequestBehavior.AllowGet);
In this way I got the exact structure I was looking for in the first place. Also, I eliminated the .toString() from the y, since Highchart expects a numeric value, not a string. If you omit this part, you'll get the following error:
String value sent to series.data, expected Number his happens if you
pass in a string as a data point

Setting additional point attributes in HighStock time series with large data sets

I know you can pass arbitrary data into your time series points, such as:
new Highcharts.Chart( {
...,
series: [{
name: 'Foo',
data: [ { y : 10.0, customData : 'value 1' },
{ y : 20.0, customData : 'value 2' },
{ y : 30.0, customData : 'value 3' } ]
}]
} );
However, I noticed that this doesn't quite work in HighStock when your time series is comprised of a large data set (1000+ points).
For example, here is a working fiddle http://jsfiddle.net/gparajon/c5fej775/ (less than 1000 points, which also happens to be the default turboThreshold). And here's the same fiddle, with more data, which breaks the tooltip formatter: http://jsfiddle.net/gparajon/5om258az/
Any workaround?
Thanks!
The error in the console is a bug and it is not really connect why you cannot access extra info in the formatter.
The difference between a chart and a stockchart is that a stockchart does data grouping, what means that in the formatter callback you receive grouped points which does not include extra data (how should they be grouped?).
example: https://jsfiddle.net/g04La2qh/1/
If you disable data grouping, you will receive non-grouped points with extra data.
dataGrouping: {
enabled: false
},
example: https://jsfiddle.net/g04La2qh/2/

Categories