update choropleth by string (not by fillKey prop) - javascript

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!

Related

Updating candlestick data point using restyle in Plotly.js

I am using a WebSocket connection to update a candlestick chart with live data.
Creating the initial candlestick chart is relatively easy:
var candleDiv = document.getElementById('candle-chart');
var data = {
x: x, //Each of these is a single dimension array of the same length
open: open,
close: close,
high: high,
low: low,
type: 'candlestick',
};
var layout = {
datarevision: candleCount,
dragmode: 'zoom',
showlegend: false,
xaxis: {
type: 'date',
range: [x[x.length - 26], x[x.length - 1]], //Only show the last 25 entries so it's not zoomed out too far.
rangeslider: {
visible: false
},
yaxis: {
autorange: true,
}
}
}
data.xaxis = 'x';
data.yaxis = 'y';
data = [data];
Plotly.plot(candleDiv, data, layout);
However, the documentation for the restyle method doesn't talk much to the update of data. More about how the data is displayed. After much tinkering, I found a reasonable workaround of updating the data variable directly:
candleDiv.data[0].open[candleDiv.data[0].open.length - 1] = updatedOpenValue;
candleDiv.data[0].close[candleDiv.data[0].close.length - 1] = updatedCloseValue;
candleDiv.data[0].high[candleDiv.data[0].high.length - 1] = updatedHighValue;
candleDiv.data[0].low[candleDiv.data[0].low.length - 1] = updatedLowValue;
Plotly.restyle(candleDiv, 'data[0]', candleDiv.data[0], [0]);
This works, except that it appears to draw the new candle on the old candle. This becomes particularly distracting when the stick changes from a green (increasing) stick to a red (decreasing) stick.
Is there a correct syntax to achieve what I am attempting to do such that I don't get display issues?
I checked out this link from this post but I couldn't get the method used to work in the context of a candlestick chart.
You may want to look at the Plotly.react method instead of Plotly.restyle: https://plot.ly/javascript/plotlyjs-function-reference/#plotlyreact

Pass parameter to c3js tooltop after .generate() and before .load()

I'm trying to graph out metrics that don't have any relation to one another, so instead of plotting out the actual values, I've calculated an alternate set of values that are scaled between 0-1 like a percentage.
For example: [1, 2, 5] => [0.2, 0.4, 1]
So now I have 2 sets of data - the original and scaled versions. I have the scaled version plotting on to my graph just fine, but I want the tooltip to show the original value to the user. See what I mean?
I checked out http://c3js.org/samples/tooltip_format.html, which shows you can set tooltip as a function when you initially generate the C3 object. But I want to change the tooltip later on after I recalculate my original/scaled values and re-load() the graph.
All attempts I've made to explicitly change myGraph.tooltip.format.value = function (...) {...} after initially setting myGraph = C3.generate({...}) have been unsuccessful.
Any ideas how I can accomplish this without having to regenerate the graph from scratch every time?
You need to override internal.getTooltipContent
var data = ['data1', 30000, 20000, 10000, 40000, 15000, 250000];
// simple fake data
var fakeData = data.map(function (d, i) {
return i ? (d / 100) : d;
})
var chart = c3.generate({
data: {
columns: [
fakeData,
['data2', 100, 200, 100, 40, 150, 250]
],
}
});
// do code to take over mars and plant potatoes
// save the original
var originalGetTooltipContent = chart.internal.getTooltipContent;
chart.internal.getTooltipContent = function (data, defaultTitleFormat, defaultValueFormat, color) {
// we modified the first series, so let's change that alone back
var originalValue = {
id: data[0].id,
index: data[0].index,
name: data[0].name,
// unfaked
value: data[0].value * 100,
x: data[0].x
};
var originalValues = data.map(function (d, i) {
return i ? d : originalValue;
})
return originalGetTooltipContent.call(this, originalValues, defaultTitleFormat, defaultValueFormat, color)
}
I assume you are already doing something about the scaled y axis label?
Fiddle - http://jsfiddle.net/puf248en/
Thanks potatopeelings,
I did turn out solving this one by simply loading the form data in all at once, and then programmatically show/hide certain metrics. So that allowed me to use all the generate() options as intended.
Did try out your solution, and it seemed to do the trick till I found the simpler option. Thanks!

Kendo ui Bar Chart width/maxWidth of Bars

I got an Kendo ui Bar Chart which is filled with an dynamic array.
One time its filled with 12 items and one time its filled with only 1 item.
Now the Bars automatically resizes, when only one item is in the array, the Bar is super big. I know, that there is no "max-width" or "width" property in the configuration.
Is there a workaround for my problem? I.E. dynamic calculation of the gap/space or whatever property? Or even with css or so?
Here is an simple fiddle
var dataset = [1,2,3,3,5,6,8];
var dataOnlyOne = [10]
//gap:0.2
// gap: function(){
return width/12*... // works not
}
Its been a while, and you probably moved on, but I was searching for something similar...
Your problem could be resolved using the below code, where the gap is calculated from the number of items in the data array:
$(function() {
var data = [1,2,3,3,5,6,8,2,3,3,5,6,8];
// var data = [10];
var gap = 8/data.length
$('#chart').kendoChart({
seriesDefaults: {
type: 'column',
stack: true,
},
series: [
{
name: 'dataset',
data: data, // dataOnlyOne
color: 'blue',
gap:gap
}
]
})
});

Adding data to a highchart chart using an array with IDs

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.

Openlayers - LayerRedraw() / Feature rotation / Linestring coords

TLDR: I have an Openlayers map with a layer called 'track' I want to remove track and add track back in. Or figure out how to plot a triangle based off one set of coords & a heading(see below).
I have an image 'imageFeature' on a layer that rotates on load to the direction being set. I want it to update this rotation that is set in 'styleMap' on a layer called 'tracking'.
I set the var 'stylemap' to apply the external image & rotation.
The 'imageFeature' is added to the layer at the coords specified.
'imageFeature' is removed.
'imageFeature' is added again in its new location. Rotation is not applied..
As the 'styleMap' applies to the layer I think that I have to remove the layer and add it again rather than just the 'imageFeature'
Layer:
var tracking = new OpenLayers.Layer.GML("Tracking", "coordinates.json", {
format: OpenLayers.Format.GeoJSON,
styleMap: styleMap
});
styleMap:
var styleMap = new OpenLayers.StyleMap({
fillOpacity: 1,
pointRadius: 10,
rotation: heading,
});
Now wrapped in a timed function the imageFeature:
map.layers[3].addFeatures(new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(longitude, latitude), {
rotation: heading,
type: parseInt(Math.random() * 3)
}
));
Type refers to a lookup of 1 of 3 images.:
styleMap.addUniqueValueRules("default", "type", lookup);
var lookup = {
0: {
externalGraphic: "Image1.png",
rotation: heading
},
1: {
externalGraphic: "Image2.png",
rotation: heading
},
2: {
externalGraphic: "Image3.png",
rotation: heading
}
}
I have tried the 'redraw()' function: but it returns "tracking is undefined" or "map.layers[2]" is undefined.
tracking.redraw(true);
map.layers[2].redraw(true);
Heading is a variable: from a JSON feed.
var heading = 13.542;
But so far can't get anything to work it will only rotate the image onload. The image will move in coordinates as it should though.
So what am I doing wrong with the redraw function or how can I get this image to rotate live?
Thanks in advance
-Ozaki
Add: I managed to get
map.layers[2].redraw(true);
to sucessfully redraw layer 2. But it still does not update the rotation. I am thinking because the stylemap is updating. But it runs through the style map every n sec, but no updates to rotation and the variable for heading is updating correctly if i put a watch on it in firebug.
If I were to draw a triangle with an array of points & linestring.
How would I go about facing the triangle towards the heading.
I have the Lon/lat of one point and the heading.
var points = new Array(
new OpenLayers.Geometry.Point(lon1, lat1),
new OpenLayers.Geometry.Point(lon2, lat2),
new OpenLayers.Geometry.Point(lon3, lat3)
);
var line = new OpenLayers.Geometry.LineString(points);
Looking for any way to solve this problem Image or Line anyone know how to do either added a 100rep bounty I am really stuck with this.
//From getJSON request//
var heading = data.RawHeading;
Adding and removing the imageFeature
Solved the problem as follows:
var styleMap = new OpenLayers.StyleMap({
fillOpacity: 1,
pointRadius: 10,
rotation: "${angle}",
});
var lookup = {
0: { externalGraphic: "Image1.png", rotation: "${angle}" },
1: { externalGraphic: "Image2.png", rotation: "${angle}" },
2: { externalGraphic: "Image3.png", rotation: "${angle}" }
}
styleMap.addUniqueValueRules("default", "type", lookup);
map.layers[3].addFeatures(new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(lon, lat), {"angle": dir, type: parseInt(Math.random() * 3)}
), {"angle": dir});
then the request:
var dir = (function () {
$.ajax({
'async': false,
'global': true,
'url': urldefault,
'dataType': "json",
'success': function (data) {
dir = data.Heading
}
});
return dir;
})();
Problem solved. Works perfectly.
You can also try to put heading on the object as an attribute:
{"mapFeatures": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": "1579001",
"x": 51.0,
"y": 1.2,
"geometry": {
"type": "Point",
"coordinates": [
51.0,
1.2
],
"crs": {
"type": "OGC",
"properties": {
"urn": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
}
},
"properties": {
"heading": 45,
"label": "some_label_goes_here"
}
}
]
}
}
Then you would have to rewrite your lookup function like this:
var lookup = {
0: {externalGraphic: "Image1.png", rotation: ${heading}},
1: {externalGraphic: "Image2.png", rotation: ${heading}},
2: {externalGraphic: "Image3.png", rotation: ${heading}}
}
Could you try that and see if it works? If you don' t know if the attributes are set correctly, you can always debug with firebug, that is what I always do. There is one tricky thing; when parsing geojson; "properties" are translated to "attributes" on the final javascript object.
First guess:
I assume your layer has a single point object that moves and rotates as when following a car with GPS?
It might be better if you would simply destroy all features on the layer (assuming it is only one feature) and redraw the feature with the new heading set.
Second guess:
Perhaps you need to use a function instead of a variable to maintain the live connection to the rotation.
Please check the documentation here: http://trac.openlayers.org/wiki/Styles on styles.
Hope this helps a bit.

Categories