توسيع برنامج ArcGIS برمجيا – ComboBox and Histogram

في هذا الدرس ستتعلم:

  • كيفية إضافة ComboBox ضمن toolbar في ArcGIS، وكيفية برمجة ComboBox.
  • إنشاء مخطط تواتر Histogram وتخزينه عن طريق مكتبة MatPlotLib في Python.

في هذا الدرس سنقوم بإضافة قائمتين منسدلتين ComboBox إحداهما لاختيار الطبقات Layer، والقائمة الثانية تحوي الأعمدة الموجودة في attribute table للطبقة التي تم اختيارها. وفي النهاية برمجة زر يقوم باستخدام المعطيات التي تم اختيارها من القوائم واستخدام MatPlotLib لإنشاء مخطط التواتر.

تسمح إضافة Python API Add-in باضافة في ComboBox ضمن Toolbar في برنامج ArcMap، هذه الإضافة تسمح للمستخدم قائمة منسدلة يمكن منها اختيار عناصر محددة مسبقا، أو كتابة كود يقوم بوضع عناصر بشكل أوتوماتيكي. إضافة إلى ذلك يمكن استخدام القيمة المختارة ضمن إضافات أخرى.

قم بتشغيل ArcGIS Python Add-In Wizard، قم بإنشاء مجلد جديد وقم بتسميته باسم تختاره، من تبويب project settings وقم بتعبئة البيانات التي تراها مناسبة. من التبويب add_in contents نقوم بالنقر بالزر الأيمن واختيار new toolbar، يمكننا إنشاء ComboBox بالنقر بالزر الأيمن على القائمة الجديدة واختيار new ComboBox، سنقوم بإنشاء اثنان من СomboBox أحدهما لعمل قائمة الطبقات Layer، وقائمة أخرى للأعمدة الخاصة columns، وفي النهاية سنحتاج لإضافة زر Histogram، بعد الانتهاء من إضافة الأزرار نقوم بالضغط على زر save. لمزيد من المعلومات حول هذه الخطوة يمكنك مراجعة الدرس الثالث.

بعد الانتهاء يمكننا الانتقال إلى المجلد Install من داخل python_api، سنجد في داخل المجلد ملف python_API_addin.py، بالنقر الزر الأيمن نختار تعديل باستخدام Idle، في الملف يوجد الكود التالي:

import arcpy			

import pythonaddins
class layer(object):
    def __init__(self):
        self.items = ["item1", "item2"]
self.editable = True
        self.enabled = True
        self.dropdownWidth = 'WWWWWW'
        self.width = 'WWWWWW'
def onSelChange(self, selection):
        pass
def onEditChange(self, text):
        pass

    def onFocus(self, focused):
        pass

    def onEnter(self):
        pass

    def refresh(self):
        pass

class column(object):
    def __init__(self):
        self.items = ["item1", "item2"]
        self.editable = True
        self.enabled = True
        self.dropdownWidth = 'WWWWWW'
        self.width = 'WWWWWW'
    def onSelChange(self, selection):
        pass
    def onEditChange(self, text):
        pass
    def onFocus(self, focused):
        pass
    def onEnter(self):
        pass
    def refresh(self):
        pass
class Histogram(object):
    def __init__(self):
        self.enabled = True
        self.checked = False
    def onClick(self):
        pass

لبرمجة الـ ComboBox الخاص بالـ Layer يجب بداية تحديد العوامل الخاصة بالـ ComboBox الموجودة في بعد __init__، من أجل هذا الدرس سنحتاج إلى تعديل:

  • إفراغ self.items من القيم الموجودة فيه، على اعتبار أن القيم سيتم تعبئتها تلقائيا من ملف mxd
  • تعديل self.dropdownWidth، لتحديد حجم القائمة المنسدلة يمكننا اضافة نص من أرقام متسلسلة لتحديد هذا العرض مثلا ‘123456789012345’ كل رقم يمثل خانة، هذا النص مثلا يمثل عرض 15 محرف.
  • تعديل self.width، لتحديد حجم الـ ComboBox ضمن الـ Toolbar، يتم التعديل بنفس طريقة الفقرة السابقة.

مجموع ما سيتم تعديله في __init__ سيكون:


self.items = []

self.dropdownWidth = '12345678901234567890'

self.width = '12345678901234567890'

لتعبئة الـComboBox بأسماء الطبقات سنعتمد على الطريقة onFocus، بالخطوات التالية:

  • تحديد الملف الذي تم قرائته، عن طريق arcpy.mapping.MapDocument
  • تحديد الـ DataFrames الموجودة في الملف الذي تم قراءته عن طريق التابع arcpy.mapping.ListDataFrames
  • تحديد مجموعة الطبقات في كل DataFrames عن طريق التابع arcpy.mapping.ListLayersوإضافتها ضمن متحول نسميه list_layers، وذلك ضمن حلقتين احداها للـ DataFrames ، والثانية للطبقات.
  • اسماء العناصر ستكون اسم الـDataFrames ومن ثم اسم الطبقة، بينهما زر نجمة.
  • تعبئة self.items حسب المتحول الذي تم list_layers الذي تم انشائه

جميع التعديلات التي تمت في طريقة onFocus، ستكون على الشكل التالي:

if focused:
 mxd_file=arcpy.mapping.MapDocument('current')
 dfs=arcpy.mapping.ListDataFrames(mxd_file)
 list_layers=[]
 for df in dfs:
 layers=arcpy.mapping.ListLayers(mxd_file,"",df)
 for layer in layers:
  list_layers.append(df.name+ "*" + layer.name)
 self.items=list_layers

عند اختيار الطبقة في الطريقة onSelChange يمكننا اضافة متحول، ونجعله متحول عام يمكن قرائته في كافة الملف عن طريق الطريقة golbal ، اسم المتحول سكون layer_selected


global layer_selected

layer_selected=self.value

بقية الطرق يمكن حذفها على اعتبار أننا لن نستخدمها، كافة التعديلات على الـ ComboBox ستكون على الشكل التالي، ما تم تعديله مكتوب بالخط الأحمر :


class layer(object):

 """Implementation for layers.combobox (ComboBox)"""

 def __init__(self):

  self.items = []

  self.editable = True

  self.enabled = True

  self.dropdownWidth = '12345678901234567890'

  self.width = '12345678901234567890'

 def onSelChange(self, selection):

  global layer_selected

  layer_selected=self.value

 def onFocus(self, focused):

  if focused:

   mxd_file=arcpy.mapping.MapDocument('current')

   dfs=arcpy.mapping.ListDataFrames(mxd_file)

   list_layers=[]

   for df in dfs:

    layers=arcpy.mapping.ListLayers(mxd_file,"",df)

    for layer in layers:

     list_layers.append(df.name+ "*" + layer.name)

    self.items=list_layers

لبرمجة الـ ComboBox الخاص بالـ Column يجب بداية تحديد العوامل الخاصة بالـ ComboBox الموجودة في بعد __init__، كما كان في الطبقة السابقة:


self.items = []

self.dropdownWidth = '12345678901234567890'

self.width = '12345678901234567890'

لتعبئة الـComboBox بأسماء الطبقات سنعتمد على الطريقة onFocus، بالخطوات التالية:

  • تفريغ القائمة المنسدلة من العناصر، هذا الأمر ضروري في حال تم تحديث العناصر.
  • تحديد العنصر الذي تم اختياريه من الـ ComboBox السابق، ستكون في المتحول selected_layer الذي تم تحديده في الكود السابق.
  • فصل الـ الـDataFrames عن الطبقة عن طريق layer_selected.split(“*”)، الطريقة split تعطينا قائمة حسب العنصر المختار وهو *، وبالتالي النتيجة ستكون [اسم الـ dataframe، اسم الطبقة] وبالتالي ستكون الطبقة العنصر الثاني من القائمة.
  • تشكيل حلقة من أسماء الأعمدة، عن طريق arcpy.ListFields(اسم الطبقة)، وادخالها ضمن المتحول
  • تعبئة self.items في حال كانت نوع العمود ليس نص.

جميع التعديلات التي تمت في طريقة onFocus، ستكون على الشكل التالي:


if focused:

self.items = []

xx=layer_selected.split("*")

fields=arcpy.ListFields(xx[1])

for field in fields:

 if field.type == 'Double' or field.type == 'Integer':

  self.items.append(field.name)

عند اختيار العمود في الطريقة onSelChange يمكننا اضافة متحول، ونجعله متحول عام يمكن قرائته في كافة الملف عن طريق الطريقة golbal


global field_selected

field_selected=self.value

لتحديث العناصر سيتم اعتماد على الطريقة refresh وفيها سيتم استدعاء الطريقة onFocus

بقية الطرق يمكن حذفها على اعتبار أننا لن نستخدمها، كافة التعديلات على الـ ComboBox ستكون على الشكل التالي، ما تم تعديله مكتوب بالخط الأحمر :


class columns(object):

 """Implementation for columns.combobox (ComboBox)"""

 def __init__(self):

  self.items = []

  self.editable = True

  self.enabled = True

  self.dropdownWidth = '12345678901234567890'

  self.width = '12345678901234567890'

 def onSelChange(self, selection):

  global field_selected

  field_selected=self.value

 def onFocus(self, focused):

  if focused:

   self.items = []

   xx=layer_selected.split("*")

   fields=arcpy.ListFields(xx[1])

   for field in fields:

    if field.type == 'Double' or field.type == 'Integer':

     self.items.append(field.name)

 def refresh(self):

  columns.onFocus(self, focused)

نهاية سنقوم ببرمجة الزر Histogram، للبرمجة سنقوم بالخطوات التالية:

  • قراءة الطبقة عن طريق الطريقة split كما في الفقرة السابقة، بالإضافة إلى قراءة اسم العمود الذي تم اختياره.
  • الحصول على البيانات من جدول الخصائص عن طريق التابع arcpy.da.SearchCursor(اسم الطبقة ,اسم العمود)
  • تحويل البيانات التي تم الحصول عليها إلى قائمة عن طريق حلقة for.
  • استيراد المكتبة matplotlib.pyplot التي تستخدم لرسم الـ histogram.
  • حجز الرسم عن طريق figure، وتشكيل الـ histogram عن طريق hist(اسم القائمة)، ومن ثم تخزين رسمه عن طريق savefig
  • استيراد المكتبة os لنتمكن من قراءة الملف وفتحه.

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


class histogram(object):

 """Implementation for api_addin.button (Button)"""

 def __init__(self):

  self.enabled = True

  self.checked = False

 def onClick(self):

  lyr=layer_selected.split("*")

  lyr=lyr[1]

  table=arcpy.da.SearchCursor(lyr,field_selected)

  values= [i[0] for i in table]

 

  import matplotlib.pyplot as plt

  plt.figure()

  plt.hist(values)

  plt.savefig("d:/histogram.png")

  plt.close()

  import os

  os.system("d:/histogram.png")

لإنهاء عملية البرمجة قم بتشغيل makeaddin.py من المجلد python_API، ومن ثم قم بتشغيل من نفس المجلد python_API.esriaddin، قم الآن بتشغيل ArcMap، في البرنامج يجب ان يكون هناك toolbar حسب الاسم الذي قمنا باختياره في الخطوة الأولى، إضافة الـ toolbar من قائمة customize، خيار toolbar. النتيجة:

الكاتب : المهندس محمد حسن