I have a .csv file that I am pulling into d3 and transforming to work for my assignment. I have one column that has the elements as percentages "xx.x%". I would like to remove the percentage sign, so that I am left with just "xx.x" for each element in that column. I know the slice() function needs to be used, and that I will be taking the values from 1 - length-2, but I'm not sure how to write the function. I'll include the other cleanup code so that you can get a feel for the file I'm working with. Thank you!!
function cleanup(raw_data) {
// remove unneeded columns
var data = [];
raw_data.forEach(function(obj){
if (obj["County"] == "Dutchess" && obj["Month"] == 12)
data.push(obj)
});
data.forEach(function(obj) {
delete obj["2012 Census Population"];
delete obj["Population 18+ Estimate"];
delete obj["OPO"];
delete obj["Location"];
delete obj["Month"];
delete obj["County"];
delete obj["Chart Month"];
});
data.sort(function (a,b) {
return a["Year"] > b["Year"];
});
return data;
}
Have you tried:
data.forEach(function(obj) {
obj["yourCol"] = obj["yourCol"].slice(0, -1);
});
Related
I am trying to remove duplicate items from a collection that I request via an API in Laravel.
This is my code:
computed: {
// slice the array of data to display
filteredList() {
/* NEW PART */
var tips = this.dublicate;
/* END NEW PART */
tips = this.items.filter(item => {
return item.tip.toLowerCase().includes(this.search.toLowerCase())
})
return tips.slice(0, this.display);
},
dublicate() {
var filtered_array = [];
for(var i =0; i < this.items.length; i++) {
if(this.items[i].tip.toLowerCase() != this.items[i+1].tip.toLowerCase()) {
filtered_array.push(this.items[i])
}
}
return filtered_array;
}
}
}
If I remove the code within the NEW PART comments, everythin works fine.
In the NEW PART I am trying to remove duplicate content, based on the items tip attribute.
If the tip attribute is the same as the next items tip attribute, it should be excluded from the tips array, which is returned as a v-for="tips in filteredList".
However, I just get an empty array with this new part. What am I doing wrong?
I get the following from Vue Devtools:
dublicate:"(error during evaluation)"
filteredList:"(error during evaluation)"
An example data from items, that are from an API request:
(This is the data that I get, when I dont try to remove duplicates, which works)
As this is in VueJS, I cant use the answer provided here.
You are looking past the end of the array with i + 1. You need to push the last item without looking for the one after it (because there isn't one). I think using filter is more straightforward than building an array with a for loop.
dublicate() {
return this.items.filter((a, i) =>
i === this.items.length - 1 ||
a.tip.toLowerCase() !== this.items[i + 1].tip.toLowerCase()
);
}
I want to add & delete datasets from chart.js using checkboxes.
Right now I am adding using this:
var ds1 = {
label: ..
data: .. etc
};
data.datasets.push(ds1);
When I uncheck any of the checkboxes, it's always deleting the last dataset added, which is not necessary the one of the checkbox.
I'm using data.datasets.pop(ds1); to remove the when a checkbox is clicked.
If you're removing using data.datasets.pop(ds1) you'll never get the result you're looking for. The dataset property is an array, so let's just focus on arrays and ignore Chart.js.
First issue is that the pop() method of the Arrays type does not take an argument, so providing which element you want to remove is irrelevant. Pop() will always remove the last element from an array.
To remove a specific element from the array you need to use the splice() function.
Let's say that ds1 is the element you want to remove.
let removalIndex = data.datasets.indexOf(ds1); //Locate index of ds1
if(removalIndex >= 0) { //make sure this element exists in the array
data.datasets.splice(removalIndex, 1);
}
This will delete the 1 record in the array starting at the index we located ds1.
If you look at ChartJS' internal object chart.data.datasets, the datasets are distinguishable by the label you gave when initially adding the datasets (it's weird that there's no ID):
So it's really just a matter of filtering out an object from the array by that Label, and calling chart.update();.
// Filter out and set back into chart.data.datasets
chart.data.datasets = chart.data.datasets.filter(function(obj) {
return (obj.label != targetLabel);
});
// Repaint
chart.update();
Thank you JNYRanger!
It got like this:
...
$(document).ready(function() {
$('#ind4').change(function(){
if (this.checked) {
graph.data.datasets.push(ds4);
graph.update();
} else {
let removalIndex = graph.data.datasets.indexOf(ds4);
graph.data.datasets.splice(removalIndex, 1);
graph.update();
}
});
});
$(document).ready(function() {
$('#ind5').change(function(){
if (this.checked) {
graph.data.datasets.push(ds5);
graph.update();
} else {
let removalIndex = graph.data.datasets.indexOf(ds5);
graph.data.datasets.splice(removalIndex, 1);
graph.update();
}
});
I just added graph.data.... (when graph is the var of my chart) and graph.update() by the end of every action.
Actually you can add an ID in your dataset :
var ds1 = {
label: ..
data: ..
id : 'myId'
};
data.datasets.push(ds1);
It will not affect your dataset or your chart in anyway
Then you can find and delete (or update) :
data.datasets.find((dataset, index) => {
if (dataset.id === 'myId') {
data.datasets.splice(index, 1);
return true; // stop searching
}
});
myChart.update();
I have data of this form (simplified, but assume 20 columns between Admin and Mining):
Date,Series,Admin,Mining,CPI
1990,Ordinary Time Earnings,20,30,96
1991,Ordinary Time Earnings,22,33,100
1990,Total Earnings,25,38,96
1991,Total Earnings,29,43,100
Which I separate out into two series like this:
d3.csv("avgearnings_v1_1.csv", function(error, data) {
if (error) throw error;
OrdinaryTimeEarnings = data
.filter(function(d) {
if(d.Series == 'Ordinary Time Earnings')
return d;
});
TotalEarnings = data
.filter(function(d) {
if(d.Series == "Total Earnings")
return d;
});
And can get that to display on a graph without any issue. What I want to do next is create two more series:
OrdinaryTimeEarningsReal = OrdinaryTimeEarnings;
TotalEarningsReal = TotalEarnings;
And then recalculate those new series. Basically:
For any column that is not Date/Series/CPI
Take the CPI value for that year
Individually divide each of the Mining-Admin columns by the CPI and multiply by 100.
So: New Value = ([Old Value]/[CPI])*100
My code is terrible but I can get the correct values using this:
OrdinaryTimeEarningsReal
.forEach(function (z,i) {
var CPI = z["CPI"];
d3.map(z, function(b) {return b;})
.forEach(function (c) {
if(c !== "Date" && c !== "Series" && c !== "CPI" )
OrdinaryTimeEarningsReal[i][c] = ((z[c])/(CPI))*100;
});
});
But, when I do this it is somehow also updating the original OrdinaryTimeEarnings series, such that they equal each other and the original data in OrdinaryTimeEarnings is lost.
I'm not sure whether it's the fact I'm using the bare object (while iterating within it, eek!) or that the code above is actually changing the values in the original data object (and all 4 of the series I've created after are just references to it).
Either way, I can't work it out! I've tried a fair few different syntax forms but can't work it out. Help would be greatly appreciated to achieve this.
If you indeed use this code to "duplicate" your arrays:
OrdinaryTimeEarningsReal = OrdinaryTimeEarnings;
TotalEarningsReal = TotalEarnings;
then you mentioned it right, when you said that they reference the same object. In JavaScript, arrays are mutable, and using the code above you just created 2 new variables with a reference to the existing array in the memory.
In order to deep clone your array of objects, use this method:
OrdinaryTimeEarningsReal = JSON.parse(JSON.stringify(OrdinaryTimeEarnings));
TotalEarningsReal = JSON.parse(JSON.stringify(TotalEarnings));
This will create duplicates of the array and assign them to the new variables, so that when you'll edit them, the initial arrays will remain unaffected.
Now, regarding your code, it's a bit too complex. If I understood correctly what are you trying to achieve, you could simplify it as follows:
OrdinaryTimeEarningsReal
.forEach(function (z,i) {
for (var c in z) {
if (z.hasOwnProperty(c) && c !== "Date" && c !== "Series" && c !== "CPI" )
z[c] = z[c] / z.CPI * 100;
});
});
Good luck!
If I understand correctly :
data.forEach(function(d) {
for (var key in d) {
if (key !== 'Date' && key !== 'Series' && key !== 'CPI') {
d['new' + key] = (d[key] / d.CPI) * 100;
}
}
})
console.log(data)
I have added new onto the new attributes so the new admin value is newAdmin
Implemented fiddle : https://jsfiddle.net/thatOneGuy/9ywLytjf/
i'm trying to implement a function on Datatables that has to look up the table data, do a regex and then, if it returns true, then, when i click on the header to sort data, it will sort it by the last 5 digits, ignoring the letters that comes up in the beginning of the string.
i have the following code
$.fn.dataTable.ext.oSort['custom'] = function (settings, col) {
return this.api().column(col, {order: 'index'}).nodes().map(function (td, i) {
var string= $(td).html();
return $.trim(string.substr(string.length - 4));
});
}
$.fn.dataTable.ext.type.detect.push(
function (value) {
var test = (/PT\d/).test(value);
return test ? 'custom' : null;
}
);
this is for a custom data that has lots of trash in the beggining, like country code and stuff, but the data order is only by the last 5 digits.
i've been searching all over i'm having a hard time to understand and debug. Debuguing the detect works, if 1 put an alert, it gives-me true when it hits the colum with the values i want, but the custom sorting doesn't work, can anybody help?
hope i'm clear about it
thanks
actualy i solved it myself.
the problem was that DataTables needs to make the entire column return true, so, if the regex fails in any value in the same column it fails.
$.fn.dataTable.ext.type.detect.unshift(
function (d) {
var pt = (/^PT\d/).test(d);
var es= (/^ES\d/).test(d);
var en= (/^EN\d/).test(d);
if (pt || es|| en) {
return 'custom'
} else {
return false;
}
}
);
$.fn.dataTable.ext.type.order['custom-pre'] = function (string) {
return $.trim(string.substr(string.length - 4));
};
so this is my last code used and it works just fine.
i'm posting it so anybody with the same problem can have a clue to solve some future problem :)
I have a two dimensional JS array in which some rows are useless and needs to be deleted;
In particular I need to delete the rows that are embedded in other rows (by saying that row B is embedded in row A I mean not just that A is a superset of B, but that A contains all the elements in B, in sequence and in the same order)
EX. I have:
var matrix = [
["User","Shop","Offer","Product","File"],
["User","Shop","File"],
["User","Shop","Map"],
["User","Shop","Promotion"],
["User","Shop","Offer","Product","Reservation"],
["User","Group","Accesslevel"],
["User","Group"],
["User","Reservation"],
["User","Shop"],
["User","Shop","Offer","Product","Markers"]
];
In this example the second row (["User","Shop","File"]) should NOT be deleted (all its elements are in the first row, but not consecutive);
Row 7 (["User","Group"]) should be deleted because is embedded in the 6th (["User","Group","Accesslevel"]) and also row 9 (["User","Shop"]) because is embedded in many others..
I'm looking for a possible efficient algorithm to check if an array is embedded in another one;
I will use this in nodejs.
This should do the trick.
// Is row2 "embedded" in row1?
function embedded(row1, row2) {
return row2.length < row1.length &&
row2.every(function(elt, i) { return elt === row1[i]; });
}
//filter out rows in matrix which are "embedded" in other rows
matrix.filter(function(row) {
return !matrix.some(function(row2) { return embedded(row2, row); });
});
here is a solution which I used few days ago for the same purpose but on the client side, This would also work on node server.
http://jsfiddle.net/8wLst3qr/
I have changed the program according to your needs,
What I have done here is,
some initialisation,
var matrix = [
["User","Shop","Offer","Product","File"],
["User","Shop","File"],
["User","Shop","Map"],
["User","Shop","Promotion"],
["User","Shop","Offer","Product","Reservation"],
["User","Group","Accesslevel"],
["User","Group"],
["User","Reservation"],
["User","Shop"],
["User","Shop","Offer","Product","Markers"]
];
var tempArr=matrix;
here are the steps
convert the array of arrays to an array of strings-(this is because you need to clear the redundant data only if it is in the same order), code as follows.
var json=[];
for(k=0;k<tempArr.length;k++)
{
json[k]=tempArr[k].toString();
}
and then match the index of each string in other strings in the array, if matches, check the string whose length is less and delete
it.
for(k=0;k<json.length;k++)
{
for(l=0;l<json.length;l++)
{
console.log("val l="+json[l]+"val k="+json[k]+"value="+json[l].indexOf(json[k]));
console.log("k="+k+";l="+l);
if(k!=l && (json[k].indexOf(json[l]) !=-1))
{
console.log("removing");
console.log("removing");
if(json[k].length>json[l].length)
{
json.splice(l, 1);
}
else
{
json.splice(k, 1);
}
}
}
}
hope it helps,
edit-sorry you would require to check the console.log for the output on fiddle