<jupyter_start><jupyter_text>Mapeamento de médias do ENEM por estado com Folium Objetivo: Mapear todas as médias do ENEM por escola, isto é, vamos colocar um pin em cada localização de uma unidade escolar a sua respectiva média.---Criado por <NAME>*   [GitHub](https://www.github.com/WendelMarques)*   [LinkedIn](https://www.linkedin.com/in/wendelmarques/)*   [Medium](https://medium.com/@WendelMarquesJS/mapeamento-de-m%C3%A9dias-do-enem-por-estado-com-folium-bf61fe23a3d8?source=your_stories_page---------------------------)  Bibliotecas<jupyter_code>from google.colab import drive
drive.mount('/content/drive')
import pandas as pd
import numpy as np
import json
import folium
from folium import Marker
from folium.plugins import MarkerCluster
from jinja2 import Template
from branca.element import Template, MacroElement<jupyter_output><empty_output><jupyter_text>Tratamento dos dados do ENEM  Leitura dos dados e visualização do conteúdo<jupyter_code>#carrega os dados no dataframe
df = pd.read_csv('/content/drive/My Drive/Colab Notebooks/enem/microdados-enem-escola.csv', encoding = 'latin-1', sep=';')
#vizualiza as primeiras 5 entradas do dataframe
df.head()
#imprime o numero de linhas e colunas do dataframe
df.shape
#imprime o tipo de dado em cada coluna
df.dtypes
#lista o nome das colunas do dataframe
list(df.columns)<jupyter_output><empty_output><jupyter_text>Remoção de colunas<jupyter_code>#remove colunas desnecessárias
df.drop(['TP_DEPENDENCIA_ADM_ESCOLA',
         'TP_LOCALIZACAO_ESCOLA',
         'NU_MATRICULAS',
         'NU_PARTICIPANTES_NEC_ESP',
         'NU_PARTICIPANTES',
         'NU_TAXA_PARTICIPACAO'], axis=1,inplace=True)
#remove mais colunas
#como a analise leva em consideracao os exames de 2009 a 2015
#as colunas 'NU_MEDIA_OBJ','NU_MEDIA_TOT' são desnecessárias
#levando em conta a alteracao do formato da prova
df.drop(['NU_MEDIA_TOT',
         'NU_MEDIA_OBJ',
         'INSE',
         'PC_FORMACAO_DOCENTE',
         'NU_TAXA_PERMANENCIA',
         'NU_TAXA_APROVACAO',
         'NU_TAXA_REPROVACAO',
         'NU_TAXA_ABANDONO',
         'PORTE_ESCOLA'], axis=1, inplace=True)
df.shape<jupyter_output><empty_output><jupyter_text>Tratamento de dados faltantes<jupyter_code>#verificando se existem valores faltantes nos dados
df.isna().any()
#verificando se existem valores faltantes nos dados
df.isna().sum()
#descartando as linhas que tem poucos valores faltantes
df.dropna(axis=0, subset=['NU_MEDIA_CN', 'NU_MEDIA_CH', 'NU_MEDIA_LP', 'NU_MEDIA_MT', 'NU_MEDIA_RED'],inplace=True)
#verificando quantas linhas de dados ainda estão no dataframe. Perdemos cerca de 39,46% dos dados
df.shape
#verificando novamente se existem valores faltantes nos dados
df.isna().sum()<jupyter_output><empty_output><jupyter_text>Inclusão de média das notas de cada escola<jupyter_code>#calculando a media simples das notas
df['MEDIA TOTAL'] = (df['NU_MEDIA_RED'] + df['NU_MEDIA_MT'] + df['NU_MEDIA_LP'] + df['NU_MEDIA_CN'] + df['NU_MEDIA_CH'])/5



df.head()
# #removendo linhas de dados de anos anteriores a 2009
# df.drop(df[df.NU_ANO < 2009].index, inplace=True)
#altera index para 0 - len(df)
indices = list(range(0, len(df)))
df.index = indices

df = df.groupby(['CO_ESCOLA_EDUCACENSO'], as_index=False)['MEDIA TOTAL'].mean()
df.head()
#salvando df
df.to_csv('tratamento-dados-enem.csv', index=False)<jupyter_output><empty_output><jupyter_text>Tratamento dados de localização das escolas<jupyter_code>listaEscolas = pd.read_csv('/content/drive/My Drive/Colab Notebooks/enem/Análise - Tabela da lista das escolas - Detalhado.csv', encoding = 'utf-8', sep=';')
listaEscolas.head()
#exclusao de colunas que não serão utilizadas
listaEscolas.drop(['Localização',	'Localidade Diferenciada',	'Categoria Administrativa',	
                   'Endereço',	'Telefone',	'Dependência Administrativa',	'Categoria Escola Privada',
                   'Conveniada Poder Público',	'Regulamentação pelo Conselho de Educação',	'Porte da Escola',
                   'Etapas e Modalidade de Ensino Oferecidas', 'Outras Ofertas Educacionais', 'Restrição de Atendimento'], 
                    axis = 1, inplace=True)
listaEscolas.head()
#verificando dados faltantes 
listaEscolas.isna().sum()
listaEscolas.shape
#descartando linhas que tem dados faltantes
listaEscolas.dropna(axis=0, subset=['Latitude', 'Longitude'], inplace=True)
#verificando quantas linhas de dados ainda estão no dataframe. Perdemos cerca de 31% dos dados
listaEscolas.shape
#salvando df
listaEscolas.to_csv('tratamento-dados-localizacao.csv', index=False)<jupyter_output><empty_output><jupyter_text>Merge dados do ENEM e localização das escolas<jupyter_code>#converte coluna "Codigo INEP" em indice
listaEscolas.index = listaEscolas['Código INEP']
#excluindo coluna 'Código INEP'
listaEscolas.drop('Código INEP', axis=1, inplace=True)
listaEscolas.head()
df.head()
df.shape
mergeEscolaLocalizacao = df.join(listaEscolas, on='CO_ESCOLA_EDUCACENSO')
mergeEscolaLocalizacao.head()
mergeEscolaLocalizacao.shape 
df.shape
#excluindo dados faltantes
mergeEscolaLocalizacao.dropna(axis=0, subset=['Longitude', 'Latitude'], inplace=True)
mergeEscolaLocalizacao.isna().sum()
#salvando merge
mergeEscolaLocalizacao.to_csv('merge-df-e-listaEscolas.csv', index=False)<jupyter_output><empty_output><jupyter_text>Plotagem do mapa  Criação do Mapa<jupyter_code>#"Passagem de propriedades personalizadas via marcador, 
#no Folium o marcador padrão não o suporta, mas a seguinte classe de 
#marcador pode ser introduzida, estendendo a classe Marker" (fonte: <NAME>/Stack OverFlow)

class MarkerWithProps(Marker):
    _template = Template(u"""
        {% macro script(this, kwargs) %}
        var {{this.get_name()}} = L.marker(
            [{{this.location[0]}}, {{this.location[1]}}],
            {
                icon: new L.Icon.Default(),
                {%- if this.draggable %}
                draggable: true,
                autoPan: true,
                {%- endif %}
                {%- if this.props %}
                props : {{ this.props }} 
                {%- endif %}
                }
            )
            .addTo({{this._parent.get_name()}});
        {% endmacro %}
        """)
    def __init__(self, location, popup=None, tooltip=None, icon=None,name=None,
                 draggable=False, props = None ):
        super(MarkerWithProps, self).__init__(location=location,popup=popup,tooltip=tooltip,icon=icon,draggable=draggable)
        self.props = json.loads(json.dumps(props))    


# Personalização da função icon_create_function do cluster de marcadores,
# para substituição do rótulo do marcador para exibir o valor personalizado em vez do padrão 
# (contagem de marcadores em um cluster) (fonte: <NAME>/Stack OverFlow)

icon_create_function = '''
    function(cluster) {
        var markers = cluster.getAllChildMarkers();
        var sum = 0;
        for (var i = 0; i < markers.length; i++) {
            sum += markers[i].options.props.mediaTotal;
        }
        var avg = sum/cluster.getChildCount();   
        avg=avg.toFixed(2);  

        function verifica_Media(media) {
            if (media < 520) {
                return 'marker-cluster marker-cluster-large'
            }
            else if (media >=  520 && media <= 600) {
                return 'marker-cluster marker-cluster-medium'
            }
            else  if (media > 600) {
                return 'marker-cluster marker-cluster-small'
            }
        }

        return L.divIcon({
             html: '<div style="display:flex;justify-content:center;align-items:center;font-size:7pt;">'+ avg +'</div>',
             className: verifica_Media(avg),
             iconSize: new L.Point(40, 40)
        });
    }
'''

## CRIAÇÃO DO MAPA
width, height = 480, 350
from branca.element import Figure
fig = Figure(width=width, height=height)

map = folium.Map(location=[-9.026078, -70.441312], zoom_start=4, tiles=None)
folium.TileLayer(name='ENEM MÉDIAS').add_to(map)

maker_data_list = []
for index, row in mergeEscolaLocalizacao.iterrows():
        maker_data_list.append({'localizacao':[row['Latitude'], row['Longitude']], 'mediaTotal': round(row['MEDIA TOTAL'], 2), 
                                'nomeEscola': row['Escola'], 'UF': row['UF']})

marker_data = tuple(maker_data_list)

estados = {}
grupos = {}
estados_unique = np.unique(mergeEscolaLocalizacao['UF'])

for uf in estados_unique:
    estados[uf] = MarkerCluster(icon_create_function=icon_create_function, name=uf)
    grupos[uf] = folium.FeatureGroup(name=uf)

for uf in estados:
    for marker_item in marker_data:
        if (marker_item['UF'] == uf):
            MarkerWithProps(
                    location=marker_item['localizacao'],
                    props = {'mediaTotal': marker_item['mediaTotal']},
                    popup=marker_item['nomeEscola'] + ":<br>" + '<b>' + str(marker_item['mediaTotal']) + '</b>',
                    icon =  (
                            folium.Icon(color='red', icon_color='#f5f6fa', icon='university', prefix='fa') 
                            if marker_item['mediaTotal'] < 600 
                            else folium.Icon(color='blue', icon_color='#f5f6fa',
                                            icon='university', prefix='fa')
                            ),
                ).add_to(estados[uf])

    grupos[uf].add_child(estados[uf])
    estados[uf].add_to(map)<jupyter_output><empty_output><jupyter_text>Legenda<jupyter_code>template = """
{% macro html(this, kwargs) %}

<!doctype html>
<html lang="utf-8">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Mapeamento de médias do ENEM por escola (2009 - 2015)</title>
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

</head>
<body>

<div id='maplegend' class='maplegend' 
    style='position: absolute; z-index:9999; border:0px; background-color:rgba(255, 255, 255, 0.8);
     border-radius:6px; padding: 10px; font-size:25px; left: 0px; top: 0px;'>
     
    <div class='legend-title'><font size="2">Mapeamento de médias do ENEM</div>
    <div class='legend-scale'><font size="1">Provas de 2009 a 2015 | github.com/WendelMarques</font></div>
</div>

 
<div id='maplegend' class='maplegend' 
    style='position: absolute; z-index:9999; border:2px solid white; background-color:rgba(255, 255, 255, 0.8);
     border-radius:6px; padding: 10px; font-size:11px; left: 20px; bottom: 20px;'>
     
<div class='legend-title'>Agrupamentos</div>
<div class='legend-scale'>
  <ul class='legend-labels'>
    <li><span style='background:orange;opacity:0.7;'></span> 339 - 520</li>
    <li><span style='background:yellow;opacity:0.7;'></span>520 - 600</li>
    <li><span style='background:green;opacity:0.7;'></span>600 - 753</li>

  </ul>
  <div class='legend-title'>Marcadores</div>
    <ul class='legend-labels'>
    <li><span style='background:red;opacity:0.7;'></span>Menor que 600 </li>
    <li><span style='background:blue;opacity:0.7;'></span>Maior que 600</li>
  </ul>

  </ul>
  <div class='legend-title'></div>
    

</div>
</div>
 
</body>
</html>

<style type='text/css'>
  .maplegend .legend-title {
    text-align: left;
    margin-bottom: 5px;
    font-weight: bold;
    font-size: 90%;
    }
  .maplegend .legend-scale ul {
    margin: 0;
    margin-bottom: 5px;
    padding: 0;
    float: left;
    list-style: none;
    }
  .maplegend .legend-scale ul li {
    font-size: 80%;
    list-style: none;
    margin-left: 0;
    line-height: 18px;
    margin-bottom: 2px;
    }
  .maplegend ul.legend-labels li span {
    display: block;
    float: left;
    height: 16px;
    width: 30px;
    margin-right: 5px;
    margin-left: 0;
    border: 1px solid #999;
    }
  .maplegend .legend-source {
    font-size: 80%;
    color: #777;
    clear: both;
    }
  .maplegend a {
    color: #777;
    }
</style>
{% endmacro %}"""

macro = MacroElement()
macro._template = Template(template)

map.get_root().add_child(macro)<jupyter_output><empty_output><jupyter_text>Salva mapa<jupyter_code>folium.LayerControl('topright', collapsed=True).add_to(map)
# map.save('/content/drive/My Drive/Colab Notebooks/mapeamento-enem/mapa-completo.html')
map.save('mapa-completo.html')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13718765311122, 'fraction_numerical': 0.019026620937448963, 'mean_word_length': 3.5544812197843063, 'pattern_counts': {'":': 1, '<': 112, '<?xml version=': 0, '>': 109, 'https://': 3, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '396475', 'license': 'MIT', 'n_tokens_mistral': 4626, 'n_tokens_neox': 4322, 'n_words': 895, 'path': 'notebook/mapeamento_enem_folium.ipynb', 'repo_name': 'wendelmarques/mapeamento-medias-enem-folium', 'size': '12274'}