Sure you can!
You need to grade/calibrate each individual on the x and y attributes, put those calibrations into an array with appropriate bins, and then you can allocate individuals into the appropriate bins and show them in a series of containers in a grid view.
Here's a silly example to get you started:
Approach:
Having no idea what you will actually be grading on, I decided to grade a random list of names (thanks to ChatGPT, with some edits to make the data interesting) on the count of consonants and vowels in each name.
[
{ name: "Alisonia" },
{ name: "Bobby" },
{ name: "Charlie" },
{ name: "David" },
{ name: "Emmaline" },
{ name: "falalalalaaaa" },
{ name: "Gracious" },
{ name: "Henry" },
{ name: "Fooooooo" },
{ name: "Jackson" },
{ name: "Katherine" },
{ name: "Liam" },
{ name: "Mia" },
{ name: "Noah" },
{ name: "Olivia" },
{ name: "Peter" },
{ name: "Quinnick" },
{ name: "Rachel" }
]
From there, it's a matter of math + JavaScript to get the counts, figure out the bin sizes to use, and assign the names to the appropriate bin:
// Array of names from the jsonExplorer component
const names = jsonExplorer1.value;
// Functions to count vowels and consonants in a string
function countVowels(str) {
return str.match(/[aeiou]/gi).length;
}
function countConsonants(str) {
return str.match(/[^aeiou]/gi).length;
}
// Find minimum and maximum counts of vowels and consonants
let minVowels = Infinity;
let maxVowels = -Infinity;
let minConsonants = Infinity;
let maxConsonants = -Infinity;
names.forEach(nameObj => {
const numVowels = countVowels(nameObj.name);
const numConsonants = countConsonants(nameObj.name);
minVowels = Math.min(minVowels, numVowels);
maxVowels = Math.max(maxVowels, numVowels);
minConsonants = Math.min(minConsonants, numConsonants);
maxConsonants = Math.max(maxConsonants, numConsonants);
});
// Define bin ranges for 3 by 3
const vowelBinWidth = Math.ceil((maxVowels - minVowels + 1) / 3);
const consonantBinWidth = Math.ceil((maxConsonants - minConsonants + 1) / 3);
const vowelBins = [
{ min: minVowels,
max: minVowels + vowelBinWidth - 1,
definition: "Low" },
{ min: minVowels + vowelBinWidth,
max: minVowels + 2 * vowelBinWidth - 1,
definition: "Medium" },
{ min: minVowels + 2 * vowelBinWidth,
max: Infinity,
definition: "High" }
];
const consonantBins = [
{ min: minConsonants,
max: minConsonants + consonantBinWidth - 1,
definition: "Low" },
{ min: minConsonants + consonantBinWidth,
max: minConsonants + 2 * consonantBinWidth - 1,
definition: "Medium" },
{ min: minConsonants + 2 * consonantBinWidth,
max: Infinity,
definition: "High" }
];
// Empty array to store names in each bin
const bins = [];
// Initialize bins with a definition of each
for (let i = 0; i < vowelBins.length; i++) {
for (let j = 0; j < consonantBins.length; j++) {
bins.push({
vowelRange: vowelBins[i],
consonantRange: consonantBins[j],
definition: `${vowelBins[i].definition} Vowels,\n ${consonantBins[j].definition} Consonants`,
names: []
});
}
}
// Iterate through names and assign them to bins
names.forEach(nameObj => {
const numVowels = countVowels(nameObj.name);
const numConsonants = countConsonants(nameObj.name);
// Find the appropriate bin
const bin = bins.find(bin =>
numVowels >= bin.vowelRange.min && numVowels <= bin.vowelRange.max &&
numConsonants >= bin.consonantRange.min && numConsonants <= bin.consonantRange.max
);
// Add the name to the bin
if (bin) {
bin.names.push(nameObj.name);
}
});
return bins
I used the JS output as the data source for the grid component, added {{item.definition}}
as the title of the containers, and added a link list as a component to the containers with the data source for the link list of {{item.names}}
.
Whew! That was fun