Wahbi-AI / styling /charts.py
EGYADMIN's picture
Upload 70 files
d9e7bdd verified
"""
مولد الرسوم البيانية لنظام إدارة المناقصات
"""
import os
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import customtkinter as ctk
class ChartGenerator:
"""فئة مولد الرسوم البيانية"""
def __init__(self, theme):
"""تهيئة مولد الرسوم البيانية"""
self.theme = theme
# تحديد مسار مجلد الرسوم البيانية
self.charts_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "data", "charts")
# إنشاء مجلد الرسوم البيانية إذا لم يكن موجودًا
os.makedirs(self.charts_dir, exist_ok=True)
# تهيئة نمط الرسوم البيانية
self._setup_chart_style()
def _setup_chart_style(self):
"""إعداد نمط الرسوم البيانية"""
# تعيين نمط الرسوم البيانية
plt.style.use('ggplot')
# تعيين الخط
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['font.sans-serif'] = ['Arial', 'DejaVu Sans', 'Liberation Sans', 'Bitstream Vera Sans', 'sans-serif']
# تعيين حجم الخط
plt.rcParams['font.size'] = 10
plt.rcParams['axes.titlesize'] = 14
plt.rcParams['axes.labelsize'] = 12
plt.rcParams['xtick.labelsize'] = 10
plt.rcParams['ytick.labelsize'] = 10
plt.rcParams['legend.fontsize'] = 10
# تعيين الألوان
if self.theme.current_theme == "light":
plt.rcParams['figure.facecolor'] = self.theme.LIGHT_CARD_BG_COLOR
plt.rcParams['axes.facecolor'] = self.theme.LIGHT_BG_COLOR
plt.rcParams['axes.edgecolor'] = self.theme.LIGHT_BORDER_COLOR
plt.rcParams['axes.labelcolor'] = self.theme.LIGHT_FG_COLOR
plt.rcParams['xtick.color'] = self.theme.LIGHT_FG_COLOR
plt.rcParams['ytick.color'] = self.theme.LIGHT_FG_COLOR
plt.rcParams['text.color'] = self.theme.LIGHT_FG_COLOR
plt.rcParams['grid.color'] = self.theme.LIGHT_BORDER_COLOR
else:
plt.rcParams['figure.facecolor'] = self.theme.DARK_CARD_BG_COLOR
plt.rcParams['axes.facecolor'] = self.theme.DARK_BG_COLOR
plt.rcParams['axes.edgecolor'] = self.theme.DARK_BORDER_COLOR
plt.rcParams['axes.labelcolor'] = self.theme.DARK_FG_COLOR
plt.rcParams['xtick.color'] = self.theme.DARK_FG_COLOR
plt.rcParams['ytick.color'] = self.theme.DARK_FG_COLOR
plt.rcParams['text.color'] = self.theme.DARK_FG_COLOR
plt.rcParams['grid.color'] = self.theme.DARK_BORDER_COLOR
def create_bar_chart(self, data, title, xlabel, ylabel):
"""إنشاء رسم بياني شريطي"""
# إنشاء الشكل والمحاور
fig, ax = plt.subplots(figsize=(8, 5), dpi=100)
# رسم الرسم البياني الشريطي
bars = ax.bar(data['labels'], data['values'], color=self.theme.PRIMARY_COLOR[self.theme.current_theme])
# إضافة القيم فوق الأشرطة
for bar in bars:
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width() / 2., height + 0.1 * max(data['values']),
f'{height:,.0f}', ha='center', va='bottom')
# تعيين العنوان والتسميات
ax.set_title(title)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
# تعيين حدود المحور y
ax.set_ylim(0, max(data['values']) * 1.2)
# إضافة الشبكة
ax.grid(True, linestyle='--', alpha=0.7)
# تضييق الشكل
fig.tight_layout()
return fig
def create_line_chart(self, data, title, xlabel, ylabel):
"""إنشاء رسم بياني خطي"""
# إنشاء الشكل والمحاور
fig, ax = plt.subplots(figsize=(8, 5), dpi=100)
# رسم الرسم البياني الخطي
line = ax.plot(data['labels'], data['values'], marker='o', linestyle='-', linewidth=2,
color=self.theme.PRIMARY_COLOR[self.theme.current_theme],
markersize=8, markerfacecolor=self.theme.SECONDARY_COLOR[self.theme.current_theme])
# إضافة القيم فوق النقاط
for i, value in enumerate(data['values']):
ax.text(i, value + 0.05 * max(data['values']), f'{value:,.0f}', ha='center', va='bottom')
# تعيين العنوان والتسميات
ax.set_title(title)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
# تعيين حدود المحور y
ax.set_ylim(0, max(data['values']) * 1.2)
# إضافة الشبكة
ax.grid(True, linestyle='--', alpha=0.7)
# تضييق الشكل
fig.tight_layout()
return fig
def create_pie_chart(self, data, title):
"""إنشاء رسم بياني دائري"""
# إنشاء الشكل والمحاور
fig, ax = plt.subplots(figsize=(8, 5), dpi=100)
# تعيين الألوان
colors = [
self.theme.PRIMARY_COLOR[self.theme.current_theme],
self.theme.SECONDARY_COLOR[self.theme.current_theme],
self.theme.ACCENT_COLOR[self.theme.current_theme],
self.theme.WARNING_COLOR[self.theme.current_theme],
self.theme.SUCCESS_COLOR[self.theme.current_theme]
]
# رسم الرسم البياني الدائري
wedges, texts, autotexts = ax.pie(
data['values'],
labels=data['labels'],
autopct='%1.1f%%',
startangle=90,
colors=colors,
wedgeprops={'edgecolor': 'white', 'linewidth': 1},
textprops={'color': self.theme.get_color('fg_color')}
)
# تعيين خصائص النص
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontweight('bold')
# تعيين العنوان
ax.set_title(title)
# جعل الرسم البياني دائريًا
ax.axis('equal')
# تضييق الشكل
fig.tight_layout()
return fig
def create_stacked_bar_chart(self, data, title, xlabel, ylabel):
"""إنشاء رسم بياني شريطي متراكم"""
# إنشاء الشكل والمحاور
fig, ax = plt.subplots(figsize=(8, 5), dpi=100)
# تعيين الألوان
colors = [
self.theme.PRIMARY_COLOR[self.theme.current_theme],
self.theme.SECONDARY_COLOR[self.theme.current_theme],
self.theme.ACCENT_COLOR[self.theme.current_theme],
self.theme.WARNING_COLOR[self.theme.current_theme],
self.theme.SUCCESS_COLOR[self.theme.current_theme]
]
# رسم الرسم البياني الشريطي المتراكم
bottom = np.zeros(len(data['labels']))
for i, category in enumerate(data['categories']):
values = data['values'][i]
bars = ax.bar(data['labels'], values, bottom=bottom, label=category, color=colors[i % len(colors)])
bottom += values
# تعيين العنوان والتسميات
ax.set_title(title)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
# إضافة وسيلة إيضاح
ax.legend()
# إضافة الشبكة
ax.grid(True, linestyle='--', alpha=0.7)
# تضييق الشكل
fig.tight_layout()
return fig
def create_risk_matrix(self, data, title):
"""إنشاء مصفوفة المخاطر"""
# إنشاء الشكل والمحاور
fig, ax = plt.subplots(figsize=(8, 5), dpi=100)
# تعيين الألوان
colors = {
'منخفض': self.theme.SUCCESS_COLOR[self.theme.current_theme],
'متوسط': self.theme.WARNING_COLOR[self.theme.current_theme],
'عالي': self.theme.ERROR_COLOR[self.theme.current_theme]
}
# تعيين قيم المحاور
probability_values = {'منخفض': 1, 'متوسط': 2, 'عالي': 3}
impact_values = {'منخفض': 1, 'متوسط': 2, 'عالي': 3}
# رسم المصفوفة
for risk in data['risks']:
prob = probability_values[risk['probability']]
impact = impact_values[risk['impact']]
color = colors[risk['probability']] if prob > impact else colors[risk['impact']]
ax.scatter(impact, prob, color=color, s=100, alpha=0.7)
ax.annotate(risk['name'], (impact, prob), xytext=(5, 5), textcoords='offset points')
# تعيين حدود المحاور
ax.set_xlim(0.5, 3.5)
ax.set_ylim(0.5, 3.5)
# تعيين تسميات المحاور
ax.set_xticks([1, 2, 3])
ax.set_xticklabels(['منخفض', 'متوسط', 'عالي'])
ax.set_yticks([1, 2, 3])
ax.set_yticklabels(['منخفض', 'متوسط', 'عالي'])
# تعيين العنوان والتسميات
ax.set_title(title)
ax.set_xlabel('التأثير')
ax.set_ylabel('الاحتمالية')
# إضافة الشبكة
ax.grid(True, linestyle='--', alpha=0.7)
# إضافة مناطق المخاطر
# منطقة المخاطر المنخفضة (أخضر)
ax.add_patch(plt.Rectangle((0.5, 0.5), 1, 1, fill=True, color=self.theme.SUCCESS_COLOR[self.theme.current_theme], alpha=0.1))
# منطقة المخاطر المتوسطة (أصفر)
ax.add_patch(plt.Rectangle((1.5, 0.5), 1, 1, fill=True, color=self.theme.WARNING_COLOR[self.theme.current_theme], alpha=0.1))
ax.add_patch(plt.Rectangle((0.5, 1.5), 1, 1, fill=True, color=self.theme.WARNING_COLOR[self.theme.current_theme], alpha=0.1))
# منطقة المخاطر العالية (أحمر)
ax.add_patch(plt.Rectangle((2.5, 0.5), 1, 3, fill=True, color=self.theme.ERROR_COLOR[self.theme.current_theme], alpha=0.1))
ax.add_patch(plt.Rectangle((0.5, 2.5), 2, 1, fill=True, color=self.theme.ERROR_COLOR[self.theme.current_theme], alpha=0.1))
ax.add_patch(plt.Rectangle((1.5, 1.5), 1, 1, fill=True, color=self.theme.ERROR_COLOR[self.theme.current_theme], alpha=0.1))
# تضييق الشكل
fig.tight_layout()
return fig
def embed_chart_in_frame(self, parent, fig):
"""تضمين الرسم البياني في إطار"""
# إنشاء إطار للرسم البياني
chart_frame = ctk.CTkFrame(parent, fg_color="transparent")
# تضمين الرسم البياني في الإطار
canvas = FigureCanvasTkAgg(fig, master=chart_frame)
canvas.draw()
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
return chart_frame
def save_chart(self, fig, name):
"""حفظ الرسم البياني"""
# تحديد مسار الملف
file_path = os.path.join(self.charts_dir, f"{name}.png")
# حفظ الرسم البياني
fig.savefig(file_path, dpi=100, bbox_inches='tight')
return file_path