File size: 5,023 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
 
115003c
7273765
 
c33d6cc
7273765
 
 
8398c29
 
115003c
7273765
115003c
7273765
 
c33d6cc
7273765
 
fa380ad
c33d6cc
 
fa380ad
 
c33d6cc
fa380ad
c33d6cc
fa380ad
 
c33d6cc
115003c
c33d6cc
 
115003c
 
fa380ad
c33d6cc
7273765
 
115003c
 
7273765
 
 
115003c
 
c33d6cc
7273765
 
 
 
 
 
 
 
8398c29
c33d6cc
8398c29
115003c
7273765
 
 
115003c
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
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:
                return f"{data['tip'].mean():.2f}"

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

        @render.express
        def average_bill():
            data = tips_data()
            if data.shape[0] > 0:
                return f"{data['سن'].mean():.1f} سال"

# نمودار و جدول
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"):
            "تحلیل پراکندگی احساس"
            with ui.popover(title="گروه‌بندی بر اساس متغیر"):
                ICONS["ellipsis"]
                ui.input_radio_buttons(
                    "tip_perc_y",
                    "گروه‌بندی بر اساس:",
                    ["جنسیت", "تأثیر", "سطح تأثیر", "موضوع"],
                    selected="جنسیت",
                    inline=True,
                )

        @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()

            samples = [[dat.percent[dat[yvar] == val]] for val in uvals]

            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())