Skip to content

Instantly share code, notes, and snippets.

@afifabroory
Created May 12, 2024 11:34
Show Gist options
  • Save afifabroory/2eebc26c1ff4d267dee81cd92d4a9559 to your computer and use it in GitHub Desktop.
Save afifabroory/2eebc26c1ff4d267dee81cd92d4a9559 to your computer and use it in GitHub Desktop.
Group Stack Column Bar Chart
<!DOCTYPE html>
<div id="container"></div>
<script src="d3.v7.js"></script>
<script type="module">
const width = 600;
const height = 400;
const margin = {top: 20, right: 20, bottom: 20, left: 50}
const balanceSheet = new d3.InternMap([
[
new Date(2024, 2, 1),
[
{'currA': 5000, 'nCurrA': 1000},
{'currL': 5000, 'nCurrL': 500, 'equity': 500},
]
],
[
new Date(2024, 5, 1),
[
{'currA': 5000, 'nCurrA': 1000},
{'currL': 5000, 'nCurrL': 500, 'equity': 500},
]
],
[
new Date(2024, 8, 1),
[
{'currA': 5000, 'nCurrA': 1000},
{'currL': 5000, 'nCurrL': 500, 'equity': 500},
]
],
[
new Date(2024, 11, 1),
[
{'currA': 5000, 'nCurrA': 1000},
{'currL': 5000, 'nCurrL': 500, 'equity': 500},
]
],
[
new Date(2025, 2, 1),
[
{'currA': 5000, 'nCurrA': 1000},
{'currL': 5000, 'nCurrL': 500, 'equity': 500},
]
],
]);
const xGroupScale = d3.scaleBand()
.domain(balanceSheet.keys())
.range([margin.left, width - margin.right])
.paddingOuter(0.15)
.paddingInner(0.20);
// xGroupScale.domain().map((a) => console.log(xGroupScale(a), xGroupScale.bandwidth()))
const xCategoryScale = d3.scaleBand()
.domain([0, 1])
.range([0, xGroupScale.bandwidth()])
.paddingInner(0.05);;
const yScale = d3.scaleLinear()
.domain([0, d3.max(balanceSheet, d => d[1][0].currA + d[1][0].nCurrA)])
.range([height - margin.bottom, margin.top])
.nice();
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
// groups
const groups = svg.selectAll('.group')
.data(balanceSheet)
.enter()
.append('g')
.attr('class', (_ , i) => `group group-${i}`)
.attr('transform', (d) => `translate(${xGroupScale(d[0])}, 0)`)
groups.selectAll()
.data(d => d[1])
.enter()
.append('rect')
.attr('transform', (_, i) => `translate(${xCategoryScale(i)}, ${0})`)
.attr('x', 0)
.attr('y', (d) => yScale(d['currA'] ?? d['currL']))
.attr('width', xCategoryScale.bandwidth())
.attr('height', (d) => height - margin.bottom - yScale(d['currA'] ?? d['currL']))
.attr('fill', 'red')
groups.selectAll()
.data(d => d[1])
.enter()
.append('rect')
.attr('transform', (_, i) => `translate(${xCategoryScale(i)}, ${0})`)
.attr('x', 0)
.attr('y', (d) => yScale(d['nCurrA'] ? (d['nCurrA'] + d['currA']) : (d['nCurrL'] + d['currL'])))
.attr('width', xCategoryScale.bandwidth())
.attr('height', (d) => height - margin.bottom - yScale(d['nCurrA'] ?? d['nCurrL']))
.attr('fill', 'blue')
groups.selectAll()
.data((d) => d[1])
.enter()
.append('rect')
.attr('transform', (_, i) => `translate(${xCategoryScale(i)}, ${0})`)
.attr('x', 0)
.attr('y', (d) => d['equity'] ? yScale(d['equity'] + d['nCurrL'] + d['currL']) : 0)
.attr('width', xCategoryScale.bandwidth())
.attr('height', (d) => d['equity'] ? height - margin.bottom - yScale(d['equity']) : 0)
.attr('fill', 'green')
// x-axis
svg.append('g')
.attr('class', 'x-axis')
.attr('transform', `translate(0, ${height - margin.bottom})`)
.call(d3.axisBottom(xGroupScale).tickFormat(((date) => `Q${Math.ceil((date.getMonth() + 1) / 3)} ${date.getFullYear()}`)));
// y-axis
svg.append('g')
.attr('transform', `translate(${margin.left}, 0)`)
.call(d3.axisLeft(yScale));
document.body.append(svg.node());
</script>
@afifabroory
Copy link
Author

afifabroory commented May 15, 2024

image

<!DOCTYPE html>
<div id="container"></div>
<script src="d3.v7.js"></script>
<script type="module">
    const width = 600;
    const height = 400;
    const margin = {top: 20, right: 20, bottom: 20, left: 50}
    
    const balanceSheet = new d3.InternMap([
        [
            new Date(2023, 2, 1), 
            [
                {'currA': 175647, 'nCurrA': 284378},
                {'currL': 132556, 'nCurrL': 65889, 'equity': 261580},
            ]
        ],
        [
            new Date(2023, 5, 1), 
            [
                {'currA': 176738 - 10000, 'nCurrA': 266237 - 10000},
                {'currL': 150007- 10000, 'nCurrL': 53999 - 10000, 'equity': 238969},
            ]
        ],
        [
            new Date(2023, 8, 1), 
            [
                {'currA': 176738, 'nCurrA': 266237},
                {'currL': 150007, 'nCurrL': 53999, 'equity': 238969},
            ]
        ],
        [
            new Date(2023, 11, 1), 
            [
                {'currA': 166186, 'nCurrA': 279493},
                {'currL': 125022, 'nCurrL': 70239, 'equity': 250418},
            ]
        ],
        [
            new Date(2024, 2, 1), 
            [
                {'currA': 175647, 'nCurrA': 284378},
                {'currL': 132556, 'nCurrL': 65889, 'equity': 261580},
            ]
        ],
    ]);

    const xGroupScale = d3.scaleBand()
                            .domain(balanceSheet.keys())
                            .range([margin.left, width - margin.right])
                            .paddingOuter(0.2)
                            .paddingInner(0.3);

    const xCategoryScale = d3.scaleBand()
                                .domain([0, 1])
                                .range([0, xGroupScale.bandwidth()])
                                .paddingInner(0.04);

    const yScale = d3.scaleLinear()
                        .domain([0, d3.max(balanceSheet, d => d[1][0].currA + d[1][0].nCurrA)])
                        .range([height - margin.bottom, margin.top])
                        .nice();

    console.log(yScale)

    const svg = d3.create("svg")
        .attr("width", width)
        .attr("height", height);

    // groups
    const groups = svg.selectAll('.group')    
        .data(balanceSheet)
            .enter()
            .append('g')
            .attr('class', (_ , i) => `group group-${i}`)
            .attr('transform', (d) => `translate(${xGroupScale(d[0])}, 0)`)

    // current
    groups.selectAll()
        .data(d => d[1])
        .enter()
        .append('rect')
            .attr('transform', (_, i) => `translate(${xCategoryScale(i)}, ${0})`)
            .attr('x', 0)
            .attr('y', (d) => yScale(d['nCurrA'] ? (d['nCurrA'] + d['currA']) : (d['nCurrL'] + d['currL'] + d['equity'])))
            .attr('ry', 3)
            .attr('width', xCategoryScale.bandwidth())
            .attr('height', (d) => height  - margin.bottom + 10 -  yScale(d['currA'] ?? d['currL']))
            .attr('fill', '#36AE7C')

    // non current
    groups.selectAll()
        .data(d => d[1])
        .enter()
        .append('rect')
            .attr('transform', (_, i) => `translate(${xCategoryScale(i)}, ${0})`)
            .attr('x', 0)
            .attr('y', (d) => yScale(d['nCurrA'] ?? d['nCurrL']))
            .attr('width', xCategoryScale.bandwidth())
            .attr('height', (d) => height - margin.bottom - yScale(d['nCurrA'] ?? d['nCurrL']))
            .attr('fill', '#EB5353')

    // equity
    groups.selectAll()
        .data((d) => [0, d[1][1]])
        .enter()
        .append('rect')
            .attr('transform', (_, i) => `translate(${xCategoryScale(i)}, ${0})`)
            .attr('x', 0)
            .attr('y', (d) => typeof d == 'object' ? yScale(d['equity'] + d['nCurrL']) : 0)
            .attr('width', xCategoryScale.bandwidth())
            .attr('height', (d) => typeof d == 'object' ? height  - margin.bottom -  yScale(d['equity']) : 0)
            .attr('fill', '#187498')

    // x-axis
    svg.append('g')
        .attr('class', 'x-axis')
        .attr('transform', `translate(0, ${height - margin.bottom})`)
        .call(d3.axisBottom(xGroupScale).tickFormat(((date) => `Q${Math.ceil((date.getMonth() + 1) / 3)} ${date.getFullYear()}`)));

    // y-axis
    svg.append('g')
        .attr('transform', `translate(${margin.left}, 0)`)
        .call(d3.axisLeft(yScale));

    document.body.append(svg.node());
</script>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment