From b84afd6bc18207f611993c3ebfa6c6aaf75a00aa Mon Sep 17 00:00:00 2001 From: domonik Date: Thu, 21 Aug 2025 13:36:12 +0200 Subject: [PATCH 1/2] changes styling and Welcome page --- RNAdist/dashboard/app.py | 2 +- RNAdist/dashboard/assets/custom.css | 20 ++++++++++++++++-- RNAdist/dashboard/assets/tableFix.css | 12 +++++++++++ RNAdist/dashboard/index.md | 29 +++++++++++++++++++++++---- RNAdist/dashboard/pages/index.py | 2 +- 5 files changed, 57 insertions(+), 8 deletions(-) diff --git a/RNAdist/dashboard/app.py b/RNAdist/dashboard/app.py index cf56105..51d3201 100644 --- a/RNAdist/dashboard/app.py +++ b/RNAdist/dashboard/app.py @@ -74,7 +74,7 @@ def get_navbar(): dbc.Collapse( [ - dbc.NavItem(dbc.NavLink(f"{page['name']}", href=page["relative_path"], id={"type": f"nav-item", "index": idx}), className="p-1") for + dbc.NavItem(dbc.NavLink(f"{page['name']}", href=page["relative_path"], id={"type": f"nav-item", "index": idx}), className="p-1 nav-link-white") for idx, page in enumerate(dash.page_registry.values()) ], is_open=False, diff --git a/RNAdist/dashboard/assets/custom.css b/RNAdist/dashboard/assets/custom.css index 4d22530..68e8ecb 100644 --- a/RNAdist/dashboard/assets/custom.css +++ b/RNAdist/dashboard/assets/custom.css @@ -1,8 +1,24 @@ +a { + color: #00a082 !important; } + a:hover, a:focus { + color: #00a082 !important; + text-decoration: underline; } + +.nav-link-white { + color: white !important; } + .nav-link-white:hover, .nav-link-white:focus { + color: white !important; + text-decoration: none; } + [data-bs-theme="dark"] { - --bs-ufr-navbar: #2c3450; } + --bs-ufr-navbar: #2c3450; + --bs-link-color-rgb: 73, 253, 13; + --bs-info-bg: #5e2455; } [data-bs-theme="light"] { - --bs-ufr-navbar: #344a9a; } + --bs-ufr-navbar: #344a9a; + --bs-link-color-rgb: 52, 74, 154; + --bs-info-bg: rgba(245, 194, 237, 0.3); } .ufr-navbar { background-color: var(--bs-ufr-navbar) !important; } diff --git a/RNAdist/dashboard/assets/tableFix.css b/RNAdist/dashboard/assets/tableFix.css index 0a7587e..9e3926b 100644 --- a/RNAdist/dashboard/assets/tableFix.css +++ b/RNAdist/dashboard/assets/tableFix.css @@ -4,6 +4,18 @@ background: #fff; } +.nav-link { + color: white !important; +} + +.warning { + border-left: 4px solid var(--bs-info); + background-color: var(--bs-info-bg); + padding: 10px; + margin: 10px 0; + border-radius: 4px; +} + .dash-spreadsheet-container .dash-spreadsheet-inner table .dash-cell.active { background-color: inherit !important; diff --git a/RNAdist/dashboard/index.md b/RNAdist/dashboard/index.md index d2149c0..ab20ee7 100644 --- a/RNAdist/dashboard/index.md +++ b/RNAdist/dashboard/index.md @@ -2,8 +2,29 @@ This is the RNAdist Webserver used to calculate nucleotide distances on the ensemble of RNA secondary structures. -In the Navbar at the top you can find and Input field to set your session token. Everything you compute here will be -stored using this token. If you want to access your data later store your token somewhere. +## What does it do +The thermodynamic ensemble of RNA secondary structures refers to the collection of all possible conformations an RNA +molecule can adopt, each associated with a specific probability determined by its free energy. -Note that data will be stored no longer than 7 days and there is the possibility that it gets deleted even earlier -depending on website traffic. Further all our jobs will be public. Meaning everyone that knows your token can access it. \ No newline at end of file +Each RNA secondary structure can be represented as a graph, where nucleotides are nodes and connections are edges. +For simplicity, both backbone links and hydrogen bonds between base pairs are assigned an edge distance of 1, allowing +the structure to be analyzed using standard graph-theoretical methods. + +By sampling structures from the RNA thermodynamic ensemble, one can compute the distances between any two nucleotides +$i$ and $j$ across the sampled graphs. This generates a distribution of distances, reflecting how often different spatial +separations occur in the ensemble and providing insights into the flexibility and connectivity of the RNA molecule. + + +## How to use +Use the Navbar at the top to enter your session token. All computations will be associated with this token, so make +sure to save it if you want to access your data later. + +Next, go to the [**Submission**](/submission) page to enter your RNA sequence and folding/sampling parameters. +Once your job is complete, it will appear as "finished" in the submissions table. + +Finally, visit the [**Visualization**](/visualization) page to explore nucleotide distance distributions and view the +sampled RNA structures. +
+Warning: Note that data will be stored no longer than 7 days and there is the possibility that it gets deleted even earlier +depending on website traffic. Further all our jobs will be public. Meaning everyone that knows your token can access it. +
diff --git a/RNAdist/dashboard/pages/index.py b/RNAdist/dashboard/pages/index.py index 91b42fc..922f2b8 100644 --- a/RNAdist/dashboard/pages/index.py +++ b/RNAdist/dashboard/pages/index.py @@ -21,7 +21,7 @@ def welcome_layout(text): [ html.Div( [ - dcc.Markdown(text, dangerously_allow_html=True, ), + dcc.Markdown(text, dangerously_allow_html=True, mathjax=True), ] ) ] From 37ac036514f6269851358ca6ee992e30b96dceaf Mon Sep 17 00:00:00 2001 From: domonik Date: Thu, 21 Aug 2025 14:25:55 +0200 Subject: [PATCH 2/2] changes i,j plot --- RNAdist/dashboard/pages/visualization.py | 3 +- RNAdist/plots/sampling_plots.py | 50 ++++++++++++++++++++---- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/RNAdist/dashboard/pages/visualization.py b/RNAdist/dashboard/pages/visualization.py index 56c1445..e3eced4 100644 --- a/RNAdist/dashboard/pages/visualization.py +++ b/RNAdist/dashboard/pages/visualization.py @@ -487,7 +487,8 @@ def plot_histo(seq_hash, i, j, switch): fig = plot_distances_with_running_j(matrix, i-1, mfe=mfe) fig.update_layout(legend=dict(orientation="h")) else: - fig = distance_histo_from_matrix(matrix, i-1, j-1) + fig = distance_histo_from_matrix(matrix, i-1, j-1, vertical_spacing=0, row_heights=[0.8, 0.2]) + fig.update_layout(showlegend=False) fig.update_layout({"margin": {"b": 20, "r": 10, "t": 10, "l": 10}}) if not switch: fig.update_layout(DARK_LAYOUT) diff --git a/RNAdist/plots/sampling_plots.py b/RNAdist/plots/sampling_plots.py index c8d1a12..9db34e0 100644 --- a/RNAdist/plots/sampling_plots.py +++ b/RNAdist/plots/sampling_plots.py @@ -3,6 +3,8 @@ import re import time +from plotly.subplots import make_subplots + def empty_figure(annotation: str = None): fig = go.Figure() @@ -39,18 +41,52 @@ def empty_figure(annotation: str = None): ) return fig -def distance_histo_from_matrix(distances, i, j, color:str ="#00a082"): - fig = go.Figure() +def distance_histo_from_matrix(distances, i, j, color:str ="#00a082", **kwargs): + total_counts = distances[0, 0, 0] + + hist = distances[i, j] + q1 = histogram_quantile(hist, 0.25, total_counts) + median = histogram_quantile(hist, 0.5, total_counts) + q3 = histogram_quantile(hist, 0.75, total_counts) + iqr = q3 - q1 + d_min = hist.nonzero()[0].min() + d_max = hist.nonzero()[0].max() + lower_whisker = max(d_min, q1 - 1.5 * iqr) + upper_whisker = min(d_max, q3 + 1.5 * iqr) + x = np.arange(hist.shape[-1]) + weighted_sum = np.sum(hist * x) + ed = weighted_sum / total_counts + + fig = make_subplots(rows=2, shared_xaxes=True, **kwargs) fig.add_trace( go.Bar( - x=np.arange(distances.shape[-1]), - y=distances[i, j] / distances[i, j].sum(), + x=x, + y=hist / hist.sum(), marker=dict(color=color), - ) + name="Histogram", + ), + row=1, col=1 + ) + fig.add_trace( + go.Box( + lowerfence=[float(lower_whisker)], + q1=[float(q1)], + median=[float(median)], + q3=[float(q3)], + upperfence=[float(upper_whisker)], + mean=[float(ed)], + name=f'Box', + marker=dict(color=color), + y=["Distribution"], + boxpoints=False # hide individual points + ), + row=2, col=1 ) fig.update_layout( - xaxis=dict(title="Distance [nt]"), - yaxis=dict(title="Probability") + xaxis2=dict(title="Distance [nt]", showgrid=True), + xaxis=dict(showgrid=True), + yaxis=dict(title="Probability", showgrid=True), + yaxis2=dict(showticklabels=False), ) return fig