leaflet and chroma.js .domain arguments not working - javascript

I am trying to incorporate chroma.js into my leaflet map so that i can toggle between quantiles, equal interval, and k-means, but the second and third argument for the domain function does not change anything
var colorScale = chroma.scale('YlGnBu').domain(voterList, 3, 'quantiles');
Here is the full code for the function
this.getRegionItemColor = function(item) {
var regionData = Mapbook.getRegionData();
var voterList = Mapbook.getColorScheme();
var colorScale = chroma.scale('YlGnBu').domain(voterList, 3, 'quantiles');
if (!_.isUndefined(item)) {
var voters = item.voters,
minVoters = regionData.min_voters,
maxVoters = regionData.max_voters;
var alpha = colorScale(voters);
return alpha;
}
else {
return 0;
}
}
Does anyone know why changing the number of buckets or classification method does not change anything?

Strange... I looked into it and I do think there is a problem with the library. Let's consider a very simple and documented example.
If you look at the documentation on github, here is what is written (https://github.com/gka/chroma.js/wiki/Color-Scales):
// Calling .domain() with no arguments will return the current domain.
chroma.scale(['white', 'red']).domain([0, 100], 4).domain() // [0, 25, 50, 75, 100]
When I do the same, however, this returns [0,100] (and not [0, 25, 50, 75, 100]); as you said, the second argument has not changed anything. You may want to flag that behavior as a bug on the plugin github page. Unless someone has a good explanation?

I was having the same problem, then I realized that at the time I defined 'ColorScale', my domain was not yet populated. are you certain that 'voterList' had your dataset in it at the time you defined ColorScale?

Related

What format polygon does D3plus largest rectangle require?

I found an interesting demo of how to find the largest rectangle in an irregular shaped polygon here using D3plus.
I'm trying to recreate this for a polygon I'm working on but currently the code is not working. It seems to runs endlessly. The code I'm using is as follows:
d3.csv("data/polyPoints.csv", function(error, polyPoints) {
if (error) return console.error(error);
// coerce string values to numbers
polyPoints.forEach(function(d) {
d3.keys(d).forEach(function(k) {
d[k] = +d[k]
})
});
// settings for geom.largestRect
var rectOptions = {
angle: 0,
maxAspectRatio: 5,
nTries: 1
};
console.log(rectOptions);
console.log(polyPoints);
var lRect = d3plus.geom.largestRect(polyPoints, rectOptions);
console.log(lRect);
});
I suspect my polygon is not in the correct format.
Update
I'm making progress. My original polygon object was taken from a csv and created an array of arrays of key value pairs (e.g. {"x": 0 "y": 1},{"x": 2, "y": 1}....)
I converted this to an array of arrays (e.g. [[1,0],[2,0]....])
Now the code is running but the output is defining rectangles that cross the boundary of the original polygon.
For anyone working with this. The largestRect docs are https://d3plus.org/docs/#largestRect and can be run with the following code.
const d3p = require('d3plus');
const polygon = [[x,y],[x,y],[x,y]...]
const rectOptions = {
maxAspectRatio: 5,
nTries: 20
};
let lRect = d3p.largestRect(rdp, rectOptions);
The algorithm used is an approximation and random points inside the polygon are chosen to do calculations from. Because of this the edges of the box won't always be touching the edge but should be "close enough".
The options.tolerance value might affect this as well but I haven't played around with it much. This is a pretty old question but hopefully it helps someone.

Changing the function in the text box is not changing the graph

I am attempting to create a fiddle which can allow me to change the graph through and input text showing below the graph. I am using jsxgraph library for that.
http://jsxgraph.uni-bayreuth.de/wiki/index.php/Change_Equation_of_a_Graph#JavaScript_Part
Above is the example which is working when you change the function in the text shown graph also changes.
Same example I am trying with the fiddle. But it is not working.
https://jsfiddle.net/me55dw4h/30/
initial code:
board = JXG.JSXGraph.initBoard('box', {boundingbox: [-6, 12, 8, -6], axis: true});
eval("function f(x){ return "+document.getElementById("eingabe").value+";}");
graph = board.create('functiongraph', [function(x){ return f(x); },-10, 10]);
How do I make it work?
This is a jsfiddle-specific problem. If the declaration of the function doIt is changed to
doIt = function (){
//redefine function f according to the current text field value
eval("function f(x){ return "+document.getElementById("eingabe").value+";}");
//change the Y attribute of the graph to the new function
graph.Y = function(x){ return f(x); };
//update the graph
graph.updateCurve();
//update the whole board
board.update();
};
instead of
function doIt() {
...
}
then the example runs.
But let me emphasize that meanwhile JSXGraph comes with it's own parser JessieCode (see https://github.com/jsxgraph/JessieCode), which allows the input of common math syntax instead of JavaScript syntax. That means, instead of Math.sin(x) the user may just input sin(x). Additionally, there is the power operator ^, i.e. instead of Math.pow(x,2) it is possible to type x^2.
A minimal example using JessieCode for function plotting looks like this, see https://jsfiddle.net/eLs83cs6/
board = JXG.JSXGraph.initBoard('box', {boundingbox: [-6, 12, 8, -6], axis: true});
doPlot = function() {
var txtraw = document.getElementById('input').value, // Read user input
f = board.jc.snippet(txtraw, true, 'x', true), // Parse input with JessieCode
curve;
board.removeObject('f'); // Remove element with name f
curve = board.create('functiongraph', [f, -10, 10], {name:'f'});
};
doPlot();
Ann additional side effect is that the parsing of the math syntax with JessieCode prevents XSS attacks which would be easily possible if the users are allowed to supply arbitrary JavaScript code as input.

Format of the Path input in the Javascript Clipper

I'm using a JS Library called Javascript Clipper for polygon operation. As stated from the manual, the coordinate format of an input path is like the follows,
var paths = [[{X:30,Y:30},{X:130,Y:30},{X:130,Y:130},{X:30,Y:130}],
[{X:60,Y:60},{X:60,Y:100},{X:100,Y:100},{X:100,Y:60}]];
My question is, how to convert a regular JS array, say
var x = [40, 100, 1, 5, 25, 10] and var y= [22, 32, 11, 45, 75, 19] to the required format shown above? The actual case is, these coordinate points will not be typed manually, but obtained from another function, the output of which is not in the format required by the Javascript Clipper Library.
Something like this:
function makePath(xVals, yVals) {
var pathArray = [];
xVals.forEach(function(xVal, index) {
var yVal = yVals[index];
var coordObj = {xVal, yVal};
pathArray.push(coordObj);
})
return pathArray;
}
You can pass it your arrays, x and y, as makePath(x,y) to get the combined array out.
My method assumes that the lengths of the arrays x and y are the same.

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!

How to change properties of element in JSXGraph?

Suppose, I have the following piece of code:
var brd2 = JXG.JSXGraph.initBoard('box2', {boundingbox: [-8.75, 2.5, 8.75, -2.5]});
var ax2 = brd2.create('axis', [[0,0],[1,0]]);
How can I change second point of axis?
Something like ax2.setSecondPoint([2,0])?
In general, how can I set property of any element?
Thank you.
Axis has two properties which names are self-explanatory: point1 and point2.
You can use setPosition method on any of them, e.g.
ax2.point2.setPosition(JXG.COORDS_BY_USER,[2,0])
Now there is one catch: you will not see this change on the chart unless you set needsRegularUpdate property of the axis object to true. Finally, to refresh the chart you should execute fullUpdate() method on the board variable. The whole looks like this:
var brd2 = JXG.JSXGraph.initBoard('box2', {boundingbox: [-8.75, 2.5, 8.75, -2.5]});
var ax2 = brd2.create('axis', [[0,0],[1,0]],{needsRegularUpdate:true});
ax2.point2.setPosition(JXG.COORDS_BY_USER,[2,0]);
brd2.fullUpdate();
References:
http://jsxgraph.uni-bayreuth.de/docs/symbols/JXG.Point.html#setPosition
http://jsxgraph.uni-bayreuth.de/wiki/index.php/Options (search for "special axis options")
Now to change properties like fixed, visible, etc. you should use setAttribute method (setProperty is deprecated). Example:
// Set property directly on creation of an element using the attributes object parameter
var board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-1, 5, 5, 1]};
var p = board.create('point', [2, 2], {visible: false});
// Now make this point visible and fixed:
p.setAttribute({
fixed: true,
visible: true
});
Source:
http://jsxgraph.uni-bayreuth.de/docs/symbols/JXG.GeometryElement.html#setAttribute
Last but not least a simple formula:
a + b = c
where:
a = using JavaScript debugging tools in browsers to investigate object properties
b = checking documentation for products you use
c= success :)

Categories