Spaces:
Runtime error
Runtime error
File size: 5,629 Bytes
ed37a0a b4e14ad ed37a0a d8a4f0d ed37a0a 9f87cb2 0d45547 561b2d9 9f87cb2 561b2d9 b58ea84 561b2d9 b4e14ad 561b2d9 9f87cb2 ed37a0a |
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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
from pathlib import Path
from typing import List, Dict, Tuple
import matplotlib.colors as mpl_colors
import pandas as pd
import seaborn as sns
import shinyswatch
from shiny import App, Inputs, Outputs, Session, reactive, render, req, ui
sns.set_theme()
www_dir = Path(__file__).parent.resolve() / "www"
df = pd.read_csv(Path(__file__).parent / "penguins.csv", na_values="NA")
numeric_cols: List[str] = df.select_dtypes(include=["float64"]).columns.tolist()
species: List[str] = df["Species"].unique().tolist()
species.sort()
app_ui = ui.page_fillable(
shinyswatch.theme.minty(),
ui.layout_sidebar(
ui.sidebar(
ui.input_file("tile_image", "Choose TIFF File", accept=[".tif"], multiple=False),
# Artwork by @allison_horst
ui.input_selectize(
"xvar",
"X variable",
numeric_cols,
selected="Bill Length (mm)",
),
ui.input_selectize(
"yvar",
"Y variable",
numeric_cols,
selected="Bill Depth (mm)",
),
ui.input_checkbox_group(
"species", "Filter by species", species, selected=species
),
ui.hr(),
ui.input_switch("by_species", "Show species", value=True),
ui.input_switch("show_margins", "Show marginal plots", value=True),
),
ui.output_image("uploaded_image"), # display the uploaded TIFF sidewalk tile image
ui.output_ui("value_boxes"),
ui.output_plot("scatter", fill=True),
ui.help_text(
"Artwork by ",
ui.a("@allison_horst", href="https://twitter.com/allison_horst"),
class_="text-end",
),
),
)
def server(input: Inputs, output: Outputs, session: Session):
@reactive.Calc
def uploaded_image_path() -> str:
"""Returns the path to the uploaded image"""
if input.tile_image() is not None:
return input.tile_image()[0] # Assuming multiple=False
else:
return "" # No image uploaded
@output
@render.ui
def uploaded_image():
"""Displays the uploaded image"""
img_src = uploaded_image_path()
if img_src:
return str(ui.tags.img(src="penguins.png", style={"max-width": "100%"}))
else:
return "" # Return an empty string if no image is uploaded
# @output
# @render.image
# def uploaded_image():
# img_src = uploaded_image_path()
# img: ImgData = {"src": img_src, "width": "100px"}
# return img
@reactive.Calc
def filtered_df() -> pd.DataFrame:
"""Returns a Pandas data frame that includes only the desired rows"""
# This calculation "req"uires that at least one species is selected
req(len(input.species()) > 0)
# Filter the rows so we only include the desired species
return df[df["Species"].isin(input.species())]
@output
@render.plot
def scatter():
"""Generates a plot for Shiny to display to the user"""
# The plotting function to use depends on whether margins are desired
plotfunc = sns.jointplot if input.show_margins() else sns.scatterplot
plotfunc(
data=filtered_df(),
x=input.xvar(),
y=input.yvar(),
palette=palette,
hue="Species" if input.by_species() else None,
hue_order=species,
legend=False,
)
@output
@render.ui
def value_boxes():
df = filtered_df()
def penguin_value_box(title: str, count: int, bgcol: str, showcase_img: str):
return ui.value_box(
title,
count,
{"class_": "pt-1 pb-0"},
showcase=ui.fill.as_fill_item(
ui.tags.img(
{"style": "object-fit:contain;"},
src=showcase_img,
)
),
theme_color=None,
style=f"background-color: {bgcol};",
)
if not input.by_species():
return penguin_value_box(
"Penguins",
len(df.index),
bg_palette["default"],
# Artwork by @allison_horst
showcase_img="penguins.png",
)
value_boxes = [
penguin_value_box(
name,
len(df[df["Species"] == name]),
bg_palette[name],
# Artwork by @allison_horst
showcase_img=f"{name}.png",
)
for name in species
# Only include boxes for _selected_ species
if name in input.species()
]
return ui.layout_column_wrap(*value_boxes, width = 1 / len(value_boxes))
# "darkorange", "purple", "cyan4"
colors = [[255, 140, 0], [160, 32, 240], [0, 139, 139]]
colors = [(r / 255.0, g / 255.0, b / 255.0) for r, g, b in colors]
palette: Dict[str, Tuple[float, float, float]] = {
"Adelie": colors[0],
"Chinstrap": colors[1],
"Gentoo": colors[2],
"default": sns.color_palette()[0], # type: ignore
}
bg_palette = {}
# Use `sns.set_style("whitegrid")` to help find approx alpha value
for name, col in palette.items():
# Adjusted n_colors until `axe` accessibility did not complain about color contrast
bg_palette[name] = mpl_colors.to_hex(sns.light_palette(col, n_colors=7)[1]) # type: ignore
app = App(
app_ui,
server,
static_assets=str(www_dir),
)
|