-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #99 from posit-dev/expressify-shiny-widgets
Expressify shiny widgets
- Loading branch information
Showing
5 changed files
with
66 additions
and
147 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,21 @@ | ||
import ipyleaflet as L | ||
from htmltools import css | ||
from shiny import App, reactive, render, ui | ||
from shinywidgets import output_widget, reactive_read, register_widget | ||
from shiny import reactive | ||
from shiny.express import input, ui | ||
from shinywidgets import render_widget | ||
import ipyleaflet as ipyl | ||
|
||
app_ui = ui.page_fluid( | ||
ui.div( | ||
ui.input_slider("zoom", "Map zoom level", value=12, min=1, max=18), | ||
ui.output_ui("map_bounds"), | ||
style=css( | ||
display="flex", justify_content="center", align_items="center", gap="2rem" | ||
), | ||
), | ||
output_widget("map"), | ||
) | ||
city_centers = { | ||
"London": (51.5074, 0.1278), | ||
"Paris": (48.8566, 2.3522), | ||
"New York": (40.7128, -74.0060), | ||
} | ||
ui.input_select("center", "Center", choices=list(city_centers.keys())) | ||
|
||
|
||
def server(input, output, session): | ||
# Initialize and display when the session starts (1) | ||
map = L.Map(center=(51.476852, -0.000500), zoom=12, scroll_wheel_zoom=True) | ||
# Add a distance scale | ||
map.add_control(L.leaflet.ScaleControl(position="bottomleft")) | ||
register_widget("map", map) | ||
@render_widget | ||
def map(): | ||
return ipyl.Map(zoom=4) | ||
|
||
# When the slider changes, update the map's zoom attribute (2) | ||
@reactive.Effect | ||
def _(): | ||
map.zoom = input.zoom() | ||
|
||
# When zooming directly on the map, update the slider's value (2 and 3) | ||
@reactive.Effect | ||
def _(): | ||
ui.update_slider("zoom", value=reactive_read(map, "zoom")) | ||
|
||
# Everytime the map's bounds change, update the output message (3) | ||
@output | ||
@render.ui | ||
def map_bounds(): | ||
center = reactive_read(map, "center") | ||
if len(center) == 0: | ||
return | ||
|
||
lat = round(center[0], 4) | ||
lon = (center[1] + 180) % 360 - 180 | ||
lon = round(lon, 4) | ||
|
||
return ui.p(f"Latitude: {lat}", ui.br(), f"Longitude: {lon}") | ||
|
||
|
||
app = App(app_ui, server) | ||
@reactive.effect | ||
def _(): | ||
map.widget.center = city_centers[input.center()] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,17 @@ | ||
import ipywidgets as ipy | ||
from shiny import App, render, ui | ||
from shinywidgets import output_widget, reactive_read, render_widget | ||
from shiny.express import input, ui | ||
from shinywidgets import render_altair | ||
|
||
app_ui = ui.page_fluid(output_widget("slider", height="50px"), ui.output_text("value")) | ||
ui.input_selectize("var", "Select variable", choices=["bill_length_mm", "body_mass_g"]) | ||
|
||
|
||
def server(input, output, session): | ||
s = ipy.IntSlider( | ||
value=5, | ||
min=0, | ||
max=10, | ||
step=1, | ||
description="Test:", | ||
continuous_update=True, | ||
orientation="horizontal", | ||
readout=False, | ||
) | ||
|
||
@output | ||
@render_widget | ||
def slider(): | ||
return s | ||
|
||
@output | ||
@render.text | ||
def value(): | ||
return f"The value of the slider is: {reactive_read(s, 'value')}" | ||
@render_altair | ||
def hist(): | ||
import altair as alt | ||
from palmerpenguins import load_penguins | ||
|
||
|
||
app = App(app_ui, server, debug=True) | ||
df = load_penguins() | ||
return ( | ||
alt.Chart(df) | ||
.mark_bar() | ||
.encode(x=alt.X(f"{input.var()}:Q", bin=True), y="count()") | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
altair | ||
anywidget | ||
palmerpenguins | ||
jsonschema |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,29 @@ | ||
from shiny import render | ||
from shiny.express import ui, input | ||
from shiny.express import ui, input, output, expressify, render | ||
import numpy as np | ||
import matplotlib.pyplot as plt | ||
|
||
|
||
ui.input_radio_buttons( | ||
"type", | ||
"Input Type", | ||
choices=["text", "select", "date", "slider", "other"], | ||
), | ||
ui.input_slider("card_n", "Number of cards", value=3, min=1, max=5) | ||
|
||
|
||
@render.ui | ||
def dyn_ui(): | ||
if input.type() == "text": | ||
return ui.input_text("x", "Text input", placeholder="Enter text") | ||
@expressify | ||
def custom_card(id): | ||
id = id + 1 | ||
with ui.card(): | ||
f"Card {id}" | ||
|
||
elif input.type() == "select": | ||
return ui.input_select( | ||
"x", | ||
"Select", | ||
{"a": "Choice A", "b": "Choice B", "c": "Choice C"}, | ||
) | ||
# Specifying the ID like this lets us include a renderer in the iterator | ||
# without causing ID conflicts. | ||
@output(id=f"hist_{id }") | ||
@render.plot(alt="A histogram") | ||
def histogram(): | ||
np.random.seed(19680801) | ||
x = 100 + 15 * np.random.randn(437) | ||
plt.hist(x, 20, density=True) | ||
|
||
elif input.type() == "date": | ||
return ui.input_date("x", "Choose a date") | ||
|
||
elif input.type() == "slider": | ||
return ui.input_slider("x", "Select a number", 1, 100, 50) | ||
|
||
else: | ||
return ui.div("You selected", ui.tags.b("other", style="color: red;")) | ||
|
||
|
||
@render.text | ||
def txt(): | ||
return f'x is: "{input.x()}"' | ||
@render.express | ||
def cards(): | ||
with ui.layout_columns(): | ||
for i in range(input.card_n()): | ||
custom_card(i) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,14 @@ | ||
# Example of using plotly via shinywidgets | ||
import plotly.express as px | ||
from shiny.express import input, ui | ||
from shinywidgets import render_plotly | ||
|
||
import numpy as np | ||
import plotly.graph_objs as go | ||
from shiny import App, reactive, ui | ||
from shinywidgets import output_widget, register_widget | ||
from sklearn.linear_model import LinearRegression | ||
ui.page_opts(title="Filling layout", fillable=True) | ||
with ui.layout_columns(): | ||
|
||
# Generate some data and fit a linear regression | ||
n = 10000 | ||
dat = np.random.RandomState(0).multivariate_normal([0, 0], [(1, 0.5), (0.5, 1)], n).T | ||
x = dat[0] | ||
y = dat[1] | ||
fit = LinearRegression().fit(x.reshape(-1, 1), dat[1]) | ||
xgrid = np.linspace(start=min(x), stop=max(x), num=30) | ||
@render_plotly | ||
def plot1(): | ||
return px.histogram(px.data.tips(), y="tip") | ||
|
||
app_ui = ui.page_fluid( | ||
ui.input_checkbox("show_fit", "Show fitted line", value=True), | ||
output_widget("scatterplot"), | ||
) | ||
|
||
|
||
def server(input, output, session): | ||
scatterplot = go.FigureWidget( | ||
data=[ | ||
go.Scattergl( | ||
x=x, | ||
y=y, | ||
mode="markers", | ||
marker=dict(color="rgba(0, 0, 0, 0.05)", size=5), | ||
), | ||
go.Scattergl( | ||
x=xgrid, | ||
y=fit.intercept_ + fit.coef_[0] * xgrid, | ||
mode="lines", | ||
line=dict(color="red", width=2), | ||
), | ||
], | ||
layout={"showlegend": False}, | ||
) | ||
|
||
register_widget("scatterplot", scatterplot) | ||
|
||
@reactive.Effect | ||
def _(): | ||
scatterplot.data[1].visible = input.show_fit() | ||
|
||
|
||
app = App(app_ui, server) | ||
@render_plotly | ||
def plot2(): | ||
return px.histogram(px.data.tips(), y="total_bill") |