차트라이브러리/Chart.js

Chart.js 로 인구피라미드 차트 그리기

세리둥절 2022. 10. 14. 16:20
반응형

가끔씩 차트를 그리다 보면 성/연령대별로 인구 분포를 나타내기 위해서 인구피라미드 차트를 그려야 할 때가 있다. 영어로는 population pyramid라고 할 때도 있고 age pyramid라고 할 때도 있는 듯하다.

 

Chart.js에서는 인구피라미드 차트를 Stacked Bar 차트를 활용해서 아주 간단하게 그릴 수 있다.

 

 

 

 

위의 차트를 그리기 위한 코드를 전체로 복붙해서 쓸모없는 부분이 일부 있기는 하지만

1) Datasets에서 데이터를 음수로 바꿔주는 부분

2) indexAxis를 'y'로 지정해서 90%로 차트를 회전시키는 부분

3) xAxes에서 음수 ticks를 양수로 바꿔주는 부분

이 가장 핵심이다

import styled from "@emotion/styled";
import React, { useRef } from "react";
import annotationPlugin from "chartjs-plugin-annotation";
import { Bar } from "react-chartjs-2";
import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  BarElement,
  Title,
  Tooltip,
  Legend,
} from "chart.js";
import { theme } from "../../../styles/theme";

ChartJS.register(
    CategoryScale,
    LinearScale,
    BarElement,
    Title,
    Tooltip,
    Legend,
    annotationPlugin
  );

const Container = styled.div`
`;

interface Props {
  data: any;
}
const AgePyramidChart = ({ data }: Props) => {
    const agePyramidchartRef = useRef<any>(null);
    const {male, female} = data;

    const dataset = {
        labels: ["10-19", "20-29", "30-39", "40-49", "50-59", "60-"].reverse(),
        datasets: [
            {
                label: "남성",
                stack: "Stack 0",
                backgroundColor: theme.colors.chart0C,
                hoverBackgroundColor: theme.colors.chart0C,
                data: [4, 10, 16, 20, 22, 12].reverse().map((k:number) => -k),
                borderRadius: 6,
                barThickness: 12,
            },
            {
                label: "여성",
                stack: "Stack 0",
                backgroundColor: theme.colors.chart67,
                hoverBackgroundColor: theme.colors.chart67,
                data: [5, 12, 18, 24, 20, 15].reverse(),
                borderRadius: 6,
                barThickness: 12,
            },
        ],
    };

    const options = { 
        responsive: true,
        maintainAspectRatio: true,
        aspectRatio: 1.7,
        animation: {
            duration: 0,
        },
        layout: {
            // padding: 20,
        },
        indexAxis: 'y' as const,
        plugins: {
            legend: {
                display: true,
                position: "bottom" as const,
                align: "start" as const,
                onClick: () => {},
                labels: {
                    usePointStyle: true,
                    boxWidth: 6, //point 크기 작게 지정
                    padding: 20,
                    font: {
                        size: 12,
                    },
                },
            },
        },

        scales: {
            xAxes: {
                suggestedMin: 0,
                suggestedMax: 30,
                ticks: {
                    autoSkip: true,
                    maxRotation: 0,
                    minRotation: 0,
                    labelOffset: 0,
                    padding: 0,
                    font: {
                        size: 12,
                    },
                    callback: function (i: any) {
                        return i < 0 ? `${-i}%` : `${i}%`;
                    },
                },
                grid: {
                    display: false, //뒷배경 라인 없애기
                },
            },
            x: {
                display: false, //하단 라인을 없애기
                ticks: {
                display: false, //새로운tick을 만들었으니 기존의 tick을 제거
                },
            },
            y: {
                ticks: {
                    font: {
                        size: 12,
                    },
                    beginAtZero: true,
                },
                grid: {
                    display: false, //뒷배경 라인 없애기
                },
                position: "left" as const,
            },
        },

    }

    return (
        <Container>
        <Bar
            options={options}
            data={dataset}
            ref={agePyramidchartRef}
            data-testid={"chart-age-pyramid"}
        />
        </Container>
    );
}

export default AgePyramidChart;

 

 

 

 

반응형