9.1. التعبيرات

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

ملاحظة

تجد قائمة بالدوال والمتغيرات الافتراضية لكتابة التعبيرات في قائمة الدوال، مع معلومات مفصلة وأمثلة.

9.1.1. منشئ نصوص التعبيرات

نافذة الحوار الرئيسية لبناء التعبيرات، Expression string builder، متاحة في أجزاء كثيرة من QGIS، ويمكن الوصول إليها خصوصًا عند:

توفّر نافذة حوار منشئ التعبيرات الوصول إلى:

9.1.1.1. الواجهة

يوفّر تبويب Expression الواجهة الرئيسية لكتابة التعبيرات باستخدام الدوال وحقول الطبقة والقيم. ويحتوي على عناصر الواجهة التالية:

../../../_images/function_list.png

شكل 9.1 تبويب التعبير

  • منطقة محرر التعبيرات لكتابة التعبيرات أو لصقها. ويتوفر الإكمال التلقائي لتسريع كتابة التعبيرات:

    • تُعرض أدناه المتغيرات وأسماء الدوال وأسماء الحقول المطابقة للنص المُدخل: استخدم السهمين Up و Down لتصفح العناصر، واضغط Tab لإدراج العنصر في التعبير، أو انقر ببساطة على العنصر المطلوب.

    • تُعرض معاملات الدالة أثناء ملئها.

    يتحقق QGIS أيضًا من صحة التعبير ويبرز جميع الأخطاء باستخدام:

    • خط سفلي: للدوال غير المعروفة، والوسائط الخاطئة أو غير الصالحة؛

    • علامة: لكل خطأ آخر (مثل قوس مفقود أو محرف غير متوقع) في موضع واحد.

    نصيحة

    وثّق تعبيرك بالتعليقات

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

    /*
    Labels each region with its highest (in altitude) airport(s)
    and altitude, eg 'AMBLER : 264m' for the 'Northwest Artic' region
    */
    with_variable(
      'airport_alti', -- stores the highest altitude of the region
      aggregate(
        'airports',
        'max',
        "ELEV", -- the field containing the altitude
        -- and limit the airports to the region they are within
        filter := within( @geometry, geometry( @parent ) )
      ),
        aggregate( -- finds airports at the same altitude in the region
          'airports',
          'concatenate',
          "NAME",
          filter := within( @geometry, geometry( @parent ) )
            and "ELEV" = @airport_alti
        )
        || ' : ' || @airport_alti || 'm'
        -- using || allows regions without airports to be skipped
    )
    
  • فوق محرر التعبيرات، تساعدك مجموعة من الأدوات على:

  • أسفل محرر التعبيرات تجد:

    • مجموعة من العوامل الأساسية لمساعدتك على بناء التعبير

    • إشارة إلى الصيغة المتوقعة للمُخرَج عند تعريف خصائص المعالم بالبيانات (data-defining)

    • معاينة حية Output preview لناتج التعبير (حتى 60 محرفًا)، تُقيَّم افتراضيًا على أول معلم في الطبقة. لعرض نص المعاينة الذي يتجاوز 60 محرفًا، يمكنك تمرير المؤشر فوق النص لإظهار تلميح منبثق يحتوي على المعاينة كاملة. ولنسخ نص المعاينة إلى الحافظة، انقر بزر الفأرة الأيمن على نص المعاينة واختر editCopy Copy Expression Value.

      يمكنك تصفح المعالم الأخرى في الطبقة وتقييمها باستخدام القائمة المنسدلة Feature (تؤخذ القيم من خاصية اسم العرض للطبقة).

      في حال وجود خطأ، يُشار إليه ويمكنك الوصول إلى تفاصيله عبر الرابط التشعبي المتوفر.

  • يعرض محدد الدوال قائمة الدوال والمتغيرات والحقول... منظمةً في مجموعات. ويتوفر مربع بحث لتصفية القائمة والعثور بسرعة على دالة أو حقل معين. والنقر المزدوج على عنصر يضيفه إلى محرر التعبيرات.

  • تعرض لوحة المساعدة شرحًا لكل عنصر محدد في محدد الدوال.

    نصيحة

    اضغط Ctrl+Click عند تمرير المؤشر فوق اسم دالة في تعبير لعرض مساعدتها تلقائيًا في نافذة الحوار.

    يساعد عنصر واجهة قيم الحقل، الذي يظهر عند تحديد حقل في محدد الدوال، على جلب البيانات الوصفية للمعالم:

    • البحث عن قيمة معينة في الحقل

    • عرض قائمة القيم All Unique (جميع القيم الفريدة) أو 10 Samples (10 عينات). ويتوفر ذلك أيضًا عبر النقر بزر الفأرة الأيمن.

      عندما يكون الحقل مرتبطًا بطبقة أخرى أو بمجموعة من القيم، أي إذا كان عنصر واجهة الحقل من نوع RelationReference أو ValueRelation أو ValueMap، يمكن سرد جميع قيم الحقل المرتبط (من الطبقة أو الجدول أو القائمة المرجعية). كما يمكنك تصفية هذه القائمة باستخدام checkbox Only show values in use لعرض القيم المستخدمة في الحقل الحالي فقط.

    النقر المزدوج على قيمة حقل في عنصر الواجهة يضيفها إلى محرر التعبيرات.

    نصيحة

    يمكن طي اللوحة اليمنى، التي تعرض مساعدة الدوال أو قيم الحقول، (إخفاؤها) في نافذة الحوار. اضغط الزر Show Values أو Show Help لإعادة إظهارها.

9.1.1.2. كتابة تعبير

تُستخدم تعبيرات QGIS لتحديد المعالم أو تعيين القيم. وتتبع كتابة التعبير في QGIS بعض القواعد:

  1. نافذة الحوار تحدد السياق: إذا كنت معتادًا على SQL، فأنت تعرف على الأرجح استعلامات من نوع select features from layer where condition أو update layer set field = new_value where condition. يحتاج تعبير QGIS أيضًا إلى كل هذه المعلومات، لكن الأداة التي تستخدمها لفتح نافذة حوار منشئ التعبيرات توفّر جزءًا منها. فمثلًا، لنفترض طبقة (buildings) فيها حقل (height):

    • الضغط على الأداة expressionSelectSelect by expression يعني أنك تريد "تحديد معالم من buildings". و الشرط هو المعلومة الوحيدة التي عليك توفيرها في عنصر واجهة نص التعبير، فمثلًا اكتب "height" > 20 لتحديد المباني التي يزيد ارتفاعها على 20.

    • بعد إجراء هذا التحديد، فإن الضغط على الزر calculateField Field calculator واختيار "height" في Update existing field يعني أنك قدّمت بالفعل الأمر "update buildings set height = ??? where height > 20". والجزء الوحيد المتبقي الذي عليك توفيره في هذه الحالة هو القيمة الجديدة، فمثلًا أدخل 50 فقط في مربع نص محرر التعبيرات لتعيين ارتفاع المباني المحددة سابقًا.

  2. انتبه إلى علامات الاقتباس: علامات الاقتباس المفردة تُعيد قيمة حرفية، لذا يُفسَّر النص الموضوع بين علامتي اقتباس مفردتين ('145') على أنه نص (string). أما علامات الاقتباس المزدوجة فتعطيك قيمة ذلك النص، لذا استخدمها للحقول ("myfield"). ويمكن أيضًا استخدام الحقول دون علامات اقتباس (myfield). ولا تُستخدم علامات اقتباس مع الأرقام (3.16).

    ملاحظة

    تأخذ الدوال عادةً اسم الحقل وسيطًا على شكل نص (string). اكتب:

    attribute( @atlas_feature, 'height' ) -- returns the value stored in the "height" attribute of the current atlas feature
    

    وليس:

    attribute( @atlas_feature, "height" ) -- fetches the value of the attribute named "height" (e.g. 100), and use that value as a field
                                          -- from which to return the atlas feature value. Probably wrong as a field named "100" may not exist.
    

نصيحة

استخدم المعاملات المسماة لتسهيل قراءة التعبير

تتطلب بعض الدوال تعيين معاملات كثيرة. ويدعم محرك التعبيرات استخدام المعاملات المسماة. وهذا يعني أنه بدلًا من كتابة التعبير المبهم clamp( 1, 2, 9)، يمكنك استخدام clamp( min:=1, value:=2, max:=9). ويسمح ذلك أيضًا بتبديل ترتيب الوسائط، مثل clamp( value:=2, max:=9, min:=1). يساعد استخدام المعاملات المسماة على توضيح ما تشير إليه وسائط دالة التعبير، وهو أمر مفيد عندما تحاول تفسير تعبير لاحقًا!

9.1.1.3. بعض حالات استخدام التعبيرات

  • من حاسبة الحقول (Field Calculator)، احسب حقل "pop_density" باستخدام الحقلين الموجودين "total_pop" و "area_km2":

    "total_pop" / "area_km2"
    
  • سمِّ المعالم أو صنّفها بناءً على مساحتها:

    CASE WHEN $area > 10 000 THEN 'Larger' ELSE 'Smaller' END
    
  • حدّث الحقل "density_level" بفئات وفقًا لقيم "pop_density":

    CASE WHEN "pop_density" < 50 THEN 'Low population density'
         WHEN "pop_density" >= 50 and "pop_density" < 150 THEN 'Medium population density'
         WHEN "pop_density" >= 150 THEN 'High population density'
    END
    
  • طبّق نمطًا مصنفًا على جميع المعالم بحسب ما إذا كان متوسط سعر المنزل فيها أقل أو أعلى من 10000€ للمتر المربع:

    "price_m2" > 10000
    
  • باستخدام الأداة "Select By Expression..."، حدّد جميع المعالم التي تمثل مناطق "ذات كثافة سكانية عالية" ويزيد متوسط سعر المنزل فيها على 10000€ للمتر المربع:

    "density_level" = 'High population density' and "price_m2" > 10000
    

    يمكن أيضًا استخدام التعبير السابق لتحديد المعالم التي تُسمّى أو تُعرض على الخريطة.

  • حدّد المعالم التي تتداخل مع منطقة طبيعية من الطبقة "lands":

    overlay_intersects( layer:='lands', filter:="zone_type"='Natural' )
    
  • احسب لكل معلم عدد المباني التي يحتويها:

    array_length( overlay_contains( layer:='buildings', expression:=@id ) )
    
  • أنشئ رمزًا مختلفًا (نوعًا) للطبقة باستخدام مولّد الأشكال الهندسية:

    point_on_surface( @geometry )
    
  • انطلاقًا من معلم نقطي، ولّد خطًا مغلقًا (باستخدام make_line) حول شكله الهندسي:

    make_line(
      -- using an array of points placed around the original
      array_foreach(
        -- list of angles for placing the projected points (every 90°)
        array:=generate_series( 0, 360, 90 ),
        -- translate the point 20 units in the given direction (angle)
        expression:=project( @geometry, distance:=20, azimuth:=radians( @element ) )
      )
    )
    
  • في تسمية ضمن تخطيط الطباعة، اعرض أسماء معالم "airports" الواقعة داخل عنصر التخطيط "Map 1":

    with_variable( 'extent',
                   map_get( item_variables( 'Map 1' ), 'map_extent' ),
                   aggregate( 'airports', 'concatenate', "NAME",
                              intersects( @geometry, @extent ), ' ,'
                            )
                 )
    

9.1.1.4. حفظ التعبيرات

باستخدام الزر fileSave Add current expression to user expressions الموجود فوق إطار محرر التعبيرات، يمكنك حفظ التعبيرات المهمة التي تريد الوصول إليها بسرعة. وتكون متاحة في مجموعة User expressions (تعبيرات المستخدم) في اللوحة الوسطى. وتُحفظ ضمن ملف تعريف المستخدم (الملف <userprofile>/QGIS/QGIS3.ini) وتكون متاحة في جميع نوافذ حوار التعبيرات داخل جميع مشاريع ملف تعريف المستخدم الحالي.

تساعدك مجموعة من الأدوات المتاحة فوق إطار محرر التعبيرات على إدارة تعبيرات المستخدم:

  • fileSaveAdd the current expression to user expressions: يخزّن التعبير في ملف تعريف المستخدم. ويمكن إضافة تسمية ونص مساعدة لتسهيل التعرف عليه.

  • symbologyEdit Edit selected expression from user expressions، وكذلك مساعدتها وتسميتها

  • deleteSelected Remove selected expression from user expressions

  • sharingImport Import user expressions من ملف .json إلى مجلد ملف تعريف المستخدم النشط

  • sharingExport Export user expressions على شكل ملف .json؛ وتُشارَك جميع تعبيرات المستخدم الموجودة في الملف QGIS3.ini الخاص بملف تعريف المستخدم

9.1.2. محرر الدوال

باستخدام تبويب Function Editor يمكنك كتابة دوالك الخاصة بلغة Python. ويوفر ذلك طريقة عملية ومريحة لتلبية الاحتياجات الخاصة التي لا تغطيها الدوال المعرّفة مسبقًا.

../../../_images/function_editor.png

شكل 9.2 تبويب Function Editor (محرر الدوال)

لإنشاء دالة جديدة:

  1. اضغط على زر symbologyAdd New File.

  2. اختر مكان حفظ الدالة الجديدة. يمكنك حفظها إما في Function file (ملف دوال) أو في Project functions (دوال المشروع).

    • إذا اخترت Function file، فعليك إدخال اسم لملف Python .py، وهو مبني على ملف قالب من QGIS ويُحفظ في المجلد /python/expressions ضمن مجلد ملف تعريف المستخدم النشط، فيكون متاحًا لكل المشاريع التي تفتحها بذلك الملف التعريفي.

      تُحمَّل دوال Python المخصصة المحفوظة كملفات دوال تلقائيًا كلما بدأت مشروعًا جديدًا ضمن ملف تعريف المستخدم. انتبه إلى أنه لمشاركة دوال Python هذه، عليك مشاركة ملف .py الموجود في المجلد /python/expressions.

    • إذا اخترت Project functions، تُحفظ الدالة الجديدة في ملف المشروع وتكون متاحة لذلك المشروع فقط.

      يمكن مشاركة دوال Python المخصصة المحفوظة كدوال مشروع بسهولة بمشاركة ملف المشروع الذي حُفظت فيه. عند فتح مشروع يحتوي على دوال مشروع، يمكن لـ QGIS تحميلها أو تجاهلها بحسب ما إذا كان تنفيذ شيفرة Python المضمّنة مفعّلًا.

    يُضاف عنصر جديد في اللوحة اليسرى من تبويب Function Editor.

  3. تعرض اللوحة اليمنى محتوى الملف: قالب سكربت Python.

  4. أزل التعليق عن كتلة الشيفرة وابدأ بتحريرها وفق احتياجاتك. يمكنك الاعتماد على الإكمال التلقائي للشيفرة وتنسيقها ومساعدات الكتابة، كما هو محدد في إعدادات Python. كما يمكن الوصول إلى توثيق API عبر الإنترنت لكائنات Qt و PyQGIS بالضغط على مفتاح F1.

    ستجد في عنصر الواجهة Help معلومات عامة عن إعداد المزخرف @qgsfunction.

  5. اضغط على زر start Save and Load Functions. تُضاف الدالة التي كتبتها إلى شجرة الدوال في تبويب Expression، افتراضيًا ضمن المجموعة Custom.

  6. استمتع بدالتك الجديدة.

  7. إذا احتاجت الدالة إلى تحسينات، فعّل تبويب Function Editor، وأجرِ التعديلات، ثم اضغط مجددًا على زر start Save and Load Functions لجعلها متاحة في الملف، ومن ثم في أي تبويب تعبيرات.

لحذف دالة مخصصة:

  1. فعّل تبويب Function Editor

  2. حدد الدالة في القائمة

  3. اضغط على symbologyRemove Remove selected function. تُزال الدالة من القائمة، وبحسب مكان التخزين، يُحذف ملف .py المقابل من مجلد ملف تعريف المستخدم، أو تُزال دوال Python من ملف المشروع.

ملاحظة

عند إغلاق ملف مشروع يحتوي على دوال مشروع، تُلغى تحميل دوال المشروع المقابلة ولا تعود متاحة في جلسة QGIS.

مثال

إليك مثالًا قصيرًا على إنشاء دالتك الخاصة my_sum التي تعمل على قيمتين.

from qgis.core import *
from qgis.gui import *

@qgsfunction(group='Custom', referenced_columns=[])
def my_sum(value1, value2):
    """
    Calculates the sum of the two parameters value1 and value2.
    <h2>Example usage:</h2>
    <ul>
      <li>my_sum(5, 8) -> 13</li>
      <li>my_sum("field1", "field2") -> 42</li>
    </ul>
    """
    return value1 + value2

يقبل المزخرف @qgsfunction الوسائط التالية:

  • يحدد الوسيط group المجموعة التي يجب إدراج الدالة ضمنها في نافذة حوار التعبيرات.

  • usesgeometry: اضبطه على True إذا كان التعبير يحتاج إلى الوصول إلى الشكل الهندسي للمعالم. القيمة الافتراضية False.

  • handlesnull: اضبطه على True إذا كان للتعبير معالجة مخصصة لقيم NULL. إذا كان False (الافتراضي)، فستكون النتيجة دائمًا NULL بمجرد أن يكون أي وسيط NULL.

  • referenced_columns: مصفوفة بأسماء السمات المطلوبة لتشغيل الدالة. القيمة الافتراضية [QgsFeatureRequest.ALL_ATTRIBUTES]. يؤدي تحديد مجموعة جزئية من الحقول أو قائمة فارغة إلى تنفيذ أسرع.

  • params_as_list: اضبطه على True لتمرير وسائط الدالة كقائمة. إذا كان False (الافتراضي)، فستتلقى الدالة الوسائط كوسائط منفصلة.

تأخذ الدالة نفسها أي عدد ونوع من الوسائط التي تريد تمريرها إليها. ويجب تعيينها قبل الوسائط الاختيارية التالية:

  • feature: المعلم الحالي

  • parent: كائن QgsExpression

  • context: إذا وُجد وسيط باسم context في الموضع الأخير، فسيحتوي هذا المتغير على كائن QgsExpressionContext يتيح الوصول إلى معلومات إضافية متنوعة مثل متغيرات التعبير. مثلًا context.variable( 'layer_id' )

إذا كانت هذه الوسائط موجودة في توقيع الدالة، فستُمرَّر إليها تلقائيًا دون الحاجة إلى تحديدها في التعبير.

يمكن بعد ذلك استخدام دالة المثال السابق في التعبيرات:

../../../_images/customFunction.png

شكل 9.3 دالة مخصصة مضافة إلى تبويب Expression

تجد مزيدًا من الأمثلة والوسائط الإضافية للدوال المخصصة في qgsfunction. ويمكن العثور على مزيد من المعلومات حول إنشاء شيفرة Python في دليل مطوّري PyQGIS (PyQGIS Developer Cookbook).