File size: 4,755 Bytes
7273765
 
 
 
 
a9cc302
7273765
a9cc302
f48c224
7273765
a9cc302
c33d6cc
7273765
a9cc302
7273765
 
f48c224
dec834f
7273765
 
 
a9cc302
7273765
a9cc302
7273765
a9cc302
 
c33d6cc
 
7273765
 
a9cc302
c33d6cc
7273765
a9cc302
7273765
 
 
 
 
 
 
a9cc302
7273765
 
c33d6cc
7273765
 
 
8398c29
a9cc302
7273765
 
c33d6cc
7273765
 
 
8398c29
 
a9cc302
7273765
 
c33d6cc
7273765
 
 
8398c29
 
a9cc302
7273765
a9cc302
7273765
 
c33d6cc
7273765
 
fa380ad
c33d6cc
 
fa380ad
 
c33d6cc
fa380ad
c33d6cc
a9cc302
fa380ad
 
c33d6cc
a9cc302
c33d6cc
 
fa380ad
c33d6cc
7273765
 
a9cc302
 
7273765
 
 
a9cc302
 
c33d6cc
7273765
 
 
 
 
 
 
 
8398c29
c33d6cc
8398c29
a9cc302
7273765
 
 
a9cc302
7273765
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a9cc302
7273765
 
a9cc302
7273765
 
 
a9cc302
 
 
 
 
dbaae56
c33d6cc
7273765
 
 
 
c33d6cc
a9cc302
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
import faicons as fa
import plotly.express as px
from shinywidgets import render_plotly
from shiny import reactive, render
from shiny.express import input, ui
from shared import app_dir, tips  # فرض بر این است که tips دیتافریم شماست

# محدوده‌ی سنی موجود در داده
bill_rng = (min(tips.سن), max(tips.سن))

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

# ------------------ Sidebar ------------------
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"),
}

# ------------------ Value Boxes ------------------
with ui.layout_columns(fill=False):
    with ui.value_box(showcase=ICONS["user"]):
        "تعداد کاربران"

        @render.express
        def total_tippers():
            data = tips_data()
            print(data.shape[0])

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

        @render.express
        def average_tip():
            data = tips_data()
            if data.shape[0] > 0:
                print(data["احساس"].mean())

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

        @render.express
        def average_bill():
            data = tips_data()
            if data.shape[0] > 0:
                print(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="احساس",
                color="جنسیت",
                trendline="lowess",
            )

    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["احساس"]
            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 ------------------

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