d3.js: tickformat - adding a % sign without multiplying by 100 - formatting

my data has percents as, for example, [10.1, 3.2, 5.4]
d3.format("0f") will give me [10, 3, 5]
d3.format("0%") will give me [1010%, 320%, 540%] (multiplies by 100)
how do I get [10%, 3%, 5%]?
I can't figure out where to add a +"%" to the first case
or eliminate the *100 in the second case
the relevant parts of the code:
var formatPercent = d3.format("0f");
var min = 0;
var max = d3.max(data, function(d) { return + d[5]; });
max = Math.round(max * 1.2); // pad it
//define the x-axis
var xAxis = d3.svg.axis()
.scale(x)
.orient('top')
.ticks(6)
.tickFormat(formatPercent);
and data comes in like this:
{
"Geography": [
["Midwest", 234017797, 498, 8.2, 9.0, 11.3],
["Northeast", 265972035, 566, 8.9, 12.1, 13.1],
["South", 246235593, 524, 8.1, 8.3, 10.8],
["West", 362774577, 772, 9.4,9.9, 11.7]
]
}
It's the last three numbers in each line that are the percentage values I'm using to chart ranges. I want the x-axis to be formatted in integer+% format based on the high and low values in the data.
Thank you!

Update for D3 v4 (using ES6):
// Can also be axisTop, axisRight, or axisBottom
d3.axisLeft()
.tickFormat(d => d + "%")
Original answer for D3 v3:
You can create your own format:
d3.svg.axis()
.tickFormat(function(d) { return d + "%"; });
If you want to get rid of the decimal places:
d3.svg.axis()
.tickFormat(function(d) { return parseInt(d, 10) + "%"; });

Related

Google Earth Engine Sentinel-2 Level2 set to NaN clouds

I would like to set to NaN or Null all clouds to a cut section of a Sentinel-2 MSI level 2, for one band only if possible (not all RGB) I have used the following code:
/**
* Function to mask clouds using the Sentinel-2 QA band
* #param {ee.Image} image Sentinel-2 image
* #return {ee.Image} cloud masked Sentinel-2 image
*/
function maskS2clouds(image) {
var qa = image.select('QA60');
// Bits 10 and 11 are clouds and cirrus, respectively.
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;
// Both flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
.and(qa.bitwiseAnd(cirrusBitMask).eq(0));
return image.updateMask(mask).divide(10000);
}
var dataset = ee.ImageCollection('COPERNICUS/S2_SR')
.filterDate('2020-01-01', '2020-01-30')
// Pre-filter to get less cloudy granules.
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',20))
.map(maskS2clouds);
var visualization = {
min: 0.0,
max: 0.3,
bands: ['B4', 'B3', 'B2'],
};
Map.setCenter(83.277, 17.7009, 12);
Map.addLayer(dataset.mean(), visualization, 'RGB');
the code used does not completely eliminate the clouds as is seen in the figure:
when I do the same for Landsat I have found out the clouds are well masked with the code:
/**
* Function to mask clouds based on the pixel_qa band of Landsat SR data.
* #param {ee.Image} image Input Landsat SR image
* #return {ee.Image} Cloudmasked Landsat image
*/
var cloudMaskL457 = function(image) {
var qa = image.select('pixel_qa');
// If the cloud bit (5) is set and the cloud confidence (7) is high
// or the cloud shadow bit is set (3), then it's a bad pixel.
var cloud = qa.bitwiseAnd(1 << 5)
.and(qa.bitwiseAnd(1 << 7))
.or(qa.bitwiseAnd(1 << 3));
// Remove edge pixels that don't occur in all bands
var mask2 = image.mask().reduce(ee.Reducer.min());
return image.updateMask(cloud.not()).updateMask(mask2);
};
var dataset = ee.ImageCollection('LANDSAT/LT05/C01/T1_SR')
.filterDate('2011-01-01', '2011-12-31')
.map(cloudMaskL457);
var visParams = {
bands: ['B3', 'B2', 'B1'],
min: 0,
max: 3000,
gamma: 1.4,
};
Map.setCenter(34.9774, 32.4916, 8);
Map.addLayer(dataset.median(), visParams);

YOLO: How to change the frequency of mAP calculation in darknet code

I am training YOLOv2 with -map option to print mean Average Precision. I need to change the frequency at which the map is calculated. At this time it is calculated every 300 iterations which is too frequent for me. I want this to be computed every (say 2000 iterations). Is there a way to change the switch ot code?
I do see the following code in detector.c file which needs to be changed. Any input?
int calc_map_for_each = 4 * train_images_num / (net.batch * net.subdivisions); // calculate mAP for each 4 Epochs
calc_map_for_each = fmax(calc_map_for_each, 100);
int next_map_calc = iter_map + calc_map_for_each;
next_map_calc = fmax(next_map_calc, net.burn_in);
next_map_calc = fmax(next_map_calc, 1000);
if (calc_map) {
printf("\n (next mAP calculation at %d iterations) ", next_map_calc);
if (mean_average_precision > 0) printf("\n Last accuracy mAP#0.5 = %2.2f %% ", mean_average_precision * 100);
}
I assume you are using Alexey's repo because of the -map option. In detector.c (https://github.com/AlexeyAB/darknet/blob/8c970498a296ed129ffef7d872ccc25d42d1afda/src/detector.c#L223) you may change the following code :
calc_map_for_each = fmax(calc_map_for_each, 100);
to
calc_map_for_each = fmax(calc_map_for_each, 1000);

How to calculate the length in mm of a string in a PDF document created with jsPDF library?

I use jsPDF library to create and print a PDF document. This library exposes low level methods which are ok, but i have tons of fields to create, many of which are similar, and i need to create higher level abstractions.
For example i have a createLabel function that i want to call instead of this low level stuff.
var doc = new jsPDF('portrait', 'mm', 'a4');
doc.addFont('Arial', "sans-serif", "normal");
// name
doc.setFontSize(14);
doc.text(10, 19, "name:");
doc.setLineWidth(0.1);
doc.line(25, 19, 100, 19); // meaning x1, y1, x2, y2
// CUI
doc.setFontSize(14);
doc.text(10, 29, "CUI:");
doc.setLineWidth(0.1);
doc.line(21, 29, 100, 29);
// same stuff but use functions instead.
createLabel("name: ", 10,50, 100); // meaning (labelName, x, y, totalWidth)
createLabel("CUI: ", 10,60, 100);
As you can see, the lines for the second group of labels are not placed in the right position. They are too much on the left. Their starting postion is generated based on the length of the labelName, and this length calculation fails. How can i make this work properly? The code so far is:
function createLabel(name, x, y, totalWidth) {
//draw name
doc.setFontSize(14);
doc.text(x, y, name);
// draw line
const nameLength = (measureLength(name)) + 2;
doc.setLineWidth(0.1);
// i want to start the line after the name ends + 2 mm.
// and end the line in such a way that nameLength + lineLength == totalWidth of the compoenent.
doc.line(x + nameLength, y, x + totalWidth, y);
}
function measureLength(str) {
let canvas = document.createElement('canvas'); // in memory canvas.. not rendered anywere..
let ctx = canvas.getContext("2d")
ctx.font = "14px Arial";
let width = ctx.measureText(str).width;
let mm = ( width * 25.4 ) / 149 // meaning (px * 25.4) / screen DPI
console.log (mm);
return mm; // of course, this calculation turns out wrong..
}
How to make this measureLength function work correctly? Most solutions i found involve DOM but this is PDF.
Notice: I use the same font ('14px Arial') for the PDF document and for the canvas. jsPDF live demo.
Any insight is appreciated, thanks :)
This might resolve your problem:
createLabel(name, x, y, totalWidth) {
doc.setFontSize(14);
doc.text(x, y, name);
// draw line
const nameLength = (doc.getTextDimensions(name).w / (72 / 25.6) ) + 2;
console.log('nameLength', nameLength); // todo remove
doc.setLineWidth(0.1);
// i want to start the line after the name ends + 2 mm.
// and end the line in such a way that nameLength + lineLength == totalWidth of the compoenent.
doc.line(x + nameLength, y, x + totalWidth, y);
}
Check how I calculate nameLength - using build in jsPDF function and converting to mm.
Helpful links:
how to calculate text size
why sometimes calculation might be wrong by few pixels
This is the result:
Remember that you use x + totalWidth for line width, so lines are longer by x compared to manual example at the top

Fabricjs line coordinates after (moved, scaled, rotated) - canvas.on('object:modified'…

I need to find the Line coordinates(x1,y1,x2,y2) after the object has been modified. (moved, scaled, rotated)
I thought to use the oCoords information and based on angle and flip information to decide which corners are the line ends, but it seems that it will not be too accurate…
Any help?
Example:
x1: 164,
y1: 295.78334045410156,
x2: 451,
y2: 162.78334045410156
x: 163, y: 161.78334045410156 - top left corner
x: 452, y: 161.78334045410156 - top right corner
x: 163, y: 296.78334045410156 - bottom left corner
x: 452, y: 296.78334045410156 - bottom right corner
When Fabric.js calculates oCoords - i.e. object's corners' coordinates - it takes into account the object's strokeWidth:
// fabric.Object.prototype
_getNonTransformedDimensions: function() {
var strokeWidth = this.strokeWidth,
w = this.width + strokeWidth,
h = this.height + strokeWidth;
return { x: w, y: h };
},
For most objects, stroke is kind of a border that outlines the outer edges, so it makes perfect sense to account for strokeWidth it when calculating corner coordinates.
In fabric.Line, though, stroke is used to draw the body of the line. There is no example in the question but I assume this is the reason behind discrepancies between the real end-point coordinates and those in oCoords.
So, if you really want to use oCoords to detect the coordinates of the end points, you'll have to adjust for strokeWidth / 2, e.g.
const realx1 = line.oCoords.tl.x + line.strokeWidth / 2
const realy1 = line.oCoords.tl.y + line.strokeWidth / 2
Keep in mind that fabric.Line's own _getNonTransformedDimensions() does adjust for strokeWidth, but only when the line's width or height equal 0:
// fabric.Line.prototype
_getNonTransformedDimensions: function() {
var dim = this.callSuper('_getNonTransformedDimensions');
if (this.strokeLineCap === 'butt') {
if (this.width === 0) {
dim.y -= this.strokeWidth;
}
if (this.height === 0) {
dim.x -= this.strokeWidth;
}
}
return dim;
},

Setting a max axis value or range step for a Morris Bar Chart?

I was wondering if it is possible to set a max axis value (say, I want the highest point of my data to be the top end of the y-axis) on a bar chart? I see there are options for ymin and ymax on line charts but I can't seem to find any information about the bar charts.
Also, it would be helpful if anyone knew how to force the range between axis lanes to be a certain amount (say step up by 250 each line instead of the generated amount which in my case is too high for my liking).
Set a maximum value for the y axis
You can, indeed, set the ymax for bar charts also (even though this is not documented).
Morris.Bar({
element: 'bar-example',
data: [
{ y: '2006', a: 100, b: 90 },
{ y: '2007', a: 75, b: 65 },
{ y: '2008', a: 50, b: 40 },
{ y: '2009', a: 75, b: 65 },
{ y: '2010', a: 50, b: 40 },
{ y: '2011', a: 75, b: 65 },
{ y: '2012', a: 100, b: 90 }
],
xkey: 'y',
ymax: 300, // set this value according to your liking
ykeys: ['a', 'b'],
labels: ['Series A', 'Series B']
});
And have your y axis set to this maximum value:
Set a range value for the y axis
It seems that it's not possible to set a range value for the y axis. This value appears to be computed according to the values of the data passed to Morris.Bar.
Not documented, but you can set maximum y by applying ymax. You can manipulate the range by setting numLines (also not documented).
E.g.
var chart = new Morris.Bar({
...
ymin: 0,
ymax: 7,
numLines: 8,
...
});
The above defined chart will display values from 0 to 7 and display a grid line for each integer between 0 and 7 (therefore 8 as a parameter)
To change to ymax call this
chart.options["ymax"] = 300;
Where chart is your chart variable
I want the highest point of my data to be the top end of the y-axis
The documentation is very sparse and confusing but this is possible using the ymin variable which is only documented in the Lines & Area Charts. The default value for that variable seems to be auto 0 and changing it to just auto seems to produce the desired result as you can see below.
how to force the range between axis lanes to be a certain amount
This does not seem to be possible, natively. However, you can kind of hack the axis label with the following function. It will round the value to multiples of 250 BUT the grid lines won't be at the number shown. E.g. say a grid line is at 570. The function below will change the label to 500 but the line will still show at 570 mark.
yLabelFormat: function(d) {
return Math.round(d) - (Math.round(d) % 250);
},
As others have mentioned, you can set ymax to a value that you want your upper bound to be but since you want the highest data point to be the upper bound, set ymax to auto. You can also try changing numLines to different values for a better aesthetic.