I am just starting with D3 and React, perhaps that's why I have been unable to solve this simple problem since a few days.
I have a CSV file from which I read columns, and one column is an array that I need to plot. Since I am new to both D3 and React, I thought let's first plot a 1D array and then move onto 2D arrays. I have been successful with the 1D array, but no matter what I try I cannot get the 2D array to work.
For simplicity let's hard-code both the data for now.
The initial 1D array was -
const emotions = ['neutral', 'surprise', 'disgust', 'fear', 'sadness', 'fear', 'joy', 'sadness', 'joy'];
Which would later become 2D as follows -
const emotions = [
['neutral', 'surprise', 'disgust', 'fear', 'sadness', 'fear', 'joy', 'sadness', 'joy'],
['sadness', 'sadness', 'joy', 'joy', 'joy']
];
I made a scale to map the categories with the colors as follows -
const emoScale = d3.scaleOrdinal()
.range(['red', 'green', 'purple', 'yellow', 'white', 'gray', 'orange'])
.domain(['anger', 'disgust', 'fear', 'joy', 'neutral', 'sadness', 'surprise']);
After which I tried successfully to show the 1D array like -
const emotion1D = ['neutral', 'surprise', 'disgust', 'fear', 'sadness', 'fear', 'joy', 'sadness', 'joy'];
const emoScale = d3.scaleOrdinal()
.range(['red', 'green', 'purple', 'yellow', 'white', 'gray', 'orange'])
.domain(['anger', 'disgust', 'fear', 'joy', 'neutral', 'sadness', 'surprise']);
console.log(emoScale("anger"));
const d3Chart = useRef();
const svg = d3.select(d3Chart.current);
var selection = svg.selectAll("rect").data(emotion1D);
// var yScale = emoScale;
selection
.enter()
.append("rect")
.attr("x", (d, i) => 0)
.attr("y", (d, i) => i*11)
.attr("width", 10)
.attr("height", 10)
.attr("fill", function(d) { return emoScale(d); })
And the output was a stacked bar of rects of different colors - which is exactly what I need. Now I need to show this for as many rows I have in the matrix. So if I get it working on a 2D matrix, then my problem is solved.
So finally, I should be able to see another bar of stacked rects of different colors and a different total size, right next to the first one...and so on depending on how many rows I have and how many elements are inside it.
While searching for how to render 2D array, I came across Nested Selection. So that's how I tried to solve this. The idea being that for the 1D array in the matrix, the Y position remains the same, X changes by x+10. And for data in 1D array, Y changes by y*rect_height and X remains same as above.
I have tried playing around with many changes to svg group, x and y positions, but nothing gave what I want. At some point I got a diagonal, but that's not what I want. The current code that I have is as follows...I am not sure why the display is not consistent...it seems to display few diagonal rects when I change something, but refreshing it always gives me a blank screen.
const emotion2D = [['neutral', 'surprise', 'disgust', 'fear', 'sadness', 'fear', 'joy', 'sadness', 'joy'],['sadness', 'sadness', 'joy', 'joy', 'joy']];
const emotion1D = ['neutral', 'surprise', 'disgust', 'fear', 'sadness', 'fear', 'joy', 'sadness', 'joy'];
const emoScale = d3.scaleOrdinal()
.range(['red', 'green', 'purple', 'yellow', 'white', 'gray', 'orange'])
.domain(['anger', 'disgust', 'fear', 'joy', 'neutral', 'sadness', 'surprise']);
console.log(emoScale("anger"));
const d3Chart = useRef();
const svg = d3.select(d3Chart.current);
var selection = svg.selectAll("rect").data(emotion2D);
selection
.enter()
.append("g")
.attr("x", (d, i) => i+10)
.attr("y", (d, i) => 0)
.selectAll("rect")
.data(function(d,i){
return d[i];
})
.enter()
.append("rect")
.attr("x", (d, i) => 0)
.attr("y", (d, i) => i*11)
.attr("width", 10)
.attr("height", 10)
.attr("fill", function(d) { return emoScale(d); })
The full react files are as follows -
Chart.jsx
import React, { Component } from 'react';
import * as d3 from 'd3';
import { useRef } from 'react';
const Chart = function() {
const emotion2D = [['neutral', 'surprise', 'disgust', 'fear', 'sadness', 'fear', 'joy', 'sadness', 'joy'],['sadness', 'sadness', 'joy', 'joy', 'joy']];
const emotion1D = ['neutral', 'surprise', 'disgust', 'fear', 'sadness', 'fear', 'joy', 'sadness', 'joy'];
const emoScale = d3.scaleOrdinal()
.range(['red', 'green', 'purple', 'yellow', 'white', 'gray', 'orange'])
.domain(['anger', 'disgust', 'fear', 'joy', 'neutral', 'sadness', 'surprise']);
console.log(emoScale("anger"));
const d3Chart = useRef();
const svg = d3.select(d3Chart.current);
var selection = svg.selectAll("rect").data(emotion2D);
// var yScale = emoScale;
selection
.enter()
.append("g")
.attr("x", (d, i) => i+10)
.attr("y", (d, i) => 0)
.selectAll("rect")
.data(function(d,i){
return d[i];
})
.enter()
.append("rect")
.attr("x", (d, i) => 0)
.attr("y", (d, i) => i*11)
.attr("width", 10)
.attr("height", 10)
.attr("fill", function(d) { return emoScale(d); })
return(
<div>
<svg style={{border: "1px solid black"}} ref={d3Chart}>
</svg>
</div>
)
}
export default Chart;
App.js
import './App.css';
import Chart from './Chart';
function App() {
return (
<Chart />
);
}
export default App;
