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.1.tar.gz (31.5 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.1-py3-none-any.whl (36.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: rnamelt-0.1.1.tar.gz
  • Upload date:
  • Size: 31.5 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.1.tar.gz
Algorithm Hash digest
SHA256 c36bc8e1b0a6fd2b0ffa8a7c39d210030cbe8ef65e5be3751aaec7153423b96b
MD5 0998c8916a431dd5ad60155711d37468
BLAKE2b-256 8c44e29f49cbd5f7972b7db68fb9f86bcf984e322da8009ea40038aa8ff01238

See more details on using hashes here.

File details

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

File metadata

  • Download URL: rnamelt-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 36.5 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ecfd149302cdd6d16c9516f224ad2b53f452b25abc853be317dd576bc1f42566
MD5 b55545fd83b918368799429fef12bb36
BLAKE2b-256 dafa1d193bf60fed00e41b75b9131e8f10f897ff46b9488895966cd16cba0b94

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