Anis2 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- anis2-0.0.1/Anis/__init__.py +5 -0
- anis2-0.0.1/Anis/main.py +184 -0
- anis2-0.0.1/Anis2.egg-info/PKG-INFO +3 -0
- anis2-0.0.1/Anis2.egg-info/SOURCES.txt +8 -0
- anis2-0.0.1/Anis2.egg-info/dependency_links.txt +1 -0
- anis2-0.0.1/Anis2.egg-info/top_level.txt +1 -0
- anis2-0.0.1/PKG-INFO +3 -0
- anis2-0.0.1/README.md +0 -0
- anis2-0.0.1/setup.cfg +4 -0
- anis2-0.0.1/setup.py +8 -0
anis2-0.0.1/Anis/main.py
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
import numpy as np
|
|
3
|
+
import matplotlib.colors as mcolors
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
def percent_to_number(value):
|
|
7
|
+
if value.endswith("%"):
|
|
8
|
+
number = float(value.strip("%"))
|
|
9
|
+
return number
|
|
10
|
+
else:
|
|
11
|
+
return float(value)
|
|
12
|
+
|
|
13
|
+
def auto_split(text, max_len=12):
|
|
14
|
+
# إذا كان النص قصير لا يحتاج تقسيم
|
|
15
|
+
if len(text) <= max_len:
|
|
16
|
+
return text
|
|
17
|
+
|
|
18
|
+
# تقسيم النص إلى كلمات
|
|
19
|
+
words = text.split()
|
|
20
|
+
lines = []
|
|
21
|
+
current_line = ""
|
|
22
|
+
|
|
23
|
+
for word in words:
|
|
24
|
+
if len(current_line + " " + word) <= max_len:
|
|
25
|
+
current_line += " " + word if current_line else word
|
|
26
|
+
else:
|
|
27
|
+
lines.append(current_line)
|
|
28
|
+
current_line = word
|
|
29
|
+
lines.append(current_line)
|
|
30
|
+
|
|
31
|
+
# دمج الأسطر مع فاصل سطر جديد
|
|
32
|
+
return "\n".join(lines)
|
|
33
|
+
|
|
34
|
+
def make_lighter(color, factor=0.3):
|
|
35
|
+
rgb = mcolors.to_rgb(color)
|
|
36
|
+
lighter_rgb = [(1 - (1 - c) * (1 - factor)) for c in rgb]
|
|
37
|
+
return lighter_rgb
|
|
38
|
+
|
|
39
|
+
def ordinal_suffix(n: int) -> str:
|
|
40
|
+
# الحالات الخاصة للأرقام التي تنتهي بـ 11, 12, 13
|
|
41
|
+
if 11 <= n % 100 <= 13:
|
|
42
|
+
suffix = "th"
|
|
43
|
+
else:
|
|
44
|
+
# اختيار اللاحقة حسب الرقم الأخير
|
|
45
|
+
last_digit = n % 10
|
|
46
|
+
if last_digit == 1:
|
|
47
|
+
suffix = "st"
|
|
48
|
+
elif last_digit == 2:
|
|
49
|
+
suffix = "nd"
|
|
50
|
+
elif last_digit == 3:
|
|
51
|
+
suffix = "rd"
|
|
52
|
+
else:
|
|
53
|
+
suffix = "th"
|
|
54
|
+
return f"{n}{suffix}"
|
|
55
|
+
|
|
56
|
+
def player(dataset,
|
|
57
|
+
First_Tittel="",
|
|
58
|
+
Secend_Tittel="",
|
|
59
|
+
Col_First_Tittel = "#000000",
|
|
60
|
+
Col_Secend_Tittel = "#570101",
|
|
61
|
+
Size_First_Tittel = 12,
|
|
62
|
+
Size_Secend_Tittel = 10,
|
|
63
|
+
bottom_Circle = 10,
|
|
64
|
+
Metric_Col = "black",
|
|
65
|
+
Option_Metric_Col = False
|
|
66
|
+
):
|
|
67
|
+
data = pd.DataFrame(dataset)
|
|
68
|
+
|
|
69
|
+
#تجهيز قائمة للاعبين بدون تكرار
|
|
70
|
+
selected_players = data["Player"].unique()
|
|
71
|
+
|
|
72
|
+
if len(selected_players) > 0:
|
|
73
|
+
# اختيار اللاعب الأول من القائمة
|
|
74
|
+
player_name = selected_players[0]
|
|
75
|
+
|
|
76
|
+
# تصفية البيانات للاعب المحدد
|
|
77
|
+
player_data = data[data["Player"] == player_name]
|
|
78
|
+
|
|
79
|
+
# ترتيب البيانات حسب الصنف
|
|
80
|
+
player_data = player_data.sort_values(by="Category")
|
|
81
|
+
|
|
82
|
+
#تخزين البيانات في قوائم منفصلة
|
|
83
|
+
metrics = player_data["Metric"].astype(str).tolist()
|
|
84
|
+
values = player_data["Value"].tolist()
|
|
85
|
+
colors = player_data["Color"].astype(str).tolist()
|
|
86
|
+
categories = player_data["Category"].astype(str).tolist()
|
|
87
|
+
|
|
88
|
+
#حساب عدد الاحصائيات
|
|
89
|
+
N = len(metrics)
|
|
90
|
+
|
|
91
|
+
#حساب الزوايا لكل إحصائية
|
|
92
|
+
angles = np.linspace(0, 2*np.pi, N+1)
|
|
93
|
+
|
|
94
|
+
#رسم المخطط
|
|
95
|
+
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True))
|
|
96
|
+
|
|
97
|
+
# إعدادات الشكل
|
|
98
|
+
ax.set_ylim(0, 110)
|
|
99
|
+
ax.set_xticks([])
|
|
100
|
+
ax.set_yticks([20, 40, 60, 80, 100])
|
|
101
|
+
ax.set_yticklabels(["20", "40", "60", "80", "100"], fontsize=0)
|
|
102
|
+
|
|
103
|
+
#إخفاء خط الدائرة الخارجية
|
|
104
|
+
ax.spines["polar"].set_visible(False)
|
|
105
|
+
|
|
106
|
+
#رسم الدوائر الدخلية للمخطط
|
|
107
|
+
ax.grid(color="gray", linestyle="--", linewidth=0.7, alpha=0.6)
|
|
108
|
+
|
|
109
|
+
#إخفاء الدوائر الدخلية للمخطط
|
|
110
|
+
ax.grid(False)
|
|
111
|
+
|
|
112
|
+
#رسم الدوائر الخارجية للمخطط
|
|
113
|
+
theta = np.linspace(0, 2*np.pi, 500)
|
|
114
|
+
ax.plot(theta, [100]*500, color="black", linewidth=0)
|
|
115
|
+
|
|
116
|
+
#رسم الخطوط بين كل إحصائية
|
|
117
|
+
for angle in angles[:-1]:
|
|
118
|
+
ax.plot([angle, angle], [bottom_Circle, 100+bottom_Circle],
|
|
119
|
+
color="white", linestyle="-", linewidth=1)
|
|
120
|
+
|
|
121
|
+
# رسم الأجزاء الخارجية والداخلية لكل إحصائية
|
|
122
|
+
for i in range(N):
|
|
123
|
+
start_angle = angles[i]
|
|
124
|
+
end_angle = angles[i+1]
|
|
125
|
+
mid_angle = (start_angle + end_angle) / 2
|
|
126
|
+
val = percent_to_number(values[i])
|
|
127
|
+
base_color = colors[i]
|
|
128
|
+
|
|
129
|
+
# الجزء الخارجي (لون فاتح)
|
|
130
|
+
ax.bar(mid_angle, 100, width=end_angle-start_angle,
|
|
131
|
+
color=make_lighter(base_color,0.8), edgecolor="white" ,bottom=bottom_Circle)
|
|
132
|
+
|
|
133
|
+
# الجزء الداخلي (القيمة الفعلية)
|
|
134
|
+
ax.bar(mid_angle, val, width=end_angle-start_angle,
|
|
135
|
+
color=base_color, edgecolor="white", bottom=bottom_Circle)
|
|
136
|
+
|
|
137
|
+
# كتابة القيمة
|
|
138
|
+
ax.text(mid_angle, 80 + bottom_Circle, f"{val:02.0f}%", ha="center", va="center", fontsize=8,fontweight="bold", color="white",bbox=dict(facecolor=make_lighter(base_color,0.1), edgecolor="none", boxstyle="round,pad=0.2"))
|
|
139
|
+
|
|
140
|
+
# حساب زاوية دوران اسم المقياس
|
|
141
|
+
rotation_angle = np.degrees(mid_angle) + 90
|
|
142
|
+
if 0< np.degrees(mid_angle) < 180:
|
|
143
|
+
rotation_angle += 180
|
|
144
|
+
|
|
145
|
+
#تحديد لون اسم المقياس بناءً على الخيار المحدد
|
|
146
|
+
if Option_Metric_Col == True:
|
|
147
|
+
Metric_Col = base_color
|
|
148
|
+
|
|
149
|
+
# كتابة اسم المقياس
|
|
150
|
+
ax.text(mid_angle, 108+bottom_Circle, auto_split(metrics[i], max_len=12), ha="center", va="center", fontsize=8, fontweight="bold", rotation=rotation_angle, rotation_mode="anchor",color=Metric_Col)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
fig.text(0.515, 0.965, First_Tittel, size=Size_First_Tittel, ha="center", color=Col_First_Tittel, fontweight="bold")
|
|
155
|
+
fig.text(0.515, 0.930, Secend_Tittel, size=Size_Secend_Tittel, ha="center", color=Col_Secend_Tittel, fontweight="bold")
|
|
156
|
+
|
|
157
|
+
categories = list(dict(zip(categories, colors)).items())
|
|
158
|
+
|
|
159
|
+
legend_handles = [ plt.Line2D([0], [0], color="none", label=label) for label, _ in categories]
|
|
160
|
+
|
|
161
|
+
# عرض الأسطورة في الأعلى بسطر واحد
|
|
162
|
+
legend = fig.legend(
|
|
163
|
+
handles=legend_handles,
|
|
164
|
+
loc='upper center',
|
|
165
|
+
bbox_to_anchor=(0.5, 0.06),
|
|
166
|
+
ncol=len(categories),
|
|
167
|
+
frameon=False,
|
|
168
|
+
fontsize=8
|
|
169
|
+
)
|
|
170
|
+
# ضبط لون النص في الأسطورة ليتناسب مع الألوان المستخدمة
|
|
171
|
+
for text, (_, color) in zip(legend.get_texts(), categories):
|
|
172
|
+
text.set_color(color)
|
|
173
|
+
|
|
174
|
+
plt.show()
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Anis
|
anis2-0.0.1/PKG-INFO
ADDED
anis2-0.0.1/README.md
ADDED
|
File without changes
|
anis2-0.0.1/setup.cfg
ADDED