اذهب إلى المحتوى

الكتابة في مستندات إكسل باستخدام لغة بايثون Python


Ola Abbas

تعرّفنا في المقال السابق على كيفية قراءة مستندات إكسل باستخدام لغة بايثون، وسنتعرّف في هذا المقال على كيفية كتابة مستندات إكسل باستخدام لغة بايثون، إذ توفّر وحدة OpenPyXL الخاصة بلغة بايثون طرقًا لكتابة البيانات، مما يعني أن برامجك يمكنها إنشاء ملفات جداول البيانات وتعديلها، ومن السهل إنشاء جداول بيانات تحتوي على آلاف الصفوف من البيانات باستخدام بايثون.

إنشاء وحفظ مستندات إكسل

استدعِ الدالة openpyxl.Workbook()‎ لإنشاء كائن مصنف Workbook جديد وفارغ، لذا أدخِل ما يلي في الصدفة التفاعلية:

>>> import openpyxl
>>> wb = openpyxl.Workbook() # إنشاء مصنف فارغ
>>> wb.sheetnames # يبدأ المصنف بورقة واحدة
['Sheet']
>>> sheet = wb.active
>>> sheet.title
'Sheet'
>>> sheet.title = 'Meat Eggs Sheet' # تغيير العنوان
>>> wb.sheetnames
['Meat Eggs Sheet']

سيبدأ المصنف بورقة واحدة تُسمَّى "Sheet"، ويمكنك تغيير اسم الورقة من خلال تخزين سلسلة نصية جديدة في السمة Attribute الخاصة بها وهي title.

لن يُحفظ ملف جدول البيانات عند تعديل كائن Workbook أو أوراقه وخلاياه حتى استدعاء تابع المصنف save()‎. أدخِل ما يلي في الصدفة التفاعلية (مع الملف example.xlsx في مجلد العمل الحالي):

>>> import openpyxl
>>> wb = openpyxl.load_workbook('example.xlsx')
>>> sheet = wb.active
>>> sheet.title = 'Spam Spam Spam'
>>> wb.save('example_copy.xlsx') # حفظ المصنف

غيّرنا اسم الورقة، وحفظنا التغييرات من خلال تمرير اسم الملف كسلسلة نصية إلى التابع save()‎. يؤدي تمرير اسم ملف مختلف عن الاسم الأصلي -مثل الاسم 'example_copy.xlsx'- إلى حفظ التغييرات في نسخة من جدول البيانات.

إذا عدّلتَ جدول بيانات حمّلته من ملف، فيجب عليك دائمًا حفظ جدول البيانات الجديد المُعدَّل باسم ملفٍ مختلف عن اسم الملف الأصلي، وبذلك سيظل لديك ملف جدول البيانات الأصلي للعمل عليه في حالة وجود خطأ في شيفرتك البرمجية، مما يؤدي إلى احتواء الملف الجديد المحفوظ على بيانات غير صحيحة أو تالفة.

إنشاء وحذف الأوراق

يمكن إضافة الأوراق وحذفها من المصنف باستخدام التابع create_sheet()‎ والعامل del. إذًا لندخِل ما يلي في الصدفة التفاعلية:

>>> import openpyxl
>>> wb = openpyxl.Workbook()
>>> wb.sheetnames
['Sheet']
>>> wb.create_sheet() # إضافة ورقة جديدة
<Worksheet "Sheet1">
>>> wb.sheetnames
['Sheet', 'Sheet1']
>>> # إنشاء ورقة جديدة في الفهرس 0
>>> wb.create_sheet(index=0, title='First Sheet')
<Worksheet "First Sheet">
>>> wb.sheetnames
['First Sheet', 'Sheet', 'Sheet1']
>>> wb.create_sheet(index=2, title='Middle Sheet')
<Worksheet "Middle Sheet">
>>> wb.sheetnames
['First Sheet', 'Sheet', 'Middle Sheet', 'Sheet1']

يعيد التابع create_sheet()‎ كائن Worksheet جديد اسمه SheetX، والذي ضُبِط افتراضيًا ليكون الورقة الأخيرة في المصنف. يمكن اختياريًا تحديد فهرس واسم الورقة الجديدة باستخدام وسطاء الكلمات المفتاحية Keyword Arguments التي هي index و title.

لنتابع المثال السابق من خلال كتابة ما يلي:

>>> wb.sheetnames
['First Sheet', 'Sheet', 'Middle Sheet', 'Sheet1']
>>> del wb['Middle Sheet']
>>> del wb['Sheet1']
>>> wb.sheetnames
['First Sheet', 'Sheet']

يمكنك استخدام العامل del لحذف ورقة من مصنف، وهذا يماثل استخدامه لحذف زوج مفتاح-قيمة من القاموس.

ملاحظة: تذكّر استدعاء التابع save()‎ لحفظ التغييرات بعد إضافة أوراق إلى المصنف أو حذفها منه.

كتابة القيم في الخلايا

تشبه كتابة القيم في الخلايا إلى حدٍ كبير كتابة القيم في المفاتيح الموجودة ضمن القاموس. إذًا لندخل ما يلي في الصدفة التفاعلية:

>>> import openpyxl
>>> wb = openpyxl.Workbook()
>>> sheet = wb['Sheet']
>>> sheet['A1'] = 'Hello, world!' # تعديل قيمة الخلية
>>> sheet['A1'].value
'Hello, world!'

إذا كان لديك إحداثيات الخلية كسلسلة نصية، فيمكنك استخدامها بالطريقة نفسها لاستخدام مفتاح القاموس في الكائن Worksheet لتحديد الخلية التي تريد الكتابة فيها.

تطبيق عملي: تحديث جدول بيانات

ستكتب في هذا التطبيق العملي برنامجًا لتحديث الخلايا في جدول بيانات مبيعات المنتجات، حيث سيبحث برنامجك في جدول البيانات، ويعثر على أنواع معينة من المنتجات، ويحدّث أسعارها. يمكنك تنزيل جدول البيانات الخاص بهذا التطبيق العملي، ويوضح الشكل التالي كيف يبدو جدول البيانات:

01.png

جدول بيانات مبيعات المنتجات

يمثّل كل صف في هذا الجدول عملية بيع واحدة، والأعمدة هي نوع المنتج المباع (A)، والتكلفة لكل كيلوجرام من هذا المنتج (B)، وعدد الكيلوجرامات المباعة (C)، وإجمالي الإيرادات من عمليات البيع (D). يُضبَط عمود "الإجمالي TOTAL" على صيغة إكسل ‎=ROUND(B3*C3, 2)‎ التي تضرب تكلفة كل كيلوجرام بعدد الكيلوجرامات المُباعة وتقريب النتيجة إلى أقرب سنت. ستحدّث الخلايا الموجودة في العمود TOTAL نفسها تلقائيًا باستخدام هذه الصيغة في حالة وجود تغيير في العمود B أو C.

لنفترض إدخال أسعار الثوم والكرفس والليمون بصورة غير صحيحة، مما يتركك أمام مهمة مملة تتمثل في المرور على آلاف الصفوف في جدول البيانات لتحديث تكلفة الكيلوجرام الواحد لصفوف الثوم Garlic والكرفس Celery والليمون Lemon. لا يمكنك إجراء عملية بحث واستبدال "find-and-replace" بسيطة للسعر بسبب وجود عناصر أخرى لها السعر نفسه ولا نريد تغييرها بصورة خاطئة. قد يستغرق تنفيذ ذلك يدويًا ساعات بالنسبة لآلاف الصفوف، ولكن يمكنك كتابة برنامج يمكنه إنجاز ذلك في ثوانٍ، حيث يطبّق برنامجك ما يلي:

  1. يتكرر على جميع الصفوف ضمن حلقة.
  2. إذا كان الصف للثوم أو الكرفس أو الليمون، فسيغيِّر السعر.

وهذا يعني أن شيفرتك البرمجية يجب أن تطبّق الخطوات التالية:

  1. فتح ملف جدول البيانات.
  2. التحقق مما إذا كانت القيمة الموجودة في العمود A هي الكرفس Celery أو الثوم Garlic أو الليمون Lemon لجميع الصفوف.
  3. إذا كان الأمر كذلك، فسيتحدّث السعر في العمود B.
  4. حفظ جدول البيانات في ملف جديد حتى لا تفقد جدول البيانات القديم.

الخطوة الأولى: إعداد هيكل البيانات باستخدام معلومات التحديث

إليك الأسعار التي يجب تحديثها:

المنتج السعر
الكرفس Celery ‫1.19
الثوم Garlic ‫3.07
الليمون Lemon ‫1.27

ويمكنك كتابة الشيفرة البرمجية التالية:

if produceName == 'Celery':
    cellObj = 1.19
if produceName == 'Garlic':
    cellObj = 3.07
if produceName == 'Lemon':
    cellObj = 1.27

يُعَد الحصول على بيانات المنتج والأسعار المُحدَّثة الثابتة باستخدام الطريقة السابقة أمرًا غير مناسب إلى حدٍ ما، فإذا كنت بحاجة إلى تحديث جدول البيانات مرة أخرى بأسعار مختلفة أو بمنتجات مختلفة، فيجب عليك تغيير الكثير من الشيفرة البرمجية، وبالتالي ستخاطر بإدخال أخطاء في كل مرة تغيّر فيها شيفرتك البرمجية. يتمثّل الحل الأفضل في تخزين معلومات السعر المُصحَّحة في قاموس وكتابة شيفرتك البرمجية لاستخدام هيكل البيانات، لذا أدخِل الشيفرة التالية في تبويب جديد لإنشاء ملف جديد في محرّرك:

#! python3
# updateProduce.py - تصحيح أسعار المنتجات في جدول بيانات المبيعات

import openpyxl

wb = openpyxl.load_workbook('produceSales.xlsx')
sheet = wb['Sheet']

# أنواع المنتجات وأسعارها المُحدَّثة
PRICE_UPDATES = {'Garlic': 3.07,
                 'Celery': 1.19,
                 'Lemon': 1.27}

# التكرار على جميع الصفوف وتحديث الأسعار

احفظ الملف بالاسم updateProduce.py. إذا أردتَ تحديث جدول البيانات مرة أخرى، فيجب تحديث القاموس PRICE_UPDATES فقط دون تغيير أي شيفرة برمجية أخرى.

الخطوة الثانية: التحقق من كافة الصفوف وتحديث الأسعار غير الصحيحة

سيتكرر الجزء التالي من البرنامج على كافة الصفوف الموجودة في جدول البيانات، لذا أضِف الشيفرة البرمجية التالية إلى نهاية الملف updateProduce.py:

 #! python3
   # updateProduce.py - تصحيح أسعار المنتجات في جدول بيانات المبيعات

   --snip--

   # التكرار على جميع الصفوف وتحديث الأسعار
 for rowNum in range(2, sheet.max_row):    # تخطي الصف الأول
     produceName = sheet.cell(row=rowNum, column=1).value
     if produceName in PRICE_UPDATES:
          sheet.cell(row=rowNum, column=2).value = PRICE_UPDATES[produceName]

 wb.save('updatedProduceSales.xlsx')

نكرّر الشيفرة البرمجية على الصفوف بدءًا من الصف 2، لأن الصف 1 هو ترويسة الجدول ➊، ونخزّن الخلية الموجودة في العمود 1 (أي العمود A) في المتغير produceName ➋، حيث إذا كان هذا المتغير موجودًا بوصفه مفتاحًا في قاموس PRICE_UPDATES ➌، فيجب أن تعلم أن هذا الصف يجب تصحيح سعره، وسيكون السعر الصحيح في PRICE_UPDATES[produceName]‎.

لاحظ مدى نظافة شيفرتك باستخدام قاموس PRICE_UPDATES، إذ لا توجد سوى تعليمة if واحدة فقط بدلًا من استخدام شيفرة تحتوي التعليمة if produceName == 'Garlic':‎ مثلًا التي تكون ضرورية لكل نوعٍ من المنتجات يجب تحديثه. بما أن هذه الشيفرة البرمجية تستخدم قاموس PRICE_UPDATES بدلًا من كتابة شيفرة ثابتة لأسماء المنتجات وأسعارها المُحدَّثة ضمن حلقة for، فهذا يعني أنك ستعدّل قاموس PRICE_UPDATES فقط دون تعديل الشيفرة البرمجية، إذا احتاج جدول بيانات مبيعات المنتجات تغييراتٍ إضافية.

تحفظ الشيفرة البرمجية كائن Workbook في الملف updatedProduceSales.xlsx ➍ بعد المرور على جدول البيانات بأكمله وإجراء التغييرات، ولا تكتب معلوماتٍ جديدة مكان معلومات جدول البيانات القديم إذا احتوى برنامجك خطأً وكان جدول البيانات المُحدَّث خاطئًا. يمكنك حذف جدول البيانات القديم بعد التحقق من أن جدول البيانات المُحدَّث صحيحًا.

ملاحظة: لا تنسَ أنه يمكنك تنزيل الشيفرة المصدرية الكاملة لهذا البرنامج.

أفكار لبرامج مماثلة

يستخدم العديد من العاملين في وظائف مكتبية جداولَ بيانات إكسل طوال الوقت، لذا قد يكون البرنامج الذي يمكنه تعديل ملفات إكسل وكتابتها تلقائيًا مفيدًا جدًا لهم، إذ يمكن أن يفعل مثل هذا البرنامج الأمور التالية:

  • قراءة البيانات من جدول بيانات واحد وكتابتها في أجزاء من جداول بيانات أخرى.
  • قراءة البيانات من مواقع الويب أو الملفات النصية أو الحافظة وكتابتها في جدول بيانات.
  • تنظيف البيانات تلقائيًا في جداول البيانات، فمثلًا يمكنه استخدام التعابير النمطية Regular Expressions لقراءة تنسيقات متعددة لأرقام الهواتف وتعديلها إلى تنسيق معياري واحد.

ضبط نمط الخط Font Style في الخلايا

يمكن أن يساعدك تنسيق خلايا أو صفوف أو أعمدة معينة في إبراز المناطق المهمة في جدول البيانات، إذ يمكن لبرنامجك في جدول بيانات المنتجات مثلًا تطبيق نص عريض على صفوف البطاطا Potato والثوم Garlic والجزر الأبيض Parsnip، أو يمكنه كتابة الصفوف التي تكلفة الكيلوجرام الواحد منها أكبر من 5 دولارات بخط مائل. قد يكون تنسيق أجزاء من جدول بيانات كبير أمرًا مملًا يدويًا، ولكن يمكن لبرامجك تطبيق ذلك مباشرةً.

يمكنك تخصيص أنماط الخطوط في الخلايا من خلال استيراد الدالة Font()‎ من الوحدة openpyxl.styles، مما يتيح لك كتابة Font()‎ بدلًا من openpyxl.styles.Font()‎ اختصارًا:

from openpyxl.styles import Font

ينشئ المثال التالي مصنفًا جديدًا ويضبط الخلية A1 ليكون الخط فيها خطًا مائلًا وبحجم 24 نقطة. إذًا لندخِل ما يلي في الصدفة التفاعلية:

  >>> import openpyxl
  >>> from openpyxl.styles import Font
  >>> wb = openpyxl.Workbook()
  >>> sheet = wb['Sheet']
 >>> italic24Font = Font(size=24, italic=True) # إنشاء الخط
 >>> sheet['A1'].font = italic24Font # ت‫طبيق الخط في الخلية A1
  >>> sheet['A1'] = 'Hello, world!'
  >>> wb.save('styles.xlsx')

تعيد الدالة Font(size=24, italic=True)‎ كائن Font المُخزَّن في المتغير italic24Font ➊، وتضبط وسطاء الكلمات المفتاحية الخاصة بالدالة Font()‎ -مثل الوسيطين size و italic- معلومات تنسيق الكائن Font، وإذا أسندنا الكائن italic24Font ➋ إلى sheet['A1'].font، فستُطبَّق جميع معلومات تنسيق الخط على الخلية A1.

كائنات الخط Font

يمكن ضبط السمات font من خلال تمرير وسطاء الكلمات المفتاحية إلى الدالة Font()‎، حيث يوضّح الجدول التالي وسطاء الكلمات المفتاحية المُحتمَلة للدالة Font()‎:

وسيط الكلمة المفتاحية نوع البيانات الوصف
name سلسلة نصية اسم الخط مثل 'Calibri' أو 'Times New Roman'
size عدد صحيح حجم الخط مقاسًا بالنقاط
bold قيمة منطقية قيمته True إذا كان الخط عريضًا
italic قيمة منطقية قيمته True إذا كان الخط مائلًا

يمكنك استدعاء الدالة Font()‎ لإنشاء كائن Font وتخزينه في متغير، ثم تسند السمة font الخاصة بكائن Cell إلى هذا المتغير، فمثلًا تنشئ الشيفرة البرمجية التالية تنسيقات خطوط مختلفة:

>>> import openpyxl
>>> from openpyxl.styles import Font
>>> wb = openpyxl.Workbook()
>>> sheet = wb['Sheet']

>>> fontObj1 = Font(name='Times New Roman', bold=True)
>>> sheet['A1'].font = fontObj1
>>> sheet['A1'] = 'Bold Times New Roman'

>>> fontObj2 = Font(size=24, italic=True)
>>> sheet['B3'].font = fontObj2
>>> sheet['B3'] = '24 pt Italic'

>>> wb.save('styles.xlsx')

نخزّن كائن Font في المتغير fontObj1 الذي نسنده إلى السمة font الخاصة بالكائن Cell للخلية A1، ونكرر العملية نفسها مع كائن خط آخر لضبط خط الخلية الثانية. إذا نفّذنا الشيفرة البرمجية السابقة، فسيُضبَط تنسيق الخلايا A1 و B3 في جدول البيانات على تنسيقات الخطوط المُخصَّصة، وستبدو كما يلي:

02 000007

جدول بيانات يحتوي على أنماط خطوط مُخصَّصة

ضبطنا اسم الخط في الخلية A1 على القيمة 'Times New Roman' والوسيط bold على القيمة true، حيث يظهر النص بالخط Times New Roman العريض، ولكننا لم نحدد حجم الخط، لذلك اُستخدِم الحجم الافتراضي للوحدة openpyxl، وهو الحجم 11. استخدمنا الخط المائل وبحجم 24 في الخلية B3، ولكن لم نحدد اسم الخط، لذلك اُستخدِم الخط الافتراضي للوحدة openpyxl، وهو الخط Calibri.

صيغ إكسل

تضبط صيغ إكسل -التي تبدأ بإشارة يساوي- الخلايا لتحتوي على قيم ناتجة عن تطبيق عمليات حسابية على خلايا أخرى، لذا سنستخدم في هذه الفقرة وحدة openpyxl لإضافة الصيغ إلى الخلايا برمجيًا مثل أيّ قيمة عادية أخرى كما يلي:

>>> sheet['B9'] = '=SUM(B1:B8)'

ستؤدي التعليمة السابقة إلى تخزين الصيغة ‎=SUM(B1:B8)‎ بوصفها قيمةً في الخلية B9، مما يؤدي إلى ضبط الخلية B9 على صيغة تحسب مجموع القيم في الخلايا من B1 إلى B8 كما في الشكل التالي:

03 000100

تحتوي الخلية B9 على الصيغة ‎=SUM(B1:B8)‎ التي تجمع القيم الموجودة في الخلايا من B1 إلى B8

تُضبَط صيغ إكسل مثل أيّ قيمة نصية أخرى في الخلية. إذًا لندخِل ما يلي في الصدفة التفاعلية:

>>> import openpyxl
>>> wb = openpyxl.Workbook()
>>> sheet = wb.active
>>> sheet['A1'] = 200
>>> sheet['A2'] = 300
>>> sheet['A3'] = '=SUM(A1:A2)' # ضبط الصيغة
>>> wb.save('writeFormula.xlsx')

ضبطنا الخلايا A1 و A2 على القيمتين 200 و 300 على التوالي، وضبطنا القيمة الموجودة في الخلية A3 على صيغة تجمع القيم الموجودة في الخليتين A1 و A2، وبالتالي ستظهر قيمة الخلية A3 على أنها 500 عند فتح جدول البيانات في إكسل.

توفر صيغ إكسل مستوًى مقبولًا من البرمجة لجداول البيانات، ولكن تصبح هذه الصيغ غير قابلة للإدارة بسرعة بالنسبة للمهام المعقدة، فمثلًا حتى لو كنت على دراية كبيرة بصيغ إكسل، فمن الصعب محاولة تفسير ما تفعله الصيغة التالية:

=IFERROR(TRIM(IF(LEN(VLOOKUP(F7, Sheet2!$A$1:$B$10000, 2, FALSE))>0,SUBSTITUTE(VLOOKUP(F7, Sheet2!$A$1:$B$10000, 2, FALSE), " ", ""),"")), "")

لاحظ أن شيفرة بايثون البرمجية أكثر قابلية للقراءة من الصيغة السابقة.

تعديل الصفوف والأعمدة

يُعَد تعديل أحجام الصفوف والأعمدة في برنامج إكسل أمرًا سهلًا مثل النقر على حواف ترويسة الصف أو العمود وسحبها، ولكن إذا أردتَ ضبط حجم صف أو عمود بناءً على محتويات خلاياه أو إذا أردتَ ضبط الأحجام في عدد كبير من ملفات جداول البيانات، فستكون كتابة برنامج بايثون لذلك أسرع بكثير.

يمكن أيضًا إخفاء الصفوف والأعمدة بصورة كاملة، أو يمكن تثبيتها بحيث تكون مرئية دائمًا على الشاشة وتظهر في جميع الصفحات عند طباعة جدول البيانات، إذ يُعَد ذلك مفيدًا للعناوين.

ضبط ارتفاع الصف وعرض العمود

تمتلك كائنات Worksheet سمات row_dimensions و column_dimensions التي تتحكم في ارتفاع الصفوف وعرض الأعمدة. إذًا لندخِل ما يلي في الصدفة التفاعلية:

>>> import openpyxl
>>> wb = openpyxl.Workbook()
>>> sheet = wb.active
>>> sheet['A1'] = 'Tall row'
>>> sheet['B2'] = 'Wide column'
>>> # ضبط الارتفاع والعرض
>>> sheet.row_dimensions[1].height = 70
>>> sheet.column_dimensions['B'].width = 20
>>> wb.save('dimensions.xlsx')

تُعَد السمات row_dimensions و column_dimensions الخاصة بالورقة قيمًا تشبه القاموس، إذ تحتوي السمة row_dimensions على كائنات RowDimension وتحتوي السمة column_dimensions على كائنات ColumnDimension. يمكنك الوصول إلى أحد الكائنات باستخدام رقم الصف (في مثالنا 1 أو 2) في row_dimensions، ويمكنك الوصول إلى أحد الكائنات باستخدام حرف العمود (في مثالنا A أو B) في column_dimensions.

يبدو جدول البيانات dimensions.xlsx كما يلي:

04 000046

ضبطنا الصف 1 والعمود B على ارتفاع وعرض أكبر

يمكنك ضبط ارتفاع الكائن RowDimension بعد الحصول عليه، ويمكنك ضبط عرض الكائن ColumnDimension بعد الحصول عليه. يمكن ضبط ارتفاع الصف ليكون عددًا صحيحًا أو عشريًا قيمته بين 0 و 409، إذ تمثّل هذه القيمة الارتفاع المُقاس بالنقاط، حيث تساوي النقطة الواحدة 1/72 من البوصة، ويكون ارتفاع الصف الافتراضي 12.75. يمكن ضبط عرض العمود ليكون عددًا صحيحًا أو عشريًا قيمته بين 0 و255، إذ تمثّل هذه القيمة عدد المحارف التي يمكن عرضها في الخلية بحجم الخط الافتراضي (11 نقطة)، ويكون عرض العمود الافتراضي 8.43 محرفًا. تُخفَى الأعمدة التي يبلغ عرضها 0 أو الصفوف التي يبلغ ارتفاعها 0 عن المستخدم.

دمج وإلغاء دمج الخلايا

يمكن دمج منطقة مستطيلة من الخلايا في خلية واحدة باستخدام التابع merge_cells()‎ الخاص بالورقة. إذًا لندخِل ما يلي في الصدفة التفاعلية:

>>> import openpyxl
>>> wb = openpyxl.Workbook()
>>> sheet = wb.active
>>> sheet.merge_cells('A1:D3') # دمج جميع هذه الخلايا
>>> sheet['A1'] = 'Twelve cells merged together.'
>>> sheet.merge_cells('C5:D5') # دمج هاتين الخليتين
>>> sheet['C5'] = 'Two merged cells.'
>>> wb.save('merged.xlsx')

وسيط التابع merge_cells()‎ هو سلسلة نصية واحدة من الخلايا العلوية اليسرى والسفلية اليمنى للمنطقة المستطيلة المُراد دمجها، حيث تدمج ‎'A1:D3'‎ اثنتا عشر خلية في خلية واحدة، ويمكنك ضبط قيمة هذه الخلايا المدموجة من خلال ضبط قيمة الخلية العلوية اليسرى لمجموعة الخلايا المدموجة.

سيبدو الملف merged.xlsx كما يلي عند تشغيل الشيفرة البرمجية السابقة:

05 000140

الخلايا المدموجة في جدول البيانات

يمكن إلغاء دمج الخلايا من خلال استدعاء التابع unmerge_cells()‎ الخاص بالورقة. إذًا لندخِل ما يلي الصدفة التفاعلية:

>>> import openpyxl
>>> wb = openpyxl.load_workbook('merged.xlsx')
>>> sheet = wb.active
>>> sheet.unmerge_cells('A1:D3') # فصل هذه الخلايا عن بعضها
>>> sheet.unmerge_cells('C5:D5')
>>> wb.save('merged.xlsx')

إذا حفظتَ تغييراتك ثم ألقيتَ نظرة على جدول البيانات، فسترى أن الخلايا المدموجة عادت إلى كونها خلايا مفردة.

تثبيت الأجزاء

من المفيد تثبيت عددٍ من الصفوف العلوية أو الأعمدة الموجودة في أقصى اليسار على الشاشة في جداول البيانات الكبيرة جدًا التي لا يمكن عرضها كاملة، فمثلًا تكون ترويسات الأعمدة أو الصفوف المُثبَّتة مرئيةً للمستخدم دائمًا حتى أثناء التمرير في جدول البيانات، ويُعرَف ذلك بتثبيت الأجزاء Freeze Panes. يحتوي كل كائن Worksheet في وحدة OpenPyXL على السمة freeze_panes التي يمكن ضبطها على كائن Cell أو سلسلة نصية من إحداثيات الخلية. لاحظ تثبيت كافة الصفوف الموجودة أعلى هذه الخلية وجميع الأعمدة الموجودة على يسارها، ولكن لن يُثبَّت صف وعمود الخلية نفسها.

يمكن إلغاء تثبيت جميع الأجزاء من خلال ضبط السمة freeze_panes على القيمة None أو 'A1'. يوضح الجدول التالي الصفوف والأعمدة التي ستُثبَّت في بعض الأمثلة عند ضبط قيمة السمة freeze_panes:

ضبط السمة freeze_panes الصفوف والأعمدة المُثبَّتة
sheet.freeze_panes = 'A2' الصف 1
sheet.freeze_panes = 'B1' العمود A
sheet.freeze_panes = 'C1' العمودان A و B
sheet.freeze_panes = 'C2' الصف 1 والعمودان A و B
sheet.freeze_panes = 'A1'‎ أو sheet.freeze_panes = None لا توجد أجزاء مُثبَّتة

تأكّد من حصولك على جدول بيانات مبيعات المنتجات، ثم أدخِل ما يلي في الصدفة التفاعلية:

>>> import openpyxl
>>> wb = openpyxl.load_workbook('produceSales.xlsx')
>>> sheet = wb.active
>>> sheet.freeze_panes = 'A2' # تثبيت الصفوف‫ الموجودة أعلى الصف A2
>>> wb.save('freezeExample.xlsx')

إذا ضبطتَ السمة freeze_panes على القيمة 'A2'، فسيُعرَض الصف 1 دائمًا بغض النظر عن المكان الذي ينتقل إليه المستخدم عند التمرير في جدول البيانات، ويمكنك رؤية ذلك في الشكل التالي:

06_000083.png

يكون الصف 1 مرئيًا دائمًا حتى عندما يمرّر المستخدم جدول البيانات إلى الأسفل، إذا ضبطنا السمة freeze_panes على القيمة 'A2'

المخططات Charts

تدعم الوحدة OpenPyXL إنشاء مخططات شريطية وخطية ومبعثرة ودائرية باستخدام البيانات الموجودة في خلايا الورقة، حيث يمكنك إنشاء مخطط باتباع الخطوات التالية:

  1. إنشاء كائن Reference من خلايا المنطقة المستطيلة المُحدّدة.
  2. إنشاء كائن Series من خلال تمرير الكائن Reference.
  3. إنشاء كائن Chart.
  4. إلحاق كائن Series بكائن Chart.
  5. إضافة الكائن Chart إلى الكائن Worksheet مع تحديد الخلية التي يجب أن تكون في الزاوية العلوية اليسرى من المخطط اختياريًا.

يمكنك إنشاء كائنات Reference من خلال استدعاء الدالة openpyxl.chart.Reference()‎ وتمرير ثلاثة وسطاء هي:

  1. كائن Worksheet الذي يحتوي على بيانات مخططك.
  2. مجموعة Tuple مكونة من عددين صحيحين، حيث تمثل هذه المجموعة الخلية العلوية اليسرى من خلايا المنطقة المستطيلة المُحدَّدة التي تحتوي على بيانات مخططك، ويمثل العددُ الصحيح الأول في المجموعة الصفَّ، ويمثل العدد الصحيح الثاني العمود. لاحظ أن العدد 1 هو الصف الأول وليس العدد 0.
  3. مجموعة مكونة من عددين صحيحين، حيث تمثل هذه المجموعة الخلية السفلية اليمنى من خلايا المنطقة المستطيلة المُحدَّدة التي تحتوي على بيانات مخططك، ويمثل العدد الصحيح الأول في المجموعة الصف، ويمثل العدد الصحيح الثاني العمود.

يوضح الشكل التالي بعض النماذج من وسطاء الإحداثيات:

07 000099

وهي من اليسار إلى اليمين:

(1, 1), (10, 1); (3, 2), (6, 4); (5, 3), (5, 3)

أدخِل مثال الصدفة التفاعلية التالي لإنشاء مخطط شريطي وإضافته إلى جدول البيانات:

>>> import openpyxl
>>> wb = openpyxl.Workbook()
>>> sheet = wb.active
>>> for i in range(1, 11): # إنشاء بعض ‫البيانات في العمود A
...     sheet['A' + str(i)] = i
...
>>> refObj = openpyxl.chart.Reference(sheet, min_col=1, min_row=1, max_col=1,
max_row=10)
>>> seriesObj = openpyxl.chart.Series(refObj, title='First series')

>>> chartObj = openpyxl.chart.BarChart()
>>> chartObj.title = 'My Chart'
>>> chartObj.append(seriesObj)

>>> sheet.add_chart(chartObj, 'C5')
>>> wb.save('sampleChart.xlsx')

وينتج عن ذلك جدول بيانات يشبه ما يلي:

08_000122.png

جدول بيانات مع مخطط مضافٍ إليه

أنشأنا مخططًا شريطيًا من خلال استدعاء الدالة openpyxl.chart.BarChart()‎، ويمكنك إنشاء مخططات خطية ومخططات مبعثرة ومخططات دائرية من خلال استدعاء الدوال openpyxl.charts.LineChart()‎ و openpyxl.charts.LineChart()‎ و openpyxl.charts.LineChart()‎.

مشاريع للتدريب

حاول كتابة البرامج التي تؤدي المهام التي سنوضّحها فيما يلي، لكسب خبرة عملية أكبر.

برنامج لإنشاء جدول الضرب

أنشئ برنامج multiplicationTable.py الذي يأخذ العدد N من سطر الأوامر وينشئ جدول الضرب N×N في جدول بيانات إكسل، فمثلًا إذا شغّلنا البرنامج كما يلي:

py multiplicationTable.py 6

يجب أن ينشئ جدول بيانات يشبه الشكل التالي:

09 000067

توليد جدول الضرب في جدول بيانات

يجب استخدام الصف 1 والعمود A للتسميات أو عناوين الصفوف والأعمدة ويجب أن يكونا بالخط العريض.

برنامج لإدراج صف فارغ

أنشئ برنامج blankRowInserter.py الذي يأخذ عددين صحيحين وسلسلة نصية لاسم الملف كوسطاء لسطر الأوامر، حيث نسمّي العدد الصحيح الأول N والعدد الصحيح الثاني M. يجب على البرنامج إدراج صفوف فارغة بعدد M في جدول البيانات بدءًا من الصف N، فمثلًا إذا شغّلنا البرنامج كما يلي:

python blankRowInserter.py 3 2 myProduce.xlsx

يجب أن تبدو جداول البيانات "قبل" و"بعد" الإدراج كما في الشكل التالي:

10 000013

قبل (يسار) وبعد (يمين) إدراج الصفين الفارغين عند الصف 3

يمكنك كتابة هذا البرنامج من خلال قراءة محتويات جدول البيانات، ثم استخدام حلقة for لنسخ الأسطر N الأولى عند كتابة جدول البيانات الجديد، وجمع العدد M مع رقم الصف في جدول البيانات الناتج بالنسبة للأسطر المتبقية.

برنامج لعكس خلايا جدول البيانات

اكتب برنامجًا لعكس الصف والعمود الخاص بالخلايا في جدول البيانات، فمثلًا ستكون القيمة في الصف 5 والعمود 3 موجودة في الصف 3 والعمود 5 والعكس صحيح، ويجب تطبيق ذلك على جميع الخلايا في جدول البيانات، إذ ستبدو جداول البيانات "قبل" و"بعد" العكس كما في الشكل التالي:

11 000108

جدول البيانات قبل (العلوي) وبعد (السفلي)

يمكنك كتابة هذا البرنامج باستخدام حلقات for متداخلة لقراءة بيانات جدول البيانات في قائمة من قوائم هيكل البيانات، ويمكن أن يحتوي هيكل البيانات على sheetData[x][y]‎ للخلية الموجودة في العمود x والصف y. استخدم بعد ذلك sheetData[y][x]‎ للخلية الموجودة في العمود x والصف y عند كتابة جدول البيانات الجديد.

برنامج لتحويل الملفات النصية إلى جدول بيانات

اكتب برنامجًا لقراءة محتويات العديد من الملفات النصية (يمكنك إنشاء الملفات النصية بنفسك) وإدراج هذه المحتويات في جدول بيانات، بحيث يقابل سطر واحد من الملف النصي صفًا واحدًا من جدول البيانات. ستكون أسطر الملف النصي الأول في خلايا العمود A، وستكون أسطر الملف النصي الثاني في خلايا العمود B، وهكذا.

استخدم التابع readlines()‎ الخاص بالكائن File لإعادة قائمة من السلاسل النصية، حيث تقابل كل سلسلة نصية واحدة سطرًا في الملف. يكون السطر الأول من الملف الأول مقابلًا للعمود 1 والصف 1، ويجب كتابة السطر الثاني في العمود 1 والصف 2، وما إلى ذلك. سيُكتَب الملف التالي المقروء باستخدام التابع readlines()‎ في العمود 2، وسيُكتَب الملف الذي يليه في العمود 3، وهكذا.

برنامج لتحويل جدول بيانات إلى ملفات نصية

اكتب برنامجًا يؤدّي مهام البرنامج السابق بترتيب عكسي، إذ يجب أن يفتح البرنامج جدول بيانات ويكتب خلايا العمود A في ملف نصي واحد، وخلايا العمود B في ملف نصي آخر، وهكذا.

الخلاصة

لا يكون الجزء الصعب من معالجة المعلومات هو المعالجة بحد ذاتها في كثير من الأحيان، بل تتمثل الصعوبة ببساطة في الحصول على البيانات بالتنسيق الصحيح المناسب لبرنامجك، ولكن يمكنك استخراج بيانات جدول بياناتك ومعالجتها بصورة أسرع بكثير مما يمكنك فعله يدويًا بعد تحميله إلى ملف بايثون.

يمكنك أيضًا توليد جداول بيانات بوصفها خرجًا لبرامجك، لذا إذا كان زملاؤك بحاجة إلى نقل ملفك النصي أو ملف PDF الذي يحتوي على آلاف جهات اتصال المبيعات إلى ملف جدول بيانات، فلن تضطر إلى نسخه ولصقه بالكامل في ملف إكسل. إذا كان لديك وحدة openpyxl وبعض المعرفة البرمجية، فستجد أن معالجة جداول البيانات الكبيرة تُعَد أمرًا سهلًا للغاية.

سنلقي نظرة في المقال التالي على استخدام لغة بايثون للتفاعل مع برنامج آخر لجداول بيانات، وهو تطبيق جداول بيانات جوجل Google Sheets الشهير على الإنترنت.

ترجمة -وبتصرُّف- للقسم Writing Excel Documents من مقال Working with Excel Spreadsheets لصاحبه Al Sweigart.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...