Personalizar Pontos de Dados em Gráficos Treemap e Sunburst em Python

Visão Geral

Os gráficos Treemap e Sunburst exibem o mesmo tipo de dados hierárquicos, mas utilizam layouts diferentes. Um Treemap desenha a hierarquia como retângulos aninhados cujas áreas representam os valores das folhas. Um Sunburst a desenha como anéis concêntricos: os grupos de nível superior ficam próximos ao centro, e as categorias folha estão no anel externo.

No Aspose.Slides for Python via Java, cada valor numérico é um ChartDataPoint. Seu método ChartDataPoint.getDataPointLevels fornece acesso à folha e aos seus grupos pais. Este artigo explica esse mapeamento e mostra como criar e formatar ambos os tipos de gráfico a partir dos mesmos dados de exemplo.

Um gráfico Treemap com os ramos Consumer e Business

Um gráfico Sunburst com a mesma hierarquia Consumer e Business

Entender Categorias, Pontos de Dados e Níveis

O exemplo usado abaixo possui três níveis de categoria e uma série numérica:

Ramo Subgrupo Folha Receita
Consumer Computers Laptops 12
Consumer Computers Desktops 8
Consumer Mobile Phones 15
Consumer Mobile Tablets 6
Business Services Consulting 10
Business Services Support 7
Business Software Licenses 11
Business Software Subscriptions 14

Cada linha cria uma categoria folha e um ponto de dados. Os níveis de agrupamento de categoria descrevem o caminho dessa folha até seus pais. Para a primeira linha, o caminho é Consumer > Computers > Laptops.

Os índices retornados por ChartDataPoint.getDataPointLevels vão da folha para cima:

getDataPointLevels() índice Nível lógico Representação Treemap Representação Sunburst
0 Folha Retângulo de valor Segmento do anel externo
1 Subgrupo Retângulo ou cabeçalho pai Segmento do anel médio
2 Ramo Retângulo ou cabeçalho de nível superior Segmento do anel interno

Essa ordem é a mesma para ambos os tipos de gráfico, embora seus layouts visuais diferam. Um segmento pai é compartilhado por várias folhas. Para formatá‑lo, use o nível correspondente do primeiro ponto de dados naquele grupo. Por exemplo, o ramo Consumer começa com o ponto Laptops, enquanto o subgrupo Software começa com o ponto Licenses. Manter referências a esses pontos é mais claro e seguro do que usar expressões não explicitas como data_points.get_Item(0) ou data_points.get_Item(6).

Criar e Personalizar Ambos os Tipos de Gráfico

O exemplo completo a seguir cria um Treemap no primeiro slide e um Sunburst no segundo slide. Ele constrói a hierarquia, exibe o valor para Tablets, aplica cores fixas a níveis selecionados, formata um rótulo de ramo e salva a apresentação.

import jpype
import asposeslides

if not jpype.isJVMStarted():
    jpype.startJVM()

from asposeslides.api import ChartType, FillType, ParentLabelLayoutType, Presentation, SaveFormat
from java.awt import Color

presentation = Presentation()
try:
    worksheet_index = 0
    leaf_level_index = 0
    stem_level_index = 1
    branch_level_index = 2

    branch_names = [
        "Consumer", "Consumer", "Consumer", "Consumer",
        "Business", "Business", "Business", "Business"
    ]
    stem_names = [
        "Computers", "Computers", "Mobile", "Mobile",
        "Services", "Services", "Software", "Software"
    ]
    leaf_names = [
        "Laptops", "Desktops", "Phones", "Tablets",
        "Consulting", "Support", "Licenses", "Subscriptions"
    ]
    revenues = [12, 8, 15, 6, 10, 7, 11, 14]
    data_point_count = len(leaf_names)

    chart_types = [ChartType.Treemap, ChartType.Sunburst]
    layout_slide = presentation.getLayoutSlides().get_Item(0)

    for chart_index, chart_type in enumerate(chart_types):
        if chart_index == 0:
            slide = presentation.getSlides().get_Item(0)
        else:
            slide = presentation.getSlides().addEmptySlide(layout_slide)

        chart = slide.getShapes().addChart(chart_type, 40, 40, 640, 440)
        chart.setTitle(False)
        chart.setLegend(False)

        chart_data = chart.getChartData()
        chart_data.getCategories().clear()
        chart_data.getSeries().clear()

        workbook = chart_data.getChartDataWorkbook()
        workbook.clear(worksheet_index)

        # Adicione as categorias folha. Um item de agrupamento é definido somente quando um novo grupo começa;
        # as categorias seguintes permanecem nesse grupo até que outro item seja definido.
        for data_index in range(data_point_count):
            row_index = data_index + 1
            leaf_name = leaf_names[data_index]
            category_cell = workbook.getCell(worksheet_index, row_index, 2, leaf_name)
            category = chart_data.getCategories().add(category_cell)

            stem_name = stem_names[data_index]
            starts_new_stem = data_index == 0
            if data_index > 0:
                previous_stem_name = stem_names[data_index - 1]
                starts_new_stem = stem_name != previous_stem_name
            if starts_new_stem:
                category.getGroupingLevels().setGroupingItem(stem_level_index, stem_name)

            branch_name = branch_names[data_index]
            starts_new_branch = data_index == 0
            if data_index > 0:
                previous_branch_name = branch_names[data_index - 1]
                starts_new_branch = branch_name != previous_branch_name
            if starts_new_branch:
                category.getGroupingLevels().setGroupingItem(branch_level_index, branch_name)

        series_name_cell = workbook.getCell(worksheet_index, 0, 3, "Revenue")
        series = chart_data.getSeries().add(series_name_cell, chart_type)
        series.getLabels().getDefaultDataLabelFormat().setShowCategoryName(True)

        laptops_data_point = None
        tablets_data_point = None
        licenses_data_point = None

        for data_index in range(data_point_count):
            row_index = data_index + 1
            leaf_name = leaf_names[data_index]
            revenue = revenues[data_index]
            value_cell = workbook.getCell(worksheet_index, row_index, 3, jpype.JDouble(revenue))

            if chart_type == ChartType.Treemap:
                data_point = series.getDataPoints().addDataPointForTreemapSeries(value_cell)
            else:
                data_point = series.getDataPoints().addDataPointForSunburstSeries(value_cell)

            if leaf_name == "Laptops":
                laptops_data_point = data_point
            elif leaf_name == "Tablets":
                tablets_data_point = data_point
            elif leaf_name == "Licenses":
                licenses_data_point = data_point

        # Exiba a categoria e o valor na folha Tablets.
        tablets_leaf_level = tablets_data_point.getDataPointLevels().get_Item(leaf_level_index)
        tablets_label_format = tablets_leaf_level.getLabel().getDataLabelFormat()
        tablets_label_format.setShowCategoryName(True)
        tablets_label_format.setShowValue(True)
        tablets_label_format.setSeparator("\n")
        tablets_label_format.setNumberFormat("$0")

        # Formate o ramo Consumer através da primeira folha desse ramo.
        consumer_branch_level = laptops_data_point.getDataPointLevels().get_Item(branch_level_index)
        consumer_branch_fill = consumer_branch_level.getFormat().getFill()
        consumer_branch_color = Color(31, 78, 121)
        consumer_branch_fill.setFillType(FillType.Solid)
        consumer_branch_fill.getSolidFillColor().setColor(consumer_branch_color)

        consumer_label_format = consumer_branch_level.getLabel().getDataLabelFormat()
        consumer_label_format.setShowCategoryName(True)
        consumer_label_format.setShowSeriesName(False)
        consumer_label_text_fill = consumer_label_format.getTextFormat().getPortionFormat().getFillFormat()
        consumer_label_text_fill.setFillType(FillType.Solid)
        consumer_label_text_fill.getSolidFillColor().setColor(Color.WHITE)

        # Formate o caule Software através da primeira folha desse caule.
        software_stem_level = licenses_data_point.getDataPointLevels().get_Item(stem_level_index)
        software_stem_fill = software_stem_level.getFormat().getFill()
        software_stem_color = Color(112, 173, 71)
        software_stem_fill.setFillType(FillType.Solid)
        software_stem_fill.getSolidFillColor().setColor(software_stem_color)

        # ParentLabelLayout afeta os rótulos pai do Treemap; Sunburst usa segmentos de anel.
        if chart_type == ChartType.Treemap:
            series.setParentLabelLayout(ParentLabelLayoutType.Overlapping)

    presentation.save("hierarchical-charts.pptx", SaveFormat.Pptx)
finally:
    presentation.dispose()

As células de categoria e as células de valor utilizam a mesma linha da planilha, portanto suas posições nas coleções permanecem alinhadas. Quando você trabalha com um gráfico existente em vez de criar um novo, inspecione primeiro as linhas de categoria e armazene referências nomeadas aos pontos de dados e níveis que pretende formatar.

Comportamento e Considerações Práticas

Diferenças entre Treemap e Sunburst

  • Um Treemap usa área para comunicar valor e retângulos aninhados para comunicar hierarquia. O método ChartSeries.setParentLabelLayout controla como os rótulos dos pais aparecem neste tipo de gráfico.
  • Um Sunburst usa ângulo para comunicar valor e profundidade de anel para comunicar hierarquia. ChartSeries.setParentLabelLayout não controla os rótulos dos anéis.
  • Ambos os tipos de gráfico utilizam os mesmos níveis de agrupamento de categoria e a mesma ordem folha‑para‑pai retornada por ChartDataPoint.getDataPointLevels, portanto o código de construção de dados e de formatação de níveis pode ser compartilhado.
  • Os valores dos pais são calculados a partir de suas folhas descendentes. Não adicione pontos numéricos separados para ramos ou subgrupos.

Ordenação e Ordem dos Segmentos

O mecanismo de layout do gráfico determina a posição final dos retângulos e dos segmentos de anel. Organize linhas de categoria relacionadas juntas antes de adicioná‑las, mas não dependa de uma posição de retângulo ou ângulo inicial específicos. Se a sequência possuir significado, inclua‑a nos rótulos ou use um tipo de gráfico com eixo de categoria explícito.

Tema e Cores Fixas

Níveis de gráfico não formatados herdam cores do tema da apresentação. O exemplo usa preenchimentos RGB explícitos para resultados previsíveis. Se o gráfico precisar seguir alterações de tema, use cores de esquema em vez de valores RGB fixos e evite sobrescrever todos os níveis. Também verifique o contraste dos rótulos após mudar o preenchimento de um ramo ou subgrupo.

Rótulos e Espaço Disponível

O PowerPoint pode ocultar ou truncar rótulos quando um segmento é muito pequeno. Aumentar o tamanho do gráfico, encurtar nomes de categoria ou mostrar menos campos de rótulo geralmente produz um resultado mais claro. Um rótulo pode combinar o nome da categoria, o nome da série e o valor através de DataLabelFormat, mas habilitar todos os campos costuma tornar gráficos hierárquicos difíceis de ler.

Exportação e Renderização

Salvar em PPTX mantém o gráfico editável. Quando o Aspose.Slides renderiza a apresentação para PDF ou imagem, os preenchimentos e configurações de rótulo suportados são renderizados junto ao gráfico. Substituição de fontes e pequenas diferenças no espaço de layout disponível podem alterar quebras de linha ou a visibilidade dos rótulos, portanto instale as fontes necessárias e verifique os alvos de exportação importantes.

Perguntas Frequentes

Por que alterando um nível pai afeta várias folhas?

Um ramo ou subgrupo é um segmento visual compartilhado. Seu ChartDataPointLevel pode ser alcançado através de uma folha descendente, mas a formatação pertence ao segmento pai compartilhado, e não somente àquela folha.

Por que um rótulo de dado está ausente?

Primeiro habilite os campos necessários no objeto DataLabelFormat do rótulo. Em seguida, verifique se o segmento tem espaço suficiente. O layout de rótulo pai do Treemap, as dimensões do gráfico, o comprimento do rótulo, o tamanho da fonte e o número de campos habilitados afetam se o rótulo pode ser exibido.

Posso definir a ordem exata ou as coordenadas dos segmentos?

Você pode controlar a ordem das linhas‑fonte e manter cada grupo contíguo, mas não pode atribuir retângulos exatos do Treemap ou ângulos exatos do Sunburst. O mecanismo de layout do gráfico os calcula a partir da hierarquia, valores e espaço disponível.

Por que as cores mudam após a alteração do tema da apresentação?

Preenchimentos baseados em tema são projetados para seguir a paleta da apresentação. Aplique cores RGB explícitas aos níveis que devem permanecer fixos ou mantenha cores de esquema quando a adaptação a um novo tema for preferida.

A formatação personalizada será preservada em exportações PDF e de imagem?

Sim, os preenchimentos de gráfico e configurações de rótulo suportados são incluídos durante a renderização. Para resultados consistentes entre sistemas, disponibilize as fontes necessárias e teste o tamanho final da exportação, pois o ajuste de rótulo depende do layout.

Veja Também