Skip to content
Open
6 changes: 6 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ def server(input, output, session):

shared = {
"preloaded_data": preloaded_data, # Preloaded data for initial load
"preloaded_file_path": file_path, # Path to preloaded file for filename extraction
"data_loaded": data_loaded, # Reactive to track if data is loaded
"adata_main": adata_main, # Main anndata object
}
Expand All @@ -124,6 +125,11 @@ def server(input, output, session):
# and add them to the shared dictionary
for key in data_keys:
shared[key] = reactive.Value(None)

# Add reactive value for input filename
shared['input_filename'] = reactive.Value(None)
shared['boxplot_fig'] = reactive.Value(None)
shared['sankey_fig'] = reactive.Value(None)

# Individual server components
getting_started_server(input, output, session, shared)
Expand Down
102 changes: 73 additions & 29 deletions server/anno_vs_anno_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,50 +11,94 @@ def anno_vs_anno_server(input, output, session, shared):
@reactive.event(input.go_sk1, ignore_none=True)
def spac_Sankey():
adata = ad.AnnData(
X=shared['X_data'].get(),
obs=pd.DataFrame(shared['obs_data'].get()),
layers=shared['layers_data'].get(),
X=shared['X_data'].get(),
obs=pd.DataFrame(shared['obs_data'].get()),
layers=shared['layers_data'].get(),
dtype=shared['X_data'].get().dtype
)
if adata is not None:
fig = spac.visualization.sankey_plot(
adata,
source_annotation=input.sk1_anno1(),
target_annotation=input.sk1_anno2()
)
return fig
return None
if adata is None:
return None
fig = spac.visualization.sankey_plot(
adata,
source_annotation=input.sk1_anno1(),
target_annotation=input.sk1_anno2()
)
shared['sankey_fig'].set(fig) # Store figure for HTML download
return fig

@output
@render_widget
@reactive.event(input.go_rhm1, ignore_none=True)
def spac_Relational():
adata = ad.AnnData(
X=shared['X_data'].get(),
X=shared['X_data'].get(),
obs=pd.DataFrame(shared['obs_data'].get())
)
if adata is not None:
result = spac.visualization.relational_heatmap(
adata,
source_annotation=input.rhm_anno1(),
target_annotation=input.rhm_anno2()
)
shared['df_relational'].set(result['data'])
return result['figure']
return None
if adata is None:
return None
result = spac.visualization.relational_heatmap(
adata,
source_annotation=input.rhm_anno1(),
target_annotation=input.rhm_anno2()
)
shared['df_relational'].set(result['data'])
return result['figure']


@render.download(filename="relational_data.csv")
def download_df_1():
df = shared['df_relational'].get()
if df is not None:
csv_string = df.to_csv(index=False)
csv_bytes = csv_string.encode("utf-8")
return csv_bytes, "text/csv"
return None
if df is None:
return None
csv_string = df.to_csv(index=False)
csv_bytes = csv_string.encode("utf-8")
return csv_bytes, "text/csv"


@render.ui
@reactive.event(input.go_rhm1, ignore_none=True)
def download_button_ui_1():
if shared['df_relational'].get() is not None:
return ui.download_button("download_df_1", "Download Data", class_="btn-warning")
return None
if shared['df_relational'].get() is None:
return None
return ui.download_button("download_df_1", "Download Data", class_="btn-warning")

def get_sankey_html_filename():
"""Generate HTML download filename for sankey."""
input_filename = shared['input_filename'].get()
if input_filename:
return f"{input_filename}_sankey.html"
return "sankey.html"

@render.download(filename=get_sankey_html_filename)
def download_sankey_html():
fig = shared['sankey_fig'].get()
if fig is None:
return None
html_string = fig.to_html(include_plotlyjs='cdn')
html_bytes = html_string.encode("utf-8")
return html_bytes, "text/html"

@render.ui
@reactive.event(input.go_sk1, ignore_none=True)
def download_button_ui_sankey():
if shared['sankey_fig'].get() is None:
return None
return ui.input_action_button(
"show_download_modal_sankey",
"Download Data",
class_="btn-warning"
)

@reactive.Effect
@reactive.event(input.show_download_modal_sankey)
def show_download_modal_sankey():
m = ui.modal(
ui.div(
ui.download_button("download_sankey_html", "HTML", class_="btn-primary"),
style="display: flex; gap: 10px; justify-content: center;"
),
title="Select a Format:",
easy_close=True,
footer=None
)
ui.modal_show(m)
59 changes: 30 additions & 29 deletions server/annotations_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,24 @@ def spac_Histogram_2():
adata,
annotation=input.h2_anno()
).values()
shared['df_histogram2'].set(df)
shared['df_histogram2'].set(df)
ax.tick_params(axis='x', rotation=input.anno_slider(), labelsize=10)
return fig

# 2) If "Group By" is CHECKED, we must always supply a
# 2) If "Group By" is CHECKED, we must always supply a
# valid multiple parameter
else:
# If user also checked "Plot Together", use their selected
# If user also checked "Plot Together", use their selected
# stack type
if input.h2_together_check():
# e.g. 'stack', 'dodge', etc.
multiple_param = input.h2_together_drop()
multiple_param = input.h2_together_drop()

together_flag = True
else:
# If grouping by but not "plot together", pick a default layout
# or 'dodge' or any valid string
multiple_param = "layer"
multiple_param = "layer"
together_flag = False

fig, ax, df = spac.visualization.histogram(
Expand All @@ -44,12 +44,12 @@ def spac_Histogram_2():
together=together_flag,
multiple=multiple_param
).values()
shared['df_histogram2'].set(df)
shared['df_histogram2'].set(df)
axes = ax if isinstance(ax, (list, np.ndarray)) else [ax]
for ax in axes:
ax.tick_params(
axis='x',
rotation=input.anno_slider(),
axis='x',
rotation=input.anno_slider(),
labelsize=10
)
return fig
Expand All @@ -59,23 +59,24 @@ def spac_Histogram_2():
@render.ui
@reactive.event(input.go_h2, ignore_none=True)
def download_histogram_button_ui():
if shared['df_histogram2'].get() is not None:
return ui.download_button(
"download_histogram2_df",
"Download Data",
class_="btn-warning"
)
return None
if shared['df_histogram2'].get() is None:
return None
return ui.download_button(
"download_histogram2_df",
"Download Data",
class_="btn-warning"
)



@render.download(filename="annotation_histogram_data.csv")
def download_histogram2_df():
df = shared['df_histogram2'].get()
if df is not None:
csv_string = df.to_csv(index=False)
csv_bytes = csv_string.encode("utf-8")
return csv_bytes, "text/csv"
return None
if df is None:
return None
csv_string = df.to_csv(index=False)
csv_bytes = csv_string.encode("utf-8")
return csv_bytes, "text/csv"

histogram2_ui_initialized = reactive.Value(False)

Expand All @@ -86,8 +87,8 @@ def histogram_reactivity_2():

if btn and not ui_initialized:
dropdown = ui.input_select(
"h2_anno_1",
"Select an Annotation",
"h2_anno_1",
"Select an Annotation",
choices=shared['obs_names'].get()
)
ui.insert_ui(
Expand All @@ -97,8 +98,8 @@ def histogram_reactivity_2():
)

together_check = ui.input_checkbox(
"h2_together_check",
"Plot Together",
"h2_together_check",
"Plot Together",
value=True
)
ui.insert_ui(
Expand All @@ -120,18 +121,18 @@ def histogram_reactivity_2():
def update_stack_type_dropdown():
if input.h2_together_check():
dropdown_together = ui.input_select(
"h2_together_drop",
"Select Stack Type",
choices=['stack', 'layer', 'dodge', 'fill'],
"h2_together_drop",
"Select Stack Type",
choices=['stack', 'layer', 'dodge', 'fill'],
selected='stack'
)
ui.insert_ui(
ui.div({
"id": "inserted-dropdown_together-1"},
"id": "inserted-dropdown_together-1"},
dropdown_together
),
selector="#main-h2_together_drop",
where="beforeEnd"
)
)
else:
ui.remove_ui("#inserted-dropdown_together-1")
Loading