"""Basic App
The purpose is to enable comparision of Panel and Reflex Dashboards.
See https://reflex.dev/docs/getting-started/dashboard-tutorial/.
"""
import panel as pn
import param
import pandas as pd
from panel_modal import Modal
ACCENT = "#805AD5"
pn.extension(
"vizzu",
"tabulator",
"modal",
notifications=True,
design="material",
sizing_mode="stretch_width",
global_css=[f":root {{ --design-primary-color: {ACCENT}; }}"],
)
class User(param.Parameterized):
"""User Model."""
name = param.String(default="")
email = param.String(default="")
gender = param.Selector(objects=["Female", "Male"])
class State(param.Parameterized):
"""Application State."""
users = param.List(
default=[
User(name="Danilo Sousa", email="danilo@panel.org", gender="Male"),
User(name="Zahra Ambessa", email="zahra@panel.org", gender="Female"),
],
item_type=User,
)
user_data = param.DataFrame()
gender_data = param.DataFrame()
def add_user(self, name, email, gender):
"""Add a user and update the data."""
new_user = User(name=name, email=email, gender=gender)
self.users = self.users + [new_user]
@param.depends("users", watch=True, on_init=True)
def _transform_to_table_data(self):
"""Transform user gender group data into a format suitable for visualization in graphs."""
data = [
{"Name": user.name, "Email": user.email, "Gender": user.gender} for user in self.users
]
self.user_data = pd.DataFrame(data).sort_values("Name").reset_index()
@param.depends("users", watch=True, on_init=True)
def _transform_to_plot_data(self):
"""Transform user gender group data into a format suitable for visualization in graphs."""
gender_counts = (
pd.DataFrame([{"gender": user.gender} for user in self.users])
.value_counts()
.reset_index(name="count")
)
gender_counts.columns = ["Name", "Count"]
self.gender_data = gender_counts
state = State()
# Create the Add User Form
new_user = User(name="")
cancel_button = pn.widgets.Button(name="Cancel")
submit_button = pn.widgets.Button(name="Submit", button_type="primary")
message = pn.pane.Alert("Please fill out all fields!", visible=False, alert_type="danger")
add_user_form = pn.Column(
"## Add New User\n\nFill the form with the user's info.",
message,
pn.widgets.TextInput.from_param(new_user.param.name, placeholder="User Name"),
pn.widgets.TextInput.from_param(new_user.param.email, placeholder="name@panel.org"),
pn.widgets.Select.from_param(new_user.param.gender),
pn.Row(cancel_button, submit_button),
)
modal = Modal(add_user_form, width=600, sizing_mode="fixed")
def open_modal(e):
modal.open = True
add_user_button = pn.widgets.Button(
name="Add User",
icon="plus",
button_type="primary",
width=150,
align="center",
on_click=open_modal,
)
header = pn.pane.Markdown(
"# Panel Dashboard", align="center", sizing_mode="fixed", styles={"font-size": "24px", "margin-left": "40px"}
)
user_table = pn.widgets.Tabulator(
state.param.user_data,
theme="materialize",
layout="fit_columns",
show_index=False,
disabled=True,
sortable=False,
)
gender_plot = pn.pane.Vizzu(
state.param.gender_data,
config={"geometry": "rectangle", "x": "Name", "y": "Count"},
duration=400,
style={"plot": {"marker": {"colorPalette": ACCENT}}},
height=400,
sizing_mode="stretch_width",
tooltip=True,
)
credits_text = "Credits: [Reflex Dashboard Tutorial](https://reflex.dev/docs/getting-started/dashboard-tutorial/)"
@param.depends(submit_button.param.value, watch=True)
def submit(_):
name_input = new_user.name
email_input = new_user.email
gender_input = new_user.gender
if name_input and email_input and gender_input:
state.add_user(name=name_input, email=email_input, gender=gender_input)
new_user.name = ""
new_user.email = ""
new_user.gender = "Female"
modal.close = True
message.visible = False
pn.state.notifications.send(
"User added successfully!",
duration=2000,
background=ACCENT,
icon='<i class="fas fa-burn"></i>',
)
else:
message.visible = True
@param.depends(cancel_button.param.value, watch=True)
def close_modal(_):
modal.close = True
pn.Column(
modal,
header,
add_user_button,
user_table,
gender_plot,
credits_text,
max_width=800,
align="center",
styles={"margin": "auto"},
).servable()