I have an value that is the count of total minutes that I am presenting within my time series. While the minutes are used for plotting, I would like to change the axis tick labels to present the hours that this data fits closest to. The way I approached this was to add a .tickFormat() that converts the minutes to hours and then return d3.timeFormat() with the hour format and a new date set to 0 that is set with the hours. While the axis tick labels are close, they aren't correct. There seems to be a slight offset, duplication of values and the scale not starting at 0 (Starts at 12). Should I use a different function call to correct the scale?.
This is the code in question:
svg.append("g")
.call(d3.axisLeft()
.scale(y)
.tickFormat((d, i) => {
var hours = Math.floor(d / 60);
console.log(hours)
console.log(new Date(0).setMinutes(hours))
return d3.timeFormat("%I")( new Date(0).setHours(hours))
}));
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<style>
div.tooltip {
position: absolute;
text-align: center;
width: 100px;
height: 30px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<script>
var data = [
{ "x": "2020-04-26", "y": 461.0, "label": "7:41" },
{ "x": "2020-04-27", "y": 421.0, "label": "7:01" },
{ "x": "2020-04-28", "y": 519.0, "label": "8:39" },
{ "x": "2020-04-29", "y": 502.0, "label": "8:22" },
{ "x": "2020-04-30", "y": 511.0, "label": "8:31" },
{ "x": "2020-05-01", "y": 513.0, "label": "8:33" },
{ "x": "2020-05-02", "y": 496.0, "label": "8:16" },
{ "x": "2020-05-03", "y": 480.0, "label": "8:00" },
{ "x": "2020-05-04", "y": 364.0, "label": "6:04" },
{ "x": "2020-05-05", "y": 498.0, "label": "8:18" },
{ "x": "2020-05-06", "y": 467.0, "label": "7:47" },
{ "x": "2020-05-07", "y": 477.0, "label": "7:57" },
{ "x": "2020-05-08", "y": 431.0, "label": "7:11" },
{ "x": "2020-05-09", "y": 419.0, "label": "6:59" },
{ "x": "2020-05-10", "y": 471.0, "label": "7:51" },
{ "x": "2020-05-11", "y": 391.0, "label": "6:31" },
{ "x": "2020-05-12", "y": 481.0, "label": "8:01" },
{ "x": "2020-05-13", "y": 494.0, "label": "8:14" },
{ "x": "2020-05-14", "y": 506.0, "label": "8:26" },
{ "x": "2020-05-15", "y": 464.0, "label": "7:44" },
{ "x": "2020-05-16", "y": 474.0, "label": "7:54" },
{ "x": "2020-05-17", "y": 383.0, "label": "6:23" },
{ "x": "2020-05-18", "y": 385.0, "label": "6:25" },
{ "x": "2020-05-19", "y": 470.0, "label": "7:50" },
{ "x": "2020-05-20", "y": 465.0, "label": "7:45" },
{ "x": "2020-05-21", "y": 574.0, "label": "9:34" },
{ "x": "2020-05-22", "y": 473.0, "label": "7:53" },
{ "x": "2020-05-23", "y": 431.0, "label": "7:11" },
{ "x": "2020-05-24", "y": 497.0, "label": "8:17" },
{ "x": "2020-05-26", "y": 482.0, "label": "8:02" },
{ "x": "2020-05-27", "y": 492.0, "label": "8:12" },
{ "x": "2020-05-28", "y": 494.0, "label": "8:14" },
{ "x": "2020-05-29", "y": 469.0, "label": "7:49" },
{ "x": "2020-05-30", "y": 395.0, "label": "6:35" },
{ "x": "2020-05-31", "y": 427.0, "label": "7:07" },
{ "x": "2020-06-01", "y": 346.0, "label": "5:46" },
{ "x": "2020-06-02", "y": 416.0, "label": "6:56" },
{ "x": "2020-06-03", "y": 461.0, "label": "7:41" },
{ "x": "2020-06-04", "y": 486.0, "label": "8:06" },
{ "x": "2020-06-05", "y": 451.0, "label": "7:31" },
{ "x": "2020-06-06", "y": 533.0, "label": "8:53" },
{ "x": "2020-06-08", "y": 462.0, "label": "7:42" },
{ "x": "2020-06-09", "y": 461.0, "label": "7:41" },
{ "x": "2020-06-10", "y": 477.0, "label": "7:57" },
{ "x": "2020-06-11", "y": 458.0, "label": "7:38" },
{ "x": "2020-06-12", "y": 484.0, "label": "8:04" },
{ "x": "2020-06-13", "y": 389.0, "label": "6:29" },
{ "x": "2020-06-15", "y": 472.0, "label": "7:52" },
{ "x": "2020-06-16", "y": 462.0, "label": "7:42" },
{ "x": "2020-06-17", "y": 486.0, "label": "8:06" },
{ "x": "2020-06-18", "y": 489.0, "label": "8:09" },
{ "x": "2020-06-19", "y": 483.0, "label": "8:03" },
{ "x": "2020-06-20", "y": 426.0, "label": "7:06" },
{ "x": "2020-06-21", "y": 453.0, "label": "7:33" },
{ "x": "2020-06-22", "y": 489.0, "label": "8:09" },
{ "x": "2020-06-23", "y": 467.0, "label": "7:47" },
{ "x": "2020-06-24", "y": 474.0, "label": "7:54" },
{ "x": "2020-06-25", "y": 451.0, "label": "7:31" },
{ "x": "2020-06-26", "y": 450.0, "label": "7:30" },
{ "x": "2020-06-27", "y": 470.0, "label": "7:50" },
{ "x": "2020-06-29", "y": 247.0, "label": "4:07" },
{ "x": "2020-06-30", "y": 502.0, "label": "8:22" },
{ "x": "2020-07-01", "y": 464.0, "label": "7:44" }
]
// D3 date parser
for (var i=0; i < data.length; i++){
var parser = d3.timeParse("%Y-%m-%d")
data[i].date = parser(data[i].x);
}
var margin = { top: 10, right: 30, bottom: 30, left: 60 }
var width = 800 - margin.left - margin.right;
var height = 800 - margin.top - margin.bottom;
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var svg = d3.select("#my_dataviz")
.append("svg")
.attr( 'preserveAspectRatio',"xMinYMin meet")
.attr("viewBox", "0 0 " + (width + margin.left + margin.right) + " " + (height + margin.top + margin.bottom))
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // translate(margin left, margin top)
var x = d3.scaleTime()
.domain([d3.min(data, function(d) { return d.date }), d3.max(data, function(d) { return d.date })])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(" + 0 + "," + height + ")")
.call(d3.axisBottom(x));
// text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," + (height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Date");
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d){ return +d.y })])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft()
.scale(y)
.tickFormat((d, i) => {
var hours = Math.floor(d / 60);
console.log(hours)
console.log(new Date(0).setMinutes(hours))
return d3.timeFormat("%I")( new Date(0).setHours(hours))
}));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Time Asleep (Minutes)");
// Add line path
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.y) })
);
// Add the scatterplot (data points)
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3)
// Add tooltip on hover
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.x + "<br/>" + d.label)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 30) + "px")
})
// Remove tooltip after hover
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
.transition()
.delay(function(d,i){ return (i*3)})
.duration(2000)
.attr("cx", function(d){ return x(d.date) })
.attr("cy", function(d){ return y(d.y) });
</script>
While your data is a time, it's not a date. Forcing it to be a date will give you many nasty complications. I just surpassed the d3 and Date logic, leading to a simpler solution:
var data = [{
"x": "2020-04-26",
"y": 461.0,
"label": "7:41"
},
{
"x": "2020-04-27",
"y": 421.0,
"label": "7:01"
},
{
"x": "2020-04-28",
"y": 519.0,
"label": "8:39"
},
{
"x": "2020-04-29",
"y": 502.0,
"label": "8:22"
},
{
"x": "2020-04-30",
"y": 511.0,
"label": "8:31"
},
{
"x": "2020-05-01",
"y": 513.0,
"label": "8:33"
},
{
"x": "2020-05-02",
"y": 496.0,
"label": "8:16"
},
{
"x": "2020-05-03",
"y": 480.0,
"label": "8:00"
},
{
"x": "2020-05-04",
"y": 364.0,
"label": "6:04"
},
{
"x": "2020-05-05",
"y": 498.0,
"label": "8:18"
},
{
"x": "2020-05-06",
"y": 467.0,
"label": "7:47"
},
{
"x": "2020-05-07",
"y": 477.0,
"label": "7:57"
},
{
"x": "2020-05-08",
"y": 431.0,
"label": "7:11"
},
{
"x": "2020-05-09",
"y": 419.0,
"label": "6:59"
},
{
"x": "2020-05-10",
"y": 471.0,
"label": "7:51"
},
{
"x": "2020-05-11",
"y": 391.0,
"label": "6:31"
},
{
"x": "2020-05-12",
"y": 481.0,
"label": "8:01"
},
{
"x": "2020-05-13",
"y": 494.0,
"label": "8:14"
},
{
"x": "2020-05-14",
"y": 506.0,
"label": "8:26"
},
{
"x": "2020-05-15",
"y": 464.0,
"label": "7:44"
},
{
"x": "2020-05-16",
"y": 474.0,
"label": "7:54"
},
{
"x": "2020-05-17",
"y": 383.0,
"label": "6:23"
},
{
"x": "2020-05-18",
"y": 385.0,
"label": "6:25"
},
{
"x": "2020-05-19",
"y": 470.0,
"label": "7:50"
},
{
"x": "2020-05-20",
"y": 465.0,
"label": "7:45"
},
{
"x": "2020-05-21",
"y": 574.0,
"label": "9:34"
},
{
"x": "2020-05-22",
"y": 473.0,
"label": "7:53"
},
{
"x": "2020-05-23",
"y": 431.0,
"label": "7:11"
},
{
"x": "2020-05-24",
"y": 497.0,
"label": "8:17"
},
{
"x": "2020-05-26",
"y": 482.0,
"label": "8:02"
},
{
"x": "2020-05-27",
"y": 492.0,
"label": "8:12"
},
{
"x": "2020-05-28",
"y": 494.0,
"label": "8:14"
},
{
"x": "2020-05-29",
"y": 469.0,
"label": "7:49"
},
{
"x": "2020-05-30",
"y": 395.0,
"label": "6:35"
},
{
"x": "2020-05-31",
"y": 427.0,
"label": "7:07"
},
{
"x": "2020-06-01",
"y": 346.0,
"label": "5:46"
},
{
"x": "2020-06-02",
"y": 416.0,
"label": "6:56"
},
{
"x": "2020-06-03",
"y": 461.0,
"label": "7:41"
},
{
"x": "2020-06-04",
"y": 486.0,
"label": "8:06"
},
{
"x": "2020-06-05",
"y": 451.0,
"label": "7:31"
},
{
"x": "2020-06-06",
"y": 533.0,
"label": "8:53"
},
{
"x": "2020-06-08",
"y": 462.0,
"label": "7:42"
},
{
"x": "2020-06-09",
"y": 461.0,
"label": "7:41"
},
{
"x": "2020-06-10",
"y": 477.0,
"label": "7:57"
},
{
"x": "2020-06-11",
"y": 458.0,
"label": "7:38"
},
{
"x": "2020-06-12",
"y": 484.0,
"label": "8:04"
},
{
"x": "2020-06-13",
"y": 389.0,
"label": "6:29"
},
{
"x": "2020-06-15",
"y": 472.0,
"label": "7:52"
},
{
"x": "2020-06-16",
"y": 462.0,
"label": "7:42"
},
{
"x": "2020-06-17",
"y": 486.0,
"label": "8:06"
},
{
"x": "2020-06-18",
"y": 489.0,
"label": "8:09"
},
{
"x": "2020-06-19",
"y": 483.0,
"label": "8:03"
},
{
"x": "2020-06-20",
"y": 426.0,
"label": "7:06"
},
{
"x": "2020-06-21",
"y": 453.0,
"label": "7:33"
},
{
"x": "2020-06-22",
"y": 489.0,
"label": "8:09"
},
{
"x": "2020-06-23",
"y": 467.0,
"label": "7:47"
},
{
"x": "2020-06-24",
"y": 474.0,
"label": "7:54"
},
{
"x": "2020-06-25",
"y": 451.0,
"label": "7:31"
},
{
"x": "2020-06-26",
"y": 450.0,
"label": "7:30"
},
{
"x": "2020-06-27",
"y": 470.0,
"label": "7:50"
},
{
"x": "2020-06-29",
"y": 247.0,
"label": "4:07"
},
{
"x": "2020-06-30",
"y": 502.0,
"label": "8:22"
},
{
"x": "2020-07-01",
"y": 464.0,
"label": "7:44"
}
]
// D3 date parser
for (var i = 0; i < data.length; i++) {
var parser = d3.timeParse("%Y-%m-%d")
data[i].date = parser(data[i].x);
}
var margin = {
top: 10,
right: 30,
bottom: 30,
left: 60
}
var width = 800 - margin.left - margin.right;
var height = 800 - margin.top - margin.bottom;
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var svg = d3.select("#my_dataviz")
.append("svg")
.attr('preserveAspectRatio', "xMinYMin meet")
.attr("viewBox", "0 0 " + (width + margin.left + margin.right) + " " + (height + margin.top + margin.bottom))
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // translate(margin left, margin top)
var x = d3.scaleTime()
.domain([d3.min(data, function(d) {
return d.date
}), d3.max(data, function(d) {
return d.date
})])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(" + 0 + "," + height + ")")
.call(d3.axisBottom(x));
// text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width / 2) + " ," + (height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Date");
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return +d.y
})])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft()
.scale(y)
.tickFormat((d, i) => {
var hours = Math.floor(d / 60);
var minutes = d - hours * 60;
return hours.toString().padStart(2, 0) + ":" + minutes.toString().padStart(2, 0).padStart(2, 0);
}));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Time Asleep (Minutes)");
// Add line path
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) {
return x(d.date)
})
.y(function(d) {
return y(d.y)
})
);
// Add the scatterplot (data points)
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3)
// Add tooltip on hover
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.x + "<br/>" + d.label)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 30) + "px")
})
// Remove tooltip after hover
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
.transition()
.delay(function(d, i) {
return (i * 3)
})
.duration(2000)
.attr("cx", function(d) {
return x(d.date)
})
.attr("cy", function(d) {
return y(d.y)
});
div.tooltip {
position: absolute;
text-align: center;
width: 100px;
height: 30px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
I'm trying to generate a drawing based on mouse events and I'm noticing some interesting rendering behavior that I can't explain why it's happening that way. Here's a jsbin that shows this example: https://jsbin.com/qiqetoy/edit?html,output
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva#4.2.0/konva.min.js"></script>
<meta charset="utf-8" />
<title>Konva Free Drawing Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f0f0f0;
}
</style>
</head>
<body>
Tool:
<select id="tool">
<option value="brush">Brush</option>
<option value="eraser">Eraser</option>
</select>
<div id="container"></div>
<script>
var width = window.innerWidth;
var height = window.innerHeight - 25;
// first we need Konva core things: stage and layer
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
var layer = new Konva.Layer();
stage.add(layer);
var isPaint = false;
var mode = 'brush';
var lastLine;
stage.on('mousedown touchstart', function(e) {
isPaint = true;
var pos = e.pos;
lastLine = new Konva.Line({
stroke: '#df4b26',
strokeWidth: 5,
globalCompositeOperation:
mode === 'brush' ? 'source-over' : 'destination-out',
points: [pos.x, pos.y]
});
layer.add(lastLine);
});
stage.on('mouseup touchend', function() {
isPaint = false;
});
// and core function - drawing
stage.on('mousemove touchmove', function(e) {
if (!isPaint) {
return;
}
const pos = e.pos;
var newPoints = lastLine.points().concat([pos.x, pos.y]);
lastLine.points(newPoints);
layer.batchDraw();
});
var select = document.getElementById('tool');
select.addEventListener('change', function() {
mode = select.value;
});
const line = [{
"et": "md",
"x": 109,
"y": 94
}, {
"et": "mm",
"x": 110,
"y": 98
}, {
"et": "mm",
"x": 110,
"y": 103
}, {
"et": "mm",
"x": 110,
"y": 111
}, {
"et": "mm",
"x": 110,
"y": 116
}, {
"et": "mm",
"x": 110,
"y": 123
}, {
"et": "mm",
"x": 110,
"y": 129
}, {
"et": "mm",
"x": 110,
"y": 135
}, {
"et": "mm",
"x": 110,
"y": 141
}, {
"et": "mm",
"x": 110,
"y": 143
}, {
"et": "mm",
"x": 110,
"y": 147
}, {
"et": "mm",
"x": 110,
"y": 150
}, {
"et": "mm",
"x": 111,
"y": 152
}, {
"et": "mm",
"x": 114,
"y": 155
}, {
"et": "mm",
"x": 112,
"y": 154
}, {
"et": "mm",
"x": 117,
"y": 155
}, {
"et": "mm",
"x": 120,
"y": 155
}, {
"et": "mm",
"x": 123,
"y": 154
}, {
"et": "mm",
"x": 127,
"y": 151
}, {
"et": "mm",
"x": 131,
"y": 148
}, {
"et": "mm",
"x": 135,
"y": 145
}, {
"et": "mm",
"x": 139,
"y": 140
}, {
"et": "mm",
"x": 142,
"y": 137
}, {
"et": "mu"
}, ];
line.forEach(point => {
if (point.et === 'mm') {
stage.fire('mousemove', {
pos: {
x: point.x,
y: point.y
}
});
} else if (point.et == 'md') {
stage.fire('mousedown', {
pos: {
x: point.x,
y: point.y
}
});
} else if (point.et === 'mu') {
stage.fire('mouseup', {
pos: {
x: point.x,
y: point.y
}
});
}
});
</script>
</body>
</html>
Here's the interesting part of that drawing:
You can see above that there're a couple of sharp edges/lines that're drawn at the curve. I can't explain how this is happening. You can also clearly see that it's not 5px wide (the stroke width is set at 5px).
Can someone who's got more experience with canvas/konvajs drawing help explain what's happening here and what should I do to get rid of this behavior?
Thanks,
K
I think I figured out what the issue here is. The data seems to have an issue. Here's the JSBin that isolates the data in question. https://jsbin.com/nayado/edit?html,output
{
"et": "md",
"x": 110,
"y": 147
}, {
"et": "mm",
"x": 110,
"y": 150
}, {
"et": "mm",
"x": 111,
"y": 152
}, {
"et": "mm",
"x": 114,
"y": 155
}, {
"et": "mm",
"x": 112,
"y": 154
}, {
"et": "mm",
"x": 117,
"y": 155
}, {
"et": "mu"
},
The data seems to be out of order which is probably what's causing the issue. I need to now figure out how's the canvas generating touch events that seem to be out of order.
For example, I'd like to detect a coded string like "A5b1x" written in handwriting. So I'd either split it up manually so that I have an image of each character, or try to have Vision recognize it immediately. Neither is working for now, as I'm not sure how to specify that it's not a language (or specify that it's singular characters). This is what I typed in a Google compute instance:
gcloud ml vision detect-document "weblink to image"
No result for image of "g":
g
No result for image of "e": e
Result for image of "fxb3":fxb3
{
"responses": [
{
"fullTextAnnotation": {
"pages": [
{
"blocks": [
{
"blockType": "TEXT",
"boundingBox": {
"vertices": [
{
"x": 2433,
"y": 1289
},
{
"x": 1498,
"y": 1336
},
{
"x": 1468,
"y": 737
},
{
"x": 2403,
"y": 691
}
]
},
"confidence": 0.56,
"paragraphs": [
{
"boundingBox": {
"vertices": [
{
"x": 2433,
"y": 1289
},
{
"x": 1498,
"y": 1336
},
{
"x": 1468,
"y": 737
},
{
"x": 2403,
"y": 691
}
]
},
"confidence": 0.56,
"words": [
{
"boundingBox": {
"vertices": [
{
"x": 2433,
"y": 1289
},
{
"x": 1498,
"y": 1336
},
{
"x": 1468,
"y": 737
},
{
"x": 2403,
"y": 691
}
]
},
"confidence": 0.56,
"symbols": [
{
"boundingBox": {
"vertices": [
{
"x": 2433,
"y": 1289
},
{
"x": 2135,
"y": 1304
},
{
"x": 2105,
"y": 706
},
{
"x": 2403,
"y": 691
}
]
},
"confidence": 0.4,
"text": "\u0967"
},
{
"boundingBox": {
"vertices": [
{
"x": 2063,
"y": 1308
},
{
"x": 1788,
"y": 1322
},
{
"x": 1758,
"y": 723
},
{
"x": 2033,
"y": 710
}
]
},
"confidence": 0.62,
"text": "\u0967"
},
{
"boundingBox": {
"vertices": [
{
"x": 1750,
"y": 1323
},
{
"x": 1498,
"y": 1336
},
{
"x": 1468,
"y": 737
},
{
"x": 1720,
"y": 725
}
]
},
"confidence": 0.67,
"property": {
"detectedBreak": {
"type": "LINE_BREAK"
}
},
"text": "X"
}
]
}
]
}
]
}
],
"height": 2112,
"width": 4608
}
],
"text": "\u0967\u0967X\n"
},
"textAnnotations": [
{
"boundingPoly": {
"vertices": [
{
"x": 1467,
"y": 690
},
{
"x": 2432,
"y": 690
},
{
"x": 2432,
"y": 1335
},
{
"x": 1467,
"y": 1335
}
]
},
"description": "\u0967\u0967X\n",
"locale": "und"
},
{
"boundingPoly": {
"vertices": [
{
"x": 2433,
"y": 1289
},
{
"x": 1498,
"y": 1336
},
{
"x": 1468,
"y": 737
},
{
"x": 2403,
"y": 691
}
]
},
"description": "\u0967\u0967X"
}
]
}
]
}
The Google Cloud Vision API is not able to recognise single characters at this point. There is a feature request submitted with regard to character recognition here. Please star it so that you could receive updates about this feature request and do not hesitate to add additional comments to provide details of the desired implementation.
With respect to your question about recognising "coded" strings, the Vision API is able to do that. I have successfully tried to pass an image with fxb3 to the API and the results were good (here is image1 and image2). The response you are getting from the API is two consecutive unicode characters and "x". The quality of the writing is what is causing the response to be quite poor. The model for OCR is constantly being improved, but at this point it cannot properly detect what might be considered rather unclear handwriting.
Currently d3.layout.stack calculates the stacked-Y value based on the layers or series given.
Now I would like to generate stacked layout by both "X" value and by series. Anyway I am having 2-dimensional array of equal size.
For eg if my given data is,
var layers = [
{
"name": "apples",
"values": [
{ "x": 0, "y": 91},
{ "x": 1, "y": 290},
{ "x": 1, "y": 190},
{ "x": null, "y": null}
]
},
{
"name": "oranges",
"values": [
{ "x": 0, "y": 9},
{ "x": 1, "y": 49},
{ "x": 1, "y": 50},
{ "x": 2, "y": 220}
]
}
];
Here I have two layers ("apple","oranges"). My "x" values are [0,1,2];But If "X " values in the same layers looks same, then Y coordinate should be calculated based on the previous X value and series. Currently Y coordinate was calculated mapped by index.
Actual output for previous data:
var stacked_actual= [
{
"name": "apples",
"values": [
{ "x": 0, "y": 91,"y0":0},
{ "x": 1, "y": 290, ,"y0":0},
{ "x": 1, "y": 190, ,"y0":0},
{ "x": null, "y": null, ,"y0":0}
]
},
{
"name": "oranges",
"values": [
{ "x": 0, "y": 9,"y0":91},
{ "x": 1, "y": 49,"y0":290},
{ "x": 1, "y": 50,"y0":190},
{ "x": 2, "y": 220,"y0":0}
]
}
];
Expected output for previous data:
var stacked_expected= [
{
"name": "apples",
"values": [
{ "x": 0, "y": 91,"y0":0},
{ "x": 1, "y": 290 ,"y0":0},
{ "x": 1, "y": 190,"y0":190},
{ "x": null, "y": null ,"y0":0}
]
},
{
"name": "oranges",
"values": [
{ "x": 0, "y": 9,"y0":91},
{ "x": 1, "y": 49,"y0":480},
{ "x": 1, "y": 50,"y0":520},
{ "x": 2, "y": 220,"y0":0}
]
}
];
Is there any way to achieve this model?
Pls check the reference image
enter link description here