<jupyter_start><jupyter_text>Introdução<jupyter_code>#!pip3 install kaleido --upgrade
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from paths import *<jupyter_output><empty_output><jupyter_text>DiretrizDe acordo com a [Diretriz Nacional do Plano de Amostragem da Vigilância da Qualidade da Água para Consumo Humano da Vigilância Sanitária](http://bvsms.saude.gov.br/bvs/publicacoes/diretriz_nacional_plano_amostragem_agua.pdf), o número mínimo de amostras mensais de alguns parâmetros (cloro residual, turbidez, coliformes, *E. coli* e fluoreto), a ser realizada pela vigilância sanitária municipal, varia de acordo com a população.  Número de Amostras para Cloro Residual, Turbidez, Coliformes, *E. coli*As amostras de cloro residual são feitas pelo prestador do serviço de abastecimento público (controle), bem como pela vigilância sanitária municipal (vigilância), sendo esse último o principal foco destas análises.![Tabela 1](https://i.imgur.com/6PJNeCp.png)Ainda, de acordo com as diretrizes, *o número mínimo mensal de análises previsto para o Plano de Amostragem Básico é definido em função das faixas populacionais e constitui um quantitativo único a ser distribuído para o monitoramento da qualidade da água referente às três formas de abastecimento de água (SAA, SAC e SAI)*. Portanto, para analisar se a vigilância sanitária municipal segue as diretrizes estipuladas pelo Ministério da Saúde para amostragem de cloro residual, não será feito, nesse momento, detalhamento sobre o número de amostras realizadas para cada sistema de abastecimento, avaliando-se somente o número total de amostras que devem ser realizadas pela vigilância municipal.Nos códigos abaixo, a tabela que consta nas diretrizes do Ministério da Saúde foi codificada, possibilitando análises.<jupyter_code>def create_table_cloro():
    # Criando tabela
    df = pd.DataFrame(
        {
            'População De': [0, 5001, 10001, 50001, 200001, 500001],
            'População Até': [5000, 10000, 50000, 200000, 500000, np.inf],
            'Nº de Amostras': [6, 9, '8 + (1 para cada 7,5 mil habitantes)', '10 + (1 para cada 10 mil habitantes)', '20 + (1 para cada 20 mil habitantes)', '35 + (1 para cada 50 mil habitantes)']
        }
    )

    # Criando e Ajustando Coluna Adicional
    df['Nº de Amostras Fixo'] = df['Nº de Amostras'].str.split('+').str[0]
    df['Nº de Amostras Fixo'] = df['Nº de Amostras Fixo'].fillna(df['Nº de Amostras']).astype(float)

    # Criando e Ajustando Coluna Adicional
    df['Nº de Amostras Variável'] = df['Nº de Amostras'].str.split('+').str[-1]
    df['Nº de Amostras Variável'] = df['Nº de Amostras Variável'].fillna(0)
    df['Nº de Amostras Variável'] = df['Nº de Amostras Variável'].replace({'\(1 para cada': '','mil habitantes\)': '',',': '.'}, regex=True).astype(float)
    df['Nº de Amostras Variável'] = (df['Nº de Amostras Variável']*1000).astype(int)

    # Tabela
    return df<jupyter_output><empty_output><jupyter_text>Uma vez cofificada, o *campo* descritivo **Nº de Amostras**, que contem o número de análises, foi dividido entre o **Nº de Amostras Fixo** e **Nº de Amostras Variável**, possibilitando a automatização dos cálculos.<jupyter_code>create_table_cloro()<jupyter_output><empty_output><jupyter_text>Com a tabela codificada, foi escrita uma função que calcula o número de amostras, seguindo as condições recomendadas pelo Ministério da Sáude.<jupyter_code>def numero_amostras_cloro(x):
    df_cloro = create_table_cloro()
    array = np.where(
        (x >= df_cloro['População De']) & (x <= df_cloro['População Até']) & (df_cloro['Nº de Amostras Variável']>0),
        (df_cloro['Nº de Amostras Fixo'] + x/(df_cloro['Nº de Amostras Variável'])),
        np.where(
            (x >= df_cloro['População De']) & (x <= df_cloro['População Até']) & (df_cloro['Nº de Amostras Variável']==0),
                 df_cloro['Nº de Amostras Fixo'], np.nan
        )
    )
    array = np.trunc(array)
    array = array[~np.isnan(array)]
    return array[0]<jupyter_output><empty_output><jupyter_text>Número de Amostras para Fluoreto![Tabel 2](https://i.imgur.com/JXvIYsK.png)<jupyter_code>def create_table_fluoreto():
    # Criando tabela
    df = pd.DataFrame(
        {
            'População De': [0, 50001, 100001, 100001, 500001, 1000001],
            'População Até': [50000, 100000, 200000, 500000, 1000000, np.inf],
            'Nº de Amostras': [5, 7, 9, 13, 18, 27]
        }
    )
    # Tabela
    return df
create_table_fluoreto()
def numero_amostras_fluoreto(x):
    df = create_table_fluoreto()
    array = np.where(
        (x >= df['População De']) & (x <= df['População Até']), df['Nº de Amostras'], np.nan
    )
    array = np.trunc(array)
    array = array[~np.isnan(array)]
    return array[0]<jupyter_output><empty_output><jupyter_text>PopulaçãoAbaixo são demonstrados alguns exemplos de cálculo empregando a tabela codificada e função. A definição do número mínimo de amostras pode ser feita utilizando um número isolado, ou em uma série de dados.<jupyter_code># Usando a função com apenas um número individual
população = 300000
n_amostras_cloro = numero_amostras_cloro(população)
n_amostras_fluoreto = numero_amostras_fluoreto(população)

# Results
print('Nº de Amostras de Cloro recomendadas para {} habitantes é {}'.format(população, n_amostras_cloro))
print('Nº de Amostras de Fluoreto recomendadas para {} habitantes é {}'.format(população, n_amostras_fluoreto))
# Usando a função em uma série
df = pd.DataFrame({'População': [1500, 10000, 180000, 350000, 600000, 650000]})
df['Nº Amostras Cloro'] = df['População'].apply(lambda x: numero_amostras_cloro(x))
df['Nº Amostras Fluoreto'] = df['População'].apply(lambda x: numero_amostras_fluoreto(x))

# Results
df.head()<jupyter_output><empty_output><jupyter_text>GráficoVisando compreender como se dá a distribuição do número de amostras em função do aumento da população, foi elaborado um gráfico que demonstra que o número de amostras tem um crescimento logaritmico, ou seja, para municípios com população até 200.000 hab há um aumento continuo do número de amostras, até 500.000 habitantes o aumento do número de amostras não segue a mesma tendância, sendo reduzido. Em municípios com mais de 500.000 o aumento do número de amostras é ainda menor.<jupyter_code># Cria tabela com população
df = pd.Series(np.arange(1000, 2000000, 3000)).array
df = pd.DataFrame(df, columns=['n_habitantes'])

# Ajustes da tabela
df['n_habitantes'] = df['n_habitantes'].astype(int)
df['Nº Amostras Cloro'] = df['n_habitantes'].apply(lambda x: numero_amostras_cloro(x))
df['Nº Amostras Fluoreto'] = df['n_habitantes'].apply(lambda x: numero_amostras_fluoreto(x))
# Criando gráfico
fig = go.Figure()

# Trace
fig.add_trace(
    go.Scatter(
        x=df['n_habitantes'],
        y=df['Nº Amostras Cloro'],
        name='Nº Amostras Cloro Residual, Turbidez, Coliformes, E. coli',
        mode='lines',
        marker={'color': 'blue'},
        opacity=0.8,
        #hovertemplate='s',
        #hovertemplate="$%{y}<br>Date: %{x}"
        hovertemplate="%{y}"
    )
)
# Trace
fig.add_trace(
    go.Scatter(
        x=df['n_habitantes'],
        y=df['Nº Amostras Fluoreto'],
        name='Nº Amostras Fluoreto',
        mode='lines',
        marker={'color': 'red'},
        opacity=0.8,
        hovertemplate="%{y}"
    )
)

# Update Layout
fig.update_layout(
    title='Nº de Amostras Mensais por População',
    xaxis={'title': 'Nº de Habitantes'},
    yaxis={'title': 'Nº de Amostras'},
    height=600,
    separators=',.',
    paper_bgcolor='rgba(0,0,0,0)',
    yaxis_tickformat=',.2r',
    xaxis_tickformat=',.2r',
    dragmode=False,
    #hovermode='closest',
    hovermode='x',
    #hoverinfo= "name+x+text",
    #hovermode='x unified',
    #hoverlabel='ssss',
    legend=dict(
        yanchor='top',
        y=1,
        xanchor='left',
        x=0.0
    )
)

# Graph
config = {
    'displaylogo': False,
    #'scrollZoom': True,
    'responsive': False,
}
fig.write_html(os.path.join(output_path_graph, 'n_amostras_habitantes.html'), config=config)
fig.write_image(os.path.join(output_path_graph, 'n_amostras_habitantes.png'), width=800, height=500, scale=1)

fig.show(config=config)<jupyter_output><empty_output><jupyter_text>Export<jupyter_code>import os
from traitlets.config import Config
from nbconvert import PythonExporter
from nbconvert.preprocessors import TagRemovePreprocessor
input_filepath = os.path.join(os.getcwd(), '01_diretriz.ipynb')
output_filepath = os.path.abspath(os.path.join(os.getcwd(), '..', 'src', 'normas', 'diretriz.py'))
print(output_filepath)
# Import the exporter
c = Config()
c.TagRemovePreprocessor.enabled=True
c.ClearOutputPreprocessor.enabled=True
c.TemplateExporter.exclude_markdown=True
c.TemplateExporter.exclude_code_cell=False
c.TemplateExporter.exclude_input_prompt=True
c.TemplateExporter.exclude_output=True
c.TemplateExporter.exclude_raw=True
c.TagRemovePreprocessor.remove_cell_tags = ('remove_cell',)
c.TagRemovePreprocessor.remove_input_tags = ('remove_cell',)
c.TagRemovePreprocessor.remove_all_outputs_tags = ('remove_output',)
c.preprocessors = ['TagRemovePreprocessor']
c.PythonExporter.preprocessors = ['nbconvert.preprocessors.TagRemovePreprocessor']

# Configure and run out exporter
py_exporter = PythonExporter(config=c)
py_exporter.register_preprocessor(TagRemovePreprocessor(config=c), True)

# Configure and run out exporter - returns a tuple - first element with html, second with notebook metadata
body, metadata = PythonExporter(config=c).from_filename(input_filepath)

# Write to output html file
with open(output_filepath,  'w', encoding='utf-8') as f:
    f.write(body)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11735588326286481, 'fraction_numerical': 0.026606166855728575, 'mean_word_length': 4.687976539589442, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 38, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '507312', 'license': 'MIT', 'n_tokens_mistral': 3715, 'n_tokens_neox': 3498, 'n_words': 892, 'path': 'test/01_diretriz.ipynb', 'repo_name': 'gaemapiracicaba/norma_diretrizes_vigilancia', 'size': '9697'}