Nociceptor Innervation Suite
1. Quantifier
2. Analyst
3. Illustrator
Image Quantifier
Drag & Drop folder logic supported via "Load Files".
1. Load -> 2. Draw ROI -> 3. Calc -> 4. Save
📂 Load Images
No files loaded
Contrast
Brightness
Noise Blur
Show Threshold (Red)
Threshold Method
Manual Cutoff
Auto (Otsu)
✏️ Draw ROI
Reset View
Calculate Index
--
💾 Save & Next
❌ Skip
⬇️ Download Log (.txt)
1. CFA Mice
Left (Inj)
0
+ Add Left
Right (Ctrl)
0
+ Add Right
2. Carrageenan Mice
Left (Inj)
0
+ Add Left
Right (Ctrl)
0
+ Add Right
GENERATE STATISTICS
Mode
Group Comparison
Raw Data
Title
Y-Label
Title Size
Label Size
Python Environment Loading...
(Once loaded, upload files on the left and click Generate)
1. Grid Configuration
Cols (Time)
Rows (Ch)
Include Merge
Create Grid
2. Upload Images
3. Finalize
Scale (µm)
Px/µm
Main Label
Header Size
Label Size
Bar H (%)
Color
Render Figure
Download PNG
Processing...
import pandas as pd import numpy as np import matplotlib.pyplot as plt import matplotlib.patches as mpatches from scipy import stats from js import document, alert from pyodide.ffi import create_proxy import io, base64 STORE = { "CFA_L": [], "CFA_R": [], "Carr_L": [], "Carr_R": [] } NAMES = { "CFA_L": [], "CFA_R": [], "Carr_L": [], "Carr_R": [] } async def add_files(key, input_id, badge_id): inp = document.getElementById(input_id) files = inp.files if files.length == 0: return for i in range(files.length): f = files.item(i) raw_name = f.name text = await f.text() clean = text.replace(',', ' ').replace('\t', ' ') tokens = clean.split() nums = [] for t in tokens: try: nums.append(float(t)) except: pass if nums: STORE[key].append(np.mean(nums)) NAMES[key].append(raw_name) bdg = document.getElementById(badge_id) bdg.innerText = f"{len(STORE[key])}" bdg.classList.add("active") inp.value = "" async def add_cfa_l(e): await add_files("CFA_L", "an_in_CFA_L", "bdg_CFA_L") async def add_cfa_r(e): await add_files("CFA_R", "an_in_CFA_R", "bdg_CFA_R") async def add_carr_l(e): await add_files("Carr_L", "an_in_Carr_L", "bdg_Carr_L") async def add_carr_r(e): await add_files("Carr_R", "an_in_Carr_R", "bdg_Carr_R") def run_analysis(event): if len(STORE["CFA_L"]) == 0: return alert("No Data Loaded") mode = document.getElementById("an-mode").value title = document.getElementById("an-title").value ylabel = document.getElementById("an-ylabel").value fs_title = int(document.getElementById("an-fs-title").value) fs_label = int(document.getElementById("an-fs-label").value) fig = None if mode == "ratio": fig = plot_summary(title, ylabel, fs_title, fs_label) else: fig = plot_raw(title, ylabel, fs_title, fs_label) document.getElementById("an-plot-area").innerHTML = "" display(fig, target="an-plot-area", append=False) # --- SAFE SEM FUNCTION (Handles N=1) --- def safe_sem(data): if len(data) < 2: return 0.0 return stats.sem(data) # --- SAFE T-TEST FUNCTION (Handles N<2 or Identical Data) --- def safe_ttest(g1, g2): if len(g1) < 2 or len(g2) < 2: return 1.0 # Not significant if not enough data if np.allclose(g1, g2): return 1.0 # Identical data = p-value 1.0 try: t, p = stats.ttest_rel(g1, g2) if np.isnan(p): return 1.0 return p except: return 1.0 def plot_summary(title, ylabel, fs_t, fs_l): cfa_r, cfa_l = STORE["CFA_R"], STORE["CFA_L"] carr_r, carr_l = STORE["Carr_R"], STORE["Carr_L"] # Validation for pairs if len(cfa_r) != len(cfa_l): return alert("CFA groups mismatch (L vs R count)") if len(carr_r) != len(carr_l): return alert("Carr groups mismatch (L vs R count)") # Calculate stats using SAFE functions means = [np.mean(cfa_r), np.mean(cfa_l), np.mean(carr_r), np.mean(carr_l)] sems = [safe_sem(cfa_r), safe_sem(cfa_l), safe_sem(carr_r), safe_sem(carr_l)] # Safe T-Tests p_cfa = safe_ttest(cfa_r, cfa_l) p_carr = safe_ttest(carr_r, carr_l) fig, ax = plt.subplots(figsize=(8, 6)) colors = ["#ccc", "#e74c3c", "#ccc", "#3498db"] x_pos = [0,1,2.5,3.5] # Bars ax.bar(x_pos, means, yerr=sems, capsize=5, color=colors, edgecolor='black', width=0.8) # Scatter & Lines # CFA for i in range(len(cfa_r)): ax.plot([0,1], [cfa_r[i], cfa_l[i]], color='black', alpha=0.3, lw=0.5) ax.scatter([0,1], [cfa_r[i], cfa_l[i]], color='black', alpha=0.5, s=20) # Carr for i in range(len(carr_r)): ax.plot([2.5,3.5], [carr_r[i], carr_l[i]], color='black', alpha=0.3, lw=0.5) ax.scatter([2.5,3.5], [carr_r[i], carr_l[i]], color='black', alpha=0.5, s=20) # Brackets Function def draw_bracket(x1, x2, p_val, y_max): h = y_max * 0.05 y_top = y_max + h ax.plot([x1, x1, x2, x2], [y_top-h*0.5, y_top, y_top, y_top-h*0.5], lw=1.5, c='black') star = "ns" if p_val < 0.001: star = "***" elif p_val < 0.01: star = "**" elif p_val < 0.05: star = "*" ax.text((x1+x2)/2, y_top, star, ha='center', va='bottom', fontsize=fs_l, fontweight='bold') return y_top # Calculate Y-Limits y_max_cfa = max(max(cfa_r), max(cfa_l)) if cfa_r else 0 y_max_carr = max(max(carr_r), max(carr_l)) if carr_r else 0 h1 = draw_bracket(0, 1, p_cfa, y_max_cfa) h2 = draw_bracket(2.5, 3.5, p_carr, y_max_carr) ax.set_ylim(bottom=0, top=max(h1, h2)*1.15) ax.set_xticks(x_pos) ax.set_xticklabels(["CFA\nCtrl", "CFA\nInj", "Carr\nCtrl", "Carr\nInj"], fontsize=fs_l) ax.set_title(title, fontsize=fs_t, fontweight='bold') ax.set_ylabel(ylabel, fontsize=fs_l) ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) stats_div = document.getElementById("an-stats-area") stats_div.style.display = "block" stats_div.innerText = f"CFA P-Value: {p_cfa:.5f}\nCarr P-Value: {p_carr:.5f}" plt.tight_layout() return fig def plot_raw(title, ylabel, fs_t, fs_l): fig, ax = plt.subplots(figsize=(10, 5)) labels = [] vals = [] colors = [] # Flatten data for raw plot for i, v in enumerate(STORE["CFA_R"]): labels.append(f"CFA_R_{i+1}"); vals.append(v); colors.append("#ccc") labels.append(f"CFA_L_{i+1}"); vals.append(STORE["CFA_L"][i]); colors.append("#e74c3c") ax.bar(range(len(vals)), vals, color=colors, edgecolor='black') ax.set_xticks(range(len(vals))) ax.set_xticklabels(labels, rotation=45, ha='right', fontsize=fs_l*0.8) ax.set_title(title + " (Raw Data)", fontsize=fs_t) ax.set_ylabel(ylabel, fontsize=fs_l) ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) plt.tight_layout() return fig def main(): document.getElementById("btn_add_CFA_L").addEventListener("click", create_proxy(add_cfa_l)) document.getElementById("btn_add_CFA_R").addEventListener("click", create_proxy(add_cfa_r)) document.getElementById("btn_add_Carr_L").addEventListener("click", create_proxy(add_carr_l)) document.getElementById("btn_add_Carr_R").addEventListener("click", create_proxy(add_carr_r)) document.getElementById("an-btn-run").addEventListener("click", create_proxy(run_analysis)) main()