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.
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.
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.
Tabela calendário
Cria uma linha para cada data entre o menor e o maior período existente na base.
Medida SVG
Desenha o cartão de cada dia e inclui as métricas selecionadas dentro da imagem.
Visual de matriz
Distribui os dias pelas semanas do mês e pelos dias da semana.
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.
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
TabelaAs 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.
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>
"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.
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 matriz | Campo recomendado | Função |
|---|---|---|
| Colunas | Dcalendario[Dia Nome] | Cria os cabeçalhos dos dias da semana. |
| Linhas | Dcalendario[Semana do Mês] | Separa o mês em linhas semanais. |
| Valores | [Calendario Animado v2] | Renderiza o cartão SVG de cada dia. |
| Segmentação | Ano e NomeMes | Seleciona 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.
| Elemento | Onde alterar | Exemplo |
|---|---|---|
| Fonte | --fonte | Calibri, Arial ou Segoe UI |
| Tamanho do dia | --txt_dia_tam | 60px |
| Tamanho dos rótulos | --txt_rotulos_tam | 25px |
| Cor do fundo | vForm_fds_bg | #d9d9d9 |
| Cor da borda | vAcima_meta_borda | #080 ou #bbb |
| Textos das métricas | Elementos rot_1 e rot_2 | Vendas, 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