تحليل البيانات في Rعلم النفس الإحصائي

كيفية عرض النسب المئوية على المدرج التكراري في ggplot2

دليل أكاديمي شامل يشرح بالتفصيل كيفية تحويل وتنسيق المحور الرأسي لعرض النسب المئوية على المدرج التكراري باستخدام حزم ggplot2 وscales في لغة R.

تاريخ النشر

يُمثّل التمثيل البصري للبيانات ركيزة جوهرية في استكشاف وتفسير الأنماط والظواهر الإحصائية الكامنة ضمن مجموعات البيانات الكمية والنوعية. وفي سياق لغة البرمجة الإحصائية R، تتربع حزمة ggplot2 على قمة الأدوات المستخدمة لبناء الرسوم البيانية العلمية والمتقدمة، وذلك بفضل استنادها إلى فلسفة “قواعد بيانات الرسوم البيانية” (Grammar of Graphics) التي أرسى دعائمها ليلاند ويلكنسون وطورها هادلي ويكهام. وتُعد المدرجات التكرارية (Histograms) من أقدم وأهم الأشكال البصرية المستخدمة لتقييم التوزيع الاحتمالي للبيانات المتصلة وتحديد معالم النزعة المركزية والشتات والالتواء، مما يجعلها خطوة لا غنى عنها في أي مسار تحليلي استكشافي جاد.

على الرغم من أن الممارسة التقليدية في بناء المدرجات التكرارية تعتمد على تمثيل التكرارات المطلقة (Raw Frequencies) على المحور الرأسي (المحور الصادي)، إلا أن هذه المقاربة قد تواجه قيوداً منهجية وتفسيرية بالغة، لا سيما عند الرغبة في مقارنة عينات ذات أحجام غير متساوية، أو عند تقديم النتائج لجمهور واسع يحتاج إلى فهم الأوزان النسبية للبيانات بدلاً من الأعداد الخام. ومن هنا تبرز الحاجة التقنية إلى تحويل المحور الرأسي ومؤشرات الأعمدة لتعكس النسب المئوية (Percentages) أو التكرارات النسبية، وهو تحول يتطلب فهماً دقيقاً لكيفية تفاعل الطبقات الهندسية والتحويلات الإحصائية التلقائية داخل بيئة ggplot2 البرمجية.

يهدف هذا الدليل المرجعي الشامل إلى تقديم تفكيك نظري وتطبيقي متكامل لآليات احتساب وعرض النسب المئوية على المدرجات التكرارية والمخططات الشريطية المرتبطة بها في ggplot2. سنستعرض في هذا المقال الأسس الرياضية لحساب التكرارات النسبية آنياً أثناء عملية التصيير البصري، والتحولات البرمجية الدقيقة من الصيغ القديمة إلى دوال التقييم الإحصائي الحديثة مثل after_stat()، إلى جانب تقنيات ضبط المحاور وتنسيق النصوص البرمجية وبطاقات البيانات وعلاج التحديات الشائعة في المعالجة والتحجيم، بما يضمن إنتاج رسوم بيانية ذات جودة نشر أكاديمية عالية.

1. مقدمة نظرية حول المدرجات التكرارية والتمثيل البصري في ggplot2

1.1 مفهوم المدرج التكراري ودوره في التحليل الإحصائي الاستكشافي

يُعرَّف المدرج التكراري بأنه تمثيل بياني ثنائي الأبعاد يُستخدم لتقدير دالة الكثافة الاحتمالية للمتغيرات الكمية المتصلة. يقوم هذا التمثيل على تقسيم المدى الكلي للبيانات إلى فترات فرعية متتالية وغير متداخلة تُعرف باسم “الحاويات” أو الفئات (Bins). يتم بعد ذلك حساب عدد المشاهدات التي تقع داخل كل حاوية، ليُرسم فوق كل فترة عمود رأسي يتناسب ارتفاعه (أو مساحته في بعض التطبيقات الرياضية) طردياً مع تكرار تلك الفئة. يُتيح هذا التركيب للباحثين استكشاف معالم التوزيع الإحصائي بصرياً، مثل تحديد نمط التوزيع (هل هو توزيع طبيعي، أم لوجستي، أم متعدد الأنماط)، وفحص مقاييس التشتت كالانحراف المعياري والتباين، ورصد القيم المتطرفة والشاذة (Outliers) التي قد تشوه نتائج النمذجة الإحصائية اللاحقة.

ومن الأهمية بمكان التمييز الجوهري بين المدرج التكراري والمخطط الشريطي (Bar Chart)؛ فالمدرج التكراري يتعامل حصراً مع بيانات عددية مستمرة ومقسمة إلى فئات مترابطة هندسياً حيث تتلامس حواف الأعمدة للإشارة إلى استمرارية المقياس، بينما يُعنى المخطط الشريطي بتمثيل المتغيرات النوعية أو الفئوية المنفصلة (Discrete/Categorical Variables)، وتفصل مسافات بصرية واضحة بين أشرطته لتعكس استقلال كل فئة تصنيفية عن الأخرى. يؤدي الخلط بين هذين المفهومين في الممارسات البرمجية إلى اختيارات خاطئة للدوال الهندسية في لغة R، مما ينتج عنه تشويه في التحليل الدلالي والتوزيعي للبيانات.

1.2 فلسفة قواعد بيانات الرسوم البيانية (Grammar of Graphics) في ggplot2

ترتكز حزمة ggplot2 على مبدأ تفكيك الرسوم البيانية إلى عناصر بنائية منفصلة تُركَّب فوق بعضها في هيئة طبقات (Layers). تبدأ هذه البنية بالطبقة الأساسية المتمثلة في كائن البيانات (Data Frame)، تليها طبقة التعيينات الجمالية (Aesthetic Mappings) التي تربط أعمدة البيانات بخصائص بصرية كالمواقع على المحاور (x و y)، والألوان (Color)، والتعبئة (Fill)، والشفافية (Alpha). وتأتي بعد ذلك الطبقات الهندسية (Geometries) مثل geom_histogram() وgeom_bar() لتحديد الشكل الفيزيائي الذي ستتخذه البيانات على مساحة الرسم.

تعتمد قوة الحزمة على التحويلات الإحصائية التلقائية (Statistical Transformations أو ما يُعرف بـ stat). عند بناء مدرج تكراري، لا ترسم الحزمة البيانات الخام مباشرة، بل تُمرر المتغير المحدد إلى دالة إحصائية داخلية تسمى stat_bin() أو stat_count(). تقوم هذه الدالة بتنفيذ عمليات تجميع البيانات، وحساب حدود الحاويات، وتوليد متغيرات إحصائية داخلية مؤقتة تحتوي على تكرارات كل حاوية وتراكماتها الكثافية. يتيح فهم هذه الدورة الحسابية الداخلية للمحلل إمكانية التدخل البرمجي لإعادة توجيه تلك المتغيرات المحسوبة ذاتياً وتحويلها من تكرارات خام إلى قيم نسبية ومئوية قبل أن تتولى محركات التصيير مهمة الرسم النهائي.

1.3 مبررات التحول من التكرارات المطلقة إلى النسب المئوية

يعد الاعتماد الحصري على التكرارات المطلقة (Absolute Frequencies) أحد أكثر العوائق المنهجية شيوعاً في التحليل المقارن. فعندما تتضمن الدراسة مجموعات تجريبية أو ضابطة ذات أحجام عينات مختلفة (Sample Sizes)، تصبح المقارنة البصرية عبر التكرارات الخام مضللة؛ إذ ستبدو المجموعة الأكبر حجماً ذات كثافة أعلى في جميع فئاتها مقارنة بالمجموعة الأصغر، بصرف النظر عن التوزيع النسبي الحقيقي للظاهرة قيد الدراسة. يحل التحويل إلى نسب مئوية هذه المعضلة من خلال توحيد المقياس التفسيري لكافة المجموعات على مسطرة موحدة تمتد من 0% إلى 100%.

إلى جانب المقارنات التجريبية، يُسهم التمثيل النسبي في تعزيز سهولة التواصل المعرفي مع صناع القرار والجمهور العام؛ فالنسب المئوية تمثل مفهوماً فطرياً ومألوفاً يسهل استيعابه فوراً مقارنة بالأعداد المطلقة الضخمة أو المجردة. كما أن التكرار النسبي يرتبط مباشرة بالمفهوم الرياضي للاحتمال التجريبي (Empirical Probability)، حيث يُشير ارتفاع كل عمود في المدرج النسبي إلى احتمال وقوع مشاهدة عشوائية ضمن نطاق تلك الحاوية المحددة، مما يمنح الرسم قيمة تفسيرية مزدوجة تجمع بين الوصف الإحصائي والاستدلال الاحتمالي.

2. الأسس الرياضية والإحصائية للتحويل النسبي داخل طبقات ggplot2

2.1 معادلة التكرار النسبي والنسبة المئوية

يقوم الحساب الرياضي للتكرار النسبي (Relative Frequency) على صياغة رياضية بسيطة لكنها صارمة في دلالتها الإحصائية. إذا افترضنا أن لدينا عينة تتكون من $N$ من المشاهدات موزعة على $k$ من الحاويات أو الفئات، وكان تكرار الحاوية رقم $i$ يُرمز له بالرمز $f_i$، فإن التكرار النسبي $RF_i$ لتلك الحاوية يُحسب وفق المعادلة التالية:

$RF_i = \frac{f_i}{\sum_{j=1}^{k} f_j} = \frac{f_i}{N}$

ولتحويل هذا التكرار النسبي إلى نسبة مئوية (Percentage) $P_i$، يتم ضرب القيمة المحسوبة في الثابت 100:

$P_i = RF_i \times 100 = \left(\frac{f_i}{N}\right) \times 100$

يضمن هذا التحويل الحفاظ على الخاصية التكاملية للتوزيع؛ حيث يعادل مجموع التكرارات النسبية لكافة الحاويات الرقم واحد صحيحاً تماماً ($\sum RF_i = 1$)، ويعادل مجموع النسب المئوية مئة بالمئة ($\sum P_i = 100%$). ومن الناحية الهندسية البصرية في برمجية ggplot2، يحافظ هذا التحويل الخطي على النسب التناسبية التامة بين أطوال الأعمدة، مع تغيير مدرج المحور الرأسي ليعكس الوزن الجزئي لكل فئة بالنسبة إلى الكل.

2.2 المتغيرات الإحصائية المولدة داخلياً (Stat Variables)

عندما تقوم دالة التجميع الإحصائي stat_bin() بتشريح البيانات، تُخزن المخرجات الرياضية في جدول بيانات مؤقت يحتوي على متغيرات خاصة يُمكن استدعاؤها داخل التعيينات الجمالية للرسم. تاريخياً، كانت لغة R وحزمة ggplot2 تعتمد على الإحاطة بالنقط المزدوجة للإشارة إلى هذه المتغيرات الداخلية، مثل ..count.. الذي يمثل التكرار العددي المطلق في كل حاوية، و..density.. الذي يعكس كثافة الاحتمال المقدرة، و..ncount.. الذي يُعبر عن التكرار الطبيعي المعاير إلى القيمة 1 كحد أقصى.

مع تطور إصدارات ggplot2 (ابتداءً من الإصدار 3.3.0 فصاعداً)، جرى استحداث دالة after_stat() لتكون الصيغة الرسمية والآمنة برمجياً للوصول إلى هذه المتغيرات المولدة. يُتيح هذا البناء الحديث للمبرمج كتابة تعبيرات رياضية معقدة يتم تقييمها بعد انتهاء مرحلة التحويل الإحصائي وقبل مرحلة التصيير الجرافيكي، كأن نكتب after_stat(count / sum(count)) لاحتساب التكرار النسبي، مما يمنع حدوث التباس مع أي أعمدة بيانات أصلية تحمل أسماء مشابهة ويوفر بنية برمجية واضحة وقابلة للصيانة والتطوير المستقبلي.

2.3 آلية الحساب الآني أثناء عملية التصيير (Rendering)

تخضع عملية التصيير البصري في ggplot2 لسلسلة من الخطوات الحسابية المتزامنة والمتعاقبة (Pipeline Execution). تبدأ السلسلة باستقبال البيانات الأولية، تليها معالجة المقاييس الأولية، ثم تمرير المتغيرات إلى طبقات التحويل الإحصائي (Stat Transformation). في هذه النقطة بالذات، يتم حساب قيم count لكل حاوية، وحساب المجموع الكلي sum(count) عبر كامل نطاق الحاوية أو المجموعة قيد المعالجة.

إن تطبيق التعبير الرياضي داخل نطاق الطبقة الجمالية يضمن أن دالة الجمع sum() ستعمل على نطاق التجميع الصحيح. إذا لم تكن البيانات مقسمة إلى مجموعات فرعية، فإن sum(count) ستمثل الحجم الكلي للعينة ($N$) بدقة متناهية، وبذلك يكون خارج القسمة مساوياً للكسر العشري الصحيح. وفي مرحلة لاحقة من المسار البرمجي، تتلقى دوال ضبط المقاييس الرأسية هذه القيم العشرية الناتجة لتحولها بصرياً إلى صيغ مئوية نصية دون المساس بالقيم الرياضية الأصلية للأعمدة، مما يضمن دقة التمثيل التراكمي وتكامله الرياضي.

3. إعداد بيئة العمل واستدعاء الحزم البرمجية الأساسية

3.1 تثبيت واستدعاء حزمة ggplot2 وتوابعها

يتطلب الشروع في بناء المدرجات التكرارية المتقدمة إعداد بيئة عمل متكاملة داخل نظام R الإحصائي. تتوفر حزمة ggplot2 رسمياً عبر الشبكة الشاملة لأرشيف لغة آر (CRAN)، ويمكن تثبيتها بشكل مستقل أو بوصفها جزءاً لا يتجزأ من منظومة tidyverse التحليلية التي تضم أدوات رائدة مثل dplyr وreadr وtidyr. يُفضل دائماً تثبيت الحزمة عبر المنظومة الشاملة لضمان تكامل دوال المعالجة المسبقة مع دوال الرسم البصري.

يتم تنفيذ أوامر التثبيت والاستدعاء في سطر الأوامر أو ضمن نصوص R البرمجية كما يلي:

# تثبيت منظومة tidyverse الشاملة
install.packages("tidyverse")
# استدعاء الحزم في جلسة العمل الحالية
library(ggplot2)
library(dplyr)

يجب التأكد بانتظام من تحديث إصدار R والحزم المستدعاة، حيث أن الدوال الحديثة مثل after_stat() تتطلب إصدارات متوافقة لمنع ظهور رسائل الخطأ المتعلقة بالوظائف المهجورة (Deprecated Functions).

3.2 حزمة scales ودورها المحوري في تنسيق المحاور

تُعد حزمة scales الأداة القياسية الأهم لدعم مهام التنسيق الرقمي والمحوري داخل رسومات ggplot2. تكمن الوظيفة الأساسية لهذه الحزمة في تحويل القيم الرقمية المجردة (مثل الكسور العشرية 0.15 أو 0.50) إلى صيغ نصية مفهومة ومصممة خصيصاً للقراءة البشرية (مثل 15% أو 50%) دون الحاجة إلى تعديل مصفوفة البيانات الأصلية رياضياً.

توفر الحزمة دالتي تنسيق أساسيتين للنسب المئوية هما percent() وpercent_format() (أو الصيغة الأحدث label_percent()). تتيح هذه الأدوات للمطورين تحكماً كاملاً في معاملات التقريب الرياضي، وعدد المنازل العشرية، واختيار رمز النسبة المئوية وموقعه، وتحديد الفواصل العشرية (نقطة أم فاصلة)، مما يمنح الرسوم البيانية مرونة فائقة للتوافق مع المعايير النشرية العالمية واللغات المختلفة. يتم استدعاء الحزمة برمجياً عبر الأمر:

library(scales)

3.3 تجهيز مجموعات البيانات التجريبية

لبناء أمثلة تطبيقية قابلة للتكرار والاختبار المباشر، سنقوم بإنشاء إطار بيانات تركيبي (Synthetic Data Frame) يُحاكي دراسة مسحية تتضمن متغيرات كمية متصلة ومتغيرات فئوية تصنيفية. سننشئ متغيراً يمثل “مؤشر الرضا الوظيفي” (كمتغير كمي مستمر) ومتغيراً يمثل “القسم الوظيفي” و”الجنس” (كمتغيرات تصنيفية نوعية)، مع محاكاة بعض القيم المفقودة لاختبار متانة المعالجة البرمجية.

# ضبط البذرة العشوائية لضمان تكرارية النتائج
set.seed(1234)
# توليد إطار البيانات التجريبي
sample_size <- 1000
survey_data <- data.frame(
 Employee_ID = 1:sample_size,
 Satisfaction_Score = rnorm(sample_size, mean = 68, sd = 12),
 Age = round(rnorm(sample_size, mean = 38, sd = 8)),
 Department = sample(c("IT", "Marketing", "Finance", "HR"), 
 size = sample_size, replace = TRUE, 
 prob = c(0.4, 0.3, 0.2, 0.1)),
 Gender = sample(c("Male", "Female"), size = sample_size, replace = TRUE)
)
# تنظيف البيانات والتحقق من الأنواع
survey_data$Department <- as.factor(survey_data$Department)
survey_data$Gender <- as.factor(survey_data$Gender)

يضمن التأكد من تصنيف المتغيرات (Numeric مقابل Factor) أن ggplot2 ستتعامل مع كل متغير بالأسلوب الإحصائي والهندسي الصحيح، متجنبة الوقوع في أخطاء المعالجة البصرية الشائعة.

4. الصياغة البرمجية الأساسية لعرض النسب المئوية على المحور الرأسي

4.1 البنية التركيبية للشفرة البرمجية الأساسية

تعتمد الشفرة البرمجية الكلاسيكية لعرض النسب المئوية على المحور الصادي لمدرج تكراري أو مخطط شريطي على دمج ثلاثة مكونات برمجية: دالة التهيئة ggplot()، والطبقة الهندسية geom_histogram() أو geom_bar()، ودالة التحكم في المقياس scale_y_continuous(). في المنهجية القديمة، كان يتم تقسيم المتغير الإحصائي الداخلي ..count.. على إجمالي تكرارات البيانات sum(..count..) ضمن التعيين الجمالي للارتفاع aes(y = ...).

تتم هذه العملية عبر استدعاء الكود التالي:

# الصياغة الكلاسيكية التاريخية (Old Syntax)
ggplot(survey_data, aes(x = Satisfaction_Score)) +
 geom_histogram(aes(y = (..count..) / sum(..count..)), 
 binwidth = 5, color = "black", fill = "#3498db") +
 scale_y_continuous(labels = scales::percent) +
 labs(title = "توزيع مؤشر الرضا الوظيفي بالنسبة المئوية",
 x = "درجة الرضا",
 y = "النسبة المئوية")

في هذا التركيب، تقوم الدالة الهندسية بحساب الكسر العشري لكل حاوية، ثم تتولى دالة scale_y_continuous(labels = scales::percent) مهمة استقبال هذه الكسور (مثل 0.05، 0.10) وتنسيقها بصرياً لتظهر على المحور الرأسي كنسب مئوية صريحة (5%, 10%) دون تغيير موضع الأعمدة في الفضاء الإحداثي.

4.2 التحول إلى بناء الجملة الحديث باستخدام after_stat

مع التحديثات الهيكلية التي شهدتها حزمة ggplot2، أصبح استخدام الصيغ المحاطة بنقاط مثل ..count.. ممارسة غير مستحسنة وتولد رسائل تحذيرية مستمرة (Deprecation Warnings). البديل القياسي والمعياري المعتمد حالياً هو استخدام دالة after_stat()، التي تُعلن بوضوح عن مرحلة تقييم التعبير الحسابي ضمن خط أنابيب التصيير الجرافيكي.

تُكتب الشفرة الحديثة المتوافقة مع أحدث المعايير البرمجية كالتالي:

# الصياغة الحديثة والمعتمدة (Modern Standard Syntax)
ggplot(survey_data, aes(x = Satisfaction_Score)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 5, 
 color = "#2c3e50", 
 fill = "#2980b9", 
 alpha = 0.85) +
 scale_y_continuous(labels = scales::label_percent(accuracy = 1)) +
 labs(title = "توزيع مؤشر الرضا الوظيفي باستخدام after_stat",
 x = "درجة الرضا (درجات مستمرة)",
 y = "النسبة المئوية من إجمالي العينة")

يتميز هذا البناء بالوضوح الهيكلي، ويضمن بقاء الكود البرمجي مستقراً وقابلاً لإعادة التشغيل عبر الإصدارات المستقبلية من بيئة R، كما يتيح دمج دوال تحكم دقيقة في التقريب والكسور مثل label_percent(accuracy = 1) بكل سلاسة.

ggplot2 histogram with percentages
ggplot2 histogram with percentages

4.3 تفسير المخرجات التكرارية ومطابقتها إحصائياً

بعد تصيير الرسم البياني باستخدام الصياغة النسبية الحديثة، تعكس أطوال الأعمدة بدقة الوزن النسبي لكل نطاق درجات بالنسبة للحجم الإجمالي للعينة ($N = 1000$). فإذا بلغ ارتفاع العمود الواقع بين درجتي 65 و70 ما قيمته 22%، فإن التفسير المباشر يعني أن 220 موظفاً من أصل 1000 تقع درجات رضاهم الوظيفي ضمن هذا النطاق بالتحديد.

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

# التحقق الإحصائي اليدوي من التوزيع النسبي للحاويات
survey_data %>%
 mutate(Score_Bin = cut(Satisfaction_Score, breaks = seq(20, 110, by = 5))) %>%
 group_by(Score_Bin) %>%
 summarise(Raw_Count = n()) %>%
 mutate(Percentage = (Raw_Count / sum(Raw_Count)) * 100)

تؤكد المقارنة بين قيم جدول التلخيص وارتفاعات الأعمدة على الرسم البياني التوافق الرياضي الكامل بنسبة 100%، مما يمنح المحلل ثقة مطلقة في النتيجة المنشورة.

5. التحكم المتقدم في دقة الأرقام والكسور العشرية

5.1 استخدام معامل الدقة (accuracy) في دالة percent

في كثير من التطبيقات الإحصائية الدقيقة، لا يكون التقريب إلى أقرب عدد صحيح كافياً؛ فقد تتضمن بعض الحاويات نسباً ضئيلة كـ 0.4% أو 1.25%، والتي قد تختفي تماماً أو تتقارب بصرياً إذا تم تقريب المحور إلى أرقام صحيحة (0%، 1%، 2%). لحل هذه المشكلة، توفر دالة label_percent() التابعة لحزمة scales وسيطاً حاسماً يُعرف باسم accuracy.

يحدد المعامل accuracy أصغر وحدة تقريب يُقاس بها المحور؛ فعند تحديد accuracy = 0.1، ستُعرض النسب المئوية مع منزلة عشرية واحدة (مثل 12.3%)، بينما يؤدي تحديد accuracy = 0.01 إلى عرض منزلتين عشريتين (مثل 12.34%). يُوضح الكود التالي كيفية ضبط هذا الخيار المتقدم:

# ضبط دقة التسميات إلى منزلة عشرية واحدة
ggplot(survey_data, aes(x = Satisfaction_Score)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 5, 
 fill = "#27ae60", 
 color = "white") +
 scale_y_continuous(labels = scales::label_percent(accuracy = 0.1)) +
 labs(title = "مدرج تكراري بنسب مئوية ذات دقة عشرية محددة",
 y = "النسبة المئوية الدقيقة (%)")

يُسهم هذا التحديد في منع الخداع البصري الناجم عن أخطاء التقريب، خاصة عند التعامل مع توزيعات ذات التواء عالٍ (Skewed Distributions) تحتوي على ذيول طويلة بتكرارات منخفضة للغاية.

5.2 تخصيص الفواصل والرموز الرقمية المرافقة

تتطلب كتابة التقارير بلغات مختلفة، أو التوافق مع المعايير الطباعية لبعض المجلات الأكاديمية الأوروبية، تعديل الفواصل والرموز المستخدمة في الترقيم. ففي بعض المعايير يُفضل استخدام الفاصلة العشرية العادية (,) كفاصل عشري بدلاً من النقطة (.)، أو وضع مسافة فاصلة بين الرقم ورمز النسبة المئوية (مثل 15 % بدلاً من 15%)، أو حتى تغيير موضع الرمز ليكون في بداية الرقم أو نهايته.

تتيح دالة label_percent() تخصيص كل هذه العناصر عبر المعاملات decimal.mark وsuffix وprefix وbig.mark كما يلي:

# تخصيص الفاصلة العشرية والرمز المئوي وفق المعايير العربية أو الأوروبية
ggplot(survey_data, aes(x = Satisfaction_Score)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 5, 
 fill = "#e67e22", 
 color = "white") +
 scale_y_continuous(labels = scales::label_percent(accuracy = 0.1, 
 decimal.mark = ",", 
 suffix = " ٪")) +
 labs(title = "تخصيص الرموز المئوية والفواصل العشرية",
 x = "درجة الرضا",
 y = "النسبة")

يمنح هذا التخصيص الرسوم البيانية مظهراً احترافياً يتوافق مباشرة مع الهوية البصرية للغة العربية أو مع الموجهات الإرشادية الخاصة بمجلة النشر المستهدفة.

5.3 تحديد نقاط التوقف (Breaks) وحدود المحور الرأسي (Limits)

تقوم حزمة ggplot2 تلقائياً بحساب حدود المحاور بناءً على القيم الدنيا والعليا للبيانات المعروضة. ومع ذلك، قد يؤدي هذا التحديد التلقائي في المدرجات النسبية إلى ظهور قيم غير منتظمة على المحور (مثل 0%, 4%, 8%, 12%)، أو قد يقطع قمم الأعمدة العالية إذا كانت التسميات تلامس الحافة العليا للمخطط. لذلك، يُعد الضبط اليدوي لنقاط التوقف (Breaks) والحدود (Limits) أمراً حيوياً لتنظيم الرسم.

يتم استخدام الدالة seq() لتوليد نقاط توقف متساوية وثابتة، وتمرير مصفوفة ثنائية إلى المعامل limits لتحديد المدى الرأسي الكامل من 0 إلى القيمة القصوى المرغوبة:

# ضبط نقاط التوقف والحدود القصوى للمحور الرأسي
ggplot(survey_data, aes(x = Satisfaction_Score)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 5, 
 fill = "#8e44ad", 
 color = "white") +
 scale_y_continuous(
 labels = scales::label_percent(accuracy = 1),
 breaks = seq(0, 0.30, by = 0.05),
 limits = c(0, 0.25),
 expand = expansion(mult = c(0, 0.05))
 ) +
 labs(title = "التحكم في نقاط توقف المحور الصادي وحدود التمدد",
 x = "الدرجة",
 y = "النسبة المئوية")

يضمن استخدام expand = expansion(mult = c(0, 0.05)) أن قاعدة الأعمدة ستبدأ تماماً من خط الصفر على المحور الأفقي، مع ترك هامش علوي بنسبة 5% لمنع التصاق قمم الأعمدة بحافة الإطار العلوي.

6. التمييز بين geom_bar و geom_histogram عند عرض النسب المئوية

6.1 تطبيق النسب المئوية على المتغيرات المنفصلة (Discrete Variables)

عندما يكون الهدف هو تمثيل توزيع متغير تصنيفي منفصل (Categorical/Factor)، مثل متغير “القسم الوظيفي” (Department) في بياناتنا التجريبية، فإن الأداة الهندسية الصحيحة منهجياً هي geom_bar(). تعمل هذه الدالة افتراضياً مع التحويل الإحصائي stat_count()، والذي يحسب عدد التكرارات لكل مستوى تصنيفي منفصل.

لحساب وعرض النسب المئوية لهذه المتغيرات المنفصلة، نطبق دالة after_stat() مع الإشارة إلى أن إجمالي العينة يُحسب عبر جمع التكرارات المنفصلة لكافة الفئات المعروضة:

# تطبيق النسب المئوية على متغير فئوي منفصل باستخدام geom_bar
ggplot(survey_data, aes(x = Department)) +
 geom_bar(aes(y = after_stat(count / sum(count))), 
 fill = "#16a085", 
 width = 0.6) +
 scale_y_continuous(labels = scales::label_percent(accuracy = 1)) +
 labs(title = "التوزيع النسبي للموظفين حسب الأقسام",
 x = "القسم الوظيفي",
 y = "النسبة المئوية من إجمالي الموظفين")

يوفر المعامل width = 0.6 مسافة بصرية واضحة بين الأعمدة، مؤكداً استقلالية الفئات التصنيفية عن بعضها البعض بما يتوافق مع القواعد الإحصائية السليمة.

6.2 تطبيق النسب المئوية على المتغيرات المتصلة (Continuous Variables)

في المقابل، عندما يكون المتغير مستمراً عددياً مثل “العمر” أو “درجة الرضا”، فإن استخدام geom_histogram() هو الخيار المنهجي الوحيد. تعتمد هذه الدالة على التحويل الإحصائي stat_bin()، والذي يتطلب تحديداً حاسماً لحجم الحاوية عبر المعامل binwidth أو تحديد إجمالي عدد الحاويات عبر المعامل bins.

يؤثر تغيير حجم الحاوية (Bin Width) بشكل جذري ومباشر على النسب المئوية المحسوبة؛ فحاوية بعرض 10 درجات ستجمع ضعف البيانات التي تجمعها حاوية بعرض 5 درجات، وبالتالي سيتضاعف ارتفاع النسبة المئوية المعروضة على المحور الصادي:

# تطبيق النسب المئوية على متغير مستمر مع توضيح تأثير binwidth
ggplot(survey_data, aes(x = Age)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 2, 
 fill = "#d35400", 
 color = "white") +
 scale_y_continuous(labels = scales::label_percent(accuracy = 0.1)) +
 labs(title = "التوزيع النسبي للأعمار بحاويات عرضها سنتان",
 x = "العمر (سنوات)",
 y = "النسبة المئوية")

يجب على المحلل توخي الحذر الشديد عند تفسير النسب الناتجة عن geom_histogram()، حيث تمثل كل نسبة حصة تلك الحاوية المحددة بالذات من المجموع الكلي، وليست كثافة احتمالية مستمرة مطلقة مستقلة عن عرض النطاق.

6.3 مقارنة السلوك الحسابي بين الأداتين الهندسيتين

يلخص الجدول التالي ومقارنة السلوك البرمجي الفروق الجوهرية بين الأداة الهندسية geom_bar() والأداة geom_histogram() عند التعامل مع التحويلات النسبية المئوية:

  • طبيعة المدخلات: تستقبل geom_bar() متغيرات نوعية فئوية (Factors/Characters)، في حين تستقبل geom_histogram() متغيرات رقمية مستمرة (Numeric/Continuous).
  • التحويل الإحصائي التلقائي: تستخدم الأولى محول stat = "count" لعد المشاهدات في كل فئة، بينما تستخدم الثانية محول stat = "bin" لتقطيع المدى المستمر إلى شرائح منتظمة.
  • الاعتماد على المعاملات: ترتبط نسب geom_histogram() ارتباطاً شرطياً بقيمة binwidth، بينما ترتبط نسب geom_bar() حصرياً بعدد المستويات الفئوية المعرفة مسبقاً في البيانات.
  • المسافات البينية: توجد مساحات بيضاء بين أعمدة geom_bar() تلقائياً للإشارة للتباين الفئوي، بينما تتلاصق أعمدة geom_histogram() بصرياً للتعبير عن الاستمرارية المكانية للتوزيع.

7. إضافة وتنسيق بطاقات النسب المئوية النصية فوق الأعمدة

7.1 دمج طبقة geom_text لإظهار القيم الرقمية

على الرغم من أن قراءة النسب المئوية من المحور الرأسي توفر نظرة شمولية على شكل التوزيع، إلا أن التقارير الاحترافية وعروض الأعمال تتطلب في كثير من الأحيان طباعة القيمة الرقمية الدقيقة كبطاقة نصية (Text Label) أعلى كل عمود مباشرة. يُمكن تحقيق ذلك بسلاسة عن طريق إضافة طبقة geom_text() مع تكرار نفس التعيين الإحصائي المستخدم لحساب الارتفاع.

يتم ربط الجمالية النصية label بتعبير after_stat() محاطاً بدالة scales::percent() لتحويل الكسر الناتج مباشرة إلى نص مئوي مصاغ كما هو موضح في الكود التالي:

# إضافة بطاقات النسب المئوية الرقمية فوق الأعمدة في geom_bar
ggplot(survey_data, aes(x = Department)) +
 geom_bar(aes(y = after_stat(count / sum(count))), 
 fill = "#34495e", 
 width = 0.6) +
 geom_text(aes(y = after_stat(count / sum(count)),
 label = scales::percent(after_stat(count / sum(count)), accuracy = 0.1)),
 stat = "count", 
 vjust = -0.5, 
 size = 4.5, 
 fontface = "bold") +
 scale_y_continuous(labels = scales::label_percent(), 
 expand = expansion(mult = c(0, 0.12))) +
 labs(title = "توزيع الأقسام مع بطاقات النسب المئوية الدقيقة",
 x = "القسم",
 y = "النسبة المئوية")

يضمن تمرير stat = "count" (أو stat = "bin" في المدرجات التكرارية) إلى طبقة geom_text() أن محرك المعالجة سيقوم بنفس الحسابات التجميعية قبل وضع النصوص في إحداثياتها الصحيحة.

7.2 التحكم في الموضع الرأسي والمحاذاة (vjust و nudge_y)

يُعد ضبط التموضع الرأسي للبطاقات النصية أمراً حاسماً لمنع تداخل الأرقام مع الحواف العلوية للأعمدة أو خروجها خارج نطاق لوحة الرسم. توفر ggplot2 معاملين رئيسيين لضبط هذا الموضع: المعامل النسبي vjust، والمعامل المطلق nudge_y.

عند استخدام vjust = -0.5، يتم دفع النص إلى الأعلى بمقدار نصف ارتفاع خط النص، مما يجعله يستقر فوق حافة العمود مباشرة. أما إذا كانت هناك رغبة في وضع النص داخل العمود وتحت حافته العلوية بقليل، فيمكن استخدام vjust = 1.5 مع اختيار لون نصي متباين (كالأبيض). من ناحية أخرى، يتيح nudge_y = 0.01 إزاحة النص رأسياً بمقدار 1% بمقياس المحور الصادي المطلق، وهو ما يمنح تحكماً أدق عند الرغبة في ترك مسافة بصرية ثابتة بصرف النظر عن حجم الخط المستخدم.

7.3 استخدام geom_label لتوفير خلفيات بارزة للنصوص

في الرسوم البيانية المعقدة أو عند استخدام خلفيات ملونة وتظليلات شبكية كثيفة، قد تصبح الأرقام المطبوعة عبر geom_text() صعبة القراءة نتيجة ضعف التباين البصري. في مثل هذه السيناريوهات، توفر طبقة geom_label() بديلاً ممتازاً من خلال وضع بطاقات نصية محاطة بمستطيلات ذات خلفيات ملونة وحواف دائرية أنيقة.

يوضح المثال البرمجي التالي كيفية تطبيق geom_label() على مدرج تكراري نسبي مع ضبط الشفافية وحجم الإطار:

# تطبيق geom_label لعرض نسب الحاويات داخل صناديق نصية مميزة
ggplot(survey_data, aes(x = Satisfaction_Score)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 10, 
 fill = "#1abc9c", 
 color = "#16a085") +
 geom_label(aes(y = after_stat(count / sum(count)),
 label = scales::percent(after_stat(count / sum(count)), accuracy = 1)),
 stat = "bin", 
 binwidth = 10,
 vjust = -0.3, 
 fill = "white", 
 color = "#2c3e50", 
 size = 3.8, 
 label.size = 0.25, 
 label.padding = unit(0.2, "lines")) +
 scale_y_continuous(labels = scales::label_percent(), 
 expand = expansion(mult = c(0, 0.15))) +
 labs(title = "مدرج تكراري مع بطاقات نصية مؤطرة (geom_label)",
 x = "درجة الرضا الوظيفي",
 y = "النسبة المئوية")

تضمن إعدادات label.padding وlabel.size المحافظة على مساحات هوامش مصغرة داخل الصندوق النصي، مما يحافظ على التوازن والجمالية العامة للرسم دون حجب تفاصيل التوزيع البياني.

8. التعامل مع المجموعات المتعددة والمتغيرات التفسيرية (Faceting and Grouping)

8.1 حساب النسب المئوية داخل المجموعات (Group-wise Percentages)

عند إدخال متغير تصنيفي إضافي لتقسيم البيانات داخل المدرج التكراري عبر التعيين الجمالي fill = Variable، ينشأ تعقيد إحصائي دقيق يتعلق بمرجع حساب النسبة المئوية (Denominator): هل المطلوب هو حساب النسبة بالنسبة لإجمالي العينة الكلية ($N_{Total}$)، أم حساب النسبة المئوية المستقلة داخل كل فئة فرعية على حدة ($N_{Group}$

افتراضياً، عند استخدام after_stat(count / sum(count)) مع تعيين fill، تقوم ggplot2 بحساب النسبة بالنسبة لإجمالي كل مجموعة فرعية إذا تم دمجها مع position = "dodge"، مما يجعل مجموع أعمدة كل مجموعة يساوي 100%. يوضح المثال التالي هذا الأسلوب لمقارنة درجات الرضا بين الذكور والإناث:

# مقارنة التوزيع النسبي لمجموعتين باستخدام position = 'dodge'
ggplot(survey_data, aes(x = Satisfaction_Score, fill = Gender)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 10, 
 position = "dodge", 
 color = "white", 
 alpha = 0.85) +
 scale_y_continuous(labels = scales::label_percent(accuracy = 1)) +
 scale_fill_manual(values = c("Female" = "#e74c3c", "Male" = "#3498db")) +
 labs(title = "توزيع درجات الرضا حسب الجنس (نسب مئوية داخل المجموعات)",
 x = "درجة الرضا",
 y = "النسبة داخل المجموعة الفرعية",
 fill = "الجنس")

تسمح هذه الطريقة للباحث بعقد مقارنة موضوعية دقيقة بين شكلي التوزيع لكلا الجنسين بغض النظر عما إذا كان عدد الذكور في العينة مساوياً لعدد الإناث أم لا.

8.2 توليد النسب المئوية مع النوافذ الشبكية (Faceting)

تُعد النوافذ الشبكية (Faceting) باستخدام facet_wrap() أو facet_grid() إحدى أقوى ميزات حزمة ggplot2 لتقسيم الرسوم البيانية المعقدة إلى مصفوفة من اللوحات الفرعية المستقلة بصرياً. عند تطبيق دالة after_stat(count / sum(count)) داخل بنية مقسمة شبكياً، يتم تنفيذ التحويل الإحصائي محلياً داخل كل لوحة فرعية (Panel) بمعزل عن اللوحات الأخرى.

هذا يعني أن مجموع أطوال الأعمدة في كل لوحة فرعية سيعادل تلقائياً 100%، مما يتيح استكشافاً معمقاً للاختلافات التوزيعية بين الأقسام المختلفة كما يظهر في الكود الآتي:

# تقسيم المدرج التكراري النسبي إلى نوافذ شبكية حسب القسم
ggplot(survey_data, aes(x = Satisfaction_Score)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 5, 
 fill = "#2c3e50", 
 color = "white") +
 facet_wrap(~ Department, nrow = 2) +
 scale_y_continuous(labels = scales::label_percent(accuracy = 1)) +
 labs(title = "التوزيع التكراري النسبي لدرجات الرضا عبر الأقسام المختلفة",
 x = "درجة الرضا",
 y = "النسبة المئوية داخل القسم")

إذا كان الباحث يرغب في تحرير المقاييس الرأسية لكل قسم لاستيعاب التباينات الكبيرة في الكثافات، يمكنه إضافة المعامل scales = "free_y" داخل دالة النوافذ الشبكية مع الإبقاء على النسب المئوية معبرة عن الوزن النسبي المحلي لكل قسم.

8.3 استخدام الأعمدة التراكمية النسبية (100% Stacked Bar Charts)

في بعض التحليلات، يتطلب الأمر عرض التركيب النسبي للمتغيرات عبر كامل الفئات في هيئة أشرطة تراكمية موحدة الارتفاع تمتد بدقة من 0% إلى 100%. يتحقق ذلك في ggplot2 بسهولة فائقة عبر تطبيق خيار التموضع position = "fill".

عند تفعيل position = "fill"، تقوم الحزمة بتطبيع أطوال الأشرطة التراكمية تلقائياً لتبلغ القيمة 1 (أي 100%)، مما يلغي الحاجة إلى كتابة معادلات after_stat() يدوية، ويكتفى فقط بربط المحور الصادي بدالة التنسيق المئوي:

# بناء مخطط شريطي تراكمي نسبي بنسبة 100%
ggplot(survey_data, aes(x = Department, fill = Gender)) +
 geom_bar(position = "fill", width = 0.6) +
 scale_y_continuous(labels = scales::label_percent()) +
 scale_fill_brewer(palette = "Set2") +
 labs(title = "التركيب النسبي للنوع الاجتماعي داخل كل قسم (100% Stacked)",
 x = "القسم الوظيفي",
 y = "النسبة المئوية التراكمية",
 fill = "النوع")

يُمثل هذا الأسلوب البصري المعيار الذهبي لدراسة تباين التوزيعات الفئوية الفرعية عبر المستويات التصنيفية المختلفة ومقارنة حصصها النسبية بشكل مباشر.

9. التخصيص الجمالي والتصميمي المتقدم للرسوم البيانية

9.1 تطبيق القوالب الجمالية المدمجة والمهنية (Themes)

يُعد المظهر الجمالي للرسم البياني عنصراً حاسماً في تسهيل نقل المعرفة الإحصائية وتقليل العبء المعرفي على القارئ. تمتلك ggplot2 نظام قوالب مرناً وقوياً يتيح تجريد الرسم من العناصر غير الضرورية (مثل الخلفية الرمادية الافتراضية) والتركيز التام على تباين الأعمدة والنسب.

يُوصى في النشر العلمي باستخدام قوالب نظيفة مثل theme_minimal() أو theme_classic() أو theme_light()، مع إمكانية تعديل خطوط الشبكة، والتحكم في محاذاة العناوين وحجم خطوط التسميات التوضيحية عبر دالة theme():

# تطبيق قالب جمالي احترافي مخصص للنشر
ggplot(survey_data, aes(x = Satisfaction_Score)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 5, 
 fill = "#2980b9", 
 color = "white") +
 scale_y_continuous(labels = scales::label_percent(accuracy = 1)) +
 theme_minimal(base_size = 12, base_family = "sans") +
 theme(
 plot.title = element_text(face = "bold", size = 14, hjust = 0.5, margin = margin(b = 10)),
 axis.title.x = element_text(face = "bold", margin = margin(t = 10)),
 axis.title.y = element_text(face = "bold", margin = margin(r = 10)),
 panel.grid.minor = element_blank(),
 panel.grid.major.x = element_blank(),
 panel.grid.major.y = element_line(color = "#ecf0f1", linewidth = 0.5)
 ) +
 labs(title = "توزيع مؤشر الرضا الوظيفي بقالب جمالي منسق",
 x = "درجة الرضا",
 y = "النسبة المئوية")

يساعد حذف خطوط الشبكة الرأسية (Major X Grid) والاحتفاظ بخطوط الشبكة الأفقية الخفيفة فقط في توجيه عين القارئ لقراءة النسب المئوية على المحور الصادي دون أي تشتيت بصري جانبي.

9.2 لوحات الألوان وتوافقها مع المعايير العلمية (Color Palettes)

يجب أن تراعي الخيارات اللونية في الرسوم الإحصائية معايير إمكانية الوصول وسهولة القراءة، بما في ذلك التوافق مع متطلبات المصابين بعمى الألوان (Color-blind Friendliness) والوضوح التام عند الطباعة بالأبيض والأسود. تقدم حزم مثل viridis وحزمة RColorBrewer حلولاً لونية قياسية ومختبرة علمياً.

يوضح المثال التالي كيفية تطبيق مدرج لوني مستمر من حزمة viridis لتلوين الحاويات تبعاً لنسبتها المئوية، مما يضيف بعداً بصرياً مزدوجاً يربط الارتفاع واللون بنفس المؤشر الإحصائي:

# تلوين الحاويات ديناميكياً بحسب نسبتها المئوية باستخدام viridis
ggplot(survey_data, aes(x = Satisfaction_Score)) +
 geom_histogram(aes(y = after_stat(count / sum(count)), 
 fill = after_stat(count / sum(count))), 
 binwidth = 5, 
 color = "white") +
 scale_y_continuous(labels = scales::label_percent(accuracy = 1)) +
 scale_fill_viridis_c(option = "viridis", labels = scales::label_percent(accuracy = 1)) +
 theme_minimal() +
 labs(title = "مدرج تكراري ملون ديناميكياً حسب النسبة المئوية",
 x = "درجة الرضا",
 y = "النسبة المئوية",
 fill = "النسبة")

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

9.3 إضافة العناوين والتعليقات الإحصائية الداعمة

يكتمل العمل البياني الاحترافي بصياغة توثيقية دقيقة للبيانات الواردة فيه؛ إذ لا ينبغي ترك القارئ في حيرة حول حجم العينة الأساسي ($N$)، أو مصدر البيانات، أو الدلالات الرياضية المستخدمة. تُتيح دالة labs() إضافة حزمة متكاملة من العناصر التوثيقية تشمل العنوان الرئيسي (Title)، والعنوان الفرعي (Subtitle)، والتسميات التوضيحية للمحاور، والحاشية السفلية (Caption).

يُفضل دائماً تضمين حجم العينة الكلي والمعادلة المعتمدة في الحاشية السفلية لضمان الشفافية العلمية الكاملة كما يلي:

# إضافة عناوين وتوثيقات إحصائية متكاملة
ggplot(survey_data, aes(x = Satisfaction_Score)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 5, 
 fill = "#3498db", 
 color = "white") +
 scale_y_continuous(labels = scales::label_percent(accuracy = 1)) +
 theme_minimal() +
 labs(
 title = "التحليل الاستكشافي لمستوى الرضا المؤسسي",
 subtitle = "توزيع التكرارات النسبية لدرجات الرضا الوظيفي للموظفين لعام 2024",
 x = "مؤشر الرضا الوظيفي (0 - 100)",
 y = "النسبة المئوية التكرارية (%)",
 caption = "المصدر: المسح الميداني الداخلي | حجم العينة N = 1000 | تم حساب النسب آنياً باستخدام after_stat"
 )

تمنح هذه البيانات الوصفية الملحقة موثوقية عالية للرسم البياني وتجعله قابلاً للنشر كعنصر مرئي مستقل بذاته ومفهوم تماماً دون الحاجة لقراءة النص التحريري المرافق.

10. المعالجة المسبقة للبيانات كبديل للحسابات اللحظية (Pre-aggregation)

10.1 تلخيص البيانات باستخدام حزمة dplyr قبل الرسم

على الرغم من مرونة الحسابات اللحظية داخل ggplot2 عبر after_stat()، إلا أن هناك سيناريوهات تطبيقية يُفضل فيها إجراء المعالجة المسبقة للبيانات (Pre-aggregation) بالكامل باستخدام أدوات حزمة dplyr قبل تمريرها لطبقات الرسم. تبرز هذه الحاجة بقوة عند التعامل مع مجموعات البيانات الضخمة (Big Data) التي تحتوي على ملايين السجلات؛ حيث يؤدي تلخيص البيانات مسبقاً إلى تسريع زمن التصيير وتوفير استهلاك الذاكرة العشوائية (RAM).

يتم استخدام دوال التجميع والتحويل الرياضي لبناء جدول تلخيصي دقيق يحتوي على التكرارات والنسب المئوية المحسوبة مسبقاً:

# تلخيص البيانات مسبقاً باستخدام dplyr
summary_table <- survey_data %>%
 count(Department, name = "Raw_Count") %>%
 mutate(
 Total_Count = sum(Raw_Count),
 Percentage = Raw_Count / Total_Count,
 Label_Text = scales::percent(Percentage, accuracy = 0.1)
 )
# طباعة الجدول الملخص
print(summary_table)

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

10.2 الرسم المباشر للبيانات الملخصة عبر geom_col

عند التعامل مع إطار بيانات مُلخص يحتوي مسبقاً على عمود النسب المئوية كمتغير عددي جاهز، نستبدل دالة geom_bar() بالدالة الهندسية المخصصة geom_col(). تتميز دالة geom_col() بأنها تستخدم التحويل الإحصائي المطابق stat = "identity" افتراضياً، مما يعني أنها تقرأ القيم الرقمية من العمود المحدد وترسمها مباشرة دون محاولة حساب أي تكرارات جديدة.

تتم صياغة الكود ببساطة وسلاسة دون الحاجة إلى دوال التقييم الإحصائي الداخلي المعقدة كما يلي:

# رسم البيانات الملخصة مسبقاً باستخدام geom_col
ggplot(summary_table, aes(x = reorder(Department, -Percentage), y = Percentage)) +
 geom_col(fill = "#2c3e50", width = 0.6) +
 geom_text(aes(label = Label_Text), vjust = -0.5, fontface = "bold") +
 scale_y_continuous(labels = scales::label_percent(), 
 limits = c(0, max(summary_table$Percentage) * 1.15)) +
 theme_minimal() +
 labs(title = "رسم النسب المئوية الملخصة مسبقاً باستخدام geom_col",
 x = "القسم (مرتب تنازلياً)",
 y = "النسبة المئوية")

يُلاحظ في الكود أعلاه استخدام دالة reorder(Department, -Percentage) لترتيب الأعمدة تنازلياً بناءً على النسبة المئوية، وهو ما يُعزز من جاذبية الرسم وسهولة قراءته الفورية.

10.3 دمج فترات الثقة (Confidence Intervals) مع النسب التكرارية

في الأبحاث الأكاديمية المحكمة واستطلاعات الرأي العام، لا يكتفي الباحثون بعرض النسبة المئوية النقطية (Point Estimate)، بل يُلزم المنهج العلمي بدمج هوامش الخطأ وفترات الثقة (Confidence Intervals) التي تعكس عدم التيقن الإحصائي الناجم عن المعاينة العشوائية. وعند استخدام أسلوب التلخيص المسبق، يمكن بسهولة حساب فترات الثقة للنسب باستخدام توزيع برنولي والتقريب الطبيعي أو معادلة ويلسون (Wilson Score Interval).

يوضح المثال التالي كيفية حساب فترات ثقة بنسبة 95% وإضافتها فوق الأعمدة النسبية باستخدام geom_errorbar():

# حساب فترات الثقة 95% للنسب المئوية
ci_table <- summary_table %>%
 mutate(
 SE = sqrt((Percentage * (1 - Percentage)) / Total_Count),
 CI_Lower = Percentage - (1.96 * SE),
 CI_Upper = Percentage + (1.96 * SE)
 )
# رسم الأعمدة مع أشرطة الخطأ لفترات الثقة
ggplot(ci_table, aes(x = Department, y = Percentage)) +
 geom_col(fill = "#3498db", width = 0.5, alpha = 0.8) +
 geom_errorbar(aes(ymin = CI_Lower, ymax = CI_Upper), 
 width = 0.2, color = "#2c3e50", linewidth = 0.8) +
 geom_text(aes(label = Label_Text), vjust = -1.8, fontface = "bold") +
 scale_y_continuous(labels = scales::label_percent(), 
 limits = c(0, max(ci_table$CI_Upper) * 1.2)) +
 theme_minimal() +
 labs(title = "التوزيع النسبي للأقسام مع فترات الثقة 95%",
 x = "القسم",
 y = "النسبة المئوية (± هامش الخطأ)")

يرفع هذا التمثيل العلمي من رصانة التحليل ويقدم دلالة إحصائية متينة تتيح للقارئ معرفة ما إذا كانت الفروق بين نسب الأقسام ذات دلالة إحصائية حقيقية أم أنها مجرد تباينات عشوائية ناتجة عن حجم العينة.

11. استكشاف الأخطاء الشائعة والتحذيرات البرمجية وإصلاحها

11.1 معالجة رسائل التحذير المتعلقة بـ deprecated syntax

واحدة من أكثر رسائل التحذير إزعاجاً وشيوعاً لدى مستخدمي ggplot2 عند نسخ أكواد قديمة من منصات مثل Stack Overflow هي الرسالة التالية:

`..count..` was deprecated in ggplot2 3.4.0. Please use `after_stat(count)` instead.

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

الحل الجذري: استبدال كافة التعبيرات التي تحتوي على ..count.. أو ..density.. بالصيغة المعيارية الحديثة after_stat(). على سبيل المثال، يتم تحويل التعبير القديم:

aes(y = (..count..) / sum(..count..))

إلى التعبير الحديث المعياري:

aes(y = after_stat(count / sum(count)))

يضمن هذا التعديل البسيط توافق الكود مع كافة أدوات منظومة tidyverse وتفادي توقف النصوص البرمجية الآلية في بيئات العمل الإنتاجية.

11.2 أخطاء المجموع غير الصحيح (Incorrect Normalization)

يحدث خطأ المجموع غير الصحيح عندما يختل مرجع الحساب (Denominator) في دالة القسمة؛ كأن يقوم المحلل بمحاولة حساب النسب المئوية داخل مجموعات فرعية مقسمة بـ fill متوقعاً أن مجموع كل عمود فرعي سيمثل نسبته من العينة الكلية ($N_{Total}$)، ليتفاجأ بأن sum(count) قامت بجمع عناصر المجموعة الفرعية فقط محلياً، أو العكس.

لحساب النسبة المئوية العامة لعنصر فرعي بالنسبة للمجتمع الكلي حتى مع وجود تقسيم لوني بـ fill، يجب تثبيت المتغير الإحصائي التجميعي عبر تحديد معامل التجميع العام group = 1 داخل الطبقة الجمالية:

# فرض الحساب على المرجع الشامل (Global Denominator)
ggplot(survey_data, aes(x = Department, fill = Gender)) +
 geom_bar(aes(y = after_stat(count / sum(count)), group = Gender), 
 position = "dodge") +
 scale_y_continuous(labels = scales::label_percent()) +
 labs(title = "حساب النسب من الإجمالي الكلي للعينة مع الحفاظ على المجموعات",
 y = "النسبة من إجمالي العينة الكلية N")

يُعد التدقيق في دلالة المرجع الحسابي خطوة حاسمة لمنع إصدار تقارير مضللة تحسب النسب المئوية على أساس خاطئ.

11.3 مشاكل تحجيم المحور وقص النصوص (Clipping Issues)

عند إضافة بطاقات النسب النصية أعلى الأعمدة الطويلة، يحدث في كثير من الأحيان أن يختفي النصف العلوي من النص أو يُقص تماماً بسبب تجاوزه الحد الأقصى لنظام الإحداثيات (Plot Panel Limits). يحاول بعض المحللين حل ذلك بزيادة قيمة limits داخل scale_y_continuous()، ولكن هذا قد يؤدي إلى إزالة بعض نقاط البيانات إذا لم يتم بحذر.

الحلول الموصى بها:

  • استخدام دالة التمدد expand = expansion(mult = c(0, 0.15)) داخل مقياس المحور الصادي لترك مساحة فارغة بنسبة 15% أعلى أطول عمود في الرسم.
  • إلغاء خاصية قص العناصر خارج الإطار الجغرافي للرسم من خلال تفعيل coord_cartesian(clip = "off") داخل نظام الإحداثيات.
  • تدوير تسميات المحور الأفقي المتزاحمة لمنع تداخلها عبر إضافة theme(axis.text.x = element_text(angle = 45, hjust = 1)).

12. تطبيقات عملية ودراسات حالة في البحث الأكاديمي والتحليل النفسي

12.1 دراسة حالة: توزيع درجات مقاييس الشخصية والتقييم النفسي

في أبحاث القياس النفسي والتقييم السلوكي، يُستخدم المدرج التكراري النسبي لتوضيح مدى تطابق درجات عينة سريرية مع التوزيع المعياري لأداة قياس نفسية (مثل مقياس بيك للاكتئاب BDI أو مقياس القلق العام GAD-7). يتطلب التحليل النفسي الدقيق تقسيم الدرجات إلى فئات سريرية معيارية (خفيف، متوسط، شديد) وعرض النسبة المئوية الدقيقة لكل شريحة لتحديد معدلات الانتشار (Prevalence Rates).

يستعرض الكود المتكامل التالي دراسة حالة تحاكي توزيع درجات القلق على عينة من 500 مريض، مع إبراز مستويات الشدة السريرية بنسب مئوية جاهزة للنشر الأكاديمي:

# توليد بيانات درجات القلق النفسي
set.seed(42)
clinical_sample <- data.frame(
 GAD7_Score = pmin(pmax(round(rnorm(500, mean = 11, sd = 4.5)), 0), 21)
)
# بناء مدرج تكراري نسبي مع تصنيف شدة الأعراض النفسية
ggplot(clinical_sample, aes(x = GAD7_Score)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 2, 
 fill = "#8e44ad", 
 color = "white", 
 alpha = 0.85) +
 geom_text(aes(y = after_stat(count / sum(count)),
 label = ifelse(after_stat(count / sum(count)) > 0.03, 
 scales::percent(after_stat(count / sum(count)), accuracy = 0.1), "")),
 stat = "bin", 
 binwidth = 2, 
 vjust = -0.5, 
 size = 3.5, 
 fontface = "bold") +
 scale_y_continuous(labels = scales::label_percent(accuracy = 1), 
 expand = expansion(mult = c(0, 0.15))) +
 scale_x_continuous(breaks = seq(0, 21, by = 3)) +
 theme_minimal(base_size = 11) +
 theme(
 plot.title = element_text(face = "bold", hjust = 0.5),
 panel.grid.minor = element_blank()
 ) +
 labs(
 title = "التوزيع النسبي لدرجات مقياس القلق العام (GAD-7)",
 subtitle = "عينة سريرية تجريبية (N = 500) موضحة بحاويات ثنائية الدرجة",
 x = "درجة المقياس الكلية (0 - 21)",
 y = "النسبة المئوية من إجمالي العينة السريرية",
 caption = "الدرجات >= 15 تشير إلى أعراض قلق حادة تتطلب تدخلاً علاجياً"
 )

يُلاحظ في الشفرة أعلاه استخدام دالة الشرط ifelse() داخل التسمية النصية؛ لمنع طباعة البطاقات النصية فوق الحاويات الهامشية التي يقل ترددها النسبي عن 3%، مما يُبقي المخطط نظيفاً وخالياً من الفوضى البصرية.

12.2 دراسة حالة: تحليل زمن الاستجابة في التجارب السلوكية

تُعد أزمنة الاستجابة أو أزمنة الرجع (Reaction Times – RT) في علم النفس التجريبي والمعرفي من المتغيرات الكلاسيكية التي تتميز بتوزيع ملتوي التواءً موجباً شديداً (Positively Skewed Distribution)، حيث تتركز معظم الاستجابات في النطاقات الزمنية السريعة (300-600 ميلي ثانية) مع وجود ذيل طويل جداً من الاستجابات البطيئة. يُساعد المدرج التكراري النسبي في تحديد النسبة المئوية للاستجابات السريعة بدقة ومقارنتها بالمعالم الإحصائية كالوسيط والمتوسط الحسابي.

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

# توليد بيانات أزمنة الاستجابة (توزيع لوغاريتمي طبيعي)
set.seed(99)
rt_data <- data.frame(
 RT = rlnorm(1200, meanlog = 6.2, sdlog = 0.35) # أزمنة بالملي ثانية
)
mean_rt <- mean(rt_data$RT)
median_rt <- median(rt_data$RT)
# بناء المدرج النسبي مع الخطوط المرجعية
ggplot(rt_data, aes(x = RT)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 50, 
 fill = "#34495e", 
 color = "#2c3e50", 
 alpha = 0.8) +
 geom_vline(aes(xintercept = mean_rt, color = "المتوسط الحسابي"), 
 linetype = "dashed", linewidth = 1) +
 geom_vline(aes(xintercept = median_rt, color = "الوسيط"), 
 linetype = "solid", linewidth = 1) +
 scale_y_continuous(labels = scales::label_percent(accuracy = 0.1), 
 expand = expansion(mult = c(0, 0.1))) +
 scale_x_continuous(breaks = seq(200, 2000, by = 200), limits = c(200, 1800)) +
 scale_color_manual(name = "المؤشرات الإحصائية", 
 values = c("المتوسط الحسابي" = "#e74c3c", "الوسيط" = "#2ecc71")) +
 theme_classic() +
 theme(
 legend.position = "top",
 plot.title = element_text(face = "bold")
 ) +
 labs(
 title = "التوزيع النسبي لأزمنة الاستجابة في اختبار التوافق الحركي",
 x = "زمن الاستجابة (ميلي ثانية)",
 y = "النسبة المئوية (%)",
 caption = "N = 1200 محاولة تجريبية | عرض الحاوية = 50 ميلي ثانية"
 )

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

12.3 تصدير المخرجات الرسومية بجودة عالية للنشر والتقارير

لا تكتمل العملية البرمجية لإنتاج الرسوم البيانية إلا بتصدير المخرجات النهائية بصيغ فيزيائية عالية الدقة تتوافق مع المعايير الصارمة لدور النشر الأكاديمية (مثل إرشادات جمعية علم النفس الأمريكية APA ومؤسسة IEEE). تُوفر حزمة ggplot2 دالة متطورة مخصصة لهذا الغرض هي ggsave().

تسمح دالة ggsave() بالتحكم الكامل في الدقة النقطية (DPI)، والأبعاد المادية (بالبوصة أو السنتيمتر)، وتنسيق الملف المصدّر (PDF للرسوم الشعاعية المتجهة، أو TIFF و PNG للصور النقطية عالية الجودة):

# حفظ الرسم الأخير في كائن برمجي
final_plot <- ggplot(survey_data, aes(x = Satisfaction_Score)) +
 geom_histogram(aes(y = after_stat(count / sum(count))), 
 binwidth = 5, fill = "#2980b9", color = "white") +
 scale_y_continuous(labels = scales::label_percent(accuracy = 1)) +
 theme_minimal() +
 labs(title = "توزيع الرضا الوظيفي", x = "الدرجة", y = "النسبة")
# تصدير الرسم بدقة 300 DPI للنشر في مجلة محكمة
ggsave(
 filename = "histogram_percentages_high_res.png",
 plot = final_plot,
 width = 8.5,
 height = 5.5,
 units = "in",
 dpi = 300
)
# تصدير بصيغة PDF متجهة (Vector Format) لأعلى جودة طباعية
ggsave(
 filename = "histogram_percentages_vector.pdf",
 plot = final_plot,
 width = 8.5,
 height = 5.5,
 units = "in"
)

يضمن ضبط معامل dpi = 300 أو التصدير بصيغة PDF بقاء النصوص والخطوط المئوية حادة وواضحة تماماً دون أي تشوه أو بكسلة عند تكبير المخطط أو طباعته في الأبحاث والرسائل الجامعية.

خاتمة وتوصيات منهجية

يُمثل عرض النسب المئوية على المدرجات التكرارية والمخططات الشريطية في بيئة ggplot2 خطوة محورية للانتقال بالتحليل الاستكشافي للبيانات من مجرد الوصف العددي الخام إلى التفسير الإحصائي المعياري المقارن. لقد استعرضنا في هذا الدليل الشامل كيف يتيح الفهم العميق لفلسفة “قواعد بيانات الرسوم البيانية” وآليات التقييم الإحصائي اللحظي عبر دالة after_stat() السيطرة الكاملة على عملية التصيير وتحويل التكرارات إلى نسب مئوية دقيقة وموثوقة رياضياً.

وختاماً، نوصي المحللين والباحثين بتبني أفضل الممارسات البرمجية والمنهجية التالية عند بناء المدرجات التكرارية النسبية:

  • الالتزام بالبناء الحديث: تجنب الصيغ القديمة مثل ..count.. والاعتماد الحصري على after_stat(count / sum(count)) لضمان استقرار الشفرات المستقبلية.
  • الاستفادة من حزمة scales: استخدام دوال label_percent() لضبط الدقة العشرية والفواصل بما يخدم وضوح المعنى الإحصائي دون تكلف.
  • التدقيق في حجم الحاوية (binwidth): تذكر دائماً أن النسبة المئوية في المدرج التكراري المستمر تعتمد مباشرة على اتساع الحاوية، ويجب توثيق هذا العرض في وصف الرسم بوضوح.
  • الموازنة بين التعقيد والوضوح: عند إضافة البطاقات النصية باستخدام geom_text() أو geom_label()، تجنب حشر الأرقام فوق الحاويات متناهية الصغر، واحرص على توفير هوامش تمدد علوية كافية لمنع قص النصوص.
  • اختيار أسلوب التلخيص المناسب: استخدم الحساب اللحظي للاستكشاف السريع والبيانات المتوسطة، والجأ إلى المعالجة المسبقة عبر dplyr وgeom_col() عند التعامل مع البيانات الضخمة أو عند الحاجة لحساب فترات الثقة المتقدمة.

References

اقتباس هذا المقال

looti, M. (2026, أغسطس 29). كيفية عرض النسب المئوية على المدرج التكراري في ggplot2. عرب سايكلوجي. https://arabpsychology.com/statistics/how-to-display-percentages-on-histogram-in-ggplot2/
looti, Mohammed. “كيفية عرض النسب المئوية على المدرج التكراري في ggplot2.” عرب سايكلوجي, 29 أغسطس 2026, https://arabpsychology.com/statistics/how-to-display-percentages-on-histogram-in-ggplot2/.
looti, Mohammed. “كيفية عرض النسب المئوية على المدرج التكراري في ggplot2.” عرب سايكلوجي. أغسطس 29, 2026. https://arabpsychology.com/statistics/how-to-display-percentages-on-histogram-in-ggplot2/.