A matplotlib é uma biblioteca de plotagem para a linguagem de programação Python, com sua extensão matemática numérica NumPy. Além delas, o pandas é muito útil para trabalhar com análise de dados. Para usar esses pacotes, existem diferentes opções para instalação: “sudo pip3 install numpy matplotlib pandas”, “sudo apt-get install python-matplotlib python-numpy python-pandas” ou “conda install matplotlib”.
A “anatomia” de uma figura vista segundo o matplotlib pode ser observada acima, para localização dos elementos. Veja um script com alguns exemplos de uso (testado em Python 2.7.6) para plotar uma série temporal de três sequências numéricas (com o eixo x mostrando datas):
#!/usr/bin/python # -*- coding: UTF-8 -*- import os import sys import pandas as pd import matplotlib.pyplot as plt import matplotlib.dates as md import dateutil # Diretorio atual path = os.path.dirname(os.path.realpath(__file__)) # Dia com os dados a serem plotados dia = sys.argv[1:][0] # Arquivo com dados arquivo = path + '/dados/indices_' + dia + '.txt' # Arquivo de imagem com grafico figname = path + '/dados/Indices_' + dia + '.png' # Ler arquivo e gravar dados em variavel dados = pd.read_csv(arquivo, delimiter=',') # Contar quantos numeros sao positivos count = sum(x > 0 for x in dados.ss) # Contar numero de linhas da tabela de dados total = len(dados) # Calcular percentual de numeros positivos percentual = (float(count)*100.0)/float(total) # String para do grafico titulo = dia + " Estatistica: " + str(count) + "/" + str(total) + " => " + str(round(percentual,1)) + "%" # Definir DPI my_dpi=96 # Definir tamanho da imagem em pixeis plt.figure(figsize=(1200/my_dpi, 800/my_dpi), dpi=my_dpi) # Formatar eixo x com data: ano-mes-dia hora dates = [dateutil.parser.parse(i) for i in dados.data] xfmt = md.DateFormatter('%Y-%m-%d %Hh') ax=plt.gca() ax.xaxis.set_major_formatter(xfmt) plt.xticks(rotation=30) # Plotar 3 series de dados em funcao da data (cores definidas automaticamente) plt.plot(dates, dados.obs, label="observado") plt.plot(dates, dados.prev, label="previsto") plt.plot(dates, dados.cor, label="correcao") # Definir label, titulo e quadro com legenda plt.ylabel("Variavel") plt.title(estacao,fontsize=30) plt.legend() # Abre janela com grafico para visualizacao plt.show() # Salva figura em arquivo plt.savefig(figname) ## Opcao para eixo com strings ## # Criar vetor com mesmo tamanho do vetor de nomes #x = range(0,total) # Vetor de nomes #my_xticks = dados.estacao #ax=plt.gca() # Ligar grid horizontal e vertical #ax.yaxis.grid(True) #ax.xaxis.grid(True) # Plotar duas series de dados em funcao de sequencia numerica (cores definidas no codigo) #plt.xticks(x, dados.estacao, rotation=30, fontsize=8) #plt.plot(x, dados.obs, 'bo-', label="observao") #plt.plot(x, dados.prev, 'go-', label="previsto") #plt.plot(x, dados.cor, 'ro-', label="corrigido")
Esse script recebe uma data como argumento ao ser executado na linha de comando. Veja um exemplo:
$ python grafico.py 2016-03-03
Também precisa de um arquivo de dados cuja primeira linha tenha um cabeçalho com os nomes de cada coluna (acessada por “nome_da_tabela.nome_da_coluna”). Note, no calculo percentual realizado, como os números utilizados são inteiros, o resultado da conta será um inteiro também. Para resultar em um número real, os números da conta devem ser convertidos para float. A função “round” arredonda o valor para o número de casas decimais informado.
Veja um exemplo de gráfico gerado com o script acima:
A opção comentada mais abaixo no código tem um truque para imprimir o eixo x com strings. Como só dá pra entrar com números nos eixos, cria-se um vetor numérico ordenado de 0 até o mesmo tamanho do vetor de nomes. Depois, basta criar a variável “my_xticks” para receber o vetor de nomes e usar a função “xticks”.
Segue outro script para gerar um gráfico de três séries temporais. Nesse caso, serão utilizados dois eixos y (também está comentado no código para usar somente um eixo y).
#!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import unicode_literals import os import sys import pandas as pd import numpy as np import matplotlib.pyplot as plt import matplotlib.dates as dates from datetime import datetime # Definir arquivos e dados path = os.path.dirname(os.path.realpath(__file__)) lugar = sys.argv[1:][0] arquivo = path + '/output/prev_' + lugar + '.csv' dados = pd.read_csv(arquivo, delimiter=',') # converter data+hora para formato do matplotlib x_orig = dados.tempo x = [datetime.strptime(d, '%Y-%m-%d %H:%M:%S') for d in x_orig] # Definir tamanho da figura my_dpi=96 fig = plt.figure(figsize=(1200/my_dpi, 800/my_dpi), dpi=my_dpi) fig, ax1 = plt.subplots() plt.gca().xaxis.set_major_formatter(dates.DateFormatter('%d/%m-%Hh')) plt.gca().xaxis.set_major_locator(dates.DayLocator()) ## Opção com 1 eixo y #plt.plot(x,dados.fsi, marker='o', linestyle='') #plt.plot(x,dados.vis, marker='o', linestyle='') #plt.plot(x,dados.h, marker='o', linestyle='') #plt.minorticks_on() #plt.grid(which='major', linestyle='--') #plt.grid(which='minor', linestyle=':') #plt.gcf().autofmt_xdate() ## Opção com 2 eixos y ax1.set_ylabel('VIS,H', color='r') ax1.tick_params('y', colors='r') lns1 = plt.plot(x,dados.vis, marker='o', linestyle='', color='r') lns2 = plt.plot(x,dados.h, marker='o', linestyle='', color='y') plt.minorticks_on() plt.grid(which='major', linestyle='--') plt.grid(which='minor', linestyle=':') plt.gcf().autofmt_xdate() ax2 = ax1.twinx() lns3 = ax2.plot(x,dados.fsi, marker='o', linestyle='', color='b') ax2.set_ylabel('FSI', color='b') ax2.tick_params('y', colors='b') ## Legenda abaixo do gráfico #plt.legend(['FSI', 'VIS', 'H'], loc='upper right') #lns = lns1+lns2+lns3 #labs = [l.get_label() for l in lns] #ax.legend(lns, labs, loc=0) ax1.legend(loc='upper left', bbox_to_anchor=(0.1, -0.15), shadow=True, ncol=5) ax2.legend(loc='upper left', bbox_to_anchor=(0.6, -0.15), shadow=True, ncol=5) ## Título titulo = lugar + ' - teste' plt.suptitle(titulo, fontsize=18) ## Salvar figura figname = path + '/output/prev_' + lugar + '.png' plt.savefig(figname) #plt.show() #sys.exit("fim de teste")
Outra diferença para o gráfico gerado com o outro script é que ele possui grades (principal e secundária), pontos em vez de linhas e a legenda em quadros fora da área de plotagem (está comentada uma opção para colocar todas as variáveis em um mesmo bloco, mas precisa definir um eixo ax comum para todas as séries). Veja a figura gerada:
Para gerar imagens sem que uma janela apareça, a maneira mais fácil de fazer isso é usar um back-end não interativo, como Agg (para PNGs), PDF, SVG ou PS. Em seu script, apenas chame a diretiva matplotlib.use() antes de importar pylab ou pyplot:
import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt
Esse tipo de solução é extremamente útil ao deixar um script rodando automaticamente e/ou em computador acessado remotamente – evita o erro do tipo XIO: fatal IO error 25 (Inappropriate ioctl for device) on X server “localhost:10.0”.
Mais opções podem ser vistas na documentação do matplotlib.
One comment