Tutorial Power BI + SVG

Como criar um calendário no Power BI com código SVG

Aprenda a criar a tabela Dcalendario no Power Query, construir uma medida SVG em DAX e organizar o visual em formato de calendário. Os dois códigos completos estão disponíveis para copiar.

Power BIPower Query MDAXSVG dinâmicoTutorial passo a passo

Um calendário visual permite analisar contratações, desligamentos, vendas, ocorrências ou qualquer outro indicador por dia. Com SVG, cada célula pode mostrar o número do dia, métricas e cores condicionais em um único cartão.

Assista: calendário no Power BI com SVG

No vídeo abaixo, Miguel Rodrigues demonstra o resultado visual. Depois de assistir, siga o tutorial escrito e copie os códigos para reproduzir o calendário no seu projeto.

Vídeo: “Como criar Calendário no Power BI com código SVG” — canal Miguel Rodrigues - Adm e Excel.

Como esse calendário funciona?

A solução combina três elementos. A dimensão calendário fornece datas, dias da semana e semanas do mês. A medida DAX lê o contexto de cada célula e monta uma imagem SVG. Por fim, uma matriz organiza essas imagens em linhas e colunas, formando o calendário.

1

Tabela calendário

Cria uma linha para cada data entre o menor e o maior período existente na base.

2

Medida SVG

Desenha o cartão de cada dia e inclui as métricas selecionadas dentro da imagem.

3

Visual de matriz

Distribui os dias pelas semanas do mês e pelos dias da semana.

Você pode adaptar para outros indicadores

Embora o exemplo use contratações e desligamentos, a mesma estrutura pode apresentar vendas, chamados, acidentes, entregas, manutenções, faltas ou qualquer medida DAX.

1. Crie a tabela Dcalendario no Power Query

A tabela abaixo é criada com linguagem M. Ela identifica o menor e o maior dia da base, completa o período até o início e o fim dos respectivos anos e gera colunas auxiliares para filtros, classificações e montagem do calendário.

Abra o Power Query

No Power BI Desktop, escolha Transformar dados.

Crie uma consulta em branco

Use Nova fonte → Consulta em branco e abra o Editor Avançado.

Cole o código

Apague o conteúdo atual, copie o código abaixo e confirme.

Ajuste somente a origem das datas

Substitua fCadastro[Data de Admissão] e fCadastro[Data de Desligamento] pelos nomes reais da sua tabela e das colunas de data.

Código M — tabela Dcalendario
let
    // Alterar somente a Tabela e a coluna de datas
    /* A Tabela é onde possui uma coluna Data que deseja usar em seus cálculos ou visuais. 
       Exemplo. Tabela fVendas que possui a coluna Data Pedido ficaria:
       List.Min (fVendas[Data Pedido]).
       Se possuir mais de uma coluna, ficaria:
       List.Min (fVendas[Data Pedido] & fVendas[Data Vencimento]).
    */

    MenorData = List.Min (fCadastro[Data de Admissão] & fCadastro[Data de Desligamento]),
    MaiorData = List.Max (fCadastro[Data de Admissão] & fCadastro[Data de Desligamento]),

    // Não alterar daqui pra baixo
    DataInicio = Date.StartOfYear(MenorData),
    DataFim = Date.EndOfYear(MaiorData),
    Dias = Duration.Days(DataFim - DataInicio) + 1,
    ListarDatas = List.Dates(DataInicio, Dias, #duration(1,0,0,0)),

    Tabela =
        #table(
            type table[
                Data = date,
                Ano = Int64.Type,
                NomeMes = text,
                MesAbre = text,
                MesAno = text,
                MesNum = number,
                AnoMesINT = number,
                InicioMes = date,
                Trimestre = Int64.Type,
                TrimestreAbreviado = text,
                Bimestre = text,
                Semestre = text,
                Semana = Int64.Type,
                DiaSemana = Int64.Type,
                NomeDia = text,
                Passado = logical,
                AnoAtual = text,
                MesAtual = text,

                // ======= Novas colunas (equivalentes aos DAX) =======
                #"Dia Nome" = text,
                #"Dia útil" = text,
                Dia = Int64.Type,
                #"Semana Ano" = Int64.Type,
                #"Semana Dia" = Int64.Type,
                #"Semana do Mês" = Int64.Type
                // =====================================================
            ],
            List.Transform(
                ListarDatas,
                each
                    let
                        d = _,
                        // Para equivalências com DAX:
                        // WEEKDAY(...,2)  => segunda=1..domingo=7
                        Weekday_2 = Date.DayOfWeek(d, Day.Monday) + 1,
                        // WEEKDAY(...,1)  => domingo=1..sábado=7
                        Weekday_1 = Date.DayOfWeek(d, Day.Sunday) + 1,
                        // WEEKNUM padrão DAX inicia no domingo
                        WeekNum_Sun = Date.WeekOfYear(d, Day.Sunday),
                        // INT(ROUNDUP(DAY/7,0))
                        SemanaDoMes = Number.RoundUp(Date.Day(d) / 7, 0)
                    in
                    {
                        d,                                             // Data
                        Date.Year(d),                                   // Ano
                        Text.Proper(Date.MonthName(d)),                 // NomeMes
                        Text.Proper(Text.Start(Date.MonthName(d), 3)),  // MesAbre
                        Text.Proper(Text.Start(Date.MonthName(d), 3)) & "-" & Text.End(Text.From(Date.Year(d)), 2), // MesAno
                        Date.Month(d),                                  // MesNum
                        Date.Year(d) * 100 + Date.Month(d),             // AnoMesINT
                        Date.StartOfMonth(d),                           // InicioMes
                        Date.QuarterOfYear(d),                          // Trimestre
                        Text.From(Date.QuarterOfYear(d)) & "º Trim ",   // TrimestreAbreviado
                        Text.From(Number.RoundUp(Date.Month(d)/2, 0)) & "º Bim",   // Bimestre
                        Text.From(Number.RoundUp(Date.Month(d)/6, 0)) & "º Sem",   // Semestre
                        Date.WeekOfMonth(d),                            // Semana
                        Date.DayOfWeek(d),                              // DiaSemana (0=Domingo por padrão)
                        Date.DayOfWeekName(d),                          // NomeDia
                        if d <= MaiorData then true else false,         // Passado
                        if Date.IsInCurrentYear(d) then "Ano Atual" else Text.From(Date.Year(d)), // AnoAtual
                        if Date.IsInCurrentYear(d) and Date.IsInCurrentMonth(d) then "Mês Atual" else Text.Proper(Date.MonthName(d)), // MesAtual

                        // ======= Valores das novas colunas =======
                        Date.ToText(d, "ddd"),                          // Dia Nome (equivalente ao FORMAT(...,"ddd"))
                        if Weekday_2 <= 5 then "True" else "false",     // Dia útil (strings como no seu DAX)
                        Date.Day(d),                                    // Dia
                        WeekNum_Sun,                                    // Semana Ano
                        Weekday_1,                                      // Semana Dia
                        SemanaDoMes                                     // Semana do Mês
                        // =========================================
                    }
            )
        )
in
    Tabela
Atenção antes de aplicar

As colunas usadas em List.Min e List.Max precisam existir e estar com o tipo Data. Se sua base utiliza apenas uma coluna de data, remova a segunda coluna da expressão.

Depois de criar a consulta, renomeie-a como Dcalendario, selecione Fechar e Aplicar e, no modelo, relacione Dcalendario[Data] à coluna de data da tabela fato. Também é recomendável marcar a Dcalendario como tabela de datas usando a coluna Data.

2. Crie a medida SVG do calendário

A medida gera uma imagem SVG de 200 × 200 pixels para cada dia. O cartão recebe número do dia, dois rótulos, cor de fundo diferenciada e borda definida conforme a comparação entre as medidas.

Código DAX — medida Calendario Animado v2
Calendario Animado v2 = 

VAR vForm_fds_bg = 
    IF(
        SELECTEDVALUE( Dcalendario[Dia útil]) = TRUE(),
        "#d9d9d9",
        "#BEB1BE"
    )

VAR vForm_fds_txt = 
    IF(
        SELECTEDVALUE( dCalendario[Dia útil]) = TRUE(),
        "#444",
        "#808"
    )

VAR vDia = 
    SELECTEDVALUE( dCalendario[Dia] )


VAR vRotulo_1 = -- Valor de Ocorrencias
    [Contrações]

VAR vRotulo_1_formatado = 
    SWITCH(
        TRUE(),
        vRotulo_1 >= 1000000000, FORMAT( vRotulo_1, "#,,,.00 Bi"),
        vRotulo_1 >= 1000000, FORMAT( vRotulo_1, "#,,.00 Mi"),
        vRotulo_1 >= 1000, FORMAT( vRotulo_1, "#,.00 K"),
        vRotulo_1 + 0
    )

VAR vRotulo_2 = -- Valor ocorrencias planejadas 
    [Desligamento]

VAR vRotulo_2_formatado = 
    SWITCH(
        TRUE(),
        vRotulo_2 >= 1000000000, FORMAT( vRotulo_2, "#,,,.00 Bi"),
        vRotulo_2 >= 1000000, FORMAT( vRotulo_2, "#,,.00 Mi"),
        vRotulo_2 >= 1000, FORMAT( vRotulo_2, "#,.00 K"),
        vRotulo_2 + 0
    )


VAR vAcima_meta_borda = 
    IF(
        vRotulo_1 = 0, 
        "#bbb",
        IF(
            vRotulo_1 <= vRotulo_2, 
            "#080", 
            "#bbb"
        )
    )



RETURN 


"
data:image/svg+xml;utf8,

    <svg width='200' height='200' viewBox='0 0 200 200' fill='none' xmlns='http://www.w3.org/2000/svg'>

       <defs>
            <style>

                :root{
                    --fonte: calibri;
            
                    --txt_dia_tam: 60px;
                    --txt_dia_cor: " & vForm_fds_txt & ";
            
                    --txt_rotulos_tam: 25px;
                    --txt_rotulos_cor: #000;
            
                    --bg_fundo: " & vForm_fds_bg  & ";
                    --bg_borda_cor: " & vAcima_meta_borda & " ;
            
                }


            
            </style>

       </defs>



        <rect id='fundo' x='4' y='4' width='200' height='200' fill='var(--bg_fundo)' stroke='var(--bg_borda_cor)' stroke-width='8' rx='5' />

        <text id='num_dia' fill='var(--txt_dia_cor)' font-family='var(--fonte)' font-size='var(--txt_dia_tam)' font-weight='bold' text-anchor='end' >
            <tspan x='185' y='59'>
                " & vDia & "
            </tspan>
        </text>

        <text id='rot_1' fill='var(--txt_rotulos_cor)' font-family='var(--fonte)' font-size='var(--txt_rotulos_tam)' font-weight='bold' >
            <tspan x='14' y='130.25'>
                Contratações: " & vRotulo_1_formatado  & "
            </tspan>
        </text>

        <text id='rot_2' fill='var(--txt_rotulos_cor)' font-family='var(--fonte)' font-size='var(--txt_rotulos_tam)' font-weight='bold' >
            <tspan x='14' y='170.25'>
                Desligamentos: " & vRotulo_2_formatado & "
            </tspan>
        </text>
       

      
    </svg>
"
Faça duas substituições importantes

Troque [Contrações] e [Desligamento] pelas medidas existentes no seu modelo. Se a primeira medida deveria se chamar Contratações, corrija o nome na variável vRotulo_1.

Compatibilidade da coluna “Dia útil”

No código M fornecido, Dia útil é texto e retorna “True” ou “false”. Se o Power BI acusar comparação entre texto e valor lógico, troque as duas comparações = TRUE() por = "True". Outra opção é alterar a coluna no Power Query para o tipo lógico.

Após criar a medida, selecione-a no painel de campos e defina a Categoria de dados como URL da imagem. Sem essa configuração, o Power BI exibirá o texto da URI em vez de renderizar o SVG.

3. Monte o calendário em um visual de matriz

Com a tabela e a medida prontas, adicione um visual de Matriz e distribua os campos da seguinte forma:

Área da matrizCampo recomendadoFunção
ColunasDcalendario[Dia Nome]Cria os cabeçalhos dos dias da semana.
LinhasDcalendario[Semana do Mês]Separa o mês em linhas semanais.
Valores[Calendario Animado v2]Renderiza o cartão SVG de cada dia.
SegmentaçãoAno e NomeMesSeleciona o mês que será mostrado.

Classifique a coluna Dia Nome por Semana Dia para manter domingo, segunda, terça e os demais dias na ordem correta. Depois, ajuste a largura das colunas e a altura das linhas até que os cartões fiquem proporcionais.

  • Desative subtotais e total geral
  • Centralize os valores da matriz
  • Reduza o espaçamento interno
  • Ajuste a grade e os cabeçalhos
  • Use uma segmentação de mês único
  • Confira a ordem dos dias da semana

Como personalizar o calendário SVG

As principais opções visuais ficam dentro do bloco :root do SVG. Você pode alterar as variáveis sem reconstruir todo o desenho.

ElementoOnde alterarExemplo
Fonte--fonteCalibri, Arial ou Segoe UI
Tamanho do dia--txt_dia_tam60px
Tamanho dos rótulos--txt_rotulos_tam25px
Cor do fundovForm_fds_bg#d9d9d9
Cor da bordavAcima_meta_borda#080 ou #bbb
Textos das métricasElementos rot_1 e rot_2Vendas, metas, chamados etc.

Para trocar os indicadores, altere as medidas atribuídas a vRotulo_1 e vRotulo_2 e substitua os textos “Contratações” e “Desligamentos” dentro dos elementos SVG.

Erros mais comuns e como corrigir

O SVG aparece como texto na matriz

Selecione a medida e configure sua Categoria de dados como URL da imagem. Confirme também que a medida começa com data:image/svg+xml;utf8,.

O Power Query não encontra fCadastro

O nome é apenas um exemplo. Substitua fCadastro pelo nome exato da tabela que existe no seu arquivo e atualize também os nomes das colunas de data.

O DAX não encontra [Contrações] ou [Desligamento]

Essas medidas precisam existir no seu modelo. Use os nomes das suas próprias medidas. Verifique especialmente se “Contrações” não deveria ser “Contratações”.

A comparação de Dia útil apresenta erro

A coluna foi criada como texto no Power Query. Nas variáveis vForm_fds_bg e vForm_fds_txt, substitua TRUE() por "True", ou converta a coluna para valor lógico na linguagem M.

Os dias da semana ficam fora de ordem

Selecione Dia Nome, use “Classificar por coluna” e escolha Semana Dia. Garanta que cada nome de dia tenha apenas um número de ordenação.

Perguntas frequentes

Posso usar o calendário com vendas ou ocorrências?

Sim. Substitua as medidas dos dois rótulos pelos indicadores que deseja analisar e altere os textos exibidos no SVG.

Preciso instalar um visual personalizado?

Não. A estrutura utiliza uma matriz nativa do Power BI e uma medida categorizada como URL da imagem.

Por que criar uma tabela calendário?

Ela centraliza os atributos de data, permite filtros consistentes, melhora cálculos temporais e fornece as colunas necessárias para organizar o calendário em semanas e dias.

Posso mudar as cores do final de semana?

Sim. Altere as cores retornadas por vForm_fds_bg e vForm_fds_txt. Essas variáveis usam a coluna Dia útil para decidir a formatação.

Calendário pronto para adaptar ao seu projeto

Agora você tem a dimensão de datas, a medida SVG e a estrutura da matriz. Copie os códigos, ajuste a origem das datas e substitua as medidas do exemplo pelos indicadores do seu modelo.

Assistir novamente no YouTube
Miguel Rodrigues
Últimos posts por Miguel Rodrigues (exibir todos)