4
respostas

[Dúvida] Chart js: Ajuda para colocar cores individuais nas barras empilhadas

Bom dia. No código abaixo fiz o gráfico de barras empilhadas de proventos recebidos de investimentos, cada dataset tem um arranjo ordenado de tickers e seus valores. Porém somente consegui colocar uma cor por dataset, não consigo setar cores individuais para cada ticker nas barras empilhadas. Não sei se me fiz claro na explicação... Agradeço por qualquer ajuda :D

<script>
    var dividendos_agrupados_por_mes = {{ dividendos_agrupados_por_mes|safe }};
    var meses = Object.keys(dividendos_agrupados_por_mes);
    var ctx = document.getElementById('grafico-barras-empilhadas').getContext('2d');
    var coresPadrao = [
            '#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd',
            '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf',
            '#aec7e8', '#ffbb78', '#98df8a', '#ff9896', '#c5b0d5',
            '#c49c94', '#f7b6d2', '#c7c7c7', '#dbdb8d', '#9edae5',
            '#393b79', '#637939', '#8c6d31', '#843c39', '#7b4173',
            '#5254a3', '#6b6ecf', '#9c9ede', '#637939'
        ];
    var dadosGrafico = {
        labels: meses,
        datasets: meses.map(function (mes, mesIndex) {
            var tickers = Object.keys(dividendos_agrupados_por_mes[mes]);
            return {
                label: mes,
                data: tickers.map(function (ticker) {
                    var valorY = dividendos_agrupados_por_mes[mes][ticker];
                    return {
                        x: mes,
                        y: valorY,
                        ticker: ticker,
                    };
                }),
                backgroundColor: coresPadrao[mesIndex % coresPadrao.length],
            };
        }),
    };
    console.log(dadosGrafico)
    var meuGrafico = new Chart(ctx, {
        type: 'bar',
        data: dadosGrafico,
        options: {
            scales: {
                x: {
                    stacked: true,
                },
                y: {
                    stacked: true,
                },
            },
            plugins: {
                legend: {
                    display: false,
                },
                tooltip: {
                    callbacks: {
                        label: function(context) {
                            var data = context.dataset.data[context.dataIndex];
                            return data.ticker + ': ' + data.y;
                        }
                    }
                }
            },
        },
    });
</script>

Abaixo exemplo de entrada de dados que vem do backend:

{'2023-7': {'IRDM11': 0.0, 'SNLG11': 0.62, 'SEQR11': 2.84, 'TVRI11': 6.3, 'FGAA11': 6.63, 'KNCR11': 6.9, 'CPTS11': 8.8, 'VGHF11': 9.72}, '2023-8': {'SNLG11': 0.0, 'IRDM11': 0.0, 'SEQR11': 2.85, 'TVRI11': 6.3, 'KNCR11': 6.9, 'FGAA11': 8.45, 'CPTS11': 8.9, 'VGHF11': 10.8}, '2023-9': {'SNLG11': 0.0, 'IRDM11': 0.0, 'SEQR11': 2.85, 'TVRI11': 6.3, 'KNCR11': 7.2, 'CPTS11': 7.9, 'FGAA11': 8.45, 'VGHF11': 10.92}, '2023-10': {'SNLG11': 0.0, 'IRDM11': 0.0, 'SEQR11': 3.58, 'CPTS11': 5.45, 'TVRI11': 6.3, 'KNCR11': 6.6, 'VGHF11': 9.2, 'FGAA11': 10.08}, '2023-11': {'SNLG11': 0.0, 'IRDM11': 0.0, 'SEQR11': 3.58, 'TVRI11': 6.37, 'KNCR11': 6.66, 'CPTS11': 9.02, 'VGHF11': 9.2, 'FGAA11': 9.66}
4 respostas

Olá Cristiano!

Entendi que você deseja aplicar cores diferentes para cada ticker em suas barras empilhadas. No Chart.js, a cor de uma barra é determinada pela propriedade backgroundColor do dataset a que a barra pertence. No seu código, você está atribuindo a mesma cor para todas as barras de um mesmo dataset, pois está definindo a propriedade backgroundColor no nível do dataset.

Para atribuir cores diferentes para cada barra, você precisa mover a propriedade backgroundColor para o nível dos dados. Aqui está um exemplo de como você pode fazer isso:

var dadosGrafico = {
    labels: meses,
    datasets: meses.map(function (mes, mesIndex) {
        var tickers = Object.keys(dividendos_agrupados_por_mes[mes]);
        return {
            label: mes,
            data: tickers.map(function (ticker, tickerIndex) {
                var valorY = dividendos_agrupados_por_mes[mes][ticker];
                return {
                    x: mes,
                    y: valorY,
                    ticker: ticker,
                    backgroundColor: coresPadrao[tickerIndex % coresPadrao.length], // Mova esta linha para cá
                };
            }),
            // backgroundColor: coresPadrao[mesIndex % coresPadrao.length], // Remova esta linha
        };
    }),
};

Neste exemplo, a cor de cada barra é determinada pelo índice do ticker no array de tickers. Note que a propriedade backgroundColor agora está dentro do objeto que é retornado pela função map que itera sobre os tickers. Isso significa que cada barra terá sua própria cor, que será escolhida a partir do array coresPadrao.

Espero ter ajudado e bons estudos!

Olá Natan. Obrigado pela ajuda.

Entendi, porém não resolveu. Olhei no console e está assim no primeiro dataset, os demais segue mesma lógica: Insira aqui a descrição dessa imagem para ajudar na acessibilidade

E o gráfico assim: Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Parece que esta sendo sobreescrita a cor automaticamente ou algo assim?

Oi Cristiano!

Estranho, era para ter funcionado. E sim, parece que tem algo sobrescrevendo. Tentaria investigar de forma manual, literalmente indo no DevTools e vendo de onde está vindo as cores.

Desculpe não conseguir ajudar mais. :(

Bons estudos!

Valeu pela tentativa, vou continuar tentando. Fiz a seguinte mudança:

<script>
    var dividendos_agrupados_por_mes = {{ dividendos_agrupados_por_mes|safe }};
    var meses = Object.keys(dividendos_agrupados_por_mes);
    var ctx = document.getElementById('grafico-barras-empilhadas').getContext('2d');
    var coresPadrao = [
            '#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd',
            '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf',
            '#aec7e8', '#ffbb78', '#98df8a', '#ff9896', '#c5b0d5',
            '#c49c94', '#f7b6d2', '#c7c7c7', '#dbdb8d', '#9edae5',
            '#393b79', '#637939', '#8c6d31', '#843c39', '#7b4173',
            '#5254a3', '#6b6ecf', '#9c9ede', '#637939'
        ];
    var dadosGrafico = {
        labels: meses,
        datasets: meses.map(function (mes, mesIndex) {
            var tickers = Object.keys(dividendos_agrupados_por_mes[mes]);
            return {
                label: mes,
                data: tickers.map(function (ticker) {
                    var valorY = dividendos_agrupados_por_mes[mes][ticker];
                    return {
                        x: mes,
                        y: valorY,
                        ticker: ticker,
                        backgroundColor: coresPadrao[mesIndex % coresPadrao.length],
                        borderColor: coresPadrao[mesIndex % coresPadrao.length],
                    };
                }),
            };
        }),
    };
    console.log(dadosGrafico)
    var meuGrafico = new Chart(ctx, {
        type: 'bar',
        data: dadosGrafico,
        options: {
            scales: {
                x: {
                    stacked: true,
                },
                y: {
                    stacked: true,
                },
            },
            plugins: {
                legend: {
                    display: false,
                },
                tooltip: {
                    callbacks: {
                        label: function(context) {
                            var data = context.dataset.data[context.dataIndex];
                            return data.ticker + ': ' + data.y;
                        }
                    }
                }
            },
            elements: {
                bar: {
                    backgroundColor: function(context) {
                        var dataset = dadosGrafico.datasets[context.datasetIndex];
                        var data = dataset.data[context.dataIndex];
                        return data.backgroundColor || coresPadrao[context.dataIndex % coresPadrao.length];
                    },
                    fill: true,
                },
            },
        },
    });
</script>

Adicionei esse elements que achei na internet, que acabou removendo a definição automatica de cor do chart.js, mas confesso que não entendi bem isso, talvez não seja uma boa idéia usar... Porém reparei que a cor de cada conjunto de dados é sempre a mesma cor do ultimo dado de cada array, como pode ser visto na imagem a seguir.

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Cada barra que é o conjunto de dados daquele mês fica com a cor do ultimo dado do array....