Issue with c3.js tooltip when rendering negative float values of x - c3

I am using c3.js for creating a chart and this is an issue I found out. If you have a data point with negative float x value, the tooltip rounds off this value to the nearest integer.
You can try doing this just by changing the data in this example. Just change one of the x values to a negative float value and then hover over that point and notice the value of x reported by the tooltip.
Is there any solution to this, or has anyone faced a similar problem?

In c3.js look for the following function:
Axis.prototype.getXAxisTickFormat = function getXAxisTickFormat() {
Inside this function there is a format variable that is causing the negative x-axis values to be rounded.
format = $$.isTimeSeries() ? $$.defaultAxisTimeFormat : $$.isCategorized() ? $$.categoryName : function (v) { return v < 0 ? v.toFixed(0) : v; }
The line of code above has a ternary operator that checks if the x-axis values are a 'time series' or 'categorized'. In our situation the values are neither so the format variable is set to be the following function:
function (v) { return v < 0 ? v.toFixed(0) : v; }
This function will leave any integer greater than 0 as is but it will round any negative integers to 0 decimal places and convert the integer to a string using .toFixed(0).
Replace the format line with the one I have written below and it will remove the rounding from the negative values:
format = $$.isTimeSeries() ? $$.defaultAxisTimeFormat : $$.isCategorized() ? $$.categoryName : function (v) { return v; };
I have only tested this today and although I haven't found any issues, there may be a reason why the negative numbers were converted to a string value and if so you may want leave the format line as is and just replace the 0 in .toFixed(0) with the # of decimals you desire.
[UPDATE] If you don't want to edit the c3.js source code you can also use the format options for tooltips and x/y ticks. See: http://c3js.org/samples/tooltip_format.html
This is a function I use for the y-axis values. It rounds the tick values to 3 decimal places but strips trailing zeros.
axis : {
y:{
tick: {
format: function (d) {
var df = Number( d3.format('.3f')(d) );
return df;
}
}
}
}

Related

Egui display an editable 3x3 matrix?

I am trying to show the 9 cells of a 3x3 matrix using egui. I want a 3x3 grid that matches the entries in the matrix. So far I have this:
Where the two numbers are the (0,0) and (0, 1) entries in the matrix, but I want them side by side.
I got them with this snippet:
let (_pos, mut mat) = dual_to_components(&mesh.verts.get_mut()[0].data);
if ui.add(ne_gui::DragValue::new(&mut mat[(0,0)]).speed(0.01)).changed()
{
update_covariance(&mut mesh.verts.get_mut()[0].data.position, &mat);
}
if ui.add(ne_gui::DragValue::new(&mut mat[(0,1)]).speed(0.01)).changed()
{
mat[(1,0)] = mat[(0,1)];
update_covariance(&mut mesh.verts.get_mut()[0].data.position, &mat);
}
});
How can I get a properly formatted 3x3?
Using egui::Ui::horizontal looks like a reasonable option here?
for row in 0..3 {
ui.horizontal(|ui| {
for col in 0..3 {
ui.add(egui::DragValue::new(&mut mat[3 * row + col]).speed(0.01));
}
});
}
This code snippet gives something like this:

D3 bar chart yaxis scaling issue, I don't want decimal/duplicate values

I have implemented D3 chart using NVD3 library below is the link for the reference.
Is there a way that I can stop this automatic scaling or get rid of this decimal values.
http://nvd3.org/livecode/index.html#codemirrorNav
Finally I got solution for this issue, problem happens when we have small set of data in which sometimes we get decimal values and when we format for integer values it duplicates the data on Y-axis.
Have a look to this plunker:
http://plnkr.co/edit/yFyShQ?p=preview
To make it dynamic you can pass min and max value to
d3.range(minValue, maxValue)
Like this
const minValue = d3.min(data, d => d.Value);
const maxValue = d3.max(data, d => d.Value);
const tickValues = d3.range(minValue > 0 ? 0 : minValue,maxValue);
return maxValue < 10 ? tickValues: null;

Bar Chart Columns Grouped Too Tightly

I have a bar chart (stacked by not yet complete) and the columns are all grouping into the left of the chart.
What is causing this?
Plnkr: https://plnkr.co/edit/DMRJfbD4ZF3xCiPdFedy?p=preview
data.forEach(function(d) {
var y0_positive = 0;
var y0_negative = 0;
d.components = keys.map(function(key) {
if (d[key] >= 0) {
// if we have a positive value, add to the postive
return {key: key, y1: y0_positive, y0: y0_positive += d[key] };
} else if (d[key] < 0) {
// if value is negative, add to the negative value
return {key: key, y0: y0_negative, y1: y0_negative += d[key] };
}
})
})
Kev
There is absolutely nothing wrong with your chart. It's correct, and the data is being accurately shown.
I know it seems the opposite, but this is the reason: you are using a time scale, and a time scale is not an ordinal scale.
Let's see your dates. The first data point is:
"date":"2016-11-03 00:00:00"
Corresponding to 3rd of November. But all the other data points are from 2016-10-06, the 6th of October.
So, the time scale will show all the dates between these two extremes (from 6th of October to 3rd of November) evenly spaced, and all your bars will be squeezed to the left, at the 6th of October (except for a little bar at the right, corresponding to the 3rd of November), because this is the correct and expected outcome when you use a time scale!
Now, see what happens if we simply delete the first object (the 3rd of November) in your data: https://plnkr.co/edit/rhmh2zxEnwO4SLTLvfNu?p=preview
If you don't want to show the time span in the correct proportion, use a ordinal scale instead, like scaleOrdinal or scaleBand.

Using d3.js is there a way to zero align two Y Axes with positive and negative values

I am new to d3, learning a lot. I have an issue I cannot find an example for:
I have two y axes with positive and negative values with vastly different domains, one being large dollar amounts the other being percentages.
The resulting graph from cobbling together examples looks really awesome with one slight detail, the zero line for each y axis is in a slightly different position. Does anyone know of a way in d3 to get the zero line to be at the same x position?
I would like these two yScales/axes to share the same zero line
// define yScale
var yScale = d3.scale.linear()
.range([height, 0])
.domain(d3.extent(dataset, function(d) { return d.value_di1; }))
;
// define y2 scale
var yScale2 = d3.scale.linear()
.range([height, 0])
.domain(d3.extent(dataset, function(d) { return d.calc_di1_di2_percent; }))
;
Here is a link to a jsfiddle with sample data:
http://jsfiddle.net/jglover/XvBs3/1/
(the x-axis ticks look horrible in the jsfiddle example)
In general, there's unfortunately no way to do this neatly. D3 doesn't really have a concept of several things lining up and therefore no means of accomplishing it.
In your particular case however, you can fix it quite easily by tweaking the domain of the second y axis:
.domain([d3.min(dataset, function(d) { return d.calc_di1_di2_percent; }), 0.7])
Complete example here.
To make the 0 level the same position, a strategy is to equalize the length/proportion of the y axes.
Here are the concepts to the solution below:
The alignment of baseline depends on the length of the y axes.
To let all value shown in the bar, we need to extend the shorter side of the dimension, which compares to the other, to make the proportion of the two axes equal.
example:
// dummy data
const y1List = [-1000, 120, -130, 1400],
y2List = [-0.1, 0.2, 0.3, -0.4];
// get proportion of the two y axes
const totalY1Length = Math.abs(d3.min(y1List)) + Math.abs(d3.max(y1List)),
totalY2Length = Math.abs(d3.min(y2List)) + Math.abs(d3.max(y2List)),
maxY1ToY2 = totalY2Length * d3.max(y1List) / totalY1Length,
minY1ToY2 = totalY2Length * d3.min(y1List) / totalY1Length,
maxY2ToY1 = totalY1Length * d3.max(y2List) / totalY2Length,
minY2ToY1 = totalY1Length * d3.min(y2List) / totalY2Length;
// extend the shorter side of the upper dimension with corresponding value
let maxY1Domain = d3.max(y1List),
maxY2Domain = d3.max(y2List);
if (maxY1ToY2 > d3.max(y2List)) {
maxY2Domain = d3.max(y2List) + maxY1ToY2 - d3.max(y2List);
} else {
maxY1Domain = d3.max(y1List) + maxY2ToY1 - d3.max(y1List);
}
// extend the shorter side of the lower dimension with corresponding value
let minY1Domain = d3.min(y1List),
minY2Domain = d3.min(y2List);
if (minY1ToY2 < d3.min(y2List)) {
minY2Domain = d3.min(y2List) + minY1ToY2 - d3.min(y2List);
} else {
minY1Domain = d3.min(y1List) + minY2ToY1 - d3.min(y1List);
}
// finally, we get the domains for our two y axes
const y1Domain = [minY1Domain, maxY1Domain],
y2Domain = [minY2Domain, maxY2Domain];

What are the indicator functions and constraints for complex grid drawing problems?

If you're looking at an array of pixels, in either 0,1,2,3, or even N dimensions, it's easy to tell if a certain pixel falls on a square or rectangular grid line within it by using an indicator function like so (I'll use imperative pseudocode to make what I'm talking about clear but I'm really only interested in the constraints and the conditionals in the indicator functions for the more general types of grids):
/* define the array of pixels in however many dimensions you want */
//define the dimensions of the array
int x-dimension-length = <some positive integer>;
int y-dimension-length = <some positive integer>;
int z-dimension-length = <some positive integer>;
[...] //you could keep gong for even higher dimensions
/* define CONSTRAINTS (for the square or rectangular case) */
//define the height and width of the grid boxes within the grid (contstraints on a square/rectangular grid)
int horizontalSpacingBetweenGridlines = <non-negative integer>;
int verticalSpacingBetweenGridlines = <non-negative integer>;
/* end definition of CONSTRAINTS */
/* define the arrays to draw the grids on */
// -- assumes that the arrays here are intialised to contain all zeros:
//0-dimensional (degenerate) example:
int point = 0;
//1d example:
int [] OneDimensionalArray = int[x-dimension-length];
//(2d example)
int [] TwoDimensionalArray = int[x-dimension-length][y-dimension-length];
//(3d example)
int [] ThreeDimensionalArray = int[x-dimension-length][y-dimension-length][z-dimension-length];
/* Indicator functions */
/* zero-dimensional (degenerate) case */
//if a point falls on a gridline, degenerate example
boolean doesAPointFallOnAGridLine0D() {
if (point % horizontalSpacingBetweenGridlines == 0) {
return true;
}
/* one-dimensional case */
//decide if a point in the 1D array at index <x-coordinateFrom1DArray> falls on a gridline
boolean doesAPointFallOnAGridLine1D(int x-coordinateFrom1DArray) {
if (x-coordinate % horizontalSpacingBetweenGridlines == 0) {
return true;
}
}
/* two-dimensional case */
//decide if a point in the 2D array at index <x-coordinateFrom2DArray>,<y-coordinateFrom2DArray> falls on a gridline
boolean doesAPointFallOnAGridLine2D(int x-coordinateFrom2DArray, int y-coordinateFrom2DArray) {
if((x-coordinateFrom2DArray % horizontalSpacingBetweenGridlines == 0) && (y-coordinateFrom2DArray % verticalSpacingBetweenGridlines == 0)) {
return true;
}
}
/* [and so on for higher-and-higher-dimensional spaces...] */
My question is, in general what do the indicator function and constraints look like for the different types of non-square and non-rectangular-grids (e.g., triangular, hexagonal, octagonal, whatever), and is there a canonical reference work that talks about constructing that sort of indicator function and the constraints it requires for the different shapes of grid?
Knuth seems out on this one.
This is a very general mathematical problem so it probably has a name/canonical solution.
As an aside, I'm most interested in hexagonal grids in n-dimensions, but I don't want to write a kludgy one-off implementation that only works for those using linear algebra instead of a proper boolean indicator function, and would rather like to know how to solve these problems in general the right way.

Resources