Update app.py
Browse files
app.py
CHANGED
@@ -1,22 +1,17 @@
|
|
1 |
import faicons as fa
|
2 |
import plotly.express as px
|
3 |
-
import pandas as pd
|
4 |
-
|
5 |
-
# بارگذاری دادهها
|
6 |
-
from shared import app_dir, tips # فرض بر این است که tips از قبل DataFrame است
|
7 |
from shinywidgets import render_plotly
|
8 |
from shiny import reactive, render
|
9 |
from shiny.express import input, ui
|
|
|
10 |
|
11 |
-
#
|
12 |
-
tips["tip"] = tips["احساس"].map({"مثبت": 1, "خنثی": 0, "منفی": -1})
|
13 |
-
|
14 |
-
# تعیین بازه سنی
|
15 |
bill_rng = (min(tips.سن), max(tips.سن))
|
16 |
|
17 |
-
# صفحه
|
18 |
ui.page_opts(title="تحلیل احساسات کاربران", fillable=True)
|
19 |
|
|
|
20 |
with ui.sidebar(open="desktop"):
|
21 |
ui.input_slider(
|
22 |
"سن",
|
@@ -24,18 +19,20 @@ with ui.sidebar(open="desktop"):
|
|
24 |
min=bill_rng[0],
|
25 |
max=bill_rng[1],
|
26 |
value=bill_rng,
|
27 |
-
pre="سال"
|
28 |
)
|
|
|
29 |
ui.input_checkbox_group(
|
30 |
-
"
|
31 |
-
"شبکه اجتماعی",
|
32 |
tips["شبکه اجتماعی"].unique().tolist(),
|
33 |
selected=tips["شبکه اجتماعی"].unique().tolist(),
|
34 |
inline=True,
|
35 |
)
|
|
|
36 |
ui.input_action_button("reset", "بازنشانی فیلتر")
|
37 |
|
38 |
-
# آیکونها
|
39 |
ICONS = {
|
40 |
"user": fa.icon_svg("user", "regular"),
|
41 |
"wallet": fa.icon_svg("wallet"),
|
@@ -43,7 +40,7 @@ ICONS = {
|
|
43 |
"ellipsis": fa.icon_svg("ellipsis"),
|
44 |
}
|
45 |
|
46 |
-
#
|
47 |
with ui.layout_columns(fill=False):
|
48 |
with ui.value_box(showcase=ICONS["user"]):
|
49 |
"تعداد کاربران"
|
@@ -51,7 +48,7 @@ with ui.layout_columns(fill=False):
|
|
51 |
@render.express
|
52 |
def total_tippers():
|
53 |
data = tips_data()
|
54 |
-
|
55 |
|
56 |
with ui.value_box(showcase=ICONS["wallet"]):
|
57 |
"میانگین احساس"
|
@@ -60,7 +57,7 @@ with ui.layout_columns(fill=False):
|
|
60 |
def average_tip():
|
61 |
data = tips_data()
|
62 |
if data.shape[0] > 0:
|
63 |
-
|
64 |
|
65 |
with ui.value_box(showcase=ICONS["currency-dollar"]):
|
66 |
"میانگین سن"
|
@@ -69,9 +66,9 @@ with ui.layout_columns(fill=False):
|
|
69 |
def average_bill():
|
70 |
data = tips_data()
|
71 |
if data.shape[0] > 0:
|
72 |
-
|
73 |
|
74 |
-
#
|
75 |
with ui.layout_columns(col_widths=[6, 6, 12]):
|
76 |
with ui.card(full_screen=True):
|
77 |
ui.card_header("جدول دادهها")
|
@@ -85,25 +82,24 @@ with ui.layout_columns(col_widths=[6, 6, 12]):
|
|
85 |
data = tips_data()
|
86 |
if data.shape[0] == 0:
|
87 |
return {}
|
|
|
88 |
return px.scatter(
|
89 |
data,
|
90 |
x="سن",
|
91 |
-
y="
|
92 |
color="جنسیت",
|
93 |
trendline="lowess",
|
94 |
-
labels={"tip": "امتیاز احساس", "سن": "سن"},
|
95 |
-
title="رابطه سن با احساس"
|
96 |
)
|
97 |
|
98 |
with ui.card(full_screen=True):
|
99 |
with ui.card_header(class_="d-flex justify-content-between align-items-center"):
|
100 |
-
"
|
101 |
-
with ui.popover(title="
|
102 |
ICONS["ellipsis"]
|
103 |
ui.input_radio_buttons(
|
104 |
"tip_perc_y",
|
105 |
-
"
|
106 |
-
["جنسیت", "
|
107 |
selected="جنسیت",
|
108 |
inline=True,
|
109 |
)
|
@@ -116,11 +112,11 @@ with ui.layout_columns(col_widths=[6, 6, 12]):
|
|
116 |
if dat.shape[0] == 0:
|
117 |
return {}
|
118 |
|
119 |
-
dat["percent"] = dat["
|
120 |
yvar = input.tip_perc_y()
|
121 |
uvals = dat[yvar].unique()
|
122 |
|
123 |
-
samples = [[dat
|
124 |
|
125 |
plt = ridgeplot(
|
126 |
samples=samples,
|
@@ -138,25 +134,23 @@ with ui.layout_columns(col_widths=[6, 6, 12]):
|
|
138 |
|
139 |
return plt
|
140 |
|
141 |
-
#
|
142 |
ui.include_css(app_dir / "styles.css")
|
143 |
|
144 |
-
#
|
145 |
-
# واکنشها
|
146 |
-
# --------------------------------------------------------
|
147 |
|
148 |
@reactive.calc
|
149 |
def tips_data():
|
150 |
-
سنی = input.سن()
|
151 |
-
|
|
|
|
|
|
|
152 |
|
153 |
-
idx1 = tips["سن"].between(سنی[0], سنی[1])
|
154 |
-
idx2 = tips["شبکه اجتماعی"].isin(تاریخ_انتخابی)
|
155 |
-
|
156 |
return tips[idx1 & idx2]
|
157 |
|
158 |
@reactive.effect
|
159 |
@reactive.event(input.reset)
|
160 |
def _():
|
161 |
ui.update_slider("سن", value=bill_rng)
|
162 |
-
ui.update_checkbox_group("
|
|
|
1 |
import faicons as fa
|
2 |
import plotly.express as px
|
|
|
|
|
|
|
|
|
3 |
from shinywidgets import render_plotly
|
4 |
from shiny import reactive, render
|
5 |
from shiny.express import input, ui
|
6 |
+
from shared import app_dir, tips # فرض بر این است که tips دیتافریم شماست
|
7 |
|
8 |
+
# محدودهی سنی موجود در داده
|
|
|
|
|
|
|
9 |
bill_rng = (min(tips.سن), max(tips.سن))
|
10 |
|
11 |
+
# تنظیمات صفحه
|
12 |
ui.page_opts(title="تحلیل احساسات کاربران", fillable=True)
|
13 |
|
14 |
+
# ------------------ Sidebar ------------------
|
15 |
with ui.sidebar(open="desktop"):
|
16 |
ui.input_slider(
|
17 |
"سن",
|
|
|
19 |
min=bill_rng[0],
|
20 |
max=bill_rng[1],
|
21 |
value=bill_rng,
|
22 |
+
pre="سال",
|
23 |
)
|
24 |
+
|
25 |
ui.input_checkbox_group(
|
26 |
+
"شبکه_اجتماعی",
|
27 |
+
"انتخاب شبکه اجتماعی",
|
28 |
tips["شبکه اجتماعی"].unique().tolist(),
|
29 |
selected=tips["شبکه اجتماعی"].unique().tolist(),
|
30 |
inline=True,
|
31 |
)
|
32 |
+
|
33 |
ui.input_action_button("reset", "بازنشانی فیلتر")
|
34 |
|
35 |
+
# ------------------ آیکونها ------------------
|
36 |
ICONS = {
|
37 |
"user": fa.icon_svg("user", "regular"),
|
38 |
"wallet": fa.icon_svg("wallet"),
|
|
|
40 |
"ellipsis": fa.icon_svg("ellipsis"),
|
41 |
}
|
42 |
|
43 |
+
# ------------------ Value Boxes ------------------
|
44 |
with ui.layout_columns(fill=False):
|
45 |
with ui.value_box(showcase=ICONS["user"]):
|
46 |
"تعداد کاربران"
|
|
|
48 |
@render.express
|
49 |
def total_tippers():
|
50 |
data = tips_data()
|
51 |
+
print(data.shape[0])
|
52 |
|
53 |
with ui.value_box(showcase=ICONS["wallet"]):
|
54 |
"میانگین احساس"
|
|
|
57 |
def average_tip():
|
58 |
data = tips_data()
|
59 |
if data.shape[0] > 0:
|
60 |
+
print(data["احساس"].mean())
|
61 |
|
62 |
with ui.value_box(showcase=ICONS["currency-dollar"]):
|
63 |
"میانگین سن"
|
|
|
66 |
def average_bill():
|
67 |
data = tips_data()
|
68 |
if data.shape[0] > 0:
|
69 |
+
print(f"{data['سن'].mean():.1f} سال")
|
70 |
|
71 |
+
# ------------------ جدول و نمودار ------------------
|
72 |
with ui.layout_columns(col_widths=[6, 6, 12]):
|
73 |
with ui.card(full_screen=True):
|
74 |
ui.card_header("جدول دادهها")
|
|
|
82 |
data = tips_data()
|
83 |
if data.shape[0] == 0:
|
84 |
return {}
|
85 |
+
|
86 |
return px.scatter(
|
87 |
data,
|
88 |
x="سن",
|
89 |
+
y="احساس",
|
90 |
color="جنسیت",
|
91 |
trendline="lowess",
|
|
|
|
|
92 |
)
|
93 |
|
94 |
with ui.card(full_screen=True):
|
95 |
with ui.card_header(class_="d-flex justify-content-between align-items-center"):
|
96 |
+
"توزیع احساس بر اساس ویژگیها"
|
97 |
+
with ui.popover(title="انتخاب ویژگی برای مقایسه"):
|
98 |
ICONS["ellipsis"]
|
99 |
ui.input_radio_buttons(
|
100 |
"tip_perc_y",
|
101 |
+
"تفکیک بر اساس:",
|
102 |
+
["جنسیت", "موضوع", "سطح تأثیر"],
|
103 |
selected="جنسیت",
|
104 |
inline=True,
|
105 |
)
|
|
|
112 |
if dat.shape[0] == 0:
|
113 |
return {}
|
114 |
|
115 |
+
dat["percent"] = dat["احساس"]
|
116 |
yvar = input.tip_perc_y()
|
117 |
uvals = dat[yvar].unique()
|
118 |
|
119 |
+
samples = [[dat["percent"][dat[yvar] == val]] for val in uvals]
|
120 |
|
121 |
plt = ridgeplot(
|
122 |
samples=samples,
|
|
|
134 |
|
135 |
return plt
|
136 |
|
137 |
+
# ------------------ CSS ------------------
|
138 |
ui.include_css(app_dir / "styles.css")
|
139 |
|
140 |
+
# ------------------ Reactive ------------------
|
|
|
|
|
141 |
|
142 |
@reactive.calc
|
143 |
def tips_data():
|
144 |
+
رنج_سنی = input.سن()
|
145 |
+
شبکهها = input.شبکه_اجتماعی()
|
146 |
+
|
147 |
+
idx1 = tips["سن"].between(رنج_سنی[0], رنج_سنی[1])
|
148 |
+
idx2 = tips["شبکه اجتماعی"].isin(شبکهها)
|
149 |
|
|
|
|
|
|
|
150 |
return tips[idx1 & idx2]
|
151 |
|
152 |
@reactive.effect
|
153 |
@reactive.event(input.reset)
|
154 |
def _():
|
155 |
ui.update_slider("سن", value=bill_rng)
|
156 |
+
ui.update_checkbox_group("شبکه_اجتماعی", selected=tips["شبکه اجتماعی"].unique().tolist())
|