كيفية بناء تصورات بيانات تتحدث تلقائياً في بايثون باستخدام IEX Cloud و Matplotlib و AWS
مقدمة: قوة بايثون في تصور البيانات الديناميكي
تُعد لغة بايثون خياراً ممتازاً لإنشاء تصورات بيانات جذابة وفعالة. ومع ذلك، فإن العمل بلغة برمجة خام مثل بايثون (بدلاً من برمجيات أكثر تطوراً مثل Tableau) يطرح بعض التحديات. يجب على المطورين الذين ينشئون تصورات أن يتقبلوا تعقيداً تقنياً أكبر مقابل تحكم أوسع في مظهر تصوراتهم.
في هذا الدليل الشامل، سنتعلم كيفية إنشاء تصورات بيانات في بايثون تتحدث تلقائياً. سنستخدم بيانات مالية من خدمة IEX Cloud، وسنستعين بمكتبة matplotlib الشهيرة، بالإضافة إلى بعض خدمات Amazon Web Services (AWS) السحابية لضمان التحديث المستمر.
الخطوة 1: جمع وتحضير البيانات
تبدو الرسوم البيانية التي تتحدث تلقائياً جذابة، ولكن قبل استثمار الوقت في بنائها، من المهم فهم ما إذا كنت بحاجة بالفعل إلى تحديث رسومك البيانية تلقائياً. لا توجد حاجة لتحديث تصوراتك تلقائياً إذا كانت البيانات التي تعرضها لا تتغير بمرور الوقت. على سبيل المثال، سيكون إنشاء سكربت بايثون يقوم بتحديث تلقائي لمتوسط نقاط مايكل جوردان السنوية لكل مباراة أمراً عديم الفائدة، فقد انتهت مسيرته المهنية، ولن تتغير مجموعة البيانات هذه أبداً.
أفضل مجموعات البيانات المرشحة للتحديث التلقائي هي بيانات السلاسل الزمنية التي تُضاف إليها ملاحظات جديدة بانتظام (على سبيل المثال، يومياً). في هذا الدليل، سنستخدم بيانات سوق الأسهم من واجهة برمجة تطبيقات IEX Cloud API. تحديداً، سنقوم بتصور أسعار الأسهم التاريخية لبعض أكبر البنوك في الولايات المتحدة:
JPMorgan Chase (JPM)Bank of America (BAC)Citigroup (C)Wells Fargo (WFC)Goldman Sachs (GS)
إنشاء حساب IEX Cloud والحصول على مفتاح API
أول شيء ستحتاج إليه هو إنشاء حساب IEX Cloud وتوليد رمز API. لأسباب واضحة، لن أنشر مفتاح API الخاص بي في هذا المقال. يكفي تخزين مفتاح API الشخصي الخاص بك في متغير يسمى IEX_API_Key لتتمكن من المتابعة.
تجهيز قائمة الرموز (Tickers)
بعد ذلك، سنقوم بتخزين قائمة رموز الأسهم في قائمة بايثون:
tickers = [
'JPM',
'BAC',
'C',
'WFC',
'GS',
]
تقبل واجهة IEX Cloud API رموز الأسهم مفصولة بفواصل. نحتاج إلى تحويل قائمة الرموز الخاصة بنا إلى سلسلة نصية مفصولة بفواصل. إليك الكود الذي سنستخدمه للقيام بذلك:
#Create an empty string called `ticker_string` that we'll add tickers and commas to
ticker_string = ''
#Loop through every element of `tickers` and add them and a comma to ticker_string
for ticker in tickers:
ticker_string += ticker
ticker_string += ','
#Drop the last comma from `ticker_string`
ticker_string = ticker_string[:-1]
تحديد نقطة نهاية API وتكوين طلب HTTP
المهمة التالية التي نحتاج إلى التعامل معها هي تحديد نقطة نهاية (endpoint) واجهة IEX Cloud API التي سنستخدمها. يكشف مراجعة سريعة لوثائق IEX Cloud أن لديهم نقطة نهاية Historical Prices، والتي يمكننا إرسال طلب HTTP إليها باستخدام الكلمة المفتاحية charts. سنحتاج أيضاً إلى تحديد كمية البيانات التي نطلبها (مقاسة بالسنوات). لاستهداف نقطة النهاية هذه لنطاق البيانات المحدد، قمت بتخزين نقطة النهاية charts وعدد السنوات في متغيرات منفصلة. ثم يتم دمج هذه المتغيرات في عنوان URL المتسلسل الذي سنستخدمه لإرسال طلب HTTP الخاص بنا. إليك الكود:
#Create the endpoint and years strings
endpoints = 'chart'
years = '10'
#Interpolate the endpoint strings into the HTTP_request string
HTTP_request = f'https://cloud.iexapis.com/stable/stock/market/batch?symbols={ticker_string}&types={endpoints}&range={years}y&token={IEX_API_Key}'
هذه السلسلة النصية المدمجة مهمة لأنها تتيح لنا تغيير قيمة السلسلة بسهولة في وقت لاحق دون تغيير كل تكرار للسلسلة في قاعدة الكود الخاصة بنا.
جلب البيانات باستخدام Pandas
الآن حان الوقت لتقديم طلب HTTP فعلياً وتخزين البيانات في بنية بيانات على جهازنا المحلي. للقيام بذلك، سأستخدم مكتبة pandas في بايثون. تحديداً، سيتم تخزين البيانات في كائن pandas DataFrame. سنحتاج أولاً إلى استيراد مكتبة pandas. حسب الاصطلاح، يتم استيراد pandas عادةً تحت الاسم المستعار pd. أضف الكود التالي إلى بداية السكربت الخاص بك لاستيراد pandas بالاسم المستعار المطلوب:
import pandas as pd
بمجرد استيراد pandas إلى سكربت بايثون الخاص بنا، يمكننا استخدام طريقة read_json الخاصة بها لتخزين البيانات من IEX Cloud في كائن pandas DataFrame:
bank_data = pd.read_json(HTTP_request)
طباعة كائن DataFrame هذا داخل Jupyter Notebook ينتج عنه الإخراج التالي:

من الواضح أن هذا ليس ما نريده. سنحتاج إلى تحليل هذه البيانات لتوليد كائن DataFrame يستحق الرسم. للبدء، دعنا نفحص عموداً محدداً من bank_data – على سبيل المثال، bank_data['JPM']:

من الواضح أن طبقة التحليل التالية ستحتاج إلى أن تكون نقطة النهاية chart:

الآن لدينا بنية بيانات شبيهة بـ JSON حيث تكون كل خلية عبارة عن تاريخ بالإضافة إلى نقاط بيانات مختلفة حول سعر سهم JPM في ذلك التاريخ. يمكننا تغليف هذه البنية الشبيهة بـ JSON في كائن pandas DataFrame لجعله أكثر قابلية للقراءة:

هذا شيء يمكننا العمل به! دعنا نكتب حلقة صغيرة تستخدم منطقاً مشابهاً لاستخراج سلسلة زمنية لسعر الإغلاق لكل سهم كسلسلة pandas Series (وهو ما يعادل عموداً في pandas DataFrame). سنقوم بتخزين هذه السلاسل في قاموس (حيث يكون المفتاح هو اسم الرمز) لسهولة الوصول إليها لاحقاً.
for ticker in tickers:
series_dict.update( {ticker : pd.DataFrame(bank_data[ticker]['chart'])['close']} )
الآن يمكننا إنشاء كائن pandas DataFrame النهائي الذي يحتوي على التاريخ كمؤشر وعمود لسعر الإغلاق لكل سهم بنك رئيسي على مدى السنوات الخمس الماضية:
series_list = []
for ticker in tickers:
series_list.append(pd.DataFrame(bank_data[ticker]['chart'])['close'])
series_list.append(pd.DataFrame(bank_data['JPM']['chart'])['date'])
column_names = tickers.copy()
column_names.append('Date')
bank_data = pd.concat(series_list, axis=1)
bank_data.columns = column_names
bank_data.set_index('Date', inplace=True)
بعد كل هذا، سيبدو كائن bank_data DataFrame الخاص بنا هكذا:

اكتمل جمع البيانات لدينا. نحن الآن جاهزون للبدء في إنشاء تصورات باستخدام مجموعة البيانات هذه لأسعار أسهم البنوك المدرجة في البورصة. كملخص سريع، إليك السكربت الذي بنيناه حتى الآن:
import pandas as pd
import matplotlib.pyplot as plt
IEX_API_Key = '' # تأكد من وضع مفتاح API الخاص بك هنا
tickers = [
'JPM',
'BAC',
'C',
'WFC',
'GS',
]
#Create an empty string called `ticker_string` that we'll add tickers and commas to
ticker_string = ''
#Loop through every element of `tickers` and add them and a comma to ticker_string
for ticker in tickers:
ticker_string += ticker
ticker_string += ','
#Drop the last comma from `ticker_string`
ticker_string = ticker_string[:-1]
#Create the endpoint and years strings
endpoints = 'chart'
years = '5'
#Interpolate the endpoint strings into the HTTP_request string
HTTP_request = f'https://cloud.iexapis.com/stable/stock/market/batch?symbols={ticker_string}&types={endpoints}&range={years}y&cache=true&token={IEX_API_Key}'
#Send the HTTP request to the IEX Cloud API and store the response in a pandas DataFrame
bank_data = pd.read_json(HTTP_request)
#Create an empty list that we will append pandas Series of stock price data into
series_list = []
#Loop through each of our tickers and parse a pandas Series of their closing prices over the last 5 years
for ticker in tickers:
series_list.append(pd.DataFrame(bank_data[ticker]['chart'])['close'])
#Add in a column of dates
series_list.append(pd.DataFrame(bank_data['JPM']['chart'])['date'])
#Copy the 'tickers' list from earlier in the script, and add a new element called 'Date'.
#These elements will be the column names of our pandas DataFrame later on.
column_names = tickers.copy()
column_names.append('Date')
#Concatenate the pandas Series together into a single DataFrame
bank_data = pd.concat(series_list, axis=1)
#Name the columns of the DataFrame and set the 'Date' column as the index
bank_data.columns = column_names
bank_data.set_index('Date', inplace=True)
الخطوة 2: إنشاء الرسوم البيانية المراد تحديثها
في هذا الجزء من الدليل، سنعمل مع مكتبة matplotlib لتصور البيانات في بايثون. تُعد matplotlib مكتبة متطورة للغاية، ويقضي الناس سنوات في إتقانها. لذلك، يرجى الأخذ في الاعتبار أننا لن نغطي سوى جزء بسيط من إمكانيات matplotlib في هذا الدليل.
كيفية استيراد Matplotlib
حسب الاصطلاح، يقوم علماء البيانات عادةً باستيراد مكتبة pyplot من matplotlib تحت الاسم المستعار plt. إليك عبارة الاستيراد الكاملة:
import matplotlib.pyplot as plt
ستحتاج إلى تضمين هذا في بداية أي ملف بايثون يستخدم matplotlib لتوليد تصورات البيانات. هناك أيضاً وسائط أخرى يمكنك إضافتها مع استيراد مكتبة matplotlib لجعل تصوراتك أسهل في العمل معها. إذا كنت تعمل في هذا الدليل في Jupyter Notebook، فقد ترغب في تضمين العبارة التالية، والتي ستجعل تصوراتك تظهر دون الحاجة إلى كتابة عبارة plt.show():
%matplotlib inline
إذا كنت تعمل في Jupyter Notebook على جهاز MacBook بشاشة Retina، يمكنك استخدام العبارات التالية لتحسين دقة تصورات matplotlib في الدفتر:
from IPython.display import set_matplotlib_formats
set_matplotlib_formats('retina')
بعد هذا التمهيد، دعنا نبدأ في إنشاء أول تصورات بياناتنا باستخدام بايثون و matplotlib!
أساسيات تنسيق Matplotlib
في هذا الدليل، ستتعلم كيفية إنشاء رسوم بيانية صندوقية (boxplots)، ورسوم بيانية مبعثرة (scatterplots)، ورسوم بيانية تكرارية (histograms) في بايثون باستخدام matplotlib. أرغب في استعراض بعض أساسيات التنسيق في matplotlib قبل أن نبدأ في إنشاء تصورات بيانات حقيقية.
- أولاً، كل ما تفعله تقريباً في
matplotlibسيتضمن استدعاء طرق على الكائنplt، وهو الاسم المستعار الذي استوردنا بهmatplotlib. - ثانياً، يمكنك إضافة عناوين إلى تصورات
matplotlibعن طريق استدعاءplt.title()وتمرير العنوان المطلوب كسلسلة نصية. - ثالثاً، يمكنك إضافة تسميات لمحوري
xوyباستخدام طريقتيplt.xlabel()وplt.ylabel(). - أخيراً، باستخدام الطرق الثلاث التي ناقشناها للتو –
plt.title()وplt.xlabel()وplt.ylabel()– يمكنك تغيير حجم الخط للعنوان باستخدام الوسيطfontsize.
دعنا نتعمق في إنشاء أول تصورات matplotlib بجدية.
كيفية إنشاء رسوم بيانية صندوقية (Boxplots) في Matplotlib
تُعد الرسوم البيانية الصندوقية (Boxplots) من أهم تصورات البيانات المتاحة لعلماء البيانات. تتيح لنا matplotlib إنشاء رسوم بيانية صندوقية باستخدام الدالة boxplot. نظراً لأننا سنقوم بإنشاء رسوم بيانية صندوقية على طول أعمدتنا (وليس على طول صفوفنا)، فسنرغب أيضاً في قلب كائن DataFrame الخاص بنا داخل استدعاء طريقة boxplot.
plt.boxplot(bank_data.transpose())

هذه بداية جيدة، لكننا بحاجة إلى إضافة بعض التنسيقات لجعل هذا التصور سهل التفسير للمستخدم الخارجي. أولاً، دعنا نضيف عنواناً للرسم البياني:
plt.title('Boxplot of Bank Stock Prices (5Y Lookback)', fontsize=20)

بالإضافة إلى ذلك، من المفيد تسمية محوري x و y، كما ذكرنا سابقاً:
plt.xlabel('Bank', fontsize=20)
plt.ylabel('Stock Prices', fontsize=20)

سنحتاج أيضاً إلى إضافة تسميات خاصة بالأعمدة إلى المحور x بحيث يكون واضحاً أي رسم بياني صندوقي يخص أي بنك. الكود التالي يقوم بالمهمة:
ticks = range(1, len(bank_data.columns)+1)
labels = list(bank_data.columns)
plt.xticks(ticks,labels, fontsize=20)

بهذه البساطة، لدينا رسم بياني صندوقي يقدم بعض التصورات المفيدة في matplotlib! من الواضح أن Goldman Sachs قد تداول بأعلى سعر على مدى السنوات الخمس الماضية بينما تداول سهم Bank of America بأدنى سعر. من المثير للاهتمام أيضاً ملاحظة أن Wells Fargo لديه أكبر عدد من نقاط البيانات الشاذة.
كملخص، إليك الكود الكامل الذي استخدمناه لتوليد رسومنا البيانية الصندوقية:
########################
#Create a Python boxplot
########################
#Set the size of the matplotlib canvas
plt.figure(figsize = (18,12))
#Generate the boxplot
plt.boxplot(bank_data.transpose())
#Add titles to the chart and axes
plt.title('Boxplot of Bank Stock Prices (5Y Lookback)', fontsize=20)
plt.xlabel('Bank', fontsize=20)
plt.ylabel('Stock Prices', fontsize=20)
#Add labels to each individual boxplot on the canvas
ticks = range(1, len(bank_data.columns)+1)
labels = list(bank_data.columns)
plt.xticks(ticks,labels, fontsize=20)
كيفية إنشاء رسوم بيانية مبعثرة (Scatterplots) في Matplotlib
يمكن إنشاء الرسوم البيانية المبعثرة في matplotlib باستخدام طريقة plt.scatter. تأخذ طريقة scatter وسيطين مطلوبين – قيمة x وقيمة y. دعنا نرسم سعر سهم Wells Fargo بمرور الوقت باستخدام طريقة plt.scatter(). أول شيء نحتاج إلى القيام به هو إنشاء متغير المحور x، والذي يسمى dates:
dates = bank_data.index.to_series()
بعد ذلك، سنقوم بعزل أسعار أسهم Wells Fargo في متغير منفصل:
WFC_stock_prices = bank_data['WFC']
يمكننا الآن رسم التصور باستخدام طريقة plt.scatter:
plt.scatter(dates, WFC_stock_prices)

انتظر لحظة – تسميات المحور x لهذا الرسم البياني مستحيلة القراءة! ما هي المشكلة؟ حسناً، matplotlib لا يتعرف حالياً على أن المحور x يحتوي على تواريخ، لذلك لا يباعد التسميات بشكل صحيح. لإصلاح ذلك، نحتاج إلى تحويل كل عنصر من سلسلة dates Series إلى نوع بيانات datetime. الأمر التالي هو الطريقة الأكثر وضوحاً للقيام بذلك:
dates = bank_data.index.to_series()
dates = [pd.to_datetime(d) for d in dates]
بعد تشغيل طريقة plt.scatter مرة أخرى، ستنشئ التصور التالي:

أفضل بكثير! خطوتنا الأخيرة هي إضافة عناوين للرسم البياني والمحاور. يمكننا القيام بذلك باستخدام العبارات التالية:
plt.title("Wells Fargo Stock Price (5Y Lookback)", fontsize=20)
plt.ylabel("Stock Price", fontsize=20)
plt.xlabel("Date", fontsize=20)

كملخص، إليك الكود الذي استخدمناه لإنشاء هذا الرسم البياني المبعثر:
########################
#Create a Python scatterplot
########################
#Set the size of the matplotlib canvas
plt.figure(figsize = (18,12))
#Create the x-axis data
dates = bank_data.index.to_series()
dates = [pd.to_datetime(d) for d in dates]
#Create the y-axis data
WFC_stock_prices = bank_data['WFC']
#Generate the scatterplot
plt.scatter(dates, WFC_stock_prices)
#Add titles to the chart and axes
plt.title("Wells Fargo Stock Price (5Y Lookback)", fontsize=20)
plt.ylabel("Stock Price", fontsize=20)
plt.xlabel("Date", fontsize=20)
كيفية إنشاء رسوم بيانية تكرارية (Histograms) في Matplotlib
الرسوم البيانية التكرارية (Histograms) هي تصورات بيانات تتيح لك رؤية توزيع الملاحظات داخل مجموعة بيانات. يمكن إنشاء الرسوم البيانية التكرارية في matplotlib باستخدام طريقة plt.hist. دعنا ننشئ رسماً بيانياً تكرارياً يتيح لنا رؤية توزيع أسعار الأسهم المختلفة داخل مجموعة بيانات bank_data (لاحظ أننا سنحتاج إلى استخدام طريقة transpose داخل plt.hist تماماً كما فعلنا مع plt.boxplot سابقاً):
plt.hist(bank_data.transpose())

هذا تصور مثير للاهتمام، لكن لا يزال لدينا الكثير لنفعله. أول شيء لاحظته على الأرجح هو أن الأعمدة المختلفة للرسم البياني التكراري لها ألوان مختلفة. هذا مقصود. تقسم الألوان الأعمدة المختلفة داخل كائن pandas DataFrame الخاص بنا. ومع ذلك، فإن هذه الألوان لا معنى لها بدون مفتاح (legend). يمكننا إضافة مفتاح إلى الرسم البياني التكراري لـ matplotlib باستخدام العبارة التالية:
plt.legend(bank_data.columns,fontsize=20)

قد ترغب أيضاً في تغيير عدد bin في الرسم البياني التكراري، والذي يغير عدد الشرائح التي تُقسم إليها مجموعة البيانات عند تجميع الملاحظات في أعمدة الرسم البياني التكراري. على سبيل المثال، إليك كيفية تغيير عدد bins في الرسم البياني التكراري إلى 50:
plt.hist(bank_data.transpose(), bins=50)
أخيراً، سنضيف عناوين للرسم البياني التكراري ومحاوره باستخدام نفس العبارات التي استخدمناها في تصوراتنا الأخرى:
plt.title("A Histogram of Daily Closing Stock Prices for the 5 Largest Banks in the US (5Y Lookback)", fontsize=20)
plt.ylabel("Observations", fontsize=20)
plt.xlabel("Stock Prices", fontsize=20)

كملخص، إليك الكود الكامل المطلوب لتوليد هذا الرسم البياني التكراري:
########################
#Create a Python histogram
########################
#Set the size of the matplotlib canvas
plt.figure(figsize = (18,12))
#Generate the histogram
plt.hist(bank_data.transpose(), bins=50)
#Add a legend to the histogram
plt.legend(bank_data.columns,fontsize=20)
#Add titles to the chart and axes
plt.title("A Histogram of Daily Closing Stock Prices for the 5 Largest Banks in the US (5Y Lookback)", fontsize=20)
plt.ylabel("Observations", fontsize=20)
plt.xlabel("Stock Prices", fontsize=20)
كيفية إنشاء رسوم بيانية فرعية (Subplots) في Matplotlib
في matplotlib، الرسوم البيانية الفرعية (subplots) هو الاسم الذي نستخدمه للإشارة إلى رسوم بيانية متعددة يتم إنشاؤها على نفس اللوحة باستخدام سكربت بايثون واحد. يمكن إنشاء الرسوم البيانية الفرعية باستخدام الأمر plt.subplot. يأخذ الأمر ثلاثة وسائط:
- عدد الصفوف في شبكة الرسوم البيانية الفرعية.
- عدد الأعمدة في شبكة الرسوم البيانية الفرعية.
- الرسم البياني الفرعي الذي حددته حالياً.
دعنا ننشئ شبكة رسوم بيانية فرعية بحجم 2×2 تحتوي على الرسوم البيانية التالية (بهذا الترتيب المحدد):
- الرسم البياني الصندوقي الذي أنشأناه سابقاً.
- الرسم البياني المبعثر الذي أنشأناه سابقاً.
- رسم بياني مبعثر مشابه يستخدم بيانات
BACبدلاً من بياناتWFC. - الرسم البياني التكراري الذي أنشأناه سابقاً.
أولاً، دعنا ننشئ شبكة الرسوم البيانية الفرعية:
plt.subplot(2, 2, 1)
plt.subplot(2, 2, 2)
plt.subplot(2, 2, 3)
plt.subplot(2, 2, 4)

الآن بعد أن أصبح لدينا لوحة رسوم بيانية فرعية فارغة، نحتاج ببساطة إلى نسخ ولصق الكود الذي نحتاجه لكل رسم بياني بعد كل استدعاء لطريقة plt.subplot. في نهاية كتلة الكود، نضيف طريقة plt.tight_layout، والتي تصلح العديد من مشكلات التنسيق الشائعة التي تحدث عند توليد رسوم بيانية فرعية في matplotlib. إليك الكود الكامل:
################################################
################################################
#Create subplots in Python
################################################
################################################
########################
#Subplot 1
########################
plt.subplot(2, 2, 1)
#Generate the boxplot
plt.boxplot(bank_data.transpose())
#Add titles to the chart and axes
plt.title('Boxplot of Bank Stock Prices (5Y Lookback)')
plt.xlabel('Bank', fontsize=20)
plt.ylabel('Stock Prices')
#Add labels to each individual boxplot on the canvas
ticks = range(1, len(bank_data.columns)+1)
labels = list(bank_data.columns)
plt.xticks(ticks,labels)
########################
#Subplot 2
########################
plt.subplot(2, 2, 2)
#Create the x-axis data
dates = bank_data.index.to_series()
dates = [pd.to_datetime(d) for d in dates]
#Create the y-axis data
WFC_stock_prices = bank_data['WFC']
#Generate the scatterplot
plt.scatter(dates, WFC_stock_prices)
#Add titles to the chart and axes
plt.title("Wells Fargo Stock Price (5Y Lookback)")
plt.ylabel("Stock Price")
plt.xlabel("Date")
########################
#Subplot 3
########################
plt.subplot(2, 2, 3)
#Create the x-axis data
dates = bank_data.index.to_series()
dates = [pd.to_datetime(d) for d in dates]
#Create the y-axis data
BAC_stock_prices = bank_data['BAC']
#Generate the scatterplot
plt.scatter(dates, BAC_stock_prices)
#Add titles to the chart and axes
plt.title("Bank of America Stock Price (5Y Lookback)")
plt.ylabel("Stock Price")
plt.xlabel("Date")
########################
#Subplot 4
########################
plt.subplot(2, 2, 4)
#Generate the histogram
plt.hist(bank_data.transpose(), bins=50)
#Add a legend to the histogram
plt.legend(bank_data.columns,fontsize=20)
#Add titles to the chart and axes
plt.title("A Histogram of Daily Closing Stock Prices for the 5 Largest Banks in the US (5Y Lookback)")
plt.ylabel("Observations")
plt.xlabel("Stock Prices")
plt.tight_layout()

كما ترى، ببعض المعرفة الأساسية، من السهل نسبياً إنشاء تصورات بيانات جميلة باستخدام matplotlib. آخر شيء نحتاج إلى القيام به هو حفظ التصور كملف .png في دليل العمل الحالي لدينا. تتمتع matplotlib بوظائف مدمجة ممتازة للقيام بذلك. ما عليك سوى إضافة العبارة التالية مباشرة بعد الانتهاء من الرسم البياني الفرعي الرابع:
################################################
#Save the figure to our local machine
################################################
plt.savefig('bank_data.png')
خلال ما تبقى من هذا الدليل، ستتعلم كيفية جدولة مصفوفة الرسوم البيانية الفرعية هذه ليتم تحديثها تلقائياً على موقع الويب الخاص بك كل يوم.
الخطوة 3: إنشاء حساب Amazon Web Services (AWS)
حتى الآن في هذا الدليل، تعلمنا كيفية:
- الحصول على بيانات سوق الأسهم التي سنقوم بتصورها من
IEX Cloud API. - إنشاء تصورات رائعة باستخدام هذه البيانات مع مكتبة
matplotlibفي بايثون.
خلال ما تبقى من هذا الدليل، ستتعلم كيفية أتمتة هذه التصورات بحيث يتم تحديثها وفق جدول زمني محدد. للقيام بذلك، سنستخدم إمكانيات الحوسبة السحابية لـ Amazon Web Services. ستحتاج إلى إنشاء حساب AWS أولاً. انتقل إلى هذا العنوان URL وانقر على “Create an AWS Account” في الزاوية العلوية اليمنى:

سيقوم تطبيق الويب الخاص بـ AWS بإرشادك خلال خطوات إنشاء حساب. بمجرد إنشاء حسابك، يمكننا البدء في العمل مع خدمتي AWS اللتين سنحتاجهما لتصوراتنا: AWS S3 و AWS EC2.
الخطوة 4: إنشاء سلة AWS S3 لتخزين تصوراتك
يرمز AWS S3 إلى Simple Storage Service (خدمة التخزين البسيطة). وهي واحدة من أكثر عروض الحوسبة السحابية شيوعاً المتاحة في Amazon Web Services. يستخدم المطورون AWS S3 لتخزين الملفات والوصول إليها لاحقاً عبر عناوين URL عامة.
لتخزين هذه الملفات، يجب علينا أولاً إنشاء ما يسمى سلة AWS S3 bucket، وهي كلمة فاخرة لمجلد يخزن الملفات في AWS. للقيام بذلك، انتقل أولاً إلى لوحة تحكم S3 داخل Amazon Web Services. على الجانب الأيمن من لوحة تحكم Amazon S3، انقر على Create bucket، كما هو موضح أدناه:

في الشاشة التالية، سيطلب منك AWS تحديد اسم لسلة S3 الجديدة الخاصة بك. لغرض هذا الدليل، سنستخدم اسم السلة nicks-first-bucket. بعد ذلك، ستحتاج إلى التمرير لأسفل وتعيين أذونات سلتك. نظراً لأن الملفات التي سنقوم بتحميلها مصممة لتكون متاحة للجمهور (بعد كل شيء، سنقوم بتضمينها في صفحات على موقع ويب)، فسترغب في جعل الأذونات مفتوحة قدر الإمكان. إليك مثال محدد لما يجب أن تبدو عليه أذونات AWS S3 الخاصة بك:

هذه الأذونات متساهلة للغاية، وفي العديد من حالات الاستخدام غير مقبولة (على الرغم من أنها تلبي بالفعل متطلبات هذا الدليل). لهذا السبب، سيطلب منك AWS الإقرار بالتحذير التالي قبل إنشاء سلة AWS S3 الخاصة بك:

بمجرد الانتهاء من كل هذا، يمكنك التمرير إلى أسفل الصفحة والنقر على Create Bucket. أنت الآن جاهز للمتابعة!
الخطوة 5: تعديل سكربت بايثون لحفظ تصوراتك في AWS S3
تم تصميم سكربت بايثون الخاص بنا في شكله الحالي لإنشاء تصور ثم حفظ هذا التصور على جهاز الكمبيوتر المحلي الخاص بنا. نحتاج الآن إلى تعديل سكربتنا لحفظ ملف .png بدلاً من ذلك في سلة AWS S3 التي أنشأناها للتو (والتي، للتذكير، تسمى nicks-first-bucket).
الأداة التي سنستخدمها لتحميل ملفنا إلى سلة AWS S3 الخاصة بنا تسمى boto3، وهي مجموعة تطوير البرامج (SDK) لـ Amazon Web Services لبايثون. أولاً، ستحتاج إلى تثبيت boto3 على جهازك. أسهل طريقة للقيام بذلك هي باستخدام مدير الحزم pip:
pip3 install boto3
بعد ذلك، نحتاج إلى استيراد boto3 إلى سكربت بايثون الخاص بنا. نقوم بذلك عن طريق إضافة العبارة التالية بالقرب من بداية سكربتنا:
import boto3
نظراً لعمق واتساع عروض منتجات Amazon Web Services، فإن boto3 هي مكتبة بايثون معقدة للغاية. لحسن الحظ، نحتاج فقط إلى استخدام بعض الوظائف الأساسية لـ boto3. ستقوم كتلة الكود التالية بتحميل تصورنا النهائي إلى Amazon S3.
################################################
#Push the file to the AWS S3 bucket
################################################
s3 = boto3.resource('s3')
s3.meta.client.upload_file('bank_data.png', 'nicks-first-bucket', 'bank_data.png', ExtraArgs={'ACL': 'public-read'})
كما ترى، تأخذ طريقة upload_file في boto3 عدة وسائط. دعنا نحللها واحدة تلو الأخرى:
bank_data.pngهو اسم الملف على جهازنا المحلي.nicks-first-bucketهو اسم سلةS3التي نريد التحميل إليها.bank_data.pngهو الاسم الذي نريد أن يحمله الملف بعد تحميله إلى سلةAWS S3. في هذه الحالة، هو نفس الوسيط الأول، لكن لا يجب أن يكون كذلك.ExtraArgs={'ACL': 'public-read'}يعني أن الملف يجب أن يكون قابلاً للقراءة من قبل الجمهور بمجرد دفعه إلى سلةAWS S3.
تشغيل هذا الكود الآن سيؤدي إلى خطأ. تحديداً، سيلقي بايثون الاستثناء التالي:
S3UploadFailedError: Failed to upload bank_data.png to nicks-first-bucket/bank_data.png: An error occurred (NoSuchBucket) when calling the PutObject operation: The specified bucket does not exist
لماذا هذا؟ حسناً، لأننا لم نقم بعد بتكوين جهازنا المحلي للتفاعل مع Amazon Web Services عبر boto3. للقيام بذلك، يجب علينا تشغيل الأمر aws configure من واجهة سطر الأوامر الخاصة بنا وإضافة مفاتيح الوصول الخاصة بنا. لمزيد من المعلومات حول كيفية تكوين واجهة سطر أوامر AWS CLI، يمكنك الرجوع إلى وثائق أمازون.
إذا كنت تفضل عدم مغادرة هذه الصفحة، فإليك الخطوات السريعة لإعداد AWS CLI الخاص بك. أولاً، مرر مؤشر الماوس فوق اسم المستخدم الخاص بك في الزاوية العلوية اليمنى، هكذا:

انقر على My Security Credentials. في الشاشة التالية، ستحتاج إلى النقر على Access keys (access key ID and secret access key) ثم انقر على Create New Access Key.

سيؤدي هذا إلى مطالبتك بتنزيل ملف .csv يحتوي على كل من مفتاح الوصول الخاص بك (Access Key) ومفتاح الوصول السري الخاص بك (Secret Access Key). احفظ هذه المفاتيح في مكان آمن. بعد ذلك، قم بتشغيل واجهة سطر أوامر Amazon Web Services عن طريق كتابة aws configure في سطر الأوامر الخاص بك. سيؤدي هذا إلى مطالبتك بإدخال مفتاح الوصول ومفتاح الوصول السري الخاص بك. بمجرد الانتهاء من ذلك، يجب أن يعمل سكربت الخاص بك كما هو متوقع. أعد تشغيل السكربت وتأكد من تحميل تصور بايثون الخاص بك بشكل صحيح إلى AWS S3 من خلال النظر داخل السلة التي أنشأناها سابقاً:

تم تحميل التصور بنجاح. نحن الآن جاهزون لتضمين التصور على موقع الويب الخاص بنا!
الخطوة 6: تضمين التصور على موقع الويب الخاص بك
بمجرد تحميل تصور البيانات إلى AWS S3، ستحتاج إلى تضمين التصور في مكان ما على موقع الويب الخاص بك. يمكن أن يكون هذا في منشور مدونة أو أي صفحة أخرى على موقعك. للقيام بذلك، سنحتاج إلى الحصول على عنوان URL للصورة من سلة S3 الخاصة بنا. انقر على اسم الصورة داخل سلة S3 للانتقال إلى الصفحة الخاصة بالملف لهذا العنصر. ستبدو هكذا:

إذا قمت بالتمرير إلى أسفل الصفحة، سيكون هناك حقل يسمى Object URL يبدو هكذا:
https://nicks-first-bucket.s3.us-east-2.amazonaws.com/bank_data.png
إذا قمت بنسخ ولصق عنوان URL هذا في متصفح ويب، فسيقوم بالفعل بتنزيل ملف bank_data.png الذي قمنا بتحميله سابقاً! لتضمين هذه الصورة في صفحة ويب، ستحتاج إلى تمريرها إلى وسم img في HTML كخاصية src. إليك كيفية تضمين صورة bank_data.png الخاصة بنا في صفحة ويب باستخدام HTML:
<img src="https://nicks-first-bucket.s3.us-east-2.amazonaws.com/bank_data.png">
ملاحظة: في صورة حقيقية مضمنة على موقع ويب، سيكون من المهم تضمين وسم alt tag لأغراض إمكانية الوصول. في القسم التالي، سنتعلم كيفية جدولة سكربت بايثون الخاص بنا ليتم تشغيله بشكل دوري بحيث تكون البيانات في bank_data.png محدثة دائماً.
الخطوة 7: إنشاء مثيل AWS EC2
سنستخدم AWS EC2 لجدولة سكربت بايثون الخاص بنا ليتم تشغيله بشكل دوري. يرمز AWS EC2 إلى Elastic Compute Cloud، وهو، جنباً إلى جنب مع S3، أحد أشهر خدمات الحوسبة السحابية من أمازون. يتيح لك استئجار وحدات صغيرة من قوة الحوسبة (تسمى instances) على أجهزة الكمبيوتر في مراكز بيانات أمازون وجدولة تلك الأجهزة لأداء مهام لك.
تُعد AWS EC2 خدمة رائعة جداً لأنه إذا استأجرت بعض أجهزة الكمبيوتر الأصغر حجماً، فإنك تتأهل بالفعل للحصول على طبقة AWS المجانية. بعبارة أخرى، الاستخدام الدقيق للتسعير داخل AWS EC2 سيسمح لك بتجنب دفع أي أموال على الإطلاق.
للبدء، سنحتاج إلى إنشاء أول مثيل EC2 لنا. للقيام بذلك، انتقل إلى لوحة تحكم EC2 داخل AWS Management Console وانقر على Launch Instance:

سيؤدي هذا إلى نقلك إلى شاشة تحتوي على جميع أنواع المثيلات المتاحة داخل AWS EC2. هناك عدد لا يصدق تقريباً من الخيارات هنا. نريد نوع مثيل مؤهل لـ Free tier eligible – تحديداً، اخترت Amazon Linux 2 AMI (HVM), SSD Volume Type:

انقر على Select للمتابعة. في الصفحة التالية، سيطلب منك AWS تحديد مواصفات جهازك. تتضمن الحقول التي يمكنك تحديدها:
FamilyTypevCPUsMemoryInstance Storage (GB)EBS-OptimizedNetwork PerformanceIPv6 Support
لغرض هذا الدليل، نريد ببساطة تحديد الجهاز الوحيد المؤهل للطبقة المجانية. يتميز هذا الجهاز بملصق أخضر صغير يبدو هكذا:

انقر على Review and Launch في أسفل الشاشة للمتابعة. ستعرض الشاشة التالية تفاصيل المثيل الجديد الخاص بك للمراجعة. راجع مواصفات الجهاز بسرعة، ثم انقر على Launch في الزاوية السفلية اليمنى. سيؤدي النقر على زر Launch إلى ظهور نافذة منبثقة تطلب منك Select an existing key pair or create a new key pair (تحديد زوج مفاتيح موجود أو إنشاء زوج مفاتيح جديد). يتكون زوج المفاتيح من مفتاح عام تحتفظ به AWS ومفتاح خاص يجب عليك تنزيله وتخزينه في ملف .pem. يجب أن يكون لديك حق الوصول إلى ملف .pem هذا للوصول إلى مثيل EC2 الخاص بك (عادةً عبر SSH). لديك أيضاً خيار المتابعة بدون زوج مفاتيح، ولكن هذا لا يُنصح به لأسباب أمنية. بمجرد الانتهاء من ذلك، سيتم تشغيل مثيلك! تهانينا على إطلاق أول مثيل لك على إحدى أهم خدمات البنية التحتية لـ Amazon Web Services.
نقل سكربت بايثون إلى مثيل EC2
بعد ذلك، ستحتاج إلى دفع سكربت بايثون الخاص بك إلى مثيل EC2 الخاص بك. إليك عبارة أمر عامة تتيح لك نقل ملف إلى مثيل EC2:
scp -i path/to/.pem_file path/to/file username@host_address.amazonaws.com:/path_to_copy
قم بتشغيل هذه العبارة مع الاستبدالات الضرورية لنقل ملف bank_stock_data.py إلى مثيل EC2. قد تعتقد أنه يمكنك الآن تشغيل سكربت بايثون الخاص بك من داخل مثيل EC2. لسوء الحظ، هذا ليس هو الحال. لا يأتي مثيل EC2 الخاص بك مع حزم بايثون الضرورية. لتثبيت الحزم التي استخدمناها، يمكنك إما تصدير ملف requirements.txt واستيراد الحزم المناسبة باستخدام pip، أو يمكنك ببساطة تشغيل ما يلي:
sudo yum install python3-pip
pip3 install pandas
pip3 install boto3
نحن الآن جاهزون لجدولة سكربت بايثون الخاص بنا ليتم تشغيله بشكل دوري على مثيل EC2 الخاص بنا! سنستكشف هذا في القسم التالي من مقالنا.
الخطوة 8: جدولة سكربت بايثون ليتم تشغيله بشكل دوري على AWS EC2
الخطوة الوحيدة المتبقية في هذا الدليل هي جدولة ملف bank_stock_data.py الخاص بنا ليتم تشغيله بشكل دوري في مثيل EC2 الخاص بنا. يمكننا استخدام أداة سطر الأوامر تسمى cron للقيام بذلك. يعمل cron عن طريق مطالبتك بتحديد شيئين:
- كم مرة تريد تنفيذ مهمة (تسمى
cron job)، معبر عنها عبر تعبيرcron expression. - ما الذي يجب تنفيذه عند جدولة مهمة
cron.
أولاً، دعنا نبدأ بإنشاء تعبير cron. قد تبدو تعبيرات cron وكأنها هراء لشخص غير مطلع. على سبيل المثال، إليك تعبير cron الذي يعني “كل يوم في الظهر”:
00 12 * * *
أنا شخصياً أستخدم موقع crontab guru، وهو مورد ممتاز يتيح لك رؤية (بمصطلحات بسيطة) ما يعنيه تعبير cron الخاص بك. إليك كيفية استخدام موقع crontab guru لجدولة مهمة cron ليتم تشغيلها كل يوم أحد في الساعة 7 صباحاً:

لدينا الآن أداة (crontab guru) يمكننا استخدامها لتوليد تعبير cron الخاص بنا. نحتاج الآن إلى توجيه خدمة cron daemon في مثيل EC2 الخاص بنا لتشغيل ملف bank_stock_data.py كل يوم أحد في الساعة 7 صباحاً. للقيام بذلك، سنقوم أولاً بإنشاء ملف جديد في مثيل EC2 الخاص بنا يسمى bank_stock_data.cron. نظراً لأنني أستخدم محرر النصوص vim، فإن الأمر الذي أستخدمه لذلك هو:
vim bank_stock_data.cron
داخل ملف .cron هذا، يجب أن يكون هناك سطر واحد يبدو هكذا: (cron expression) (statement to execute). تعبير cron الخاص بنا هو 00 7 * * 7 وعبارتنا للتنفيذ هي python3 bank_stock_data.py. بجمع كل ذلك معاً، إليك ما يجب أن تكون عليه المحتويات النهائية لـ bank_stock_data.cron:
00 7 * * 7 python3 bank_stock_data.py
الخطوة الأخيرة في هذا الدليل هي استيراد ملف bank_stock_data.cron إلى crontab الخاص بمثيل EC2 الخاص بنا. crontab هو في الأساس ملف يجمع المهام لخدمة cron daemon لتنفيذها بشكل دوري. دعنا نأخذ لحظة للتحقق من ذلك في crontab الخاص بنا. الأمر التالي يطبع محتويات crontab إلى وحدة التحكم الخاصة بنا:
crontab -l
نظراً لأننا لم نضيف أي شيء إلى crontab الخاص بنا وأننا أنشأنا مثيل EC2 الخاص بنا قبل لحظات قليلة فقط، فيجب أن لا تطبع هذه العبارة شيئاً. الآن دعنا نستورد bank_stock_data.cron إلى crontab. إليك العبارة للقيام بذلك:
crontab bank_stock_data.cron
الآن يجب أن نكون قادرين على طباعة محتويات crontab الخاص بنا ورؤية محتويات bank_stock_data.cron. لاختبار ذلك، قم بتشغيل الأمر التالي:
crontab -l
يجب أن تطبع:
00 7 * * 7 python3 bank_stock_data.py
الخلاصة التقنية
في هذا الدليل، استعرضنا رحلة متكاملة لإنشاء نظام تصور بيانات آلي باستخدام بايثون وخدمات أمازون السحابية. بدأنا بفهم أهمية البيانات المتغيرة زمنياً وقمنا بجمعها وتحليلها بكفاءة باستخدام مكتبة pandas وواجهة IEX Cloud API. ثم انتقلنا إلى الجانب المرئي، حيث أتقنا أساسيات matplotlib لإنشاء رسوم بيانية صندوقية، ومبعثرة، وتكرارية، بالإضافة إلى تجميعها في رسوم بيانية فرعية متكاملة. الجزء الأكثر أهمية كان أتمتة العملية، حيث استخدمنا AWS S3 لتخزين التصورات بشكل عام، و AWS EC2 كبيئة حوسبة، وأخيراً cron لجدولة تحديث السكربت بشكل دوري. هذا النهج يضمن أن تظل تصورات البيانات على موقع الويب الخاص بك حديثة ودقيقة باستمرار، مما يوفر قيمة تحليلية مستمرة للمستخدمين دون تدخل يدوي.