File size: 7,814 Bytes
cc0607e
33c855c
 
 
cc0607e
a6beb3a
 
 
 
 
 
 
 
 
33c855c
 
 
 
 
 
 
a6beb3a
 
33c855c
 
a6beb3a
 
 
 
 
33c855c
 
a6beb3a
33c855c
 
 
 
 
a6beb3a
33c855c
 
 
 
 
a6beb3a
33c855c
 
 
 
a6beb3a
 
33c855c
 
a6beb3a
 
33c855c
 
 
 
 
a6beb3a
33c855c
 
 
a6beb3a
33c855c
 
 
 
 
 
 
 
 
a6beb3a
 
33c855c
 
a6beb3a
 
 
 
 
33c855c
 
a6beb3a
33c855c
 
 
 
 
a6beb3a
 
 
33c855c
a6beb3a
33c855c
 
a6beb3a
33c855c
a6beb3a
33c855c
a6beb3a
33c855c
a6beb3a
 
 
33c855c
 
 
 
 
a6beb3a
33c855c
 
 
 
a6beb3a
33c855c
 
 
 
 
 
 
 
 
a6beb3a
 
33c855c
 
a6beb3a
 
 
33c855c
 
a6beb3a
33c855c
 
 
 
 
a6beb3a
 
 
 
 
 
 
 
 
33c855c
a6beb3a
 
 
33c855c
a6beb3a
 
 
33c855c
 
 
a6beb3a
 
 
 
 
 
 
33c855c
a6beb3a
 
 
 
 
 
 
cc0607e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# utils/report/graph_creation.py
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
from typing import Optional, Tuple # Dict e List não são mais necessários para as constantes globais

# Importa a Enum para centralizar as definições de categoria, rótulos e cores
from .icf_categories import ICFComponent

# Obtém as informações de ordenação e cores diretamente da Enum ICFComponent
ORDERED_ICF_LABELS = ICFComponent.get_ordered_labels()
ICF_COLOR_MAP_FROM_LABEL = ICFComponent.get_color_map() # Mapeia Rótulo Completo -> Cor
ICF_COLOR_MAP_FROM_SHORT_CODE = { # Mapeia Código Curto -> Cor (para o Treemap)
    member.short_code: member.color for member in ICFComponent
}

def create_pie_chart(
    input_df: pd.DataFrame,
    title: str = "Distribuição da Classificação"
) -> Optional[go.Figure]:
    """
    Gera um gráfico de pizza a partir de um DataFrame, usando cores consistentes
    para as categorias CIF presentes nos dados de entrada.

    Args:
        input_df (pd.DataFrame): DataFrame com colunas 'Componente CIF' (rótulos)
                                 e 'Frequencia' (valores).
                                 Espera-se que 'Componente CIF' já esteja como
                                 pd.Categorical ordenado.
        title (str): O título do gráfico.

    Returns:
        Optional[go.Figure]: Objeto Plotly Figure ou None se não houver dados válidos.
    """
    if input_df.empty:
        print(f"Aviso: DataFrame de entrada para o gráfico de pizza '{title}' está vazio. Retornando None.")
        return None

    plot_df = input_df[input_df['Frequência'] > 0].copy()

    if plot_df.empty:
        print(f"Aviso: Nenhum dado com frequência positiva para gerar o gráfico de pizza: '{title}'. Retornando None.")
        return None

    category_order_map = {'Componente CIF': ORDERED_ICF_LABELS}

    figure = px.pie(
        plot_df,
        names='Componente CIF',
        # values='Frequencia', # ANTES
        values='Frequência', # DEPOIS
        title=title,
        color='Componente CIF',
        color_discrete_map=ICF_COLOR_MAP_FROM_LABEL,
        category_orders=category_order_map
    )

    figure.update_layout(legend_title_text='Componentes')
    figure.update_traces(
        direction='clockwise',
        rotation=-30,
        textinfo="label+value+percent",
        textposition='outside',
        textfont_size=16,
        pull=[0.05 if val > 0 else 0 for val in plot_df['Frequência']], # DEPOIS
        hovertemplate="<b>%{label}</b><br>Frequência: %{value}<br>Porcentagem: %{percent}<extra></extra>"
    )
    return figure

def create_bar_chart(
    input_df: pd.DataFrame,
    title: str = "Frequência da Classificação"
) -> Optional[go.Figure]:
    """
    Gera um gráfico de barras a partir de um DataFrame, usando cores consistentes
    para as categorias CIF.

    Args:
        input_df (pd.DataFrame): DataFrame com colunas 'Componente CIF' (eixo X)
                                 e 'Frequencia' (eixo Y).
                                 Espera-se que 'Componente CIF' já esteja como
                                 pd.Categorical ordenado.
        title (str): O título do gráfico.

    Returns:
        Optional[go.Figure]: Objeto Plotly Figure ou None se não houver dados válidos.
    """
    if input_df.empty:
        print(f"Aviso: DataFrame de entrada para o gráfico de barras '{title}' está vazio. Retornando None.")
        return None

    # Para gráficos de barra, podemos plotar frequências zero, então não filtramos > 0
    if not input_df['Frequência'].any(): # DEPOIS
         print(f"Aviso: Todos os dados em input_df têm frequência 0 para o gráfico de barras: '{title}'.")

    category_order_map = {'Componente CIF': ORDERED_ICF_LABELS}

    figure = px.bar(
        input_df,
        x='Componente CIF',
        y='Frequência', # DEPOIS
        title=title,
        labels={'Componente CIF': 'Componentes CIF', 'Frequência': 'Frequência'}, # DEPOIS (chave 'Frequência')
        color='Componente CIF',
        color_discrete_map=ICF_COLOR_MAP_FROM_LABEL,
        category_orders=category_order_map,
        text_auto=True
    )
    figure.update_layout(
        legend_title_text='Componentes',
        xaxis_title="Componentes CIF",
        yaxis_title="Frequência",
        showlegend=True
    )
    figure.update_traces(
        textfont_size=14,
        textangle=0,
        textposition="inside",
        hovertemplate="<b>%{x}</b><br>Frequência: %{y}<extra></extra>"
    )
    return figure

def create_tree_map_chart(
    tree_map_df: pd.DataFrame,
    title: str = "Treemap de Frequências por Hierarquia de Códigos"
) -> Optional[go.Figure]:
    """
    Gera um gráfico Treemap a partir de um DataFrame hierárquico.
    As cores do nível 'Parent' são baseadas nos códigos curtos dos componentes CIF.

    Args:
        tree_map_df (pd.DataFrame): DataFrame com colunas 'Parent', 'Subparent',
                                    'Filho' (Rótulo), e 'Frequencia'.
        title (str): O título do gráfico.

    Returns:
        Optional[go.Figure]: Objeto Plotly Figure ou None se o DataFrame estiver vazio.
    """
    if tree_map_df.empty:
        print(f"Aviso: DataFrame vazio para gerar o Treemap: '{title}'.")
        return None

    # Filtra linhas onde 'Filho' é nulo ou vazio, pois podem causar problemas no treemap
    # e geralmente representam nós estruturais que não devem ser folhas.
    plot_df = tree_map_df.dropna(subset=['Código'])
    plot_df = plot_df[plot_df['Código'] != ""]

    if plot_df.empty:
        print(f"Aviso: DataFrame para Treemap não contém 'Códigos' válidos após filtragem: '{title}'.") # DEPOIS
        return None

    figure = px.treemap(
        plot_df,
        path=['Componente', 'Capítulo', 'Código'],
        values='Frequência',
        title=title,
        color='Componente',
        color_discrete_map=ICF_COLOR_MAP_FROM_SHORT_CODE,
        height=700
    )

    figure.update_traces(
        textinfo="label+value+percent entry", # Informações exibidas
        # Para hovertemplate, %{customdata} pode ser usado se você adicionar colunas extras
        # Exemplo: customdata=plot_df[['Parent', 'Subparent']]
        # hovertemplate='<b>%{label}</b> (%{customdata[0]} > %{customdata[1]})<br>Frequência: %{value}<br>Porcentagem da Entrada: %{percentEntry:.1%}<extra></extra>',
        hovertemplate='<b>%{label}</b><br>Frequência: %{value}<br>Porcentagem da Entrada: %{percentEntry:.1%}<extra></extra>',
        marker_line_width=1,
        marker_line_color='white' # Linhas brancas para separar os blocos
    )
    
    figure.update_layout(
        hoverlabel=dict(
            bgcolor="white",
            font_size=12,
        )
    )
    return figure

def create_report_plots(df_group: pd.DataFrame, df_individual_treemap: pd.DataFrame) -> Tuple[go.Figure, go.Figure, go.Figure]:
    """
    Cria as figuras Plotly dos gráficos a partir dos DataFrames processados.

    Args:
        df_group (pd.DataFrame): DataFrame de frequência por grupo CIF.
        df_individual_treemap (pd.DataFrame): DataFrame para o treemap de códigos individuais.
                                            (Esperado ter colunas: 'Filho', 'Parent', 'Frequencia')

    Returns:
        Tuple[go.Figure, go.Figure, go.Figure]: Figuras de pizza, barras e treemap.
    """
    print("Gerando gráficos...")
    
    fig_pie = create_pie_chart(df_group, title="Distribuição da Classificação por Componentes CIF")
    fig_bar = create_bar_chart(df_group, title="Frequência da Classificação por Componentes CIF")
    fig_tree_map = create_tree_map_chart(df_individual_treemap, title="Treemap de Frequência por Código CIF")
    
    return fig_pie, fig_bar, fig_tree_map