File size: 6,186 Bytes
7273765
 
115003c
 
 
 
7273765
 
 
 
115003c
 
 
 
f48c224
7273765
115003c
c33d6cc
7273765
 
 
f48c224
dec834f
7273765
 
 
115003c
7273765
 
115003c
 
c33d6cc
 
7273765
 
c33d6cc
7273765
115003c
7273765
 
 
 
 
 
 
115003c
7273765
 
c33d6cc
7273765
 
 
8398c29
edda389
7273765
 
c33d6cc
7273765
 
 
8398c29
 
a6c3a42
3d65c8f
 
7273765
 
c33d6cc
7273765
 
 
8398c29
 
3d65c8f
 
 
7273765
115003c
7273765
 
c33d6cc
7273765
3d65c8f
7273765
fa380ad
c33d6cc
 
3d65c8f
fa380ad
 
c33d6cc
fa380ad
3d65c8f
fa380ad
 
c33d6cc
115003c
c33d6cc
 
115003c
 
fa380ad
c33d6cc
7273765
3d65c8f
7273765
115003c
3d65c8f
115003c
7273765
 
 
115003c
 
c33d6cc
7273765
 
 
3d65c8f
7273765
 
 
 
 
8398c29
3d65c8f
8398c29
3d65c8f
 
 
7273765
3d65c8f
115003c
7273765
3d65c8f
7273765
 
 
 
 
 
 
 
3d65c8f
7273765
 
 
 
 
 
3d65c8f
 
7273765
115003c
7273765
 
115003c
 
 
7273765
 
 
115003c
 
dbaae56
115003c
 
 
c33d6cc
7273765
 
 
 
c33d6cc
115003c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import faicons as fa
import plotly.express as px
import pandas as pd

# بارگذاری داده‌ها
from shared import app_dir, tips  # فرض بر این است که tips از قبل DataFrame است
from shinywidgets import render_plotly
from shiny import reactive, render
from shiny.express import input, ui

# تبدیل احساس به عدد (تحلیل احساسات)
tips["tip"] = tips["احساس"].map({"مثبت": 1, "خنثی": 0, "منفی": -1})

# تعیین بازه سنی
bill_rng = (min(tips.سن), max(tips.سن))

# صفحه و سایدبار
ui.page_opts(title="تحلیل احساسات کاربران", fillable=True)

with ui.sidebar(open="desktop"):
    ui.input_slider(
        "سن",
        "رنج سنی",
        min=bill_rng[0],
        max=bill_rng[1],
        value=bill_rng,
        pre="سال"
    )
    ui.input_checkbox_group(
        "تاریخ",
        "شبکه اجتماعی",
        tips["شبکه اجتماعی"].unique().tolist(),
        selected=tips["شبکه اجتماعی"].unique().tolist(),
        inline=True,
    )
    ui.input_action_button("reset", "بازنشانی فیلتر")

# آیکون‌ها
ICONS = {
    "user": fa.icon_svg("user", "regular"),
    "wallet": fa.icon_svg("wallet"),
    "currency-dollar": fa.icon_svg("dollar-sign"),
    "ellipsis": fa.icon_svg("ellipsis"),
}

# باکس‌های آماری
with ui.layout_columns(fill=False):
    with ui.value_box(showcase=ICONS["user"]):
        "تعداد کاربران"

        @render.express
        def total_tippers():
            data = tips_data()
            ui.h3(f"تعداد کاربران: {data.shape[0]}")

    with ui.value_box(showcase=ICONS["wallet"]):
        "میانگین احساس"

        @render.express
        def average_tip():
            data = tips_data()
            if data.shape[0] > 0:
                ui.h3(f"میانگین احساس مثبت یا منفی: {data['tip'].mean():.2f}")
            else:
                ui.h3("داده‌ای برای محاسبه میانگین وجود ندارد.")

    with ui.value_box(showcase=ICONS["currency-dollar"]):
        "میانگین سن"

        @render.express
        def average_bill():
            data = tips_data()
            if data.shape[0] > 0:
                ui.h3(f"میانگین سن: {data['سن'].mean():.1f} سال")
            else:
                ui.h3("داده‌ای برای محاسبه میانگین سن وجود ندارد.")

# نمودار و جدول
with ui.layout_columns(col_widths=[6, 6, 12]):
    with ui.card(full_screen=True):
        ui.card_header("جدول داده‌ها")

        # رندر کردن داده‌ها در قالب جدول
        @render.data_frame
        def table():
            return tips_data()

        # رندر کردن نمودار پراکندگی
        @render_plotly
        def scatterplot():
            data = tips_data()
            if data.shape[0] == 0:
                return {}  # بازگرداندن داده‌های خالی در صورت عدم وجود داده
            return px.scatter(
                data,
                x="سن",
                y="tip",
                color="جنسیت",
                trendline="lowess",
                labels={"tip": "امتیاز احساس", "سن": "سن"},
                title="رابطه سن با احساس"
            )

    with ui.card(full_screen=True):
        # عنوان برای تحلیل پراکندگی احساس
        with ui.card_header(class_="d-flex justify-content-between align-items-center"):
            "تحلیل پراکندگی احساس"
            # ایجاد یک Popover برای انتخاب متغیر گروه‌بندی
            with ui.popover(title="گروه‌بندی بر اساس متغیر"):
                ICONS["ellipsis"]
                ui.input_radio_buttons(
                    "tip_perc_y",
                    "گروه‌بندی بر اساس:",
                    ["جنسیت", "تأثیر", "سطح تأثیر", "موضوع"],
                    selected="جنسیت",
                    inline=True,
                )

        # رندر کردن نمودار ridgeplot
        @render_plotly
        def tip_perc():
            from ridgeplot import ridgeplot

            dat = tips_data()
            if dat.shape[0] == 0:
                return {}  # بازگرداندن داده‌های خالی در صورت عدم وجود داده

            dat["percent"] = dat["tip"]  # استفاده از 'tip' به عنوان درصد احساس
            yvar = input.tip_perc_y()  # دریافت انتخاب از کاربر
            uvals = dat[yvar].unique()  # استخراج مقادیر یکتای متغیر انتخابی

            # ایجاد نمونه‌ها برای رسم نمودار ridgeplot
            samples = [[dat.percent[dat[yvar] == val]] for val in uvals]

            # ایجاد نمودار ridgeplot
            plt = ridgeplot(
                samples=samples,
                labels=uvals,
                bandwidth=0.01,
                colorscale="viridis",
                colormode="row-index",
            )

            # تنظیمات نهایی برای نمودار
            plt.update_layout(
                legend=dict(
                    orientation="h", yanchor="bottom", y=1.02, xanchor="center", x=0.5
                )
            )

            return plt  # بازگشت نمودار


# اعمال CSS
ui.include_css(app_dir / "styles.css")

# --------------------------------------------------------
# واکنش‌ها
# --------------------------------------------------------

@reactive.calc
def tips_data():
    سنی = input.سن()
    تاریخ_انتخابی = input.تاریخ()

    idx1 = tips["سن"].between(سنی[0], سنی[1])
    idx2 = tips["شبکه اجتماعی"].isin(تاریخ_انتخابی)
    
    return tips[idx1 & idx2]

@reactive.effect
@reactive.event(input.reset)
def _():
    ui.update_slider("سن", value=bill_rng)
    ui.update_checkbox_group("تاریخ", selected=tips["شبکه اجتماعی"].unique().tolist())