نمودارهای متحرک در پایتون – از صفر تا صد
Matplotlib و Seaborn دو مورد از کتابخانههای پایتون هستند که نمودارهایی با ظاهر عالی ایجاد میکنند. اما این نمودارها همگی استاتیک هستند و به تصویر کشیدن تغییرات مقادیر به روشی دینامیک و با ظاهر مناسب کاری دشوار است. شاید برای شما نیز پیش آمده باشد که بخواهید در یکی از ارائههای خود یا در طی یک ویدئو یا پست در رسانههای اجتماعی، تغییرات رخ داده در یک مجموعه داده را به وسیله یک ویدئو کلیپ کوتاه به نمایش بگذارید. در این نوشته روش ایجاد نمودارهای متحرک را به شما آموزش میدهیم. شاید تعجب کنید اگر بدانید که برای انجام این کار، حتی نیاز نیست که کتابخانههای Matplotlib و Seaborn با هر کتابخانه دیگری که برای ترسیم نمودار استفاده میکنید را تغییر دهید.
در این نوشته از برخی دادههایی که در مورد بحران مواد مخدر در ایالات متحده وجود دارد، استفاده شده است. این دادهها به صورت عمومی از سوی موسسه ملی مبارزه با مواد مخدر ایالات متحده و GDC انتشار یافته است که میتوانید از این لینک دانلود کنید.
کتابخانههای مورد نیاز
در این نوشته از Matplotlib به اضافه Seaborn برای ترسیم و از Numpy به همراه Panda برای مدیریت دادهها استفاده شده است. Matplotlib برای ایجاد انیمیشن (متحرکسازی) تابعهایی دارد که میتوانیم از آنها بهره بگیریم.
بنابراین با ما همراه باشید تا همه وابستگیها را ایمپورت بکنیم.
import numpy as np import pandas as pd import seaborn as sns import matplotlib import matplotlib.pyplot as plt import matplotlib.animation as animation
اینک برای آماده شدن جهت متحرکسازی دادهها تنها باید دادهها را بارگذاری کرده و درون قاب داده Pandas قرار دهیم. زمانی که میخواهیم چندین نمودار در مورد اوردوز (Overdose) مواد مخدر مختلف ایجاد کنیم، بهتر است یک تابع برای بارگذاری دادهها از ردیفهای مطلوب خود بنویسیم.
overdoses = pd.read_excel('overdose_data_1999-2015.xls',sheetname='Online',skiprows =6) def get_data(table,rownum,title): data = pd.DataFrame(table.loc[rownum][2:]).astype(float) data.columns = {title} return data
نتبوک ژوپیتر
بنابراین اینک میتوانیم کار خود را آغاز کرده و انیمیشن بسازیم. قبل از هر کاری اگر از نتبوک ژوپیتر (Jupiter notebook) استفاده میکنید، بهتر است این سلول را با یک matplotlib notebook% آغاز کنید تا بتوانید انیمیشن را به راحتی در نتبوک خودتان ببینید و بدین ترتیب بی درنگ در نتبوک ذخیره میشود.
در این نوشته ما قصد داریم اعداد و ارقام اوردوز هروئین را با استفاده از تابع get_data از جدول بازیابی کرده و آن را در قاب داده Pandas که دو ستون دارد قرار دهیم.
%matplotlib notebook title = 'Heroin Overdoses' d = get_data(overdoses,18,title) x = np.array(d.index) y = np.array(d['Heroin Overdoses']) overdose = pd.DataFrame(y,x) #XN,YN = augment(x,y,10) #augmented = pd.DataFrame(YN,XN) overdose.columns = {title}
در مرحله بعد یک تابع writer را مقداردهی اولیه میکنیم که از ffmpeg استفاده کرده و ویدئویی را با نرخ فریم 20 fps و نرخ بیت 1800 ثبت میکند.
Writer = animation.writers['ffmpeg'] writer = Writer(fps=20, metadata=dict(artist='Me'), bitrate=1800)
اینک تصویری با تعدادی برچسب ایجاد میکنیم. اطمینان حاصل کنید که محدودههایی برای محورهای x و y تعیین کردهاید و این محدودهها چندان از بازه دادههایی که قصد دارید نمایش دهید، دور نیست.
fig = plt.figure(figsize=(10,6)) plt.xlim(1999, 2016) plt.ylim(np.min(overdose)[0], np.max(overdose)[0]) plt.xlabel('Year',fontsize=20) plt.ylabel(title,fontsize=20) plt.title('Heroin Overdoses per Year',fontsize=20)
تابع animation
بخش کلیدی انیمیشن، تابع animation است که در آن تعریف میکنیم در هر فریم از ویدئو چه اتفاقی قرار است رخ دهد. در این تابع از i برای نمایش اندیس فریم از انیمیشن استفاده میکنیم. با استفاده از این اندیس میتوانیم محدوده دادههایی که باید در فریم مشاهده شوند را تعیین میکنیم. پس از انجام این کار از Seaborn برای ترسیم خطی نمودار این گزیده دادهها استفاده میکنیم. دو خط آخر صرفاً به این منظور هستند که ظاهر نمودار تا حدودی زیباتر شود.
def animate(i): data = overdose.iloc[:int(i+1)] #select data range p = sns.lineplot(x=data.index, y=data[title], data=data, color="r") p.tick_params(labelsize=17) plt.setp(p.lines,linewidth=7)
برای شروع انیمیشن از matplotlib.animation.FuncAnimation استفاده میکنیم که در آن تابع animation لینک شده و تعداد فریمهای موجود در انیمیشن تعریف میشود. از این رو frames در واقع تعداد دفعات فراخوانی (animate(i را تعریف میکند.
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=17, repeat=True)
برای ذخیرهسازی این انیمیشن به صورت فایل mp4 میتوانید به سادگی تابع ()ani.save را فراخوانی کنید. اگر بخواهید پیش از ذخیره کردن انیمیشن نگاهی به آن بیندازید میتوانید از ()plt.show استفاده کنید.
ani.save('HeroinOverdosesJumpy.mp4', writer=writer)
بدین ترتیب در این مرحله انیمیشن چیزی شبیه تصویر زیر خواهد بود:
هموارسازی حرکت
این نمودار متحرک کارکرد صحیحی دارد؛ اما مشکل آن صرفاً این است که پرش زیادی دارد. برای جلوگیری از این پرشها به نقاط دادهای بیشتری بین نقاطی که هم اینک وجود دارند، نیاز داریم. بدین منظور میتوانیم از تابع دیگری که augment مینامیم، استفاده کنیم.
def augment(xold,yold,numsteps): xnew = [] ynew = [] for i in range(len(xold)-1): difX = xold[i+1]-xold[i] stepsX = difX/numsteps difY = yold[i+1]-yold[i] stepsY = difY/numsteps for s in range(numsteps): xnew = np.append(xnew,xold[i]+s*stepsX) ynew = np.append(ynew,yold[i]+s*stepsY) return xnew,ynew
اینک کافی است از این تابع در مورد دادههای خود استفاده کنیم و تعداد فریمها را در تابع matplotlib.animation.FuncAnimation افزایش دهیم. در این تابع augment را با numsteps = 10 فراخوانی میکنیم. این بدان معنی است که دادههای آموزشی خود را به 160 مورد افزایش میدهیم و باید فریم را به صورت frames=60 تعیین کنیم. نتیجه کار نموداری بسیار هموارتر است؛ اما همچنان لبههای تیزی در نقاطی که تغییرات مقدار وجود دارد، مشاهده میشود.
برای رهایی از شر این لبههای تیز میتوانیم از یک تابع هموارسازی به صورت زیر استفاده کنیم:
def smoothListGaussian(listin,strippedXs=False,degree=5): window=degree*2-1 weight=np.array([1.0]*window) weightGauss=[] for i in range(window): i=i-degree+1 frac=i/float(window) gauss=1/(np.exp((4*(frac))**2)) weightGauss.append(gauss) weight=np.array(weightGauss)*weight smoothed=[0.0]*(len(listin)-window) for i in range(len(smoothed)): smoothed[i]=sum(np.array(listin[i:i+window])*weight)/sum(weight) return smoothed
همچنین میتوانیم پارامترهای رنگ و سبکبندی بیشتری به نمودار خود اضافه کنیم تا نمودار ظاهری منحصر به فرد بیابد.
sns.set(rc={'axes.facecolor':'lightgrey', 'figure.facecolor':'lightgrey','figure.edgecolor':'black','axes.grid':False})
سخن پایانی
بدین ترتیب موفق شدیم یک نمودار متحرک مناسب را به دست آوریم. در این نوشته تابع انیمیشن matplotlib را بر روی یک مثال نمایش دادیم. البته شما میتوانید از این تابع برای هر گونه نموداری که میخواهید متحرکسازی سازی کنید بهره بگیرید. با اندکی تغییر دادن پارامترها و نوع نمودار در تابع ()animate میتوانید گزینههای بی نهایت متنوعی به دست آورید. امیدواریم از این آموزش بهرهمند شده باشید و بتوانید از کارکردهای matplotlib به نحو مناسبی استفاده کنید.
اگر این نوشته مورد توجه شما واقع شده، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- چگونه نمودارهای متحرک بسازیم؟ — یک راهنما برای زبان R
- اینفوگرافیک چیست و چه فرقی با بصری سازی دادهها دارد؟
- مجموعه آموزشهای آمار، احتمالات و دادهکاوی
- نمایش و رسم نمودار برای دادهها — معرفی و کاربردها
- نمودار های میله ای و ستونی – به زبان ساده
- آموزش طراحی و گرافیک کامپیوتری
- کد رسم شکل در پایتون – کد ترسیم اشکال گرافیکی مختلف
==
سلام خسته نباشید.
چرا من با این read_excel() got an unexpected keyword argument ‘sheetname’ خطا مواجه میشوم؟؟
سلام خسته نباشید.
چرا من با این read_excel() got an unexpected keyword argument ‘sheetname’ خطا مواجه میشوم؟؟
سلام خطا زیر نمایش می دهد.
RuntimeError: Requested MovieWriter (ffmpeg) not available
الگوریتم هموارسازی باعث خراب شدن داده ها می شود بطوری که از سال 2006 به بعد دو منحنی (اصلی و هموار شده) کاملا از هم جدا می شوند. در کار پژوهشی جدی ، استفاده از آن توصیه نمی شود.
مشکل حل شد!
تنها اشکالی که به نظر می رسد در هموارسازی، تعداد نقاط از 160 به 151 کاهش می یابد. نیاز به کاهش نقاط ضروری به نظر نمی رسد!
سپاس از شما
فقط در قسمت آخر، متوجه نشدم که تابع smoothListGaussian را چگونه استفاده می کنیم و آرگومان ورودی آن ، listin ، چیست؟
ممنون می شوم توضیح دهید. آیا همان overdose است؟