Skip to main content

Two-state thermodynamic analysis (ΔH, ΔS, ΔG, Tm) of RNA melting curves

Project description

rnamelt

PyPI Python versions License: MIT

Two-state thermodynamic analysis (ΔH, ΔS, ΔG, Tm) of UV-absorbance and fluorescence RNA / DNA melting curves. One small, dependency-light Python package that works as a library, a CLI, and a browser app.

  • Libraryfrom rnamelt import MeltAnalysis, typed result objects, optional matplotlib plotting.
  • CLIrnamelt FILE.csv [...] for batch / scripted runs.
  • Browser — the same Python pipeline runs client-side via Pyodide. Live demo: https://tspich.github.io/RNAmelt/.

Install

pip install rnamelt                 # base — numpy, pandas, scipy
pip install 'rnamelt[plots]'        # adds matplotlib for .plot() helpers

Requires Python ≥ 3.10.

Quickstart

from rnamelt import MeltAnalysis

m = MeltAnalysis.from_csv("melt.csv", struct_type="heterodimer")
r = m.single("sample_1", oligo=0.5)     # oligo in µM
print(r.Tm_fit, r.fit.dH, r.fit.dG)
rnamelt melt.csv --column sample_1 --oligo 0.5 --struct-type heterodimer

CSV input format

temperature, sample_1, sample_2, ...
20.0,        0.412,    0.388, ...
20.5,        0.415,    0.391, ...
  • Column 0: temperature in °C (any header name).
  • Columns 1+: absorbance or fluorescence (any header name).
  • Rows entirely NaN, or with a missing temperature, are dropped.

CLI

Same orchestrator as the library. JSON on stdout; pass --csv-out for a results CSV in the same format the browser produces.

# van't Hoff + full fit on every signal column
rnamelt melt.csv --csv-out batch.csv

# single column
rnamelt melt.csv --column sample_1 --struct-type heterodimer \
    --oligo 5.0 --T-low 20 --T-high 90 --csv-out single.csv

# shared-ΔH joint fit across columns
rnamelt melt.csv --column __multi__ --struct-type heterodimer \
    --oligo-multi sample_1=0.5 --oligo-multi sample_2=5.0

# concentration-series van't Hoff (1/Tm vs ln(C_T/f))
rnamelt melt.csv --column __concentration__ --struct-type heterodimer \
    --oligo-multi sample_1=0.5 --oligo-multi sample_2=5.0 --oligo-multi sample_3=50 \
    --csv-out conc.csv

rnamelt --help lists every flag, including three solver-tuning groups (scipy.optimize.least_squares overrides, van't Hoff linearisation, full-fit initial guesses). Exit codes: 0 success, 1 analysis error, 2 bad input.

Python API

The recommended surface is MeltAnalysis. It holds the DataFrame and every configuration knob (struct type, salt, transition window, baseline offsets, solver / vH / fit-init overrides) and exposes the three modes as methods returning typed result objects from rnamelt.results.

from rnamelt import MeltAnalysis, FitFailed

m = MeltAnalysis.from_csv(
    "melt.csv",
    struct_type="heterodimer",   # "heterodimer" | "homodimer" | "monomer"
    salt=150.0,                  # NaCl (mM) — metadata only
    T_low=None, T_high=None,     # transition window (°C); None = full range
    bl_lower_offset=10.0,        # folded baseline span above T_low (°C)
    bl_upper_offset=10.0,        # unfolded baseline span below T_high (°C)
)
m.signal_columns                 # ['sample_1', 'sample_2', ...]

Three modes

# Single column — returns SingleResult; numpy arrays live on the object
r = m.single("sample_1", oligo=0.5)
r.Tm_raw, r.vh.dH, r.fit.Tm, r.fit.dG

try:
    r.fit.require()              # raises FitFailed if not r.fit.ok
except FitFailed as e:
    print(e)

# Shared-ΔH joint fit across columns
multi = m.multi({"sample_1": 0.5, "sample_2": 5.0, "sample_3": 50.0})
multi.dH, multi.dS
for c in multi.columns:
    print(c.name, c.Tm_fit, c.oligoC)

# Concentration-series van't Hoff — three regressions (raw / vH / full fit)
conc = m.concentration({"sample_1": 0.5, "sample_2": 5.0, "sample_3": 50.0})
for s in (conc.series_raw, conc.series_vh, conc.series_fit):
    if s.ok:
        print(s.dH, s.dG_37, s.r_squared)

# Every column at once
batch = m.single_all(oligo=0.5)  # dict[str, SingleResult]

# Export forms (same shape the browser download produces)
r.to_dict(); r.to_dataframe(); r.to_csv("out.csv")

From raw arrays — no CSV

signals accepts a 1D array, a {name: array} mapping, or a 2D array (one column per signal, with optional names=):

import numpy as np
from rnamelt import MeltAnalysis

T = np.linspace(20, 90, 71)

m = MeltAnalysis.from_arrays(T, signal_F4)                        # 1D
m = MeltAnalysis.from_arrays(T, {"F4": sigF4, "F5": sigF5})       # mapping
m = MeltAnalysis.from_arrays(T, arr2d, names=["A", "B", "C"])     # 2D

Plotting (optional)

pip install 'rnamelt[plots]'. Each result class has a .plot() method that lazy-imports rnamelt.plots, so matplotlib never enters the browser/Pyodide bundle.

fig, axes = m.single("F4").plot(figsize=(15, 5))      # raw / vH / full fit
fig, ax   = m.multi(oligo_multi).plot()
fig, axes = m.concentration(oligo_multi).plot()

# Convenience shortcut on the analyzer
fig, axes, result = m.plot("F4")

Functional helpers (back-compat)

Thin wrappers around the same orchestrator that take a cleaned pandas.DataFrame and return the legacy dict directly:

import pandas as pd
from rnamelt import (
    analyze_single, analyze_multi, analyze_concentration, analyze_csv,
)
from rnamelt.cleaning import clean

df = clean(pd.read_csv("melt.csv"))
analyze_single(df, "sample_1", struct_type="heterodimer", oligo=0.5)
analyze_multi(df, {"sample_1": 0.5, "sample_2": 5.0})
analyze_concentration(df, {"sample_1": 0.5, "sample_2": 5.0})

# read_csv + clean + dispatch in one call
analyze_csv("melt.csv", mode="single", column="sample_1", oligo=0.5)

Analysis modes

All three modes go through rnamelt.analysis_melting.run(df, params); the column param selects the mode.

column value Mode What it does
any signal-column name Single column Tm by baseline intersection, van't Hoff linearisation, and a full two-state nonlinear fit. Returns ΔH / ΔS / ΔG / Tm from each method.
__multi__ Shared-ΔH joint fit Fit every column with common ΔH, ΔS but independent baselines. Each column carries its own concentration.
__concentration__ Concentration-series van't Hoff Three Tm values per column (raw / vH / full-fit) → 1/Tm = (R/ΔH)·ln(C_T/f) + ΔS/ΔH regression for each. f = 1 (homodimer) or f = 4 (heterodimer).

Two-state model

Observed signal is a linear combination of folded and unfolded baselines, weighted by the fraction unfolded θ(T):

A(T) = (m_F·T + b_F)·(1 − θ) + (m_U·T + b_U)·θ
K(T) = exp(−ΔG / RT),    ΔG = ΔH − T·ΔS
θ    = K / (1 + K)                       (monomer)
θ    = (√(1 + 8·c₀·K) − 1) / (4·c₀·K)    (dimer)

Units: ΔH in kcal/mol, ΔS in kcal/(mol·K), T in K (T_K = T_C − T0, T0 = −273.15).

Browser app

The same Python package runs client-side via Pyodide; no server, no upload, no install. Drop a CSV onto https://tspich.github.io/RNAmelt/ to try it. The source for the page is index.html in the repository.

Development

git clone https://github.com/tspich/RNAmelt
cd RNAmelt
pip install -e '.[plots]'

pytest tests/                 # or: python -m unittest discover tests
python -m build               # sdist + wheel into dist/

Module layering is strict: functionsmethodsanalysis_meltingapi__main__ / browser. functions stays stateless. plots is lazy-imported so the browser bundle never pulls matplotlib.

License

MIT.

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rnamelt-0.1.0.tar.gz (31.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rnamelt-0.1.0-py3-none-any.whl (36.3 kB view details)

Uploaded Python 3

File details

Details for the file rnamelt-0.1.0.tar.gz.

File metadata

  • Download URL: rnamelt-0.1.0.tar.gz
  • Upload date:
  • Size: 31.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for rnamelt-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c445f1402aeab4f7789c00ffb8496f86c681ddefd0628ef11220e7e784e2b8bb
MD5 30138f5d7ac2cfc101130019351ac3cb
BLAKE2b-256 f825ecb5974c163c96de7299cba2a21a82c52bdbc9e426593ca8ac9e94974b97

See more details on using hashes here.

File details

Details for the file rnamelt-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: rnamelt-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 36.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for rnamelt-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7b43d9d265e6f938feb1079defe9636beee842e9520fc0b4869fd231abb6d29e
MD5 5c0752fac7bdde5c2597e197f24819b6
BLAKE2b-256 3941e5af47d7b12ff14cd816a372c6802689f2a222632f956d6b061e1d5358b1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page