import faicons as fa import plotly.express as px # Load data and compute static values from shared import app_dir, tips from shinywidgets import render_plotly from shiny import reactive, render from shiny.express import input, ui bill_rng = (min(tips.سن), max(tips.سن)) # Add page title and sidebar ui.page_opts(title="Restaurant tipping", 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( "تاریخ", " service", ["Twitter", "Instagram"], selected=["Twitter", "Instagram"], inline=True, ) ui.input_action_button("reset", "Reset filter") # Add main content 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"]): "id" @render.express def total_tippers(): data = tips_data() return data.shape[0] with ui.value_box(showcase=ICONS["wallet"]): "Average tip" @render.express def average_tip(): data = tips_data() if data.shape[0] > 0: perc = data.tip / data.سن return f"{perc.mean():.1%}" with ui.value_box(showcase=ICONS["currency-dollar"]): "Average bill" @render.express def average_bill(): data = tips_data() if data.shape[0] > 0: bill = data.سن.mean() return f"${bill:.2f}" with ui.layout_columns(col_widths=[6, 6, 12]): with ui.card(full_screen=True): ui.card_header("Tips data") @render.data_frame def table(): return render.DataGrid(tips_data()) with ui.card(full_screen=True): with ui.card_header(class_="d-flex justify-content-between align-items-center"): "Total bill vs tip" with ui.popover(title="Add a color variable", placement="top"): ICONS["ellipsis"] ui.input_radio_buttons( "scatter_color", None, ["none", "جنسیت", "تأثیر", "سطح ", "موضوع"], inline=True, ) @render_plotly def scatterplot(): color = input.scatter_color() data = tips_data() if data.shape[0] == 0: return {} # return empty plot if no data available return px.scatter( data, x="سن", y="id", color=None if color == "none" else color, trendline="lowess", ) with ui.card(full_screen=True): with ui.card_header(class_="d-flex justify-content-between align-items-center"): "Tip percentages" with ui.popover(title="Add a color variable"): ICONS["ellipsis"] ui.input_radio_buttons( "tip_perc_y", "Split by:", [ "جنسیت", "تأثیر", "سطح ", "موضوع"], selected="day", inline=True, ) @render_plotly def tip_perc(): from ridgeplot import ridgeplot dat = tips_data() if dat.shape[0] == 0: return {} # return empty plot if no data available dat["percent"] = dat.tip / 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 ui.include_css(app_dir / "styles.css") # -------------------------------------------------------- # Reactive calculations and effects # -------------------------------------------------------- @reactive.calc def tips_data(): سنی = input.سن() idx1 = tips.سن.between(سنی[0], سنی[1]) # Corrected range filter idx2 = tips.تاریخ.isin(input.time()) # Filter based on selected time (Twitter, Instagram) return tips[idx1 & idx2] # Apply filters to the tips data @reactive.effect @reactive.event(input.reset) def _(): ui.update_slider("رنج سنی", value=bill_rng) ui.update_checkbox_group("تاریخ", selected=["Twitter", "Instagram"])