|
|
|
import plotly.express as px |
|
import plotly.graph_objects as go |
|
import pandas as pd |
|
from typing import Optional, Tuple |
|
|
|
|
|
from .icf_categories import ICFComponent |
|
|
|
|
|
ORDERED_ICF_LABELS = ICFComponent.get_ordered_labels() |
|
ICF_COLOR_MAP_FROM_LABEL = ICFComponent.get_color_map() |
|
ICF_COLOR_MAP_FROM_SHORT_CODE = { |
|
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='Frequência', |
|
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']], |
|
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 |
|
|
|
|
|
if not input_df['Frequência'].any(): |
|
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', |
|
title=title, |
|
labels={'Componente CIF': 'Componentes CIF', 'Frequência': '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 |
|
|
|
|
|
|
|
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}'.") |
|
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", |
|
|
|
|
|
|
|
hovertemplate='<b>%{label}</b><br>Frequência: %{value}<br>Porcentagem da Entrada: %{percentEntry:.1%}<extra></extra>', |
|
marker_line_width=1, |
|
marker_line_color='white' |
|
) |
|
|
|
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 |