Animasyon, Matplotlib, Mayavi
Hareketli bilimsel grafikler (hareketli dalga, cisim) için şu an
tercih edilen yaklaşım bir dinamik sistem içinden "fotoğraf kareleri"
almak, mesela en basit ortamda Matplotlib ile plt.savefig('')
kullanarak, ve bu dosyaları ardından İmageMagick convert
ile
birleştirip bir animasyonlu .gif yaratmak. Bu sayede genel
grafiklemede zaten kullandığımız, bildiğimiz plt.plot
çağrılarını
kullanmış oluyoruz, ve alttaki yöntemlerle gerekli bazı fotoğraf
karelerini birleştirince bir anımasyon da elde etmiş
oluyoruz. Animasyon için farklı şekilde çağrılar yapmak, farklı
kütüphaneler kullanmak gerekmiyor.
Matplotlib
En basit 3 boyutlu parçacık grafiği,
N = 100
c1 = np.random.multivariate_normal(np.array([-3,-3,-3]), np.eye(3), size=N)
c2 = np.random.multivariate_normal(np.array([3,3,3]), np.eye(3), size=N)
c = np.vstack((c1,c2))
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig=plt.figure()
ax=Axes3D(fig)
ax.plot(c[:, 0], c[:, 1], c[:, 2],'.')
plt.savefig('mayavi6.png')
Animasyon bağlamında sistem ileri doğru işletilirken bir indis i
ile
hangi karede, hangi zaman diliminde olduğumuzu biliyorsak, bunu
kullanarak, belli dilimlerde (mesela her 5'inci dilim) çıktıyı alıp
diske yazabiliriz,
for i in ..
# hesaplar yap
if i%5 == 0:
plt.plot(...)
...
plt.savefig('out-%02d.png' % i)
plt.close('all')
Dikkat, eğer close
çağrısı olmazsa fazla resim basma ve yoğun grafik
işlemleri ardindan hafıza tükenebilir.
Bu program işleyince elimizde out-01.png
, out-02.png
, gibi dosyalar
olacak. Bu dosyaları basit bir şekilde
convert -delay 20 -loop 0 out*.png out.gif
ile birleştirebiliriz. Üstte %02d
kullanmış olmamız dosya
isimlerinde iki basamaklı sayı eklenmesini sağladı, 01, 02 gibi,
böylece basit yıldız kullanımı dosyaları sıralı bir şekilde
getirecektir.
Üç Boyutlu Grafikler İçin Mayavi
Simulasyon amaçlı pek çok parçacığı ekranda çizmemiz hareketlerini
takip etmemiz gerekebilir. Fakat çok hızlı olarak bilinen bir dilden,
mesela C++'dan bile, OpenGL çağırıp ekranda parçacıkları
glutSolidSphere
ile çizdirmemiz hızlı bir cevap almamız için yeterli
olmayabilir. Belki arka planda, gözükmeyecek toplar vardır, bunları
göstermeye gerek var mı?
Bilgisayar grafikleme algoritmalarından (ki bilgisayar oyunlarında yaygın şekilde kullanılır) ışın takip etme (ray tracing) burada gerekli olabilir, görüntüye bakılma açısından sanal ışınlar hayal edip bunların sadece ilk çarpıktıklarını çizmek, arka plana kalanları çizmemek bir hızlandırıcı ilerleme olurdu.
O zaman teker teker top çiz demek yerine tüm topların kordinatlarını bir seferde verip özel bir kütüphanenin görünecek olan objelere karar vermesi daha mantıklı olabilir. MayaVi ve onun arka planda kullandığı VTK işte bu işi başarıyor.
Kurmak icin
pip install pyqt5 mayavi
En basit örnek üzerinde görelim,
from mayavi import mlab
mlab.options.offscreen = True
N = 100
c1 = np.random.multivariate_normal(np.array([-3,-3,-3]), np.eye(3), size=N)
c2 = np.random.multivariate_normal(np.array([3,3,3]), np.eye(3), size=N)
c = np.vstack((c1,c2))
fig = mlab.figure(fgcolor=(0., 0., 0.), bgcolor=(1, 1, 1), size=(640, 360))
r = np.ones(2*N)*0.2
color=(0.2, 0.4, 0.5)
mlab.points3d(c[:, 0], c[:, 1], c[:, 2], r, color=color,
colormap = 'gnuplot', scale_factor=1, figure=fig)
mlab.outline()
mlab.view(azimuth=00, elevation=80, focalpoint=[1, 1, 1], distance=30.0, figure=fig)
mlab.savefig(filename='mayavi7.png')
Farklı boyutlarda,
mlab.figure(fgcolor=(0., 0., 0.), bgcolor=(1, 1, 1))
N = 100
c = np.random.rand(N, 3)
r = np.random.rand(N) / 10.
mlab.points3d(c[:, 0], c[:, 1], c[:, 2], r, color=(0.2, 0.4, 0.5))
mlab.outline()
mlab.savefig(filename='mayavi1.png')
Şimdi 80,000 tane topu, arka arkaya iki grafikte çizdirelim,
mlab.figure(fgcolor=(0., 0., 0.), bgcolor=(1, 1, 1))
N = 80000
c = np.random.rand(N, 3)
r = np.random.rand(N) / 10.
mlab.points3d(c[:, 0], c[:, 1], c[:, 2], r, color=(0.2, 0.4, 0.5))
mlab.outline()
mlab.savefig(filename='mayavi2.png')
mlab.figure(fgcolor=(0., 0., 0.), bgcolor=(1, 1, 1))
N = 80000
c = np.random.rand(N, 3)
r = np.random.rand(N) / 10.
mlab.points3d(c[:, 0], c[:, 1], c[:, 2], r, color=(0.2, 0.4, 0.5))
mlab.outline()
mlab.savefig(filename='mayavi3.png')
Bu iki grafikleme oldukca hızlı şekilde geri döndü. Eğer bir sıvı dinamiğini simüle ediyorsak ve milyonlarca parçacık varsa bu perfomans belki anlık ekranda göstermek için yeterli olmayabilir, fakat arka planda birkaç dakika beklenerek tüm simülasyonun gidişatı belli birkaç kare yanyana koyularak kabul edilir bir zaman içinde yaratılabilir.
Kordinat Eksenleri
Eğer outline
kullanmak yerine sabit büyüklükte, x,y,z kordinat
eksenlerini göstermek istersek, bunu teker teker kendimizin yapması
lazım. Altta orijinde duran her kenarı 2 birim büyüklükte bir küp
gösteriyoruz,
BS = 2.0
N = 100
c = np.random.rand(N, 3)*2.0
r = np.ones(N)*0.1
fig = mlab.figure(figure=None, fgcolor=(0., 0., 0.), bgcolor=(1, 1, 1), engine=None)
color=(0.2, 0.4, 0.5)
mlab.points3d(c[:, 0], c[:, 1], c[:, 2], r, color=color, colormap = 'gnuplot', scale_factor=1, figure=fig)
mlab.points3d(0, 0, 0, 0.1, color=(1,0,0), scale_factor=1.0, figure=fig)
mlab.plot3d([0.0,0.0],[0.0, 0.0],[0.0, BS], color=(0,0,0), tube_radius=None, figure=fig)
mlab.plot3d([0.0,BS],[0.0, 0.0],[0.0, 0.0], color=(1,0,0), tube_radius=None, figure=fig)
mlab.plot3d([0.0,0.0],[0.0, BS],[0.0, 0.0], color=(0,1,0), tube_radius=None, figure=fig)
mlab.plot3d([0.0,0.0],[0.0, BS],[BS, BS], color=(0,0,0), tube_radius=None, figure=fig)
mlab.plot3d([0.0,BS],[0.0,0.0],[BS,BS], color=(0,0,0), tube_radius=None, figure=fig)
mlab.plot3d([BS,BS],[0.0,BS],[BS,BS], color=(0,0,0), tube_radius=None, figure=fig)
mlab.plot3d([BS,0],[BS,BS],[BS,BS], color=(0,0,0), tube_radius=None, figure=fig)
mlab.plot3d([0,0],[BS,BS],[BS,0], color=(0,0,0), tube_radius=None, figure=fig)
mlab.plot3d([BS,BS],[0.0,0.0],[0.0,BS], color=(0,0,0), tube_radius=None, figure=fig)
mlab.plot3d([BS,BS],[0.0,BS],[0.0,0.0], color=(0,0,0), tube_radius=None, figure=fig)
mlab.plot3d([BS,0.0],[BS,BS],[0.0,0.0], color=(0,0,0), tube_radius=None, figure=fig)
mlab.plot3d([BS,BS],[BS,BS],[0.0,BS], color=(0,0,0), tube_radius=None, figure=fig)
mlab.view(azimuth=50, elevation=80, focalpoint=[1, 1, 1], distance=8.0, figure=fig)
mlab.savefig(filename='mayavi5.png')
Problemler
Eğer ardı ardına grafik basıyorsak, döngü dışında fig = mlab.figure
komutu kullanıp, her döngü sonunda mlab.savefig
ardından
mlab.clf()
uygulamak hafıza problemlerini çözecektir.
Daha once yazdigimiz kesit seviyeleri yazisini not defteri ortamina gecirdik, ve bu yazida kesit seviyeleri diferansiyel denklemi hesaplanirken, onun uzerinden yapilan imaj bolumu aninda not defteri icinde gosteriliyor. Not defteri icinde animasyon gostermek icin kullanilan kalip
Eski bazi yaklasimlar altta bulunabilir
Not Defteri Icinde Animasyon
from IPython.display import clear_output
f, ax = plt.subplots()
..
while True: # bir dongu
...
ax.imshow(...)
CS = ax.contour(...)
clear_output()
display(f)
ax.cla()
Biz ax.imshow
, ax.contour
kullandık, fakat ax
üzerinde pek çok
grafiksel işlem yapılabilir tabii ki.
Not: iPython not defterinin indirilip yerel, ya da kod işletilmesine izin veren bir defter servisi üzerinde işletilmesi lazım.
Matplotlib, Pylab ve hareketli plot, animasyonlar
Bir kordinat sistemı üzerinde canlı olarak bir hesabın sonucunu seyretmek istersek, Pylab için faydalı bir örnek kod altta. Kod arka arkaya 10 tane x,y değeri üretiyor, sayılar 0..1 arası, ve eksenlerin sabit kalması için setxlim, setylim çağrılarını yapmak lazım.
from pylab import *
from random import *
from time import *
ion()
fig = plt.figure()
ax = fig.add_subplot(111)
for i in xrange(10):
sleep(0.5)
ax.plot([random()], [random()], 'd')
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
hold(False)
draw()
Kaynaklar
[1] https://docs.enthought.com/mayavi/mayavi/mlab.html
[2] https://www.toptal.com/data-science/3d-data-visualization-with-open-source-tools-an-example-using-vtk
Yukarı