Site icon AranaCorp

Criar gráficos com Matplotlib em Python

O pacote Matplotlib Python é uma ferramenta poderosa para criar gráficos e analisar dados em formato gráfico. Neste tutorial, vamos ver como utilizar esta biblioteca e algumas das caraterísticas que precisa de conhecer.

Instalar o Matplotlib

A biblioteca Matplotlib é instalada como qualquer outro pacote Python

python -m pip install matplotlib

Para manipular os dados, pode utilizar o Numpy e o Panda

python -m pip install numpy pandas

Recuperação de dados a rastrear

É possível recuperar dados de ficheiros CSV com o Pandas

timemyData
032.0
146.2
22490
10-2,45
import pandas as pd
df = pd.read_csv(filename,sep=";",encoding = "ISO-8859-1",header=1)
mydata = df["myData"]

Também é possível processar os dados criados pelo seu programa com o Numpy

import numpy as np

ylist=[]
x = np.linspace(0, 10, 1000)

for i in range(8):
    y = np.random.randn(1)*np.sin((i+1)*np.random.randn(1)*x) # + 0.8 * np.random.randn(50)
    ylist.append(y)

Vamos utilizar este último método para desenhar curvas

Desenhar uma figura simples

Para traçar uma curva, comece por criar uma janela (figura) e depois crie uma curva (traçado).

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

#plt.close('all') #close all figure

#process data
ylist=[]
x = np.linspace(0, 10, 1000)

for i in range(8):
    y = np.random.randn(1)*np.sin((i+1)*np.random.randn(1)*x)
    ylist.append(y)

#single plot
fig = plt.figure()
plt.plot(x, y) # plot(y)

#mutliple plots
fig = plt.figure()
for y in ylist:
    plt.plot(x, y)

O gráfico é apresentado na figura ativa. Para tornar uma figura ativa, pode atribuir-lhe nomes ou números ou recordar a ordem pela qual foi criada.

fig1 = plt.figure(1)
fig2 = plt.figure(2)
fig3 = plt.figure("myData")
# use fig2
plt.figure(1) # make fig1 active 
#use fig1

Números aproximados

Depois de ter feito o que pretendia com a figura, pode fechá-la com o comando plt.close().

plt.close() #close active figure
plt.close(1) # plot first created figure or figure 1
plt.close("myData") #plot figure named myData
plt.close('all') # close all figures

N.B.: plt.close(‘all’) pode ser colocado no início do programa para fechar todas as janelas previamente abertas quando o programa é executado.

Guardar uma figura em formato de imagem

É possível guardar cada imagem traçada utilizando o ícone de guardar na janela. Também pode pedir ao pyplot para guardar a figura em formato PNG ou JPG.

plt.savefig("myImg.jpg",bbox_inches='tight') #png no label

Personalizar a figura

Vimos que podemos atribuir um identificador à figura (plt.figure(“myData”). É possível definir outros parâmetros, nomeadamente

pyplot.figure(num=None, figsize=None, dpi=None, *, facecolor=None, edgecolor=None, frameon=True, FigureClass=<class 'matplotlib.figure.Figure'>, clear=False, **kwargs)
#customize figure
fig = plt.figure("myData",figsize=(12,4),facecolor=(0.5, 0.8, 0.3))
fig.suptitle("myFigure")
plt.plot(x, y)

Personalizar o gráfico

Para completar a personalização da figura, podemos personalizar o gráfico

#customize plot
fig = plt.figure("myData",figsize=(12,4),facecolor=(1, 1, 1))
plt.title("myData y(x)")
plt.plot(x, y, label="y(x)")
plt.axis([min(x)-1, max(x)+1, min(y)*1.05, max(y)*1.05]);
plt.xlabel("x [s]")
plt.ylabel("y [SI]")
plt.legend(loc='upper left')

Personalizar a curva

Como vimos, quando desenha várias curvas, o Matplotlib seleciona estilos diferentes para cada curva. É possível personalizar as curvas de uma forma específica.

## customize curve
fig = plt.figure()
plt.plot(x, y, "ko--")
plt.axis([4, 4.5, min(y)*1.05, max(y)*1.05]);
#plt.plot(x, y, color="k", linestyle="--", linewidth=1, marker= "o") #equivalent
#customize marker
fig = plt.figure()
plt.plot(x, y, marker = 'o', ms = 5, mfc = 'r', mec = 'k')
plt.axis([4, 4.5, min(y)*1.05, max(y)*1.05]);

Criar uma função para desenhar curvas

Como há um grande número de parâmetros a definir para a criação de gráficos com o Matplotlib, aconselho-o vivamente a criar uma função de criação de gráficos que simplifique a sua vida e que possa ser adaptada conforme necessário.

# -*- coding: utf-8 -*-

import matplotlib.pyplot as plt
import numpy as np

plt.close("all")

ylist=[]
ylbl = []
x = np.linspace(0, 10, 1000)

for i in range(8):
    y = np.random.choice([-1,1])*(i+1)*np.sin((i+1)*x)
    ylist.append(y)
    ylbl.append('y{}(x)'.format(i))
    
##styles options
lstyles= ['-', '--', '-.', ':', 'None', ' ', '', 'solid', 'dashed', 'dashdot', 'dotted']
markers = [None,'o','*','.',',','x','X','+','P','s','D','d','p','H','h','v','^','<','>','1','2','3','4','|','_']


def tracefig(x,y,lbl,ls=None,mrkr=None,title=None,xlbl=None,ylbl=None,size=(12,4),zoomx=None,gridon=False):
    fig = plt.figure(figsize=size,facecolor=(1, 1, 1))
    if title is not None:
        title = "tracefig - {}".format(title)
        plt.title(title)

    if type(y) is not list:
        if ls is None:
            ls=np.random.choice(lstyles)
        if mrkr is None:
            mrkr=np.random.choice(markers) 
        plt.plot(x, y, linestyle=ls, marker = mrkr, label=lbl)
    else:
        for i,y in enumerate(ylist):
            if ls is None:
                ls=np.random.choice(lstyles)
            if mrkr is None:
                mrkr=np.random.choice(markers) 
            plt.plot(x, y, linestyle=ls, marker = mrkr, label=lbl[i])
    plt.xlabel(xlbl)
    plt.ylabel(ylbl)
    plt.legend(loc='upper left')
    if zoomx is None:
        plt.axis([min(x), max(x), np.min(ylist)*1.2, np.max(ylist)*1.2]); 
    else:
        plt.axis([zoomx[0], zoomx[1], np.min(ylist)*1.2, np.max(ylist)*1.2]); 
        
    if gridon:
        plt.grid() #diplay grid

    return fig

fig = tracefig(x,y,"y(x)",ls="-",mrkr="o",title="Single plot",xlbl="x [s]",ylbl="y [SI]",size=(12,4),zoomx=[0,2])    
fig = tracefig(x,ylist,ylbl,ls="-",mrkr=None,title="Multi plots",xlbl="x [s]",ylbl="y [SI]",size=(12,4),zoomx=[0,2], gridon=True)    

Com estes conhecimentos, pode desenhar e analisar todos os tipos de curvas utilizando Matplotlib e Python.

Visualizar nuvens de pontos

Para a análise de dados, também é possível apresentar gráficos de dispersão. Neste exemplo, corimos os pontos em função de uma terceira variável

import matplotlib.pyplot as plt
import numpy as np

plt.close("all")
    
x = np.random.randn(50)
y = np.random.randn(50)
z = np.random.randint(1,100,50) #np.random.randn(50)

value=(z>50)
colors = np.where( value==True , "red", "#3498db")
fig = plt.figure()
plt.scatter(x,y,marker='s',color=colors)

plt.show()

Desenhar histogramas

Para cada tipo de dados existe uma representação adequada. Em alguns casos, um histograma é mais significativo.

import matplotlib.pyplot as plt
import numpy as np

plt.close("all")

nb = 10
x_multi = [np.random.randn(n) for n in [10000, 5000, 2000]]

fig = plt.figure()
plt.hist(x_multi, nb, histtype='bar', label=['d1','d2','d3'])
plt.legend(prop={'size': 10})
plt.title('Histogram')
plt.show() 

Desenhar gráficos de pizza

import matplotlib.pyplot as plt

labels = 'Insurance', 'Workshop', 'Salary', 'Bank'
sizes = [15, 30, 45, 10]
explode = (0, 0.05, 0, 0)

fig, ax = plt.subplots()
ax.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',colors=['olivedrab', 'rosybrown', 'gray', 'saddlebrown'],startangle=80)

Desenhar contornos

Os contornos são úteis para traçar dados 3D, tais como gradientes, em 2D.

import numpy as np
import matplotlib.pyplot as plt

def g(x, obs = [[-2,0],[8,-5]], param = [[1000,20, 60],[500,10, 30]]):
	res = 200
	for i in range(0,len(obs)):
		alpha_obstacle, a_obstacle,b_obstacle = param[i]
		x_obstacle , y_obstacle = obs[i]
		res += -alpha_obstacle * np.exp(-((x[0] - x_obstacle)**2 / a_obstacle
								   + (x[1] - y_obstacle)**2 / b_obstacle)) 
	return res 

x = np.linspace(-10, 10, 200)
y = np.linspace(-10, 10, 200)
X = np.meshgrid(x, y)
Z = g(X)
	
CS = plt.contour(X[0], X[1], Z) #, colors='black')
plt.clabel(CS, fontsize=9, inline=True)
plt.show()

Criar gráficos com Matplotlib

Para uma visão mais abrangente dos dados, uma técnica importante é poder traçar vários gráficos na mesma figura.

Utilização de subparcelas

É possível dividir uma figura em linhas e colunas para organizar as curvas de forma mais clara e ligar os eixos mais facilmente.

fig = plt.figure()
ax_list = fig.subplots(row, col, sharex=True, sharey=True)
import matplotlib.pyplot as plt
import numpy as np

plt.close("all")

ylist=[]
ylbl = []
x = np.linspace(0, 10, 1000)

for i in range(8):
    y = np.random.choice([-1,1])*(i+1)*np.sin((i+1)*x)
    ylist.append(y)
    ylbl.append('y{}(x)'.format(i))
    

fig2 = plt.figure(figsize=(8, 6))
fig2.suptitle("my Plots")

#devide figure in 3 rows and 2 columns with shared axis
(row1col1, row1col2),(row2col1, row2col2),(row3col1, row3col2) = fig2.subplots(3, 2,sharex=True,sharey=True)

ax = row1col1
ax.plot(x, ylist[0], label="y1(x)")
ax.set_title('Y(X)')
ax = row1col2
ax.plot(x, ylist[1], label="y1(x)")
ax = row2col1
ax.plot(x, ylist[2], label="y2(x)")
ax = row2col2
ax.plot(x, ylist[3], label="y3(x)")
ax = row3col1
ax.plot(x, ylist[4], label="y4(x)")
ax = row3col2
ax.plot(x, ylist[5], label="y5(x)")

Utilização de subfiguras

Para layouts mais complexos, é possível utilizar a subfigura

fig = plt.figure(figsize=(10, 8))

(row1fig, row2fig) = fig.subfigures(2, 1, height_ratios=[1, 2])
row1fig.suptitle("Subfigure")
(fig_row2left, fig_row2right) = row2fig.subfigures(1, 2)

row1_ax = row1fig.add_subplot()
row2l_axs = fig_row2left.subplots(2,1)
row2r_ax = fig_row2right.add_subplot()

ax = row1_ax
ax.plot(x, ylist[0])
ax = row2l_axs[0]
ax.plot(x, ylist[2],'ro-')
ax = row2l_axs[1]
ax.plot(x, ylist[3],'k.-')
ax = row2r_ax
ax.plot(ylist[4], ylist[5],'g-')

Utilização do GridSpec

O GridSpec torna possível desenhar rapidamente layouts complexos. Em vez de dividir as áreas uma após a outra, vamos definir uma grelha que será preenchida à medida que avançamos com sub-gráficos.

fig = plt.figure(figsize=(10, 8))
fig.suptitle("GridSpec")
gs = plt.GridSpec(3, 3)
gs.update(wspace=0.4, hspace=0.6)

col1fig0     = fig.add_subplot(gs[0, :2])
col1fig1     = fig.add_subplot(gs[1, :2],sharex=col1fig0)
col1fig2     = fig.add_subplot(gs[2, :2],sharex=col1fig0)
col2fig0     = fig.add_subplot(gs[:1, 2])
col2fig1     = fig.add_subplot(gs[1:, 2])


ax=col1fig0
ax.plot(x, ylist[1], label="y1(x)")
ax=col1fig1
ax.plot(x, ylist[2], 'kx-',label="y2(x)")
ax=col1fig2
ax.plot(x, ylist[3], 'ro:', label="y3(x)")
ax=col2fig0
ax.plot(ylist[4], ylist[5], 'g-',label="y5(y4)")
ax=col2fig1
ax.plot(ylist[6],x,'s',  label="y6(x)")
fig.legend(loc='upper left')

N.B.: Pode combinar subfigura, subparcela e gridspec e encaixá-los como quiser para criar os gráficos mais bonitos.

Adicionar um cursor aos seus gráficos

Para facilitar a leitura, pode adicionar um cursor para visualizar certos pormenores com mais precisão. Este cursor pode ser partilhado entre várias curvas. Por exemplo, podemos adicionar um cursor às três curvas à esquerda da figura anterior e definir os seguintes parâmetros

from matplotlib.widgets import MultiCursor
figlist = (col1fig0,col1fig1,col1fig2)
cursor = MultiCursor(fig.canvas, figlist, color='r',lw=0.5, ls='--', horizOn=True,vertOn=True)

Detetar eventos do rato

Para além de desenhar e animar curvas, também pode utilizar o rato para interagir com o gráfico.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backend_bases import MouseButton

def on_click(event):
	if event.button is MouseButton.LEFT:
		print("Click detected at X,Y: {}".format([event.xdata, event.ydata]))
fig = plt.figure()
plt.plot([0,1],[0,2])
plt.connect('button_press_event', on_click)

plt.show()

Criar uma animação com Matplotlib

É possível criar gráficos animados e guardá-los em vários formatos utilizando a ferramenta matplotlib.animation. Para tal, é necessário traçar o gráfico quadro a quadro numa função update(frame), que devolve o objeto que contém o gráfico (neste caso, a curva).

import math
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

#create data
#process data
x = np.linspace(0, 10, 100)
y =  np.sin(2*x)

# plot first point
fig = plt.figure()
curve = plt.plot(x[0], y[0])
plt.axis([0, 10, -1.2, 1.2])

def update(frame):
    # update data
    xi = x[:frame]
    yi = y[:frame]
    
    # update plot
    curve[0].set_xdata(xi)
    curve[0].set_ydata(yi)
    return (curve)

#display animation
ani = animation.FuncAnimation(fig=fig, func=update, frames=100, interval=30)
plt.show()
#save animation as gif
ani.save(filename="./tmp/sinewave.gif", writer="pillow")

Existem diferentes formas de criar animações, consoante os tipos de dados. Também pode guardar as animações em diferentes formatos, consoante a sua utilização. Não hesite em consultar a documentação sobre animações.

Aplicações

Fontes

Exit mobile version