引言
❝
之前我介绍过一些 R 里面的关于 shiny 的知识分享,自己也写过几个制作的 shiny 包,后面在 python 中也开发了类似于 shiny 的框架,Shiny for Python(2022 年首次推出) 是一个框架,专门用来使用 Python 创建交互式 web 应用程序,尤其在 数据分析 和 数据可视化 场景中表现优异。它灵感来源于 R 语言的 Shiny 框架,由 RStudio 团队(现在更名为 Posit)开发,具备与 R 版本类似的核心理念,但设计上更 Pythonic,并融入了 Python 的数据科学生态。虽然 Shiny 最初是为 R 语言设计的,但 Shiny for Python 并不是简单的移植,而是一个全新为 Python 生态设计的框架。
支持两种语法(Core 和 Express) :
Core 是原始的标准语法,提供更强的灵活性和细粒度的控制。
Express 是 2024 年推出的简化语法,降低了新手用户的开发门槛,适合快速开发和构建原型。
以下是 Core,Express 的区别:
两者应用区别:
❝
R 的 Shiny
定位:专为 R 环境设计,主要面向统计学家、数据分析师,以及深度依赖 R 的用户。
生态:和 R 的统计和可视化生态深度结合,如 ggplot2 和 dplyr 等 R 包。Shiny 非常适合需要统计建模和高质量数据可视化的工作流程。
特性:框架更专注于数据展示和解释,这是 Shiny 和 R 的强项。
Shiny for Python
定位:面向 Python 用户,尤其是数据科学家、机器学习工程师和全栈开发者,填补了 Python 中交互式 web 应用开发的空白。
生态:可用 Python 的庞大生态(如 pandas、matplotlib、plotly、scikit-learn)。不仅适合数据分析,也能轻松扩展到机器学习、数据管道或更大规模的应用(如与 FastAPI 或 Flask 集成)。
灵活性:更适合作为多领域开发(数据科学 + 应用程序开发)的工具。
性能和扩展性:
R 的 Shiny
❝
性能:由于 R 是单线程语言,Shiny 的性能在处理大规模数据或并发访问时会受到限制,可能需要通过扩展(如 shinyapps.io 的负载均衡)来提升。
扩展性:R 的 Shiny 专注于数据分析和展示,扩展性较低;不适合作为后端支持更复杂系统的核心服务。
Shiny for Python
性能:Python 可以支持多线程、多进程以及与高性能计算的良好集成,适合更复杂的数据流和并发场景。
扩展性:Shiny for Python 不仅可以用于创建简单的交互数据应用,也非常适合与其他 Python 框架(如 Flask、FastAPI)或工具(如 TensorFlow、PyTorch)配合,支持机器学习、API 开发等更复杂的场景。
安装
学习地址:https://shiny.posit.co/py/docs/overview.html
!pip install –upgrade pip wheel
!pip install shiny
!pip install –upgrade shiny htmltools
在 vscode 拓展里安装 shiny 拓展:
基础入门
主要包含 Inputs,Outputs 和 Layouts 三个部分,类似于 R shiny 的输入控件,ui.input_*() 来添加控件:
from shiny import reactive
from shiny.express import input, ui
ui.input_text(“text”, label=”Enter some text”)
@reactive.effect
def _():
print(input.text())
官网语法有两种,core 语法包含 ui 和 server 两部分,类似于 R,express 的是高度封装的,更易于使用和快速开发:
express:
core:
使用 @render.* 来展示输出:
from shiny.express import input, render, ui
ui.input_text(“text”, label=”Enter some text”)
@render.text
def text_out():
return f”Input text: {input.text()}”
使用 ui.layout_*() 展示不同的布局:
from shiny.express import ui
with ui.layout_column_wrap(gap=”2rem”):
ui.input_slider(“slider1”, “Slider 1”, min=0, max=100, value=50)
ui.input_slider(“slider2”, “Slider 2”, min=0, max=100, value=50)
官网提供了不同的布局示例:
不同类型的控件展示方式:
一个综合示例:
import faicons as fa
import plotly.express as px
from shinywidgets import render_plotly
from shiny import reactive, render, req
from shiny.express import input, ui
Load data and compute static values
tips = px.data.tips()
bill_rng = (min(tips.total_bill), max(tips.total_bill))
Add page title and sidebar
ui.page_opts(title=”Restaurant tipping”, fillable=True)
with ui.sidebar(open=”desktop”):
ui.input_slider(“total_bill”, “Bill amount”, min=bill_rng[0], max=bill_rng[1], value=bill_rng, pre=”$”)
ui.input_checkbox_group(“time”, “Food service”, [“Lunch”, “Dinner”], selected=[“Lunch”, “Dinner”], 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”),
“gear”: fa.icon_svg(“gear”)
}
with ui.layout_columns(fill=False):
with ui.value_box(showcase=ICONS["user"]):
"Total tippers"
@render.express
def total_tippers():
tips_data().shape[0]
with ui.value_box(showcase=ICONS["wallet"]):
"Average tip"
@render.express
def average_tip():
d = tips_data()
if d.shape[0] > 0:
perc = d.tip / d.total_bill
f"{perc.mean():.1%}"
with ui.value_box(showcase=ICONS["currency-dollar"]):
"Average bill"
@render.express
def average_bill():
d = tips_data()
if d.shape[0] > 0:
bill = d.total_bill.mean()
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["gear"]
ui.input_radio_buttons(
"scatter_color", None,
["none", "sex", "smoker", "day", "time"],
inline=True
)
@render_plotly
def scatterplot():
color = input.scatter_color()
return px.scatter(
tips_data(),
x="total_bill",
y="tip",
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["gear"]
ui.input_radio_buttons(
"tip_perc_y", "Split by:",
["sex", "smoker", "day", "time"],
selected="day",
inline=True
)
@render_plotly
def tip_perc():
from ridgeplot import ridgeplot
# Must make a copy of this pandas dataframe before we mutate it!
# See https://shiny.posit.co/py/docs/reactive-mutable.html
dat = tips_data().copy()
dat["percent"] = dat.tip / dat.total_bill
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
——————————————————–
Reactive calculations and effects
——————————————————–
@reactive.calc
def tips_data():
bill = input.total_bill()
idx1 = tips.total_bill.between(bill[0], bill[1])
idx2 = tips.time.isin(input.time())
return tips[idx1 & idx2]
@reactive.effect
@reactive.event(input.reset)
def _():
ui.update_slider(“total_bill”, value=bill_rng)
ui.update_checkbox_group(“time”, selected=[“Lunch”, “Dinner”])
点击箭头 run 即可运行 app:
❝
更多内容和学习可以参看官网教程。
结尾
❝
路漫漫其修远兮,吾将上下而求索。
欢迎加入生信交流群。加我微信我也拉你进 微信群聊 老俊俊生信交流群 (微信交流群需收取 20 元入群费用,一旦交费,拒不退还!(防止骗子和便于管理)) 。
声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/424648.html