ApexChart column resize on zoom - javascript

I would like to resize the columns width when the user zoom on my chart. Could you suggest any method or option? I searched through the documentation but I didn't find any solution. Until now I tried by changing the bar width percentage, the responsive option and the stroke width. The stroke has the side effect of overlapping the bars but I need them separate
Before Zoom
After Zoom actual behaviour
After Zoom desired behaviour
Code used until now
<!DOCTYPE html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Bar with Custom DataLabels</title>
<link href="../../assets/styles.css" rel="stylesheet" />
<style>
#chart {
max-width: 650px;
margin: 35px auto;
}
</style>
<script>
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/promise-polyfill#8/dist/polyfill.min.js"><\/script>'
);
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/eligrey-classlist-js-polyfill#1.2.20171210/classList.min.js"><\/script>'
);
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/findindex_polyfill_mdn"><\/script>'
);
</script>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script>
// Replace Math.random() with a pseudo-random number generator to get reproducible results in e2e tests
// Based on https://gist.github.com/blixt/f17b47c62508be59987b
var _seed = 42;
Math.random = function () {
_seed = (_seed * 16807) % 2147483647;
return (_seed - 1) / 2147483646;
};
</script>
</head>
<body>
<div id="chart"></div>
<script>
var options = {
series: [
{
name: 'Net Profit',
data: [
95, 4, 48, 95, 71, 16, 44, 98, 75, 94, 28, 61, 76, 1, 54, 90, 19,
5, 37, 57, 88, 31, 41, 59, 27, 96, 20, 65, 84, 49, 67, 73, 78, 22,
75, 82, 67, 16, 4, 95, 84, 100, 76, 88, 66, 65, 14, 15, 46, 23,
48, 91, 23, 18, 32, 15, 71, 73, 28, 2, 61, 21, 63, 30, 35, 62, 29,
11, 71, 95, 43, 9, 59, 20, 85, 46, 59, 82, 4, 54, 60, 11, 15, 51,
34, 12, 19, 45, 2, 89, 3, 6, 60, 17, 57, 16, 90, 13, 46, 8,
],
},
{
name: 'Revenue',
data: [
97, 46, 49, 16, 11, 41, 36, 38, 16, 89, 71, 42, 68, 79, 52, 64,
40, 38, 29, 32, 50, 74, 88, 76, 65, 50, 66, 56, 42, 45, 46, 39,
29, 57, 68, 75, 34, 5, 100, 47, 79, 76, 53, 78, 39, 46, 13, 80,
22, 61, 67, 61, 17, 86, 65, 76, 82, 63, 27, 58, 64, 6, 100, 39,
25, 39, 14, 79, 12, 44, 9, 72, 63, 96, 27, 77, 70, 36, 100, 96, 5,
36, 89, 25, 67, 53, 61, 86, 64, 46, 52, 41, 56, 1, 93, 45, 49, 23,
35, 11,
],
},
{
name: 'Free Cash Flow',
data: [
20, 32, 92, 20, 36, 25, 4, 61, 77, 49, 11, 74, 15, 21, 49, 52, 11,
12, 12, 21, 78, 47, 95, 6, 68, 51, 66, 29, 67, 22, 100, 66, 42,
48, 8, 94, 87, 74, 43, 72, 90, 34, 66, 23, 82, 79, 64, 79, 89, 53,
25, 70, 25, 48, 43, 11, 17, 63, 30, 100, 79, 29, 41, 3, 99, 78,
93, 53, 12, 99, 30, 76, 30, 18, 5, 11, 16, 38, 49, 87, 21, 67, 41,
28, 13, 82, 1, 88, 79, 53, 3, 63, 61, 4, 5, 75, 83, 62, 17, 43,
],
},
],
annotations: {
points: [
{
x: 'Bananas',
seriesIndex: 0,
label: {
borderColor: '#775DD0',
offsetY: 0,
style: {
color: '#fff',
background: '#775DD0',
},
text: 'Bananas are good',
},
},
],
},
chart: {
height: 350,
type: 'bar',
},
plotOptions: {
bar: {
columnWidth: '100%',
},
},
dataLabels: {
enabled: false,
},
stroke: {
width: 2,
},
grid: {
row: {
colors: ['#fff', '#f2f2f2'],
},
},
xaxis: {
labels: {
rotate: -45,
},
categories: [
31, 48, 33, 88, 5, 91, 76,
],
tickPlacement: 'on',
},
yaxis: {
title: {
text: 'Servings',
},
},
fill: {
type: 'gradient',
gradient: {
shade: 'light',
type: 'horizontal',
shadeIntensity: 0.25,
gradientToColors: undefined,
inverseColors: true,
opacityFrom: 0.85,
opacityTo: 0.85,
stops: [50, 0, 100],
},
}
};
var chart = new ApexCharts(document.querySelector('#chart'), options);
chart.render();
</script>
</body>

this is not a complete answer but wanted to share my findings.
IMO the functionality the OP requests should be the default behavior.
regardless, I found that by using the zoomed event, we can find the x-axis range of the zoom.
then remove the data points from the series that are outside of that range and re-draw the chart.
which results in exactly the desired behavior.
however, this kills the ability to zoom out to original series.
to make this work, I think you would need to implement custom zoom buttons,
to allow keeping track of which action occurred, zoom in or out.
this would allow you to know which data points to include when the chart is re-drawn.
you can use the zoomX method to manually set the zoom level.
see following working snippet for zoom-in only functionality.
<!DOCTYPE html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Bar with Custom DataLabels</title>
<link href="../../assets/styles.css" rel="stylesheet" />
<style>
#chart {
max-width: 650px;
margin: 35px auto;
}
</style>
<script>
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/promise-polyfill#8/dist/polyfill.min.js"><\/script>'
);
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/eligrey-classlist-js-polyfill#1.2.20171210/classList.min.js"><\/script>'
);
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/findindex_polyfill_mdn"><\/script>'
);
</script>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script>
// Replace Math.random() with a pseudo-random number generator to get reproducible results in e2e tests
// Based on https://gist.github.com/blixt/f17b47c62508be59987b
var _seed = 42;
Math.random = function () {
_seed = (_seed * 16807) % 2147483647;
return (_seed - 1) / 2147483646;
};
</script>
</head>
<body>
<div id="chart"></div>
<script>
var data = [
{
name: 'Net Profit',
data: [
95, 4, 48, 95, 71, 16, 44, 98, 75, 94, 28, 61, 76, 1, 54, 90, 19,
5, 37, 57, 88, 31, 41, 59, 27, 96, 20, 65, 84, 49, 67, 73, 78, 22,
75, 82, 67, 16, 4, 95, 84, 100, 76, 88, 66, 65, 14, 15, 46, 23,
48, 91, 23, 18, 32, 15, 71, 73, 28, 2, 61, 21, 63, 30, 35, 62, 29,
11, 71, 95, 43, 9, 59, 20, 85, 46, 59, 82, 4, 54, 60, 11, 15, 51,
34, 12, 19, 45, 2, 89, 3, 6, 60, 17, 57, 16, 90, 13, 46, 8,
],
},
{
name: 'Revenue',
data: [
97, 46, 49, 16, 11, 41, 36, 38, 16, 89, 71, 42, 68, 79, 52, 64,
40, 38, 29, 32, 50, 74, 88, 76, 65, 50, 66, 56, 42, 45, 46, 39,
29, 57, 68, 75, 34, 5, 100, 47, 79, 76, 53, 78, 39, 46, 13, 80,
22, 61, 67, 61, 17, 86, 65, 76, 82, 63, 27, 58, 64, 6, 100, 39,
25, 39, 14, 79, 12, 44, 9, 72, 63, 96, 27, 77, 70, 36, 100, 96, 5,
36, 89, 25, 67, 53, 61, 86, 64, 46, 52, 41, 56, 1, 93, 45, 49, 23,
35, 11,
],
},
{
name: 'Free Cash Flow',
data: [
20, 32, 92, 20, 36, 25, 4, 61, 77, 49, 11, 74, 15, 21, 49, 52, 11,
12, 12, 21, 78, 47, 95, 6, 68, 51, 66, 29, 67, 22, 100, 66, 42,
48, 8, 94, 87, 74, 43, 72, 90, 34, 66, 23, 82, 79, 64, 79, 89, 53,
25, 70, 25, 48, 43, 11, 17, 63, 30, 100, 79, 29, 41, 3, 99, 78,
93, 53, 12, 99, 30, 76, 30, 18, 5, 11, 16, 38, 49, 87, 21, 67, 41,
28, 13, 82, 1, 88, 79, 53, 3, 63, 61, 4, 5, 75, 83, 62, 17, 43,
],
},
];
var options = {
series: data,
annotations: {
points: [
{
x: 'Bananas',
seriesIndex: 0,
label: {
borderColor: '#775DD0',
offsetY: 0,
style: {
color: '#fff',
background: '#775DD0',
},
text: 'Bananas are good',
},
},
],
},
chart: {
height: 350,
id: 'thisChart',
type: 'bar',
events: {
zoomed: function(chartContext, {xaxis, yaxis}) {
console.log('zoom', xaxis);
var newSeries = data.map(function (series) {
var newData = [];
series.data.forEach(function (row, index) {
if ((index >= xaxis.min) && (index <= xaxis.max)) {
newData.push(row);
}
});
return {
name: series.name,
data: newData
};
});
ApexCharts.exec('thisChart', 'updateSeries', newSeries, true);
}
}
},
plotOptions: {
bar: {
columnWidth: '100%',
},
},
dataLabels: {
enabled: false,
},
stroke: {
width: 2,
},
grid: {
row: {
colors: ['#fff', '#f2f2f2'],
},
},
xaxis: {
labels: {
rotate: -45,
},
categories: [
31, 48, 33, 88, 5, 91, 76,
],
tickPlacement: 'on',
},
yaxis: {
title: {
text: 'Servings',
},
},
fill: {
type: 'gradient',
gradient: {
shade: 'light',
type: 'horizontal',
shadeIntensity: 0.25,
gradientToColors: undefined,
inverseColors: true,
opacityFrom: 0.85,
opacityTo: 0.85,
stops: [50, 0, 100],
},
}
};
var chart = new ApexCharts(document.querySelector('#chart'), options);
chart.render();
</script>
</body>

Related

ASP.NET Populate Apex Chart using a String Array from Controller

I am trying to populate the chart data from within my controller. I think im on the right path by using a string array but ive also tried an int array and had the same result.
Currently the page shows this,
Picture of the chart live
And this is my output on the Dev Tools,
Picture of Dev Tools Console
Here is how I'm currently grabbing the data from my Model,
<script type="text/javascript">
$(document).ready(function () {
var error = #((TempData["errorMessage"] != null).ToString().ToLower());
if (error == true) {
console.log("hello world");
$('#errorModal').modal('show');
}
var EmbroideryTally = #Html.Raw(Json.Serialize(Model.EmbroideryTally));
console.log(EmbroideryTally);
var options = {
chart: {
height: 550,
type: "line",
stacked: false
},
colors: ["#E5AE10", "#6D77E0", "#15BE90", "#E15C79", "#68727A"],
series: [
{
name: "Embroidery",
data: []
}
//,
//{
// name: "Engraving",
// data: [108, 128, 98, 83, 193, 26, 55, 66, 79, 29, 37, 66, 154, 64, 104, 172, 34, 29, 37, 66, 44, 150, 50, 200]
//},
//{
// name: "Metal",
// data: [167, 108, 27, 177, 198, 12, 141, 172, 118, 175, 165, 52, 19, 157, 33, 42, 121, 176, 43, 14, 158, 80, 82, 125]
//},
//{
// name: "Uvp",
// data: [0, 54, 2, 13, 199, 46, 165, 183, 167, 7, 152, 185, 17, 27, 169, 25, 9]
//},
//{
// name: "Unknown",
// data: [93, 170, 52, 16, 126, 176, 82, 40, 132, 4, 62, 43, 35, 34, 195, 75, 122]
//}
],
stroke: {
width: [8, 8, 8, 8, 8]
},
plotOptions: {
bar: {
columnWidth: "20%"
}
},
xaxis: {
categories: [01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
},
labels: ['Embroidery', 'Engraving', 'Metal', 'UV', 'Unknown'],
noData: { text: 'Waiting for scans...', style: { color: '#ffffff' }}
};
var barCodeChart = new ApexCharts(document.querySelector("#barCodeChart"), options);
barCodeChart.render();
barCodeChart.updateSeries([{
name: "Embroidery",
data: [#Html.Raw(Json.Serialize(Model.EmbroideryTally))]
}]);
});
</script>
Here is my Model
namespace MyApp.Models
{
public class BarcodeViewModel
{
public BarcodeViewModel()
{
BarcodeScan = new BarcodeScan();
EmbroideryTally = new String[24];
}
public string[] EmbroideryTally { get; set; }
}
}
And heres my Controller (I've taken a good chunk of stuff out as its not important)
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind("BarcodeScanCode")] BarcodeScan barcode)
{
try
{
_barcodeViewModel.EmbroideryTally[0] = "21";
_barcodeViewModel.EmbroideryTally[1] = "14";
_barcodeViewModel.EmbroideryTally[2] = "64";
_barcodeViewModel.EmbroideryTally[3] = "150";
_barcodeViewModel.EmbroideryTally[4] = "32";
catch (Exception e)
{
Console.WriteLine("An issue has arisen:" + e.Message);
TempData["errorMessage"] = "An ERROR has occurred. Barcode not properly submitted. Barcode: " + barcode.BarcodeScanCode;
}
finally
{
await conn.CloseAsync();
}
return View("Index", _barcodeViewModel);
}

Do you know why executing the following expressions take more time than the same within a function call in javascript?

I'm trying to compare the difference in terms of execution time in JS between running some expressions sequentially versus running the same expressions within a function call.
Given the following code:
const t1 = Date.now();
console.log(Array.from(Array(500)).map((i, idx) => idx));
const t2 = Date.now();
console.log('t=', t2 - t1, 'ms', t2, t1);
function traverseArrAndPrint() {
console.log(Array.from(Array(500)).map((i, idx) => idx));
}
const t3 = Date.now();
traverseArrAndPrint();
const t4 = Date.now();
console.log('t=', t4 - t3, 'ms', t4, t3);
Now look at the output:
node a.js
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99,
... 400 more items
]
t= 8 ms 1620926365937 1620926365929
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99,
... 400 more items
]
t= 1 ms 1620926365938 1620926365937
Why would a function call take less time to execute than the sequential expressions before it?

Replace ArrayBuffer variable in JS chrome console

I am trying to replace the below ArrayBuffer a, from chrome console.
But when I do a = [43,43,....], it makes it an array. How can I initialise a new Arraybuffer ?
a: ArrayBuffer(86)
[[Int8Array]]: Int8Array(86) [-8, 6, 9, 91, 75, 107, -4, 2, 49, 51, -8, 1, -8, 2, 52, -4, 69, 10, 53, 10, 27, 57, 49, 56, 50, 56, 53, 54, 49, 48, 56, 56, 55, 64, 115, 46, 119, 104, 97, 116, 115, 97, 112, 112, 46, 110, 101, 116, 16, 1, 26, 20, 51, 69, 66, 48, 57, 69, 50, 48, 49, 51, 69, 65, 65, 67, 50, 56, 66, 51, 55, 54, 18, 4, 10, 2, 108, 111, 24, -32, -71, -91, -35, 5, 32, 1]
[[Int16Array]]: Int16Array(43) [1784, 23305, 27467, 764, 13105, 504, 760, -972, 2629, 2613, 14619, 14385, 14386, 13877, 12337, 14392, 16439, 11891, 26743, 29793, 24947, 28784, 28206, 29797, 272, 5146, 17715, 12354, 17721, 12338, 13105, 16709, 17217, 14386, 13122, 13879, 1042, 522, 28524, -8168, -23111, 1501, 288]
[[Uint8Array]]: Uint8Array(86) [248, 6, 9, 91, 75, 107, 252, 2, 49, 51, 248, 1, 248, 2, 52, 252, 69, 10, 53, 10, 27, 57, 49, 56, 50, 56, 53, 54, 49, 48, 56, 56, 55, 64, 115, 46, 119, 104, 97, 116, 115, 97, 112, 112, 46, 110, 101, 116, 16, 1, 26, 20, 51, 69, 66, 48, 57, 69, 50, 48, 49, 51, 69, 65, 65, 67, 50, 56, 66, 51, 55, 54, 18, 4, 10, 2, 108, 111, 24, 224, 185, 165, 221, 5, 32, 1]
byteLength: (...)
__proto__: ArrayBuffer
For just a new ArrayBuffer it would just be
a = new ArrayBuffer(length)
If you are needing a new buffer with given values you have to use a a typed array or view in order to manipulate its contents. For instance a Uint8Array:
buffer = new ArrayBuffer(4);
view = new Uint8Array(buffer);
view.set([1,2,3,4]);
//or
buffer = Uint8Array.from([1,2,3,4]).buffer;
TypedArray#set()
TypedArray.from()
You can initialize an ArrayBuffer with a particular type using something like a = Uint8Array.from([1, 2, 3]).

Javascript declare multiple variables with the same values

Maybe I should use some kind of loop or something. But I don't have any idea how to declare this, excluding do it manually.
Is there any solution that will have only a few lines for all of this. Because, there should be 100 variable, despite I only presented 5, I didn't want to type all night.
a1=1; a2=1; a3=1; a4=1; a5=1;
function myfn1() {
a1++;
//unique function code
}
function myfn2() {
a2++;
//unique function code
}
function myfn3() {
a3++;
//unique function code
}
function myfn4() {
a4++;
//unique function code
}
function myfn5() {
a5++;
//unique function code
}
Although this isn't answering your question, I think this approach will help you more in the long run (and probably in the short run too). Check out using an array, which is just a collection of data. Check out the following code.
var arr = [];
for(var i =0; i <= 100; i++){
arr[i] = i;
}
this gives you a collection like this [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100] that you can then manipulate, etc etc.
*edit or if you want them all to have the same value, then
var arr = [];
for(var i =0; i <= 100; i++){
arr[i] = 1;
}

How to do statistical classification on an array in javascript?

I've got a bunch of numbers in an array and I need to do some statistics on them. I need to know how many of each number there are in the array.
Here's the array:
myArray =
[2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 27, 27, 28, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 34, 34, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 40, 40, 40, 41, 41, 42, 42, 42, 42, 42, 42, 43, 43, 43, 44, 44, 44, 44, 44, 45, 45, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 55, 55, 55, 55, 55, 56, 57, 57, 57, 57, 57, 57, 57, 58, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64, 65, 65, 66, 66, 66, 67, 67, 67, 68, 68, 68, 69, 69, 69, 69, 69, 69, 70, 70, 71, 71, 71, 71, 71, 71, 71, 72, 73, 73, 73, 73, 74, 74, 74, 75, 75, 75, 76, 77, 78, 78, 79, 79, 80, 80, 81, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84, 85, 85, 85, 85, 85, 86, 86, 86, 86, 86, 86, 87, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91, 91, 92, 93, 94, 95, 95, 95, 95, 95, 96, 96, 96, 96, 97, 97, 99, 99, 99, 99, 99, 101, 101, 102, 102, 103, 103, 105, 105, 105, 106, 107, 107, 108, 108, 109, 109, 109, 109, 110, 112, 112, 113, 113, 113, 114, 114, 115, 116, 116, 117, 118, 120, 121, 121, 121, 122, 122, 123, 123, 123, 124, 124, 124, 124, 125, 126, 127, 128, 129, 130, 130, 131, 131, 131, 131, 132, 133, 133, 134, 134, 134, 136, 136, 136, 136, 137, 137, 137, 138, 138, 138, 139, 139, 139, 140, 141, 141, 142, 142, 143, 144, 144, 144, 144, 145, 150, 150, 153, 155, 159, 160, 160, 161, 162, 164, 164, 166, 176, 180, 180, 180, 181, 181, 187, 191, 192, 193, 194, 197, 200, 203, 211, 216, 224, 251, 280, 333]
Here's what I'm using to parse through it currently (which is not working very well):
for (var key in myArray){
var obj = myArray[key];
var count = 0;
while(obj < 30){
myArrayStats[0] = count;
obj++;
}
while(obj > 30 && obj < 40){
myArrayStats[1] = count;
obj++;
}
//etc....
}
Creating a new array using object literals would be much nicer and easier to use, but I'm not sure how to do it.
This just works whether your array is sorted or not, but it shouldn't be much slower than any algorithm that takes advantage of the fact that it is sorted anyways:
var myArrayStats = [];
for(var i = myArray.length; i--;)
myArrayStats[myArray[i]] = (myArrayStats[myArray[i]] || 0) + 1;
console.log(myArrayStats[6]); // Outputs 7
console.log(myArrayStats[10]); // Outputs 5
console.log(myArrayStats[20]); // Outputs 5
If you want to do this for only a portion of the original array than use slice() to get the portion of the array you want and then do the same thing as above on that array:
var mySubArray = myArray.slice(0,30);
var myArrayStats = [];
for(var i = mySubArray.length; i--;)
myArrayStats[mySubArray[i]] = (myArrayStats[mySubArray[i]] || 0) + 1;
console.log(myArrayStats[6]); // Outputs 7
console.log(myArrayStats[9]); // Outputs 7
console.log(myArrayStats[10]); // Outputs undefined
It sounds like you have equally spaced bins and want to count how many values fall in each. Since this question was tagged with jQuery, let's use a utility function from that to avoid an explicit loop to show another way to do things. (I guess PaulPRO's approach is superior though.)
function hist(values, min, max, numBins) {
var bins = [];
var range = max - min;
jQuery.each(values, function(i, value) {
var bin = Math.floor(numBins * (value - min) / range);
bin = Math.min(Math.max(bin, -1), numBins) + 1;
bins[bin] = (bins[bin] || 0) + 1;
});
return bins;
}
We can exercise the above code with the following:
function consoleHist(values, min, max, numBins) {
var bins = hist(values, min, max, numBins);
var step = (max - min) / numBins;
jQuery.each(bins, function(i, count) {
var lower = (i - 1) * step + min;
var upper = lower + step;
if (lower < min) {
lower = -Infinity;
}
if (upper > max) {
upper = Infinity;
}
console.log('[' + lower + ', ' + upper + '): ' + (count || 0));
});
}
consoleHist([-10, 0, 11, 29, 30, 59, 60, 1000], 0, 60, 2);
Produces the following output on the console:
[-Infinity, 0): 1
[0, 30): 3
[30, 60): 2
[60, Infinity): 2
myArray = [2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8,
8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11,
11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 14, 14]
for (var a = myArray, b = {}, i = 0; i < myArray.length; i++) b[a[i]] ? b[a[i]]++ : b[a[i]] = 1;
console.log(JSON.stringify(Object.keys(b)
.map(function(c) {
return [c, b[c]]
})));

Categories

Resources