🇧🇷 SAP Analytics Cloud – Como Criar um Gráfico de Barras Dinâmico com 2 Padrões de Cores

Pode parecer uma tarefa simples. No entanto, replicar o gráfico acima no SAC não é tão simples e requer muita atenção aos detalhes. Neste tutorial vamos mostrar, passo a passo, como criar um gráfico de barras híbrido que responde aos seus filtros de maneira dinâmica.

Exemplo

Para começar, abra uma tela em branco no SAC e adicione um elemento de Gráfico. Em seguida, selecione o modelo de dados de sua preferência.

Criando Contas Restritas de Valores Realizados (Actuals)

  1. Vá para o painel “Gerador” e navegue até a seção de “Contas”. Clique no botão “+Adicionar Conta” e escolha “Adicionar Cálculo”.
  2. Selecione “Conta Restrita” como tipo de conta.
  3. Nomeie a conta como “Actual” (Realizado) e certifique-se de que esteja alinhada com sua métrica desejada.
  4. Em dimensões, selecione Data e depois “Selecionar por Intervalo”.
    • Modifique a opção “Data Atual” de “Data do Sistema” para “+”Criar Controle de Data Atual”.
    • Dê um nome para o Controle de Entrada Data Atual e defina a granularidade como “Mês”.
    • Clique em “Ok”
  5. Habilite a opção “Incluir Intervalo até o Intervalo de Tempo Atual” na seção “Intervalo 1”, permitindo que os usuários ajustem o intervalo de acordo com o mês desejado.
  6. Clique em “OK”
  7. Adicione outra dimensão selecionando “+Adicionar uma Dimensão” após a Data e escolha “Versão”. Escolha a opção “Selecionar por Membro” e selecione a versão “Actual” (Realizado).
  8. Clique em “OK”
  9. Confirme que a seleção “Habilitar Seleção Constante” está ativada e apenas a dimensão de Versão está selecionada, excluindo Data.
  10. Clique em “Ok” para finalizar a criação da conta.

Criando a Conta Restrita de Previsão (Forecast) para o Ano Inteiro

Em seguida, vamos duplicar a conta de Valores Realizados (Actuals) e ajustá-la para representar os valores previstos (Forecast).

  • Clique no icone com três pontinhos da conta de Valores Realizados (Actuals) que você acabou de criar e selecione “Duplicar”. Essa nova conta duplicada servirá como base para a segunda conta.
  • Clique no icone dos três pontinhos da conta duplicada e escolha “Editar Cálculo”.
  • Renomeie a conta para “Full Year Forecast” (Previsão Ano Inteiro) e ajuste o valor da dimensão de data para abranger todo o ano de 2023. Defina a Versão como “Previsão”.
  • Clique em “OK.”

Criando a Conta Restrita de Previsão (Forecast)

Para exibir apenas o período de previsao, vamos criar uma conta calculada que calcula a diferença entre a Conta de Previsão Ano Inteiro (Full Year Forecast) e a Conta de Valores Realizados (Actuals).

  • Em seguida, remova a conta de “Previsão Ano Inteiro” do painel gerador do gráfico.
  • Configure o gráfico de barras selecionando a opção Barra/Coluna Empilhada e alterando a orientação para Vertical.
  • Adicione uma medida e uma dimensão de data ao gráfico.
  • Certifique-se de que o painel gerador esteja refletindo essas seleções.

Estilo e Formatação

  • Role para baixo até o painel de “Definição de Estilo” e ative a opção “Evitar sobreposição de Etiqueta de Dados” para evitar a exibição dos zeros.
  • Clique no gráfico e selecione “Mostrar/Ocultar” nos três pontos no canto superior direito e desative as Etiquetas de Dados.
  • Teste cores diferentes para as categorias e o fundo para maximizar o visual do gráfico.

Observe o resultado final ajustando os meses no painel de filtros.

Espero que você tenha curtido e achado esse exemplo útil. Se você tiver alguma pergunta ou sugestão, deixe um comentário abaixo.

Obrigado e até a próxima!

Jorge Rocha

Read this article in English.

🇨🇦 SAP Analytics Cloud – How to Create a Dynamic Bar Chart with 2 Color Patterns

It might seem like a simple task. However, getting the chart above in SAC isn’t as straightforward and it requires careful steps and attention to detail. In this tutorial, we’ll go through the process, step by step, on how to create a visually stunning hybrid bar chart.

Example

To begin, open a blank canvas in SAC and add a Chart element. Select your preferred data model for the chart.

Creating Actuals Restricted Accounts

  1. Head to the builder panel and navigate to the Accounts section. Click on the “+Add Account” button and choose “Add Calculation.”
  2. Opt for a “Restricted Account” as the account type.
  3. Assign the name “actuals” to the account and ensure it aligns with your desired metric.
  4. Under dimensions, select Date and then Select by Range
    • Modify the “Current Date” option from “System Date” to “+Create Current Date Input Control.”
    • Provide a name for the Current Date Input Control and set the granularity to “Month.”
    • Click “Ok”
  5. Enable the “Include Range up to Current Time Interval” option in the “Range 1” section, allowing users to adjust the range as per their preferred month.
  6. Click “OK”
  7. Add another dimension by selecting “+Add a Dimension” after Date and choose “Version.” Opt for “Select by Member” and select your desired “Actual” version.
  8. Click “OK”
  9. Confirm that the “Enable Constant Selection” toggle is on and only the Version dimension is selected, excluding Date.
  10. Click “OK” to finalize the creation of the account.

Creating the Full Year Forecast Restricted Account

Next, let’s duplicate the Actuals account and tailor it to represent the Forecasted values.

  • Click on the three dots of the Actuals account you just created and select “Duplicate.” This duplication serves as the foundation for the second measure.
  • Click on the three dots of the duplicated account and choose “Edit Calculation.”
  • Rename the account as “Full Year Forecast” and adjust the date dimension value to encompass the entire year of 2023. Set the Version as “Forecast.”
  • Click “OK.”

Creating the Forecast Restricted Account

To exclusively display the forecasted period, we’ll create a calculated account that calculates the difference between the Full Year Forecast and Actual accounts.

  • Next, remove the Full Year Forecast account from the widget.
  • Configure the bar chart by selecting the Stacked Bar/Column option and changing the orientation to Vertical.
  • Add a measure and a date dimension to the chart.
  • Ensure that the builder panel reflects these selections.

Styling and Formatting

  • Scroll down to the styling panel and activate the “Avoid Data Label Overlap” option to prevent the display of zeros.
  • Click on the chart, then select “Show/Hide” from the three dots on the top right corner, and disable Data Labels.

  • Play around with different colors for the categories and background to maximize the visual impact of the chart.

Observe the final result by adjusting the months under the filters panel.

I hope you found this example helpful. If you have any questions or suggestions, please leave a comment below.

Thanks for reading, and see you next time!

Jorge Rocha

Ler este artigo em Português Brasileiro

🇧🇷 SAP Analytics Cloud – Como editar um gráfico de Ponto Numérico utilizando CSS

Fala pessoal!

Já tentou aplicar uma formatação condicional em um gráfico de Ponto Numérico e descobre só depois que ela se aplica para o elemento como um todo e não apenas para o valor primário? Pode acreditar, eu já cometi o mesmo erro incontáveis vezes.

Então para tentar encontrar uma solução, me aprofundei na documentação de CSS do SAP Analytics Cloud e encontrei umas informações muito interessantes que podem te ajudar a economizar um tempo também.

O classe CSS abaixo te permite controlar exatamente o valor que queremos formatar neste tutorial:

.sap-custom-number-chart-secondary-values:
* Descrição: Classe CSS para numeros de um gráfico no valor secundário;
* Propriedades: font-family, font-size, color, font-style, font-weight, text-decoration;
* Descendentes: N/A;
* Pseudos: N/A;

Agora vamos explorar mais como a classe CSS mencionada acima pode ser aplicada ao elemento de Ponto Numérico. Para exemplificar melhor, vamos identificar quais são os valores primários (primary) e secundários (secondary) em um elemento:

Primary and secondary values in a numeric widget

O principal objetivo deste post é demonstrar como ignorar a formatação condicional que é aplicada automaticamente no valor secundário através de CSS, garantindo que apenas os valores primários sejam impactados pela formatação condicional.

Exemplo

A resultado abaixo é o que estamos tentando replicar:

Objetivo final do tutorial
Actual (Realizado) РBudget (Or̤amento) РMonthly Volume (Volume Mensal)

Passo 1: Primeiramente, crie uma nova tela de história. Em seguida adicione um elemento gráfico para a tela. Depois de adicionado, poderemos modificar da forma que queremos. Neste exemplo vamos selecionar o gráfico de “Ponto Numérico”.

Passo 2: Agora que temos nosso gráfico criado, é hora de popular com dados. Adicione uma conta ao valor primário, uma conta ao valor secundário e uma medida (adicione também uma versão caso nao esteja trabalhando com medidas de restrição).

Passo 3: Agora podemos criar a formatação condicional que compara o valor contido na conta primária contra o valor na conta secundária. Isso vai nos permitir visualizar de forma rápida quando nossos valores realizados e orçados estão dentro ou fora do esperado.

Passo 4: Se quisermos ir um passo além e personalizar a aparencia do elemento ainda mais, podemos editar o estilo CSS. Para fazer isso, siga os passos abaixo:

  • Clique no ícone de pincel localizado nas Configurações globais. O painel CSS vai abrir após clicar.

  • Copie o pedaço de código abaixo que passa um código de cores HEX para o valor secundário:
.chart .sap-custom-number-chart-secondary-values {
    color: #58595b;
}
  • Cole o código dentro do painel CSS. Lembre-se de alterar a seleção para gráfico.

Passo 5: Para garantir que a customização CSS seja aplicada ao gráfico, precisamos adicionar o nome da classe criada dentro do gráfico de Ponto Numérico. Aqui vai o exemplo de como fazer isso:

  1. Selecione o elemento gráfico.
  2. Vá ao painel de Definição de Estilo e licalize o campo “Nome da Classe CSS”.
  3. Escreva “chart” como o nome da classe CSS e aperte enter.

Passo 6: Agora você pode salvar sua história e ir para o modo de visualização e ver o novo estilo.

As outras formatações que você vê no elemento são simplesmente elementos cosméticos, tais como contorno e tamanho de fonte para torná-lo mais apresentável.

Espero que você tenha curtido e achado esse exemplo útil. Se você tiver alguma pergunta ou sugestão, deixe um comentário abaixo.

Obrigado e até a próxima!

Jorge Rocha

Read this article in English.

🇨🇦 SAP Analytics Cloud – How to enhance Numeric Point widgets through CSS

Hey everyone!

Have you ever tried to apply conditional formatting to a Numeric Point widget, only to find out that it affects the entire widget instead of just the primary value? Trust me, I’ve been there countless times myself.

I embarked on a quest to find a solution, delving into the depths of SAP’s CSS documentation. And guess what? I discovered some valuable info that can save you from the same problem.

This following CSS class allows you to control the exact value we’re trying to change:

.sap-custom-number-chart-secondary-values:
* Description: CSS class for number chart secondary values;
* Properties: font-family, font-size, color, font-style, font-weight, text-decoration;
* Descendants: N/A;
* Pseudos: N/A;

Now, let’s explore more how the CSS class mentioned above can be applied to the Numeric Point widget. To provide a clearer picture, let’s identify the primary and secondary values on the widget itself:

Primary and secondary values in a numeric widget

The primary goal of this blog post is to demonstrate how you can overwrite conditional formatting colors in the secondary value, ensuring that only the primary value responds to the conditional formatting rules.

Example

Here’s what we’re aiming to achieve:

End goal of the tutorial

Step 1: To get started, create a new story in your canvas. Begin by adding a Chart element to your canvas. Once added, we can modify its format to suit our needs. In this case, we’ll change the chart format to “Numeric Point.”

Step 2: Now that we have our chart in place, it’s time to populate it with data. Add one account to the primary value and another to the secondary value. Additionally, include a measure (and a version if you’re not working with measures restricted on the version).

Step 3: We can now create color thresholds (Conditional formatting) against the account on the secondary value. This will allow us to visually highlight important points, which is the comparison of actuals vs budget.

Step 4: If we want to take it a step further and personalize its appearance, we can edit the CSS style. To do so, follow the steps below:

  • Click on the paintbrush icon located under Global Settings. This will open up the CSS page.

  • Copy the following code snippet:
.chart .sap-custom-number-chart-secondary-values {
    color: #58595b;
}
  • Paste the code into the CSS Class Name field. Remember to set chart as the widget to receive the formatting.

Step 5: To ensure that our CSS customization is applied to the chart, we need to add the chart class to the CSS Class Name field in the Styling panel. Here’s an example of how to do it:

  1. With the widget selected.
  2. Locate the CSS Class Name field in the Styling panel.
  3. Enter “chart” as the CSS class name and hit enter.

Step 6: You can now save your story and switch to view mode to see how the new styling has been applied.

The other formatting you see on this widget is simply cosmetic changes such as borders and font size to make it look more presentable.

I hope you found this example helpful. If you have any questions or suggestions, please leave a comment below.

Thanks for reading, and see you next time!

Jorge Rocha

Ver este artigo em Português Brasileiro

🇧🇷 SAP Analytics Cloud – Como Simplificar o Gerenciamento de Controle de Entrada com a API .setSelectedMembers

Fala pessoal!

A SAP adicionou uma API muito útil para definir membros ativos de dimensões nos controles de entrada (filtros) do SAP Analytics Cloud chamada .setSelectedMembers().

Isso pode não ter recebido toda a atenção que merece quando foi anunciado, mas acredite em mim, vai mudar a forma que você cria suas histórias quando se trata de gerenciar controles de entrada.

Neste tutorial, vou mostrar as aplicações da API .setSelectedMembers() usando dois exemplos aplicáveis. Imagine que você tem um tela com tabelas e graficos ligadas a vários modelos de dados e, para complicar ainda mais, essas tabelas possuem medidas restritas. Lidar com inúmeros controles de entrada personalizados pode ser realmente complicado, não é?

A ideia é a seguinte: você pode facilmente buscar os membros selecionados de apenas um controle de entrada, armazená-los em uma variável e, em seguida, passá-los facilmente para outros controles de entrada usando a API setSelectedMembers(). Não precisa mais gastar tempo mudando seleções em vários controles de entrada diferentes.

Vamos então para os exemplos:

Exemplo 1

Digamos que, por exemplo, você tenha dois controles de entrada (filtros) em sua história, e eles estão conectados a dois modelos diferentes que contêm a mesma dimensão Version (Versão). O objetivo aqui é garantir que o conteúdo do primeiro controle de entrada seja o mesmo que o segundo.

Para isso, siga as etapas abaixo:

  • Clique no botão fx do primeiro controle de entrada que você deseja selecionar (Version_1).
  • Em seguida, escreva o seguinte código no bloco onSelect:
//Obter o membro selecionado do controle de entrada Version_1
var inputVersion = this.getInputControlDataSource().getActiveSelectedMembers();
 
//Definir a mesma versão para o segundo controle de entrada Version_2
Version_2.getInputControlDataSource().setSelectedMembers(inputVersion);

Conforme explicado nos comentários, a linha 2 define uma variável para armazenar o membro selecionado, e a linha 5 o passa para o outro controle de entrada. Esse método pode ser aplicado mesmo se você tiver mais de dois controles de entrada.

Após salvar a história, clique no modo Exibição.

Aqui está a saída final no modo de visualização:

Exemplo 2

Agora vamos explorar um exemplo mais avançado que adiciona uma lógica à forma como gerenciar o segundo controle de entrada (ou terceiro, quarto, etc).

Neste cenário, temos dois controles de entrada de data. No entanto, em vez de ter a mesma seleção para ambos sempre, queremos que o filtro Date_1 controle o segundo controle de entrada, ao mesmo tempo em que garantimos que o filtro Date_2 represente sempre o mês anterior ao Date_1.

Para alcançar isso, siga estas etapas abaixo:

  • Clique no botão fx do primeiro controle de entrada que você deseja selecionar (Date_1).

Em seguida, escreva o seguinte código no bloco onSelect:

  • Obtenha o membro selecionado do controle de entrada Date_1 na variável inputMonth.
var inputMonth = this.getInputControlDataSource().getActiveSelectedMembers();
  • Extraia o ano e o mês do ID do controle de entrada, que se parece com isso: [Date].[YM].&[YYYYMM].
var year = inputMonth[0].id.slice(-7, -3);
var month = inputMonth[0].id.slice(-3, -1);
  • Converta as strings extraídas para inteiros.
var yearInt = ConvertUtils.stringToInteger(year);
var monthInt = ConvertUtils.stringToInteger(month);
  • Calcule o mês anterior.
if (monthInt === 1) {
  yearInt--;
  monthInt = 12;
} else {
  monthInt--;
}

Verifique se o mês é menor que 10 e adicione um zero à esquerda, se necessário.

if (monthInt < 10) {
  month = "0".concat(ConvertUtils.numberToString(monthInt));
}
  • Crie a variável previousMonth combinando o ano e o mês.
var previousMonth = ConvertUtils.numberToString(yearInt).concat(month);
  • Defina o previousMonth como o segundo controle de entrada Date_2.
Date_2.getInputControlDataSource().setSelectedMembers(previousMonth);

Este trecho de código obtém o ID do membro selecionado no filtro Date_1, manipula as strings para extrair o mês anterior e, em seguida, o passa para o segundo controle de entrada. Imagine as possibilidades que essa abordagem oferece para diferentes aplicações!

Aqui está o código completo:

//Obter o membro selecionado do controle de entrada Data_1
var inputMonth = this.getInputControlDataSource().getActiveSelectedMembers();
 
//Extrair o ano e o mês do ID do controle de entrada que se parece com isso: [Date].[YM].&[YYYYMM]
var year = inputMonth[0].id.slice(-7, -3);
var month = inputMonth[0].id.slice(-3, -1);
 
//Converter as strings para numeros inteiros
var yearInt = ConvertUtils.stringToInteger(year);
var monthInt = ConvertUtils.stringToInteger(month);
 
//Calcula o mês anterior
if (monthInt === 1) {
  yearInt --;
  monthInt = 12;
} else {
  monthInt --;
}
 
//Verifica se o mês é menor que 10 e adiciona um zero à esquerda, case necessário
if (monthInt < 10) {
    month = "0".concat(ConvertUtils.numberToString(monthInt));
 
    var previousMonth = ConvertUtils.numberToString(yearInt).concat(month);
}
 
//Define o priorMonth como o segundo controle de entrada Date_2
Date_2.getInputControlDataSource().setSelectedMembers(previousMonth);

Após salvar a história, clique no modo Exibição. Aqui está o resultado final em ação:

Limitações

Conforme mencionado por Orla Cullen aqui, esta API não suporta controles de entrada que mostram:

  • Membros não reservados (Unbooked members)
  • Membros excluídos
  • Filtros de intervalo e filtros avançados

Espero que você tenha curtido e achado esses exemplos úteis. Se você tiver alguma pergunta ou sugestão, deixe um comentário abaixo.

Obrigado e até a próxima!

Jorge Rocha

Artigo em ingles

🇨🇦 SAP Analytics Cloud – How to Simplify Input Control Management with .setSelectedMembers API

Hey everyone!

SAP has added a very useful API to set active dimension members on input controls to SAP Analytics Cloud called .setSelectedMembers().

This might not have grabbed all the attention it deserves, but trust me, it’s a game-changer when it comes to managing input controls.

In this brief tutorial, I’ll walk you through the capabilities of the .setSelectedMembers() API using two examples. Imagine you have a dashboard with tables linked to multiple data models, and to make things more challenging, these tables have restricted measures. Dealing with numerous custom input controls can be a real pain, right?

Here’s the deal: You can easily fetch the members selected from just one input control, store them in a variable, and then effortlessly pass them along to other input controls using the .setSelectedMembers() API. No more wasting time flipping selections in many different input controls.

Here’s a simple example first:

Example 1

Let’s say, for example, that you have two input controls (filters) in your story, and they are linked to two different models that contain the same Version dimension. The goal here is to ensure that the content of the first input control matches that of the second.

To achieve this, follow these steps:

  • Click on the fx button of the first input control that you want to select (Version_1).
  • Write the following code onSelect:
//Get selected member from Input control Version_1
var inputVersion = this.getInputControlDataSource().getActiveSelectedMembers();

//Set the same version to the second Input control Version_2.
Version_2.getInputControlDataSource().setSelectedMembers(inputVersion);

As explained in the comments, line 2 defines a variable to store the selected member, and line 5 passes it to the other input control. This method can be applied even if you have more than two input controls.

After saving the story, switch to View mode.

Here’s the final output in view mode:

Example 2

Now, let’s explore a more advanced example that adds some logic to the way we control the second input control.

In this scenario, we have two Date input controls. However, instead of having the same selection for both always, we want to ensure that the Date_1 filter drives the second one, while also ensuring that the Date_2 filter always represents the month prior to Date_1.

To achieve this, follow these steps:

  • Click on the fx button of the first input control that you want to select (Date_1).

Write the following code onSelect:

  • Get the selected member from the Input control Date_1.
var inputMonth = this.getInputControlDataSource().getActiveSelectedMembers();
  • Extract the year and month from the input control ID, which looks something like this: [Date].[YM].&[YYYYMM].
var year = inputMonth[0].id.slice(-7, -3);
var month = inputMonth[0].id.slice(-3, -1);
  • Convert the extracted strings to integers.
var yearInt = ConvertUtils.stringToInteger(year);
var monthInt = ConvertUtils.stringToInteger(month);
  • Calculate the previous month.
if (monthInt === 1) {
  yearInt--;
  monthInt = 12;
} else {
  monthInt--;
}
  • Check if the month is lower than 10 and add a leading zero if necessary.
if (monthInt < 10) {
  month = "0".concat(ConvertUtils.numberToString(monthInt));
}
  • Create the previousMonth variable by combining the year and month.
var previousMonth = ConvertUtils.numberToString(yearInt).concat(month);
  • Set the previousMonth to the second Input control Date_2.
Date_2.getInputControlDataSource().setSelectedMembers(previousMonth);
  • This code snippet grabs the ID of the selected member on the Date_1 filter, manipulates the strings to extract the previous month, and then passes it to the second input control. Imagine the possibilities this approach offers for different applications!

Here’s the complete code snippet:

//Get selected member from Input control Date_1
var inputMonth = this.getInputControlDataSource().getActiveSelectedMembers();

//Extract year and month from the input control id that looking something like this: [Date].[YM].&[YYYYMM]
var year = inputMonth[0].id.slice(-7, -3);
var month = inputMonth[0].id.slice(-3, -1);

//Convert strings to Integers
var yearInt = ConvertUtils.stringToInteger(year);
var monthInt = ConvertUtils.stringToInteger(month);

//Calculates previous month
if (monthInt === 1) {
  yearInt --;
  monthInt = 12;
} else {
  monthInt --;
}

//If statement checks if month is lower than 10 and adds leading zero if necessary
if (monthInt < 10) {
	month = "0".concat(ConvertUtils.numberToString(monthInt));

	var previousMonth = ConvertUtils.numberToString(yearInt).concat(month);
}

//Set the previousMonth to the second Input control Date_2
Date_2.getInputControlDataSource().setSelectedMembers(previousMonth);

After saving the story, switch to View mode. Here’s the final output in action:

Limitations

As mentioned by Orla Cullen here. This API does not support input controls that show:​

  • Unbooked members
  • Excluded members
  • Range filters and advanced filters

I hope you found these examples helpful. If you have any questions or suggestions, please leave a comment below.

Thanks for reading, and see you next time!

Jorge Rocha

Article in Brazilian Portuguese