I have a dimple chart displaying some large numbers. I want the precise values to appear in the toolbox (not truncated to 14k) so I changed the tickFormat. However, dimple/d3 seems to ignore the grouping comma, which makes large numbers hard to process.
// this prints "12,345" as expected
var f = d3.format(",.0f");
console.log(f(12345.123));
var data = [{"date":"2016-01-18","completed":1234123.100},{"date":"2016-01-19","completed":1345123.0},{"date":"2016-01-20","completed":2123123.1}]
var svg = dimple.newSvg("#foo", "100%", "100%");
var myChart = new dimple.chart(svg, data);
var x = myChart.addTimeAxis("x", "date", "%Y-%m-%d", "%d/%m");
var y = myChart.addMeasureAxis("y", "completed");
// this does not work
// tooltips and y axis values appear without grouping comma
y.tickFormat = d3.format(",.0f");
myChart.setMargins("60px", "30px", "30px", "70px");
series = myChart.addSeries(null, dimple.plot.line);
myChart.draw();
According to the API documentation the property dimple.axis.tickFormat will accept the format specifier string (i.e. ",.0f"). as it is passed to d3.format(). You don't have to call d3.format() yourself; this is done internally in function _getFormat(). Thus your code becomes
y.tickFormat = ",.0f";
Related
I have a small menu made with dat.gui JavaScript library. I use different lines with some initial values which are displayed (these initial values are modified during the execution of code).
My issue is, for example, that instead of display a value "15", I would like to display "15.0000". I try to used toFixed(4) function but without success.
Here's the raw (without "toFixed(4)" function) code snippet :
var componentThetaInit = 15;
var componentPhiInit = 15;
var gui = new dat.GUI({
autoplace: false,
width: 350,
height: 9 * 32 - 1
});
var params = {
StartingVector : '',
ComponentVectorTheta : componentThetaInit,
ComponentVectorPhi : componentPhiInit
};
gui.add(params, 'StartingVector').name('Starting Vector :');
controllerComponentVectorTheta = gui.add(params, 'ComponentVectorTheta', minComponentTheta, maxComponentTheta, 0.0001).name('Component θ ');
controllerComponentVectorPhi = gui.add(params, 'ComponentVectorPhi', minComponentPhi, maxComponentPhi, 0.0001).name('Component φ ');
Now I tried :
var params = {
StartingVector : '',
ComponentVectorTheta : componentThetaInit.toFixed(4),
ComponentVectorPhi : componentPhiInit.toFixed(4)
};
but this doesn't work. Here's below a capture of what I get ("15" instead of "15.0000") before the execution :
Once the code is running, the 4 floating points are well displayed (because values are no more integers) : this is actually the initial values (before animation) that I would like to be displayed like "15.0000" instead of "15".
The result is the same by declaring :
var componentThetaInit = 15.0000;
var componentPhiInit = 15.0000;
I have also tried :
ComponentVectorTheta : parseFloat(componentThetaInit.toFixed(4)),
ComponentVectorPhi : parseFloat(componentPhiInit.toFixed(4))
If anyone could see what's wrong, this would be nice.
Thanks
First, some minor bugs. There were some missing variable declarations. I added:
var minComponentTheta = -10.0;
var maxComponentTheta = 100.0;
var minComponentPhi = -100.0;
var maxComponentPhi = 100.0;
2) The autoplace param (which should be autoPlace, capital P) has nothing to do with decimal places... it appears to be an option to automatically add the UI to the DOM.
None of this actually fixes the issue. It's a problem that starts with javascript. If you put this code in the console you'll see the same problem:
var a = 15.0000;
console.log(a);
// prints 15 and not 15.0000
When a number is an integer, it's an integer. To get around this, you can have your default value have a non integer value like 15.0001.
This probably isn't what you're looking for though. So, if you are up for modifying the code for dat.gui.js you can force it to set the value of the input to the string version of the number value. Find the code that looks like this and copy and paste the code below replacing it. I've simply added a toFixed at the end of the first line in the function. Be aware that when you get the value now, it will be a string and not a number, so to do math with it you'll want to parseFloat() on it before using it.
NumberControllerBox.prototype.updateDisplay = function updateDisplay() {
this.__input.value = this.__truncationSuspended ? this.getValue() : roundToDecimal(this.getValue(), this.__precision).toFixed(this.__precision);
return _NumberController.prototype.updateDisplay.call(this);
};
In the unminified JS version, ^ that's on line 2050.
I verified this works as you want
Just leave it like this:
ComponentVectorTheta : componentThetaInit.toFixed(4),
ComponentVectorPhi : componentPhiInit.toFixed(4)
Consider this:
a = 15; // a is an integer now
b = a.toFixed(4); // b is the string "15.0000"
c = parseFloat(b); // c is a number (internally, probably an integer)
d = c.toString(2); // d is the string "1111"
e = parseInt(d, 2);// e is an integer again
assert(a === e); // true
I've got a basic AmGraph:
graph = new AmCharts.AmGraph();
graph.lineThickness = 4;
graph.valueAxis = valueAxis;
graph.fillAlphas = 0;
graph.valueAxis = valueAxis;
graph.valueAxis.minimum = 0;
graph.title = "likes";
graph.labelText = " ";
graph.valueField = "likes_1";
The problem is that the numberFormatter doesn't format values if I'm using a custom balloonText function:
graph.numberFormatter = {precision: -1, decimalSeparator:",", thousandsSeparator:","};
So if I use this:
graph.balloonText = "<b>got: [[likes_1]] </b>";
The tooltip looks like this:
"got: 1000"
How can I format the value? if I try to use javascript for formatting it (Numeral.js):
graph.balloonText = "<script>numeral( [[likes_1]] ).format("0,0") </script>";
The wildcard isn't replaced with the actual value when building the page (but rather when hovering the chart?), so I just get:
Uncaught ReferenceError: likes_32 is not defined
What should I do?
(First I highly recommend to use the newer way of chart
initialization! Look
here
for that.)
Instead of balloonText you can use balloonFunction, which allows you to change the text with JavaScript. Inside there you can format the number according to your wishes.
I prepared a demo using the AmCharts.formatNumber formatter.
return AmCharts.formatNumber(graphDataItem.values.value, {
precision: -1,
decimalSeparator: '.',
thousandsSeparator: ','
}, -1);
You can still use Numeral.js in there though (it's syntax seems a little more straight forward to me).
return numeral(graphDataItem.values.value).format("0,0");
When I am zooming the chart then the Y scale is changing automatically to select the range fitting to the values limited by x.
I know valueRange param where I can fix the range, but I am searching for an option to define some maximal range.
So that the Y scale is changing when zooming , but the scale is limited by some parameter
In the interest of clarity and brevity, I have omitted some things - such as the creation process.
You would be able to do something similar to limit the minimum range.
g = new Dygraph(
... your parameters ...
);
window.intervalId = setInterval(
function(){
var extents = g.yAxisRange();
var lowerExtent = extents[0];
var upperExtent = extents[1];
if(upperExtent > MY_MAX_DESIRED){
var range = [lowerExtent, MY_MAX_DESIRED];
g.updateOptions('valueRange': range);
}
},
500
);
Using the above solution, you would notice a half-second 'glitch' on zooming when the range it set. As an alternative, you could also use the zoomCallBack, specified when you create the graph object:
g = new Dygraph(
document.getElementById("div_g"),
[[0,0]],
{
zoomCallBack: function(minDate, maxDate, yRanges){
var extents = yRanges;
var lowerExtent = extents[0];
var upperExtent = extents[1];
if(upperExtent > MY_MAX_DESIRED){
var range = [lowerExtent, MY_MAX_DESIRED];
g.updateOptions('valueRange': range);
}
}
}
);
One caveat, I haven't tested the above solutions. I just believe they should work. Good luck!
thank you!
I have tried to use your suggestion
I have some issues:
"http://jsfiddle.net/stojak/zL6es924/4/"
my goal: e.g when y values in data are in between 10 and 11 then I want to zoom on Y to 0 (10-10) to 21 (11+10)
the code is nearly working, however I do not know how to let say reset my valueRange.
the result is that after each one zoom action the range increase.
I am developing a simple multi-line graph with dual time axes and zooming/dragging features. Please take a look at my JSFiddle.
I am trying to implement the drag feature on the line graph, whereupon dragging a particular line will result in its respective axis also getting updated. Every time the drag is applied to the graph, I am trying to update the domain values of its respective axis, and redraw both the axis and the line graph.
Here is the logic that I implemented to update the domain values (referenced from a D3 Example):
var mousePoint = d3.mouse(this);
x1 = x1Scale.domain()[0],
x2 = x1Scale.domain()[1],
console.log("x1 = "+x1+", x2 = " +x2);
xextent = x1 - x2;
x1 += mousePoint[0];
x2 += mousePoint[0];
var newDomain = [x1, x2];
x1Scale.domain(newDomain);
When I implement this logic, I get a NaN error. Is this the correct way to update the domain values after the drag? If so, how do I solve the NaN error and achieve the desired functionality?
It is important to convert numbers into date objects, there was a typo in your code (data1[0].time instead of data1[0].date). Also you shouldn't multiply by 1000, since your data was already in milliseconds.
In your drag code, it is also important to convert your date objects back to numbers, in order that += will work on them. Of course you also need to convert them back to date when setting the domain again.
function draggedData1(d) {
console.log("dragging of data1 going on!!")
var mousePoint = d3.mouse(this);
var x1 = x1Scale.domain()[0].valueOf(); //date to number
var x2 = x1Scale.domain()[1].valueOf();
var xextent = x1 - x2;
x1 += mousePoint[0];
x2 += mousePoint[0];
var newDomain = [new Date(x1), new Date(x2)]; //number back to date
x1Scale.domain(newDomain);
redraw();
zoomBottom.x(x1Scale);
zoom.x(x2Scale);
}
I've created a fiddle with the full code and fixes here:
http://jsfiddle.net/pb3cod6q/2/
How do I add the following text boxes together with the logic below?
oneTextBox = $120.00,
twoTextBox = .03*oneTextBox,
threeTextBox = oneTextBox + twoTextBox
I would also like the units of each text box to be in dollars ($).
function doGet(e) {
var app = UiApp.createApplication();
var VertPanel = app.createVerticalPanel().setId('VertPanel');
var oneTextBox = app.createTextBox().setText("$120.00").setId("oneTextBox").setName("oneTextBox");
var twoTextBox = app.createTextBox().setId("twoTextBox").setName("twoTextBox");
var threeTextBox = app.createTextBox().setId("threeTextBox").setName("threeTextBox");
app.add(VertPanel);
VertPanel.add(oneTextBox).add(twoTextBox).add(threeTextBox);
return app;
}
The value returned by e.parameter.oneTextBox in the handler function is a string, in your example it should be "$120.00," and what you want is a numeric value... what I'd suggest is to use a replace() to remove all non numeric characters and convert that to a number like this :
var oneTextBoxNumValue = Number(e.parameter.oneTextBox.replace(/[^0-9]/g,''));// the regex ^0-9 takes everything not between 0 and 9 (and replace by '')
Using the same process on other textBoxes you can do everything you want with math operations after this conversion.
To get the results in $, simply add a '$' to your result
getElementById('oneTextBox').setText(resultNumeric+"$")
the only tricky thing is the decimal point, you'll need to take this into account in your conversion : $120.00, will become 12000 in numeric value so don't forget to divide the result somewhere or your stuff will become very expensive ! ;-)
Also I've had some rounding errors sometimes but it's always possible to handle quite easily, for example in a similar case I had to use something like this to get the correct result : (2.00 instead of 1.99 if quant = 2 in the example below, note that I divide the integer by 100 to get value with 2 decimals)
var total = parseInt(Number(quant)*valtotal*100+0.01)/100;
Hoping it will give some ideas to start with.
EDIT : here is a small code to illustrate :
function calcTest() {
var app = UiApp.createApplication().setTitle('TextField Calculator');
var button = app.createButton('Calculate');
var handler = app.createServerHandler('calc');
button.addClickHandler(handler);
var grid = app.createGrid(5, 2);
grid.setText(0, 0, 'value1 ');
grid.setWidget(0, 1, app.createTextBox().setName('value1').setText('$ 45.00/unit'));
grid.setText(1, 0, 'value2');
grid.setWidget(1, 1, app.createTextBox().setName('value2').setText('3 units'));
grid.setText(2, 0, 'press button to calculate');
grid.setWidget(2, 1, button);
grid.setText(3, 0, 'value3 = value1*1.35');
grid.setWidget(3, 1, app.createTextBox().setId('value3').setEnabled(false));
grid.setText(4, 0,'sum value1 + value2 + value3');
grid.setWidget(4, 1, app.createTextBox().setId('sum').setEnabled(false));
handler.addCallbackElement(grid);
app.add(grid);
var ss = SpreadsheetApp.getActive();
ss.show(app);
}
function calc(e){
var app = UiApp.getActiveApplication();
var value1 = Number(e.parameter.value1.replace(/[^0-9]/g,''))/100;
var value2 = Number(e.parameter.value2.replace(/[^0-9]/g,''));
var calcvalue = parseInt(value1*1.35*100)/100
var sumcalc = calcvalue+value1+value2
app.getElementById('value3').setText('$ '+calcvalue)
app.getElementById('sum').setText(sumcalc+' without unit;)')
return app
}
EDIT 2 : here is another code, a function that I use in an application to convert string values to Euros, it is slightly different in its approach but works pretty well.
function toEuro(val){
if(val==''){temp='';return temp}
var temp = val.toString().replace(/[^\d\.-]/g,'').split('.');
if(temp[0]==''){temp[0]='0'}
if(temp.length==1){var result = temp[0]+',00 €'}
else{
var int = temp[0]
var dec = temp[1]
if(dec.length==1){var result=int+','+dec+'0 €'}else{var result=int+','+dec+' €'}
}
return result
}