My json look like this
[ {
"type": "quant",
"name": "horizontalError",
"prop": [
0.12,
12.9
]
},
{
"type": "categor",
"name": "magType",
"prop": [
"ml",
"md",
"mb"
]
}]
I have created drop-down menu using the "name" property of each object. Now I am trying to create checkboxes if the type is categor and slider if the type is quant based on the name the user chooses in the drop down menu
I have come so far but stuck here--
d3.json("hashmap.json", function(error,data) {
if(error) {console.log("error fetching data");}
var hashap = data;
var dropDown = d3.select("#sel").selectAll("option").data(hashap).enter().append("option").text(function(d) { return d.name} ).attr("value",function(d, i) {
return i;});
d3.select("#sel").on("change", function() {
var checkSlider = d3.select("#checkSlider"); // clearing previous checkbox or slider
if(hashap[this.value].type == "categor") {
console.log(hashap[this.value].prop.length);
for(var i =0; i >= hashap[this.value].prop.length; i++){
checkSlider.append("input").attr("type","checkbox");
checkSlider.append("label").text(hashap[this.value].prop[i]);
}
}
else {
checkSlider.append("input").attr("type","range").attr("min", hashap[this.value].prop[0]).attr("max", hashap[this.value].prop[1]);
checkSlider.append("label").text(hashap[this.value].name);
}
});
I have added comments in the code. Hope this helps
var hashap = [ {
"type": "quant",
"name": "horizontalError",
"prop": [
0.12,
12.9
]
},
{
"type": "categor",
"name": "magType",
"prop": [
"ml",
"md",
"mb"
]
}];
// creating drop down
var dropDown = d3.select("#dropdown").selectAll("option").data(hashap).enter().append("option").text(function(d) { return d.name} ).attr("value",function(d, i) {
return i;});
// adding onchange function
d3.select("#dropdown").on("change", function() {
var checkSlider = d3.select("#checkSlider").html(""); // clearing previous checkbox or slider
if(hashap[this.value].type == "categor") {
checkSlider.append("input").attr("type","checkbox");
checkSlider.append("label").text(hashap[this.value].name);
}
else {
checkSlider.append("input").attr("type","range").attr("min", 0).attr("max", 100);
checkSlider.append("label").text(hashap[this.value].name);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<select id="dropdown" ></select>
<div id="checkSlider"><div>
Related
Example JSON file:
[
{
"discordId": "9273927302020",
"characters": [
{
"name": "Rare_Character",
"value": 1
},
{
"name": "Ultra_Rare_Character",
"value": 1
}
]
}
]
Let's just say for example I ran this simple gacha and got 4 characters:
let i = 1
var picks = []
while(i <= 4){
const { pick } = gacha.simple(alpha)
picks.push(pick)
i++
}
Now, picks has an array like this:
[
{
"name": "Common_Character"
},
{
"name": "Ultra_Rare_Character"
},
{
"name": "Common_Character"
},
{
"name": "Rare_Character"
}
]
How do I increment the value in My Example JSON file based on the name from what I got in my gacha results picks while ignoring the Common_Character and only passing those Rare and Ultra_Rare ones?
I've tried filtering them like this:
var filter = picks.filter(t => t.name === 'Rare_Character' || t.name === 'Ultra_Rare_Character')
Now I don't know how to increase those values in my JSON file and what if in the gacha results I got two Rare_Characters or Ultra_Rare_Character
I'm using fs to read my JSON file but I just don't know the logic to increase values
const src = [
{
"discordId": "9273927302020",
"characters": [
{
"name": "Rare_Character",
"value": 1
},
{
"name": "Ultra_Rare_Character",
"value": 1
}
]
}
];
const gacha = [
{
"name": "Common_Character"
},
{
"name": "Ultra_Rare_Character"
},
{
"name": "Common_Character"
},
{
"name": "Rare_Character"
}
];
const updateValues = (src, gacha) => {
const gachaSums = gacha.reduce((collector, current) => {
collector[current.name] = (collector[current.name] | 0) + 1;
return collector;
}, {});
src.characters.forEach(srcChar => {
gachaSums[srcChar.name] = srcChar.value + (gachaSums[srcChar.name] | 0);
});
src.characters = Object.entries(gachaSums).map(([key, value]) =>
({ name: key, value: value })
);
return src;
}
console.log(updateValues(src[0], gacha));
Maybe this version could help
there is a list of users
filterData = [
{
"position":"lawyer",
"department_positions":[],
"group_positions":[
{"group":{"id":2,"code":"234","name":"group1"},"lead":false},
{"group":{"id":1,"code":"123","name":"group12"},"lead":true}
]
},
{
"position":"director",
"department_positions":[
{"department":{"id":3,"code":"333","name":"subDep"},"lead":false}
],
"group_positions":[
{"group":{"id":2,"code":"234","name":"group1"},"lead":false},
{"group":{"id":1,"code":"123","name":"group12"},"lead":true}
]
},
{
"position":"director",
"department_positions":[],
"group_positions":[]
}
]
and list of filters
categories = {
"position":["lawyer","director"],
"group_positions":["group1","group12"],
"department_positions":["generalDep", "subDep"]
}
It is necessary to filter users taking into account the fact that several filters can be selected at the same time. For example, i want to find user with position = "director" and AND group_positions = "group1" AND department_positions = "subDep"
my code doesn't allow filtering by multiple conditions. how can i fix it?
this.filter = this.filterData.filter(item => {
for (let key in this.categories) {
if (item[key].find(el =>
this.categories[key].includes(
el.group?.name || el.department?.name
)
)) {
return true
}
}
return false
})}
This is a good place to employ an es6 class to give behavior to the object being filtered. Augment each object to determine if it matches the "category" object.
(from the example data, this assumes the OP is looking for a "product of sums" match: for all of the category keys match at least one of the category values)
class FilterMe {
constructor(item) {
Object.assign(this, item);
}
namesForKey(key) {
switch (key) {
case 'position':
return [this.position]; // always answer an array
case 'group_positions':
return this.group_positions.map(gp => gp.group.name);
case 'department_positions':
return this.department_positions.map(dp => dp.department.name);
default:
return [];
}
}
// return true if a single filter key-value pair is matched
matchesFilterKeyValue(filterKey, filterOptions) {
const myNames = this.namesForKey(filterKey);
const matches = filterOptions.filter(e => myNames.includes(e));
return matches.length > 0;
}
// return true if all filter key-values pairs are matched
matchesFilter(filter) {
return Object.entries(filter).every(keyValue => {
return this.matchesFilterKeyValue(...keyValue);
})
}
}
const filterData = [{
"position": "lawyer",
"department_positions": [],
"group_positions": [{
"group": {
"id": 2,
"code": "234",
"name": "group1"
},
"lead": false
}, {
"group": {
"id": 1,
"code": "123",
"name": "group12"
},
"lead": true
}]
},
{
"position": "director",
"department_positions": [{
"department": {
"id": 3,
"code": "333",
"name": "subDep"
},
"lead": false
}],
"group_positions": [{
"group": {
"id": 2,
"code": "234",
"name": "group1"
},
"lead": false
}, {
"group": {
"id": 1,
"code": "123",
"name": "group12"
},
"lead": true
}]
},
{
"position": "director",
"department_positions": [],
"group_positions": []
}
]
const categories = {
"position": ["lawyer", "director"],
"group_positions": ["group1", "group12"],
"department_positions": ["generalDep", "subDep"]
}
// convert the filterData to the objects and test them...
let objects = filterData.map(d => new FilterMe(d));
let matches = objects.filter(o => o.matchesFilter(categories))
console.log(matches)
You can try something like this:
let filtered = example.filter(item => {
let valid = false
if (item.includes('something')) {
valid = true
}
if (!valid) {
// check second condition
}
return valid
})
Use a temporary placeholder so you don't immediately have to return true/false.
I get an input like this:
input 1:
{
"name": "Ben",
"description": "Ben",
"attributes": [
{
"type": "Background",
"value": "Default"
},
{
"type": "Hair-color",
"value": "Brown"
}
]
}
input 2
{
"name": "Ice",
"description": "Ice",
"attributes": [
{
"type": "Background",
"value": "Green"
},
{
"type": "Hair-color",
"value": "White"
}
]
}
input 3
{
"name": "Itay",
"description": "Itay",
"attributes": [
{
"type": "Background",
"value": "Default"
},
{
"type": "Hair-color",
"value": "Brown"
}
]
}
What I want to do is count the amount of each type of background and each type of hair-color appearing.
(These are sample examples and in reality there are more types and different values)
Let's say in these examples we have 2 objects that have a background as default then I want to have a count of that like so:
export interface TraitCount {
value: string,
count: number
}
export interface CountOfEachAttribute {
trait_type: string,
trait_count: traitCount[] | null,
total_variations: number
}
I want the most effective code because there are other aspects to the code, in addition it will run on 5-10k queries not just three, so needs
to run in good times too :D
(It's similar to my other question done with python but now I need it in js also)
Atm it's something like this:
(Apart of a much bigger code so keep that in mind)
setInitalCountOfAllAttribute( state, { payload }: PayloadAction<CountOfEachAttribute[] | null> ) {
if (payload === null) {
state.countOfAllAttribute = null;
} else {
state.countOfAllAttribute = payload;
}
},
setCountOfAllAttribute(state, { payload }: PayloadAction<Attribute>) {
if (state.countOfAllAttribute !== null) {
state.countOfAllAttribute.map(
(countOfEachAttribute: CountOfEachAttribute) => {
// Find the trait type
if (countOfEachAttribute.trait_type === payload.trait_type) {
// initiate the trait count array to store all the trait values and add first trait value
if (countOfEachAttribute.trait_count === null) {
const new_trait_count = { value: payload.value, count: 1 };
countOfEachAttribute.trait_count = [new_trait_count];
countOfEachAttribute.total_variations++;
}
// Trait array already existed.
else {
// Check if value already present or not
const checkValue = (obj: any) => obj.value === String(payload.value);
const isPresent = countOfEachAttribute.trait_count.some(checkValue)
const isPresent2 = countOfEachAttribute.trait_count.find((elem: any) => elem.value === String(payload.value))
// Value matched, increase its count by one
if (isPresent2) {
countOfEachAttribute.trait_count &&
countOfEachAttribute.trait_count.map((trait) => {
if (trait.value === payload.value) {
trait.count++;
}
});
}
// Value doesn't match, add a new entry and increase the count of variations by one
else {
const new_trait_count = { value: payload.value, count: 1 };
countOfEachAttribute.trait_count = [
...countOfEachAttribute.trait_count,
new_trait_count,
];
countOfEachAttribute.total_variations++;
}
}
}
}
);
}
},
You can merge all arrays and use Array.reduce.
const input1 = {
"name": "Ben",
"description": "Ben",
"attributes": [{
"type": "Background",
"value": "Default"
},
{
"type": "Hair-color",
"value": "Brown"
}
]
}
const input2 = {
"name": "Ice",
"description": "Ice",
"attributes": [{
"type": "Background",
"value": "Green"
},
{
"type": "Hair-color",
"value": "White"
}
]
}
const input3 = {
"name": "Itay",
"description": "Itay",
"attributes": [{
"type": "Background",
"value": "Default"
},
{
"type": "Hair-color",
"value": "Brown"
}
]
}
const mergedInput = [input1, input2, input3];
const result = mergedInput.reduce((acc, item) => {
item.attributes.forEach(attrItem => {
const existType = acc.find(e => e.trait_type == attrItem.type);
if (existType) {
var existAttr = existType.trait_count.find(e => e.value == attrItem.value);
if (existAttr) {
existAttr.count++;
} else {
existType.trait_count.push({
value: attrItem.value,
count: 1
});
existType.total_variations++;
}
} else {
acc.push({
trait_type: attrItem.type,
trait_count: [{
value: attrItem.value,
count: 1
}],
total_variations: 1
})
}
});
return acc;
}, []);
console.log(result);
I suggest instead of creating an array for trait_count to make it an object so you don't have to iterate over it whenever you are adding a new attribute. In the snippet below I'm using the value of the attribute as a sort of hash that allows the access to the given property without having to call the Array.prototype.find function
const input1 = {"name":"Ben","description":"Ben","attributes":[{"type":"Background","value":"Default"},{"type":"Hair-color","value":"Brown"}]};
const input2 = {"name":"Ice","description":"Ice","attributes":[{"type":"Background","value":"Green"},{"type":"Hair-color","value":"White"}]};
const input3 = {"name":"Itay","description":"Itay","attributes":[{"type":"Background","value":"Default"},{"type":"Hair-color","value":"Brown"}]};
function countAtributes(input, totalCounts={}) {
input.attributes.forEach((attribute) => {
if (!totalCounts[attribute.type])
totalCounts[attribute.type] = {trait_type: attribute.type, trait_count: {}, total_variations: 0};
if (!totalCounts[attribute.type].trait_count[attribute.value]) {
totalCounts[attribute.type].trait_count[attribute.value] = {value: attribute.value, count: 1};
totalCounts[attribute.type].total_variations+=1;
}
else totalCounts[attribute.type].trait_count[attribute.value].count +=1;
})
}
const totalCounts = {};
countAtributes(input1, totalCounts);
countAtributes(input2, totalCounts);
countAtributes(input3, totalCounts);
console.log(totalCounts);
It could be turned into the array afterwards with Object.values if necessary
I believe it is a much better approach to what you had before as you don't have to iterate over the tables of trait_counts. In theory it should significantly reduce the time taken. Iterating over the array and checking a condition each time is much slower than key lookup in Javascript object
I am trying to get a bubble chart to populate using ngx-charts. The problem is the swimlane documentation on it is almost non-existent and I haven't been able to find any good examples.
I have read the open source code that swimlane provides and have created what I believe are the appropriate variables in Typescript and have constructed my data points using an example line graph I found using the same tools. However the chart still appears empty on the page.
HTML:
<ngx-charts-bubble-chart
[view]="view"
[results]="bubbleDemoTempData"
[showGridLines]="showGridLines"
[legend]="showLegend"
[legendTitle]="legendTitle"
[xAxis]="showXAxis"
[yAxis]="showYAxis"
[showXAxisLabel]="showXAxisLabel"
[showYAxisLabel]="showYAxisLabel"
[xAxisLabel]="xAxisLabel"
[yAxisLabel]="yAxisLabel"
[autoScale]="autoScale"
[scheme]="colorScheme"
[minRadius]="minRadius"
[maxRadius]="maxRadius"
(select)="onSelectBubbleInteractivePoint($event)"
*ngIf="dataTypeDisplay == 'GraphForm'"
[#fade]>
</ngx-charts-bubble-chart>
TypeScript:
view: any[] = [700, 400];
// options
showXAxis = true;
showXAxisLabel = true;
showYAxisLabel = true;
showYAxis = true;
gradient = false;
showLegend = true;
legendTitle = "Hi";
xAxisLabel = 'Number';
yAxisLabel = 'Color Value';
showGridLines = true;
autoScale=true;
minRadius = 1;
maxRadius = 1;
colorScheme = {
domain: ['#5AA454', '#A10A28', '#C7B42C', '#AAAAAA']
};
Data Points:
public multi = [
{
"name": "Germany",
"series": [
{
"name": "2010",
"value": 7300000
},
{
"name": "2011",
"value": 8940000
}
]
},
{
"name": "USA",
"series": [
{
"name": "2010",
"value": 7870000
},
{
"name": "2011",
"value": 8270000
}
]
},
{
"name": "France",
"series": [
{
"name": "2010",
"value": 5000002
},
{
"name": "2011",
"value": 5800000
}
]
}
];
I would appreciate if someone could give me some advice on correctly populating the chart.
I was eventually able to get it worked out. I will post the same 3 code snippets from above here in their updated forms.
HTML:
<ngx-charts-bubble-chart
[results]="bubbleDemoTempData"
[view]="view"
[showGridLines]="showGridLines"
[legend]="legend"
[legendTitle]="legendTitle"
[legendPosition]="legendPOsition"
[xAxis]="XAxis"
[yAxis]="YAxis"
[showXAxisLabel]="showXAxisLabel"
[showYAxisLabel]="showYAxisLabel"
[xAxisLabel]="xAxisLabel"
[yAxisLabel]="yAxisLabel"
[trimXAxisTicks]="trimXAxisTicks"
[trimYAxisTicks]="trimYAxisTicks"
[maxXAxisTickLength]="maxXAxisTickLength"
[maxYAxisTickLength]="maxYAxisTickLength"
[roundDomains]="roundDomains"
[minRadius]="minRadius"
[maxRadius]="maxRadius"
[autoScale]="autoScale"
[schemeType]="schemeType"
(select)="onSelectBubbleInteractivePoint($event)"
*ngIf="dataTypeDisplay == 'GraphForm'"
[#fade]>
</ngx-charts-bubble-chart>
TypeScript:
view: any[] = [700, 400];
// options
showGridLines = true;
legend = true;
legendTitle = "Dots Mf'er";
legendPosition = "right";
xAxis = true;
yAxis = true;
showXAxisLabel = true;
showYAxisLabel = true;
xAxisLabel = "LR";
yAxisLabel = "Jobs";
trimXAxisTicks = true;
trimYAxisTicks = true;
rotateXAxisTicks = true;
maxXAxisTickLength = 16;
maxYAxisTickLength = 16;
// xAxisTicks;
// yAxisTicks;
roundDomains = false;
maxRadius = 5;
minRadius = 5;
autoScale = true;
schemeType = "ordinal";
tooltipDisabled = false;
Data Points:
public bubbleDemoTempData = [
{
"name": "Example1",
"series": [
{
"name": "a",
"x": 0,
"y": 0,
"r": 1
},
{
"name": "b",
"x":10,
"y":3,
"r":10
}
]
},
{
"name":"Example2",
"series": [
{
"name":"1",
"x":20,
"y":1,
"r":30
},
{
"name":"2",
"x":3,
"y":3,
"r":500
}
]
}
];
This works and definitely answers my question from above. That being said the grid lines are still not appearing but that's an entirely different issue that I may have to post a new ticket for.
I have following Json which i need to insert into a table.
I want to convert each student detail into a row.
Because if i loop through the rows as per the existing structure i am reading one column as a row.
var json {
"Students":[
{
"name":{
"value":"Allan"
},
"number":{
"value":"123"
}
},
{
"name":{
"value":"Frank"
},
"number":{
"value":"456"
}
}
]
}
Ideally i want to the above as
{ "name": "Allan", "number": 123};
{ "name": "Frank", "number": 456};
I am looping through the Json as below
var objectKeys = Object.keys(json);
for (var key in objectKeys)
{
var student = json.Students;
for (var i = 0; i < student .length; i++) {
for (var column in json.Students[i]) {
window.print(column);
window.print(json.Students[i][column].value);
}
}
}
NOTE: No JQuery, want to achieve the above through normal Javascript.
If you want to transform the data, you can use Array.map
var json = {"Students":[{"name":{"value":"Allan"},"number":{"value":"123"}},{"name":{"value":"Frank"},"number":{"value":"456"}}]};
let result = json.Students.map(o => ({
name: o.name.value,
number: o.number.value
}));
console.log(result);
If you want to access the data, you can use Array.forEach
var json = {"Students":[{"name":{"value":"Allan"},"number":{"value":"123"}},{"name":{"value":"Frank"},"number":{"value":"456"}}]};
json.Students.forEach(o => console.log({name: o.name.value, number: o.number.value}));
var json = {
"Students":[
{
"name":{
"value":"Allan"
},
"number":{
"value":"123"
}
},
{
"name":{
"value":"Frank"
},
"number":{
"value":"456"
}
}
]
}
var studentData = JSON.stringify(json.Students);
var convertedData = JSON.parse(studentData.replace(/\{\"value\"\:/g,"").replace(/\}\,\"number/g,',"number').replace(/\"\}\}/g,'"}'));
Try this :)
No map or reduce. Just classic Javascript.
var json = {
"Students": [{
"name": {
"value": "Allan"
},
"number": {
"value": "123"
}
},
{
"name": {
"value": "Frank"
},
"number": {
"value": "456"
}
}
]
};
for (var student of json["Students"]) {
console.log(student); //your logic goes here.
}