WilhelmHe2002/project_unsupervised_learning
0
1from pathlib import Path2from typing import List, Dict, Tuple3import matplotlib.colors as mpl_colors4 5import pandas as pd6import seaborn as sns7import shinyswatch8 9import shiny.experimental as x10from shiny import App, Inputs, Outputs, Session, reactive, render, req, ui11 12sns.set_theme()13 14www_dir = Path(__file__).parent.resolve() / "www"15 16df = pd.read_csv(Path(__file__).parent / "penguins.csv", na_values="NA")17numeric_cols: List[str] = df.select_dtypes(include=["float64"]).columns.tolist()18species: List[str] = df["Species"].unique().tolist()19species.sort()20 21app_ui = x.ui.page_fillable(22 shinyswatch.theme.minty(),23 ui.layout_sidebar(24 ui.panel_sidebar(25 # Artwork by @allison_horst26 ui.input_selectize(27 "xvar",28 "X variable",29 numeric_cols,30 selected="Bill Length (mm)",31 ),32 ui.input_selectize(33 "yvar",34 "Y variable",35 numeric_cols,36 selected="Bill Depth (mm)",37 ),38 ui.input_checkbox_group(39 "species", "Filter by species", species, selected=species40 ),41 ui.hr(),42 ui.input_switch("by_species", "Show species", value=True),43 ui.input_switch("show_margins", "Show marginal plots", value=True),44 width=2,45 ),46 ui.panel_main(47 ui.output_ui("value_boxes"),48 x.ui.output_plot("scatter", fill=True),49 ui.help_text(50 "Artwork by ",51 ui.a("@allison_horst", href="https://twitter.com/allison_horst"),52 class_="text-end",53 ),54 ),55 ),56)57 58 59def server(input: Inputs, output: Outputs, session: Session):60 @reactive.Calc61 def filtered_df() -> pd.DataFrame:62 """Returns a Pandas data frame that includes only the desired rows"""63 64 # This calculation "req"uires that at least one species is selected65 req(len(input.species()) > 0)66 67 # Filter the rows so we only include the desired species68 return df[df["Species"].isin(input.species())]69 70 @output71 @render.plot72 def scatter():73 """Generates a plot for Shiny to display to the user"""74 75 # The plotting function to use depends on whether margins are desired76 plotfunc = sns.jointplot if input.show_margins() else sns.scatterplot77 78 plotfunc(79 data=filtered_df(),80 x=input.xvar(),81 y=input.yvar(),82 palette=palette,83 hue="Species" if input.by_species() else None,84 hue_order=species,85 legend=False,86 )87 88 @output89 @render.ui90 def value_boxes():91 df = filtered_df()92 93 def penguin_value_box(title: str, count: int, bgcol: str, showcase_img: str):94 return x.ui.value_box(95 title,96 count,97 {"class_": "pt-1 pb-0"},98 showcase=x.ui.as_fill_item(99 ui.tags.img(100 {"style": "object-fit:contain;"},101 src=showcase_img,102 )103 ),104 theme_color=None,105 style=f"background-color: {bgcol};",106 )107 108 if not input.by_species():109 return penguin_value_box(110 "Penguins",111 len(df.index),112 bg_palette["default"],113 # Artwork by @allison_horst114 showcase_img="penguins.png",115 )116 117 value_boxes = [118 penguin_value_box(119 name,120 len(df[df["Species"] == name]),121 bg_palette[name],122 # Artwork by @allison_horst123 showcase_img=f"{name}.png",124 )125 for name in species126 # Only include boxes for _selected_ species127 if name in input.species()128 ]129 130 return x.ui.layout_column_wrap(1 / len(value_boxes), *value_boxes)131 132 133# "darkorange", "purple", "cyan4"134colors = [[255, 140, 0], [160, 32, 240], [0, 139, 139]]135colors = [(r / 255.0, g / 255.0, b / 255.0) for r, g, b in colors]136 137palette: Dict[str, Tuple[float, float, float]] = {138 "Adelie": colors[0],139 "Chinstrap": colors[1],140 "Gentoo": colors[2],141 "default": sns.color_palette()[0], # type: ignore142}143 144bg_palette = {}145# Use `sns.set_style("whitegrid")` to help find approx alpha value146for name, col in palette.items():147 # Adjusted n_colors until `axe` accessibility did not complain about color contrast148 bg_palette[name] = mpl_colors.to_hex(sns.light_palette(col, n_colors=7)[1]) # type: ignore149 150 151app = App(152 app_ui,153 server,154 static_assets=str(www_dir),155)156 