Skip to content

Instantly share code, notes, and snippets.

@ndvo
Created June 3, 2018 23:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ndvo/366184bbf4d4916e8b822d07bb669669 to your computer and use it in GitHub Desktop.
Save ndvo/366184bbf4d4916e8b822d07bb669669 to your computer and use it in GitHub Desktop.
Preparador de arquivos csv para mapas estáticos do SIMPR
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import xlrd #leitor de arquivos em excel
import csv #lidar com arquivos em csv
import os # lidar com o sistema operacional (pastas e arquivos)
import sys # lidar com diferentes sistemas operacionais (linux e windows)
import codecs # lidar com difirentes codificações de caracteres
import cStringIO
from Tkinter import * # Criar janelas e interfaces gráficas
import tkSimpleDialog
import tkMessageBox
import Tkconstants
import tkFileDialog
coluna_cod_mun = 2
coluna_info = 4
coluna_nome = 9
class UnicodeWriter:
"""
A CSV writer which will write rows to CSV file "f",
which is encoded in the given encoding.
"""
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
# Redirect output to a queue
self.queue = cStringIO.StringIO()
self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
self.stream = f
self.encoder = codecs.getincrementalencoder(encoding)()
def writerow(self, row):
self.writer.writerow([unicode(s).encode("utf-8") for s in row])
# Fetch UTF-8 output from the queue ...
data = self.queue.getvalue()
data = data.decode("utf-8")
# ... and reencode it into the target encoding
data = self.encoder.encode(data)
# write to the target stream
self.stream.write(data)
# empty queue
self.queue.truncate(0)
def writerows(self, rows):
for row in rows:
self.writerow(row)
def unicode_csv_reader(utf8_data, dialect=csv.excel, **kwargs):
csv_reader = csv.reader(utf8_data, dialect=dialect, **kwargs)
for row in csv_reader:
yield [unicode(cell, 'utf-8') for cell in row]
class Regiao():
def __init__(self, nome, codigo):
self.nome = nome
self.codigo = codigo
self.itens = {}
self.empreendimentos = []
self.totais = {}
class StatusBar(Frame):
def __init__(self, root):
Frame.__init__(self, root)
self.label = Label(self, bd=1, relief=SUNKEN, anchor=W)
self.label.pack(fill=X)
def set(self, format, *args):
self.label.config(text=format % args)
self.label.update_idletasks()
def clear(self):
self.label.config(text="")
self.label.update_idletasks()
class App():
def __init__(self, root):
self.source_file = None
self.operacoes_disponiveis = ['Ocultar','soma', 'max','min']
self.cabecalho = []
self.operacao_selecionada = {}
self.dados_municipais_padrao = os.path.join(os.path.expanduser('~'),'dados_municipais.csv')
self.dados_municipais = None
frame = Frame(root,width=200, height=100)
self.frame = frame
namelbl = Label(frame, text=u"Agregador para construção de mapas SIM-PR")
name = Entry(frame)
# create a menu
menu = Menu(root)
root.config(menu=menu)
filemenu = Menu(menu)
menu.add_cascade(label="Arquivo", menu=filemenu)
filemenu.add_command(label="Fonte de Dados Municipais", command=self.open_dados_municipais)
filemenu.add_command(label="Arquivo com os dados a trabalhar", command=self.open_dados_a_trabalhar)
filemenu.add_separator()
filemenu.add_command(label="Sair", command=callback)
settingsmenu = Menu(menu)
menu.add_cascade(label=u"Configurações",menu=settingsmenu)
settingsmenu.add_command(label=u"Definir Coluna do Código do Município", command=self.set_coluna_codmun)
helpmenu = Menu(menu)
menu.add_cascade(label="Ajuda", menu=helpmenu)
helpmenu.add_command(label="Como Usar", command=self.help)
helpmenu.add_command(label="Sobre", command=self.about)
#Prepara a caixa de texto do log
self.text_scroll=Scrollbar(frame, orient=VERTICAL)
self.text=Text(frame,height=40,width=80,background='white',yscrollcommand=self.text_scroll.set)
self.text_scroll.config(command=self.text.yview)
self.text.tag_config("blue_white", foreground="blue",background="white")
self.print_initial_message()
self.button_sair = Button(frame, text="Sair", fg="red", command=frame.quit)
self.button_executar = Button(frame, text="Executar", fg="black", command=self.aplicar_script)
self.button_agregar = Button(frame, text="Agregar", fg="black", command=self.agregar_por_regioes)
listrotulo = Label(frame, text="Selecione a coluna")
self.listbox_scrollbar = Scrollbar(frame, orient=VERTICAL)
self.listbox = Listbox(frame, yscrollcommand=self.listbox_scrollbar.set, exportselection = 0)
self.listbox_scrollbar.config(command=self.listbox.yview)
self.listbox.bind('<<ListboxSelect>>', self.action_listbox)
operacaorotulo = Label(frame, text=u"Selecione as operações\n para cada nível de agregação")
operacao_pais_rotulo = Label(frame, text=u"País")
self.operacao_pais_listbox = Listbox(frame, exportselection=0,height=3)
self.operacao_pais_listbox.bind('<<ListboxSelect>>', self.action_operacao_listbox)
operacao_regiao_rotulo = Label(frame, text=u"Região")
self.operacao_regiao_listbox = Listbox(frame, exportselection=0,height=3)
self.operacao_regiao_listbox.bind('<<ListboxSelect>>', self.action_operacao_listbox)
operacao_estado_rotulo = Label(frame, text=u"Estado")
self.operacao_estado_listbox = Listbox(frame, exportselection=0,height=3)
self.operacao_estado_listbox.bind('<<ListboxSelect>>', self.action_operacao_listbox)
operacao_municipio_rotulo = Label(frame, text=u"Município")
self.operacao_municipio_listbox = Listbox(frame, exportselection=0,height=3)
self.operacao_municipio_listbox.bind('<<ListboxSelect>>', self.action_operacao_listbox)
self.niveis_operacoes = [
self.operacao_pais_listbox,
self.operacao_regiao_listbox,
self.operacao_estado_listbox,
self.operacao_municipio_listbox,
]
agregada_rotulo = Label(frame, text=u'Colunas a Agregar\n Por região na Tabela')
self.agregada_scroll = Scrollbar(frame, orient=VERTICAL)
self.agregada_text = Text(frame,height=10, width=25,background="#d9d9d9")
self.agregada_scroll.config(command=self.agregada_text.yview)
#### Posiciona os widgets na tela ###
frame.grid(column=0, row=0, columnspan=10, rowspan=6)
namelbl.grid(column=1, row=0)
self.text.grid(column=1,row=1, columnspan=3,rowspan=14, sticky=N+S)
self.text_scroll.grid(column=5, row=1, rowspan=14,sticky=N+S)
listrotulo.grid(column=6, row=0)
self.listbox.grid(column=6, row=1, sticky=N+S)
self.listbox_scrollbar.grid(column=7, row=1, sticky=N+S)
operacaorotulo.grid(column=6, row=2, sticky = S)
operacao_pais_rotulo.grid(column=6, row=3, sticky = S)
self.operacao_pais_listbox.grid(column = 6, row = 4, sticky=N)
operacao_regiao_rotulo.grid(column=6, row=5, sticky = S)
self.operacao_regiao_listbox.grid(column = 6, row = 6, sticky=N)
operacao_estado_rotulo.grid(column=6, row=7, sticky = S)
self.operacao_estado_listbox.grid(column = 6, row = 8, sticky=N)
operacao_municipio_rotulo.grid(column=6, row=9, sticky = S)
self.operacao_municipio_listbox.grid(column = 6, row = 10, sticky=N)
agregada_rotulo.grid(column=6, row=11, sticky=S)
self.agregada_text.grid(column=6,row=12,sticky=N, columnspan=1)
self.agregada_text.config(state=DISABLED)
self.button_sair.grid(column=1, row=15)
self.button_executar.grid(column=2, row=15)
self.button_agregar.grid(column=3, row=15)
#Informa o usuário que não há ainda um arquivo selecionado
self.listbox.insert(END, u"Não há arquivo selecionado.")
self.status = StatusBar(root)
self.status.grid(column=0,row=10,columnspan=10,sticky=E+W)
self.status.set('Nenhuma planilha selecionada.')
self.resultados = None
def set_coluna_codmun(self):
nova_coluna = tkSimpleDialog.askinteger('Que coluna contém o código do município?', 'Digite o número da coluna que contém o código do município.')
if nova_coluna.__class__ == int:
coluna_cod_mun = nova_coluna+1
def print_initial_message(self):
self.text.insert(END, u"» Este programa ajusta um arquivo em Excel para o formato esperado pelo Mapa Estático do SIM-PR.\n", ("blue_white",))
self.text.insert(END, u"» Até o momento ele funciona somente para o programa Minha Casa Minha Vida.\n", ("blue_white",))
self.text.insert(END, u"» O arquivo em excel pode conter algumas variáveis que serão substituídas pelos valores correspondentes, observando-se o código do município.\n", ("blue_white",))
self.text.insert(END, u"» tais variáveis são:\n", ("blue_white",))
self.atualiza_de_para()
for i in self.de_para.keys():
self.text.insert(END, " - "+i+"\n", ("blue_white",))
self.text.insert(END, u"» Modo de usar:\n", ("blue_white",))
self.text.insert(END, u"» Selecione o arquivo em excel a ser trabalhado. O pograma criará na mesma pasta em que o arquivo está uma série de outros arquivos, em csv. A última coluna será considerada um separador. Será criado um arquivo em csv para cada valor único da última coluna (à exceção da primeira linha). Isto será feito para cada planilha constante do arquivo. Os arquivos em csv resultantes serão nomeados com uma junção do nome do arquivo mais o nome da planilha mais o nome do valor único da última coluna.\n", ("blue_white",))
self.text.insert(END, u"» ATENÇÃO: Caso existam arquivos com nomes idênticos aos que serão criados, eles serão sobrescritos.\n", ("blue_white",))
def help(self):
tkMessageBox.showinfo("Ajuda", u"Selecione a Planilha Excel na qual você pretende aplicar o script.")
def about(self):
tkMessageBox.showinfo("Sobre", u"Script para preparação de planilhas do programa MCMV.")
def open_dados_a_trabalhar(self):
self.source_file = tkFileDialog.askopenfilename(filetypes=[('Excel 1997 - 2000', '*.xls'),])
wb = xlrd.open_workbook(self.source_file)
self.resultados = {}
for i in wb.sheet_names():
sheet = wb.sheet_by_name(i)
self.cabecalho = []
self.operacao_selecionada = {}
for ii in sheet.row_values(0):
self.cabecalho.append(ii)
self.operacao_selecionada[ii] = [None,None,None,None]
if self.source_file:
self.status.set("Fonte de dados: "+self.source_file)
self.atualiza_colunas()
def open_dados_municipais(self):
self.dados_municipais = tkFileDialog.askopenfilename(filetypes=[('Texto CSV', '*.csv'),])
self.atualiza_de_para()
self.text.insert(END, u"» Um novo arquivo de dados municipais foi selecionado. As variáveis disponíveis agora são:\n", ("blue_white",))
self.atualiza_de_para()
for i in self.de_para.keys():
self.text.insert(END, " - "+i+"\n", ("blue_white",))
def atualiza_colunas(self):
self.listbox.delete(0, END)
counter =0
for i in self.cabecalho:
self.listbox.insert(END, str(counter)+" - "+i)
counter+=1
for i in self.niveis_operacoes:
i.delete(0,END)
for i in self.operacoes_disponiveis:
for ii in self.niveis_operacoes:
ii.insert(END, i)
def aplicar_script(self):
self.text.yview(END)
fonte_de_dados = self.dados_municipais or self.dados_municipais_padrao
criar_resultado = []
excelfile = self.source_file
dic_populacao= {}
for i in self.populacao:
dic_populacao[i[0]] = i
planilhas = {}
if excelfile:
self.text.insert(END, u"\n\n\n» ~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~ \n\n\n", ("blue_white",))
self.text.insert(END, u"» Arquivo a ser trabalhado: "+excelfile+"\n", ("blue_white",))
self.text.insert(END, u"» Arquivos resultantes: \n", ("blue_white",))
#Extrai do excel
wb = xlrd.open_workbook(excelfile)
resultados = {}
for i in wb.sheet_names():
sheet = wb.sheet_by_name(i)
planilhas[i] = []
primeira_linha = True
cabecalho = []
for rownum in range(sheet.nrows):
if primeira_linha:
for ii in sheet.row_values(rownum):
cabecalho.append(ii)
primeira_linha = False
if len(criar_resultado)<1:
criar_resultado.append(cabecalho)
else:
linha = []
contador = 0
for ii in sheet.row_values(rownum):
if contador==2:
cod_mun = int(ii)
if unicode(ii) in self.de_para.keys():
#print ii
#print dic_populacao[unicode(cod_mun)][self.de_para[unicode(ii)]]
linha.append(dic_populacao[unicode(cod_mun)][self.de_para[unicode(ii)]])
else:
linha.append(ii)
contador +=1
#linha.append(ii)
nome = excelfile[:-4]+'_'+i+'_'+unicode(linha[-1])
if nome not in resultados.keys():
resultados[nome] = []
resultados[nome].append(cabecalho)
resultados[nome].append(linha)
criar_resultado.append(linha)
for r in resultados.keys():
atual = resultados[r]
nome_arquivo = r+'.csv'
self.text.insert(END, " - "+nome_arquivo+"\n", ("blue_white",))
csvfile = UnicodeWriter(open(nome_arquivo, 'w'))
for ii in atual:
csvfile.writerow(ii)
else:
print "It is necessary to provide a xls file."
arquivo_resultado = UnicodeWriter(open(excelfile[:-4]+"_resultado.csv", 'w'))
self.resultados = criar_resultado
#for ii in criar_resultado:
# arquivo_resultado.writerow(ii)
arquivo_resultado = []
def printhelp(self):
print 'Usage: call the script followed by a xls file. The script will create one csv with , and " separators and utf-8 encoding for each sheet in the file.'
def atualiza_de_para(self):
self.text.yview(END)
fonte_de_dados = self.dados_municipais or self.dados_municipais_padrao
try:
#print fonte_de_dados
self.populacao = [i for i in unicode_csv_reader(open(fonte_de_dados))]
self.de_para ={}
for i in range(len(self.populacao[0])):
self.de_para[self.populacao[0][i]] = i
except:
self.populacao = []
self.de_para = {}
self.text.insert(END, u"» ATENÇÃO: NÃO HÁ FONTE DE DADOS MUNICIPAIS DISPONÍVEL. O SCRIPT NÃO FUNCIONARÁ CORRETAMENTE. \n", ("blue_white",))
self.text.insert(END, u"» Antes de tentar rodar o script selecione uma fonte de dados municipais. \n", ("blue_white",))
def action_listbox(self, args):
print self.operacao_selecionada[self.cabecalho[int(self.listbox.curselection()[0])]]
for i in self.niveis_operacoes:
i.selection_clear(0, END)
valor_atual = self.operacao_selecionada[self.cabecalho[int(self.listbox.curselection()[0])]]
for i in range(4):
if valor_atual[i] is not None:
self.niveis_operacoes[i].selection_set(valor_atual[i])
def action_operacao_listbox(self, args):
contador = 0
for i in self.niveis_operacoes:
if len(i.curselection())>0:
self.operacao_selecionada[self.cabecalho[int(self.listbox.curselection()[0])]][contador] = i.curselection()[0]
contador+=1
self.agregada_text.config(state=NORMAL)
self.agregada_text.delete("1.0",END)
for i in self.operacao_selecionada.keys():
for ii in self.operacao_selecionada[i]:
if ii is not None and ii not in (0,"0"):
self.agregada_text.insert(END, i+'\n',("blue_white"))
break
self.agregada_text.config(state=DISABLED)
def agregar_por_regioes(self):
dicionario_regioes = {
1 : "Norte",
2 : "Nordeste",
3 : "Sudeste",
4 : "Sul",
5 : "Centro-Oeste",
}
dicionario_estados = {
12: "Acre ", 16: "Amapá", 13: "Amazonas", 15: "Pará", 11: "Rondônia", 14: "Roraima", 17: "Tocantins",
27: "Alagoas", 29: "Bahia",23: "Ceará", 21: "Maranhão", 25: "Paraíba", 26: "Pernambuco", 22: "Piauí", 24: "Rio Grande do Norte", 28: "Sergipe",
32: "Espírito Santo", 31: "Minas Gerais", 33: "Rio de Janeiro", 35: "São Paulo",
41: "Paraná", 43: "Rio Grande do Sul",42: "Santa Catarina",
53: "Distrito Federal", 52: "Goiás", 51: "Mato Grosso", 50: "Mato Grosso do Sul",
}
dicionario_linha_operacao = {
2: "Brasil",
3: "Região",
4: "Estado",
5: "Município",
}
totais = {'brasil':{},'regioes':{}}
linha = 1
municipio_padrao = {}
consolidado = {}
for regiao in dicionario_regioes.keys():
regiao_atual = Regiao(dicionario_regioes[regiao], regiao)
for estado in dicionario_estados.keys():
if str(estado)[0] == str(regiao):
regiao_atual.itens[estado] = Regiao(dicionario_estados[estado], estado)
consolidado[regiao_atual.codigo] = regiao_atual
"""for codigo,regiao in consolidado.items():
print "Regiao:" +regiao.nome
for cod_estado,estado in regiao.itens.items():
print "Estado: "+estado.nome"""
contador = 1
for linha in self.resultados:
if contador == 1:
cabecalho= linha
else:
codigo_municipio = linha[coluna_cod_mun]
regiao = str(codigo_municipio)[0]
estado = str(codigo_municipio)[:2]
codigo_municipio = str(linha[coluna_cod_mun])[:5]
#print "consolidado: "+str(consolidado)
#print "regiao: "+str(regiao)
#print "estado: "+str(estado)
municipio_atual = Regiao(linha[9], int(codigo_municipio))
dic_linha = {}
#print zip(cabecalho, linha)
for chave,valor in zip(cabecalho,linha):
dic_linha[chave] = valor
municipio_atual.empreendimentos.append(dic_linha)
#print estado#str(codigo_municipio)
#print consolidado.keys()
if int(codigo_municipio) not in consolidado[int(regiao)].itens[int(estado)].itens.keys():
consolidado[int(regiao)].itens[int(estado)].itens[int(codigo_municipio)] = municipio_atual
contador +=1
print len(consolidado)
for codigo,regiao in consolidado.items():
print "Regiao:" +regiao.nome
for cod_estado,estado in regiao.itens.items():
print " : "+estado.nome
for cod_mun,municipio in estado.itens.items():
print " : "+municipio.nome
def callback():
pass
root = Tk()
app = App(root)
root.mainloop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment