So if I have a 2D array such as
const array = [
[1, 2, 3, 4, 5],
[9, 8, 7, 6, 5],
[1, 8, 3, 6, 5],
[9, 8, 7, 6, 5],
[1, 8, 3, 6, 5],
[1, 2, 3, 4, 5]
];
which could for the point of the question be any size, square or not square.
and I want to extract 3x3 arrays out of it, for instance at 1,1 that would be const sub = [[8, 7, 6], [8, 3, 6], [8, 7, 6]]. So far so good - I can do this. However I am flattening the 2D array so that its represented as a 1D array (long story as to why), i.e
const array = [1, 2, 3, 4, 5, 9, 8, 7, 6, 5, 1, 8, 3, 6, 5, 9, 8, 7, 6, 5, 1, 8, 3, 6, 5, 1, 2, 3, 4, 5];
What I'm trying to do is extract the same (or any) 3x3 array out of this but while its represented as a 1D array, so I would then get back [8, 7, 6, 8, 3, 6, 8, 7, 6].
I almost got there, however I made an error of only working with arrays that were 9x9 and always extracting 3x3 subsets which mean that my solution only works for that specific case, and the more I stare at my solution, the more I cannot work out what the generic solution would look like.
My solution:
const extractSubsetFrom1D = (array, subHeight, subWidth, startRow, startCol) => {
const kWH = subWidth * subHeight
const subset = array.slice(((((kWH - 2) * startRow) + startCol) * kWH), ((((kWH - 2) * startRow) + startCol) * kWH) + kWH)
return subset
}
In my case subHeight and subWidth were always equalling 3 respectively, and as the array itself was always 9x9 I believe I accidentally stumbled on a solution for that specific case as they divide nicely into each other.
To be clear my solution will fail for the startRow = 1 startCol = 0 for the provided array (it works for the startRow = 0 scenario
It's not entirely clear to me how you came to your current implementation, but I can at least tell:
✅ You correctly determined the size of the sub grid array to return (kWH)
❌ You incorrectly assume you can slice out a sub grid as one continuous part of the original 1d array
🟠 The calculation of the first element seems kind-of-right but is actually wrong (probably because of the previous mistake)
From (y,x) to i
Let's start from scratch and work our way up to a nice one liner.
In a 2d-array, you can get a cell's value by doing:
cellValue = grid2d[y][x]
Once you flatten it, you'll need to do:
cellValue = grid1d[y * GRID_WIDTH + x]
y * GRID_WIDTH takes you to the start of the right row, and + x gets you to the right column.
As you can see, you need to know the original grid's size before you can even query a specific cell. That means your extract function would need an argument to pass the original width (or, if the grids are guaranteed to be square, you can do Math.sqrt(array.length).
A slice per row
Let's use this math to find the indices of a 2x2 sub grid at (1,1) extracted from a 3x3 source grid:
0 1 2
3 [4][5]
6 [7][8]
As you can see, the resulting indices are [4,5,7,8]. There is no way to slice these indices out of the source array directly because we don't want to include the 6.
Instead, we can use a nested loop to skip the gaps between our rows:
const to1d = (x, y, w) => y * w + x;
const extractSubGrid1D = (grid, gridWidth, x, y, w, h) => {
const yTop = y;
const yBottom = y + h
const xLeft = x;
const xRight = x + w;
const subgrid = [];
for (let y = yTop; y < yBottom; y += 1) {
for (let x = xLeft; x < xRight; x += 1) {
const index = to1d(x, y, gridWidth);
subgrid.push(grid[index]);
}
}
return subgrid;
}
const originalGrid = [
0, 1, 2,
3, 4, 5,
6, 7, 8
];
console.log(
extractSubGrid1D(originalGrid, 3, 1, 1, 2, 2)
)
Once you get a feel for the logic, feel free to refactor.
The other way around
To go from a 1d-index to a 2d coordinate, you can do:
x = i % w
y = Math.floor(i / w)
Applying this logic, you can also fill your sub grid like so:
Create a new array of the right size
For each of its indices, determine the original grid's (x, y) coordinate
Transform that coordinate back to an index to query the original grid with
const to1d = (x, y, w) => y * w + x;
const extractSubGrid1D = (grid, gridWidth, x, y, w, h) => Array.from(
{ length: w * h },
(_, i) => grid[to1d(x + i % w, y + Math.floor(i / w), gridWidth)]
)
const originalGrid = [
0, 1, 2,
3, 4, 5,
6, 7, 8
];
console.log(
extractSubGrid1D(originalGrid, 3, 1, 1, 2, 2)
)
I have one GeoJSON with about 100 polygons. I need a way to filter several polygons and dissolve them to put on a Leaflet map. Instead of creating a new GeoJSON with the dissolve polygons I want to try to use Turf.js, try to follow their examples but result are blank and no errors. What is missing or is it a wrong approach?
var poly = new L.layerGroup();
$.getJSON("/geodata/polygons.geojson", function(json) {
L.geoJson(json, {
turf: function(feature, latlng){
var select = (feature.properties.id >= 65 && feature.properties.id <= 68);
features = turf.featureCollection([select], {combine: 'yes'});
var dissolved = turf.dissolve(features, {propertyName: 'combine'}).addTo(poly);
}
});
});
Example from turf website for dissolve:
var features = turf.featureCollection([
turf.polygon([[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]], {combine: 'yes'}),
turf.polygon([[[0, -1], [0, 0], [1, 0], [1, -1], [0,-1]]], {combine: 'yes'}),
turf.polygon([[[1,-1],[1, 0], [2, 0], [2, -1], [1, -1]]], {combine: 'no'}),
]);
var dissolved = turf.dissolve(features, {propertyName: 'combine'});
I want to set minimum and maximum values in an axis in highcharts. I have tried min, max, ceiling and floor attributes. They change the range of axis.
Link to the JS Fiddle
yAxis: {
floor: 0,
ceiling: 40,
title: {
text: 'Percentage'
}
},
series: [{
data: [0, 1, -5, 2, 3, 5, 8, 5, 50, 14, 25, 54]
}]
I want the data to be modified automatically based on the minimum/floor and maximum/ceiling values declared in the axis declaration.
For example, if in the above mentioned case, the last and last 4th elements of series should be automatically modified to 40 and the 3rd element to 0.
Is there any attribute of highchart using which I can achieve this without manually checking all the series elements to fall between the min and max values?
No I don't think there is no such a function. Highcharts does not alter your data, it just changes what is displayed. But checking for values beneath or above certain thresholds is really simple:
var data = [0, 1, -5, 2, 3, 5, 8, 5, 50, 14, 25, 54];
var max = 40;
var min = 0;
// clamping "by hand"
console.log( data.map(function(d) { return Math.max(min, Math.min(max, d)); }) );
If you use a library like lodash: these often provide a clamp function so you could write
console.log( _.map(data, function(d) { return _.clamp(d, min, max) }
I want to add dataLabels labels for s1 donut and dataLabels percent or no label for s2.How can i do that?
function drawDonut(chartId){
var s1 = [['a',6], ['b',8], ['c',14], ['d',20]];
var s2 = [['e', 6], ['f', 8], ['g', 14], ['h', 20]];
var plot = $.jqplot(chartId,[s1,s2], {
seriesDefaults: {
// make this a donut chart.
renderer:$.jqplot.DonutRenderer,
rendererOptions:{
// Donut's can be cut into slices like pies.
sliceMargin: 0,
dataLabelThreshold: 0,
// Pies and donuts can start at any arbitrary angle.
startAngle: -90,
showDataLabels: true,
// By default, data labels show the percentage of the donut/pie.
// You can show the data 'value' or data 'label' instead.
dataLabels: 'label'
}
}
}
That's because you're setting showDataLabels in seriesDefaults. Check out http://www.jqplot.com/docs/files/jqPlotOptions-txt.html for how to set options per series.
Ok I am using Flotr2 to make a graph, and apparently the only way to get the curved line between two coordinates is to add a new coordinate every say 0.1, between two different coordinates.
So. I have data = [[1, 2], [2, 3]];
Where it is [[x, y], [x, y]].
How would i loop through the coordinates, and do like.. [1, 2], [1.1. 2.1], [1.2, 2.2] etc..?
I need to do this in jquery or javascript, doesnt matter which one.
Use a for-loop to iterate from x_min to x_max, adding 0.1 with each iteration. You can then generate coordinates by pushing a new array composed of the current values for x and y to your current array.
var data = [[1, 2], [2, 3]];
var x_min = data[0][0];
var x_max = data[1][0];
var initial = data[0];
var iteration = 0.1;
data.length = 0;
for (var i = 0; i < (x_max-x_min); i+=iteration) {
data.push([initial[0]+i, initial[1]+i]);
}
console.log(data)