rnamelt 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ __pycache__
rnamelt-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 tspich
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
rnamelt-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,258 @@
1
+ Metadata-Version: 2.4
2
+ Name: rnamelt
3
+ Version: 0.1.0
4
+ Summary: Two-state thermodynamic analysis (ΔH, ΔS, ΔG, Tm) of RNA melting curves
5
+ Project-URL: Homepage, https://github.com/tspich/RNAmelt
6
+ Project-URL: Issues, https://github.com/tspich/RNAmelt/issues
7
+ Author: tspich, RaumZeit
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: melting curve,rna,thermodynamics
11
+ Requires-Python: >=3.10
12
+ Requires-Dist: numpy>=1.23
13
+ Requires-Dist: pandas>=1.5
14
+ Requires-Dist: scipy>=1.10
15
+ Provides-Extra: plots
16
+ Requires-Dist: matplotlib>=3.5; extra == 'plots'
17
+ Description-Content-Type: text/markdown
18
+
19
+ # rnamelt
20
+
21
+ [![PyPI](https://img.shields.io/pypi/v/rnamelt.svg)](https://pypi.org/project/rnamelt/)
22
+ [![Python versions](https://img.shields.io/pypi/pyversions/rnamelt.svg)](https://pypi.org/project/rnamelt/)
23
+ [![License: MIT](https://img.shields.io/pypi/l/rnamelt.svg)](https://github.com/tspich/RNAmelt/blob/main/LICENSE)
24
+
25
+ Two-state thermodynamic analysis (ΔH, ΔS, ΔG, Tm) of UV-absorbance and
26
+ fluorescence RNA / DNA melting curves. One small, dependency-light Python
27
+ package that works as a library, a CLI, and a browser app.
28
+
29
+ - **Library** — `from rnamelt import MeltAnalysis`, typed result objects,
30
+ optional `matplotlib` plotting.
31
+ - **CLI** — `rnamelt FILE.csv [...]` for batch / scripted runs.
32
+ - **Browser** — the same Python pipeline runs client-side via Pyodide.
33
+ Live demo: <https://tspich.github.io/RNAmelt/>.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ pip install rnamelt # base — numpy, pandas, scipy
39
+ pip install 'rnamelt[plots]' # adds matplotlib for .plot() helpers
40
+ ```
41
+
42
+ Requires Python ≥ 3.10.
43
+
44
+ ## Quickstart
45
+
46
+ ```python
47
+ from rnamelt import MeltAnalysis
48
+
49
+ m = MeltAnalysis.from_csv("melt.csv", struct_type="heterodimer")
50
+ r = m.single("sample_1", oligo=0.5) # oligo in µM
51
+ print(r.Tm_fit, r.fit.dH, r.fit.dG)
52
+ ```
53
+
54
+ ```bash
55
+ rnamelt melt.csv --column sample_1 --oligo 0.5 --struct-type heterodimer
56
+ ```
57
+
58
+ ## CSV input format
59
+
60
+ ```
61
+ temperature, sample_1, sample_2, ...
62
+ 20.0, 0.412, 0.388, ...
63
+ 20.5, 0.415, 0.391, ...
64
+ ```
65
+
66
+ - Column 0: temperature in °C (any header name).
67
+ - Columns 1+: absorbance or fluorescence (any header name).
68
+ - Rows entirely NaN, or with a missing temperature, are dropped.
69
+
70
+ ## CLI
71
+
72
+ Same orchestrator as the library. JSON on stdout; pass `--csv-out` for a
73
+ results CSV in the same format the browser produces.
74
+
75
+ ```bash
76
+ # van't Hoff + full fit on every signal column
77
+ rnamelt melt.csv --csv-out batch.csv
78
+
79
+ # single column
80
+ rnamelt melt.csv --column sample_1 --struct-type heterodimer \
81
+ --oligo 5.0 --T-low 20 --T-high 90 --csv-out single.csv
82
+
83
+ # shared-ΔH joint fit across columns
84
+ rnamelt melt.csv --column __multi__ --struct-type heterodimer \
85
+ --oligo-multi sample_1=0.5 --oligo-multi sample_2=5.0
86
+
87
+ # concentration-series van't Hoff (1/Tm vs ln(C_T/f))
88
+ rnamelt melt.csv --column __concentration__ --struct-type heterodimer \
89
+ --oligo-multi sample_1=0.5 --oligo-multi sample_2=5.0 --oligo-multi sample_3=50 \
90
+ --csv-out conc.csv
91
+ ```
92
+
93
+ `rnamelt --help` lists every flag, including three solver-tuning groups
94
+ (`scipy.optimize.least_squares` overrides, van't Hoff linearisation,
95
+ full-fit initial guesses). Exit codes: `0` success, `1` analysis error,
96
+ `2` bad input.
97
+
98
+ ## Python API
99
+
100
+ The recommended surface is `MeltAnalysis`. It holds the DataFrame and
101
+ every configuration knob (struct type, salt, transition window, baseline
102
+ offsets, solver / vH / fit-init overrides) and exposes the three modes as
103
+ methods returning typed result objects from `rnamelt.results`.
104
+
105
+ ```python
106
+ from rnamelt import MeltAnalysis, FitFailed
107
+
108
+ m = MeltAnalysis.from_csv(
109
+ "melt.csv",
110
+ struct_type="heterodimer", # "heterodimer" | "homodimer" | "monomer"
111
+ salt=150.0, # NaCl (mM) — metadata only
112
+ T_low=None, T_high=None, # transition window (°C); None = full range
113
+ bl_lower_offset=10.0, # folded baseline span above T_low (°C)
114
+ bl_upper_offset=10.0, # unfolded baseline span below T_high (°C)
115
+ )
116
+ m.signal_columns # ['sample_1', 'sample_2', ...]
117
+ ```
118
+
119
+ ### Three modes
120
+
121
+ ```python
122
+ # Single column — returns SingleResult; numpy arrays live on the object
123
+ r = m.single("sample_1", oligo=0.5)
124
+ r.Tm_raw, r.vh.dH, r.fit.Tm, r.fit.dG
125
+
126
+ try:
127
+ r.fit.require() # raises FitFailed if not r.fit.ok
128
+ except FitFailed as e:
129
+ print(e)
130
+
131
+ # Shared-ΔH joint fit across columns
132
+ multi = m.multi({"sample_1": 0.5, "sample_2": 5.0, "sample_3": 50.0})
133
+ multi.dH, multi.dS
134
+ for c in multi.columns:
135
+ print(c.name, c.Tm_fit, c.oligoC)
136
+
137
+ # Concentration-series van't Hoff — three regressions (raw / vH / full fit)
138
+ conc = m.concentration({"sample_1": 0.5, "sample_2": 5.0, "sample_3": 50.0})
139
+ for s in (conc.series_raw, conc.series_vh, conc.series_fit):
140
+ if s.ok:
141
+ print(s.dH, s.dG_37, s.r_squared)
142
+
143
+ # Every column at once
144
+ batch = m.single_all(oligo=0.5) # dict[str, SingleResult]
145
+
146
+ # Export forms (same shape the browser download produces)
147
+ r.to_dict(); r.to_dataframe(); r.to_csv("out.csv")
148
+ ```
149
+
150
+ ### From raw arrays — no CSV
151
+
152
+ `signals` accepts a 1D array, a `{name: array}` mapping, or a 2D array
153
+ (one column per signal, with optional `names=`):
154
+
155
+ ```python
156
+ import numpy as np
157
+ from rnamelt import MeltAnalysis
158
+
159
+ T = np.linspace(20, 90, 71)
160
+
161
+ m = MeltAnalysis.from_arrays(T, signal_F4) # 1D
162
+ m = MeltAnalysis.from_arrays(T, {"F4": sigF4, "F5": sigF5}) # mapping
163
+ m = MeltAnalysis.from_arrays(T, arr2d, names=["A", "B", "C"]) # 2D
164
+ ```
165
+
166
+ ### Plotting (optional)
167
+
168
+ `pip install 'rnamelt[plots]'`. Each result class has a `.plot()` method
169
+ that lazy-imports `rnamelt.plots`, so matplotlib never enters the
170
+ browser/Pyodide bundle.
171
+
172
+ ```python
173
+ fig, axes = m.single("F4").plot(figsize=(15, 5)) # raw / vH / full fit
174
+ fig, ax = m.multi(oligo_multi).plot()
175
+ fig, axes = m.concentration(oligo_multi).plot()
176
+
177
+ # Convenience shortcut on the analyzer
178
+ fig, axes, result = m.plot("F4")
179
+ ```
180
+
181
+ ### Functional helpers (back-compat)
182
+
183
+ Thin wrappers around the same orchestrator that take a cleaned
184
+ `pandas.DataFrame` and return the legacy dict directly:
185
+
186
+ ```python
187
+ import pandas as pd
188
+ from rnamelt import (
189
+ analyze_single, analyze_multi, analyze_concentration, analyze_csv,
190
+ )
191
+ from rnamelt.cleaning import clean
192
+
193
+ df = clean(pd.read_csv("melt.csv"))
194
+ analyze_single(df, "sample_1", struct_type="heterodimer", oligo=0.5)
195
+ analyze_multi(df, {"sample_1": 0.5, "sample_2": 5.0})
196
+ analyze_concentration(df, {"sample_1": 0.5, "sample_2": 5.0})
197
+
198
+ # read_csv + clean + dispatch in one call
199
+ analyze_csv("melt.csv", mode="single", column="sample_1", oligo=0.5)
200
+ ```
201
+
202
+ ## Analysis modes
203
+
204
+ All three modes go through `rnamelt.analysis_melting.run(df, params)`;
205
+ the `column` param selects the mode.
206
+
207
+ | `column` value | Mode | What it does |
208
+ |------------------------|-------------------------------------|--------------|
209
+ | 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. |
210
+ | `__multi__` | **Shared-ΔH joint fit** | Fit every column with common ΔH, ΔS but independent baselines. Each column carries its own concentration. |
211
+ | `__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). |
212
+
213
+ ## Two-state model
214
+
215
+ Observed signal is a linear combination of folded and unfolded baselines,
216
+ weighted by the fraction unfolded θ(T):
217
+
218
+ ```
219
+ A(T) = (m_F·T + b_F)·(1 − θ) + (m_U·T + b_U)·θ
220
+ K(T) = exp(−ΔG / RT), ΔG = ΔH − T·ΔS
221
+ θ = K / (1 + K) (monomer)
222
+ θ = (√(1 + 8·c₀·K) − 1) / (4·c₀·K) (dimer)
223
+ ```
224
+
225
+ Units: ΔH in kcal/mol, ΔS in kcal/(mol·K), T in K
226
+ (`T_K = T_C − T0`, `T0 = −273.15`).
227
+
228
+ ## Browser app
229
+
230
+ The same Python package runs client-side via [Pyodide](https://pyodide.org/);
231
+ no server, no upload, no install. Drop a CSV onto
232
+ <https://tspich.github.io/RNAmelt/> to try it. The source for the page is
233
+ `index.html` in the [repository](https://github.com/tspich/RNAmelt).
234
+
235
+ ## Development
236
+
237
+ ```bash
238
+ git clone https://github.com/tspich/RNAmelt
239
+ cd RNAmelt
240
+ pip install -e '.[plots]'
241
+
242
+ pytest tests/ # or: python -m unittest discover tests
243
+ python -m build # sdist + wheel into dist/
244
+ ```
245
+
246
+ Module layering is strict: `functions` → `methods` → `analysis_melting` →
247
+ `api` → `__main__` / browser. `functions` stays stateless. `plots` is
248
+ lazy-imported so the browser bundle never pulls matplotlib.
249
+
250
+ ## License
251
+
252
+ [MIT](LICENSE).
253
+
254
+ ## Links
255
+
256
+ - Source: <https://github.com/tspich/RNAmelt>
257
+ - Issues: <https://github.com/tspich/RNAmelt/issues>
258
+ - Live demo: <https://tspich.github.io/RNAmelt/>
@@ -0,0 +1,240 @@
1
+ # rnamelt
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/rnamelt.svg)](https://pypi.org/project/rnamelt/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/rnamelt.svg)](https://pypi.org/project/rnamelt/)
5
+ [![License: MIT](https://img.shields.io/pypi/l/rnamelt.svg)](https://github.com/tspich/RNAmelt/blob/main/LICENSE)
6
+
7
+ Two-state thermodynamic analysis (ΔH, ΔS, ΔG, Tm) of UV-absorbance and
8
+ fluorescence RNA / DNA melting curves. One small, dependency-light Python
9
+ package that works as a library, a CLI, and a browser app.
10
+
11
+ - **Library** — `from rnamelt import MeltAnalysis`, typed result objects,
12
+ optional `matplotlib` plotting.
13
+ - **CLI** — `rnamelt FILE.csv [...]` for batch / scripted runs.
14
+ - **Browser** — the same Python pipeline runs client-side via Pyodide.
15
+ Live demo: <https://tspich.github.io/RNAmelt/>.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ pip install rnamelt # base — numpy, pandas, scipy
21
+ pip install 'rnamelt[plots]' # adds matplotlib for .plot() helpers
22
+ ```
23
+
24
+ Requires Python ≥ 3.10.
25
+
26
+ ## Quickstart
27
+
28
+ ```python
29
+ from rnamelt import MeltAnalysis
30
+
31
+ m = MeltAnalysis.from_csv("melt.csv", struct_type="heterodimer")
32
+ r = m.single("sample_1", oligo=0.5) # oligo in µM
33
+ print(r.Tm_fit, r.fit.dH, r.fit.dG)
34
+ ```
35
+
36
+ ```bash
37
+ rnamelt melt.csv --column sample_1 --oligo 0.5 --struct-type heterodimer
38
+ ```
39
+
40
+ ## CSV input format
41
+
42
+ ```
43
+ temperature, sample_1, sample_2, ...
44
+ 20.0, 0.412, 0.388, ...
45
+ 20.5, 0.415, 0.391, ...
46
+ ```
47
+
48
+ - Column 0: temperature in °C (any header name).
49
+ - Columns 1+: absorbance or fluorescence (any header name).
50
+ - Rows entirely NaN, or with a missing temperature, are dropped.
51
+
52
+ ## CLI
53
+
54
+ Same orchestrator as the library. JSON on stdout; pass `--csv-out` for a
55
+ results CSV in the same format the browser produces.
56
+
57
+ ```bash
58
+ # van't Hoff + full fit on every signal column
59
+ rnamelt melt.csv --csv-out batch.csv
60
+
61
+ # single column
62
+ rnamelt melt.csv --column sample_1 --struct-type heterodimer \
63
+ --oligo 5.0 --T-low 20 --T-high 90 --csv-out single.csv
64
+
65
+ # shared-ΔH joint fit across columns
66
+ rnamelt melt.csv --column __multi__ --struct-type heterodimer \
67
+ --oligo-multi sample_1=0.5 --oligo-multi sample_2=5.0
68
+
69
+ # concentration-series van't Hoff (1/Tm vs ln(C_T/f))
70
+ rnamelt melt.csv --column __concentration__ --struct-type heterodimer \
71
+ --oligo-multi sample_1=0.5 --oligo-multi sample_2=5.0 --oligo-multi sample_3=50 \
72
+ --csv-out conc.csv
73
+ ```
74
+
75
+ `rnamelt --help` lists every flag, including three solver-tuning groups
76
+ (`scipy.optimize.least_squares` overrides, van't Hoff linearisation,
77
+ full-fit initial guesses). Exit codes: `0` success, `1` analysis error,
78
+ `2` bad input.
79
+
80
+ ## Python API
81
+
82
+ The recommended surface is `MeltAnalysis`. It holds the DataFrame and
83
+ every configuration knob (struct type, salt, transition window, baseline
84
+ offsets, solver / vH / fit-init overrides) and exposes the three modes as
85
+ methods returning typed result objects from `rnamelt.results`.
86
+
87
+ ```python
88
+ from rnamelt import MeltAnalysis, FitFailed
89
+
90
+ m = MeltAnalysis.from_csv(
91
+ "melt.csv",
92
+ struct_type="heterodimer", # "heterodimer" | "homodimer" | "monomer"
93
+ salt=150.0, # NaCl (mM) — metadata only
94
+ T_low=None, T_high=None, # transition window (°C); None = full range
95
+ bl_lower_offset=10.0, # folded baseline span above T_low (°C)
96
+ bl_upper_offset=10.0, # unfolded baseline span below T_high (°C)
97
+ )
98
+ m.signal_columns # ['sample_1', 'sample_2', ...]
99
+ ```
100
+
101
+ ### Three modes
102
+
103
+ ```python
104
+ # Single column — returns SingleResult; numpy arrays live on the object
105
+ r = m.single("sample_1", oligo=0.5)
106
+ r.Tm_raw, r.vh.dH, r.fit.Tm, r.fit.dG
107
+
108
+ try:
109
+ r.fit.require() # raises FitFailed if not r.fit.ok
110
+ except FitFailed as e:
111
+ print(e)
112
+
113
+ # Shared-ΔH joint fit across columns
114
+ multi = m.multi({"sample_1": 0.5, "sample_2": 5.0, "sample_3": 50.0})
115
+ multi.dH, multi.dS
116
+ for c in multi.columns:
117
+ print(c.name, c.Tm_fit, c.oligoC)
118
+
119
+ # Concentration-series van't Hoff — three regressions (raw / vH / full fit)
120
+ conc = m.concentration({"sample_1": 0.5, "sample_2": 5.0, "sample_3": 50.0})
121
+ for s in (conc.series_raw, conc.series_vh, conc.series_fit):
122
+ if s.ok:
123
+ print(s.dH, s.dG_37, s.r_squared)
124
+
125
+ # Every column at once
126
+ batch = m.single_all(oligo=0.5) # dict[str, SingleResult]
127
+
128
+ # Export forms (same shape the browser download produces)
129
+ r.to_dict(); r.to_dataframe(); r.to_csv("out.csv")
130
+ ```
131
+
132
+ ### From raw arrays — no CSV
133
+
134
+ `signals` accepts a 1D array, a `{name: array}` mapping, or a 2D array
135
+ (one column per signal, with optional `names=`):
136
+
137
+ ```python
138
+ import numpy as np
139
+ from rnamelt import MeltAnalysis
140
+
141
+ T = np.linspace(20, 90, 71)
142
+
143
+ m = MeltAnalysis.from_arrays(T, signal_F4) # 1D
144
+ m = MeltAnalysis.from_arrays(T, {"F4": sigF4, "F5": sigF5}) # mapping
145
+ m = MeltAnalysis.from_arrays(T, arr2d, names=["A", "B", "C"]) # 2D
146
+ ```
147
+
148
+ ### Plotting (optional)
149
+
150
+ `pip install 'rnamelt[plots]'`. Each result class has a `.plot()` method
151
+ that lazy-imports `rnamelt.plots`, so matplotlib never enters the
152
+ browser/Pyodide bundle.
153
+
154
+ ```python
155
+ fig, axes = m.single("F4").plot(figsize=(15, 5)) # raw / vH / full fit
156
+ fig, ax = m.multi(oligo_multi).plot()
157
+ fig, axes = m.concentration(oligo_multi).plot()
158
+
159
+ # Convenience shortcut on the analyzer
160
+ fig, axes, result = m.plot("F4")
161
+ ```
162
+
163
+ ### Functional helpers (back-compat)
164
+
165
+ Thin wrappers around the same orchestrator that take a cleaned
166
+ `pandas.DataFrame` and return the legacy dict directly:
167
+
168
+ ```python
169
+ import pandas as pd
170
+ from rnamelt import (
171
+ analyze_single, analyze_multi, analyze_concentration, analyze_csv,
172
+ )
173
+ from rnamelt.cleaning import clean
174
+
175
+ df = clean(pd.read_csv("melt.csv"))
176
+ analyze_single(df, "sample_1", struct_type="heterodimer", oligo=0.5)
177
+ analyze_multi(df, {"sample_1": 0.5, "sample_2": 5.0})
178
+ analyze_concentration(df, {"sample_1": 0.5, "sample_2": 5.0})
179
+
180
+ # read_csv + clean + dispatch in one call
181
+ analyze_csv("melt.csv", mode="single", column="sample_1", oligo=0.5)
182
+ ```
183
+
184
+ ## Analysis modes
185
+
186
+ All three modes go through `rnamelt.analysis_melting.run(df, params)`;
187
+ the `column` param selects the mode.
188
+
189
+ | `column` value | Mode | What it does |
190
+ |------------------------|-------------------------------------|--------------|
191
+ | 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. |
192
+ | `__multi__` | **Shared-ΔH joint fit** | Fit every column with common ΔH, ΔS but independent baselines. Each column carries its own concentration. |
193
+ | `__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). |
194
+
195
+ ## Two-state model
196
+
197
+ Observed signal is a linear combination of folded and unfolded baselines,
198
+ weighted by the fraction unfolded θ(T):
199
+
200
+ ```
201
+ A(T) = (m_F·T + b_F)·(1 − θ) + (m_U·T + b_U)·θ
202
+ K(T) = exp(−ΔG / RT), ΔG = ΔH − T·ΔS
203
+ θ = K / (1 + K) (monomer)
204
+ θ = (√(1 + 8·c₀·K) − 1) / (4·c₀·K) (dimer)
205
+ ```
206
+
207
+ Units: ΔH in kcal/mol, ΔS in kcal/(mol·K), T in K
208
+ (`T_K = T_C − T0`, `T0 = −273.15`).
209
+
210
+ ## Browser app
211
+
212
+ The same Python package runs client-side via [Pyodide](https://pyodide.org/);
213
+ no server, no upload, no install. Drop a CSV onto
214
+ <https://tspich.github.io/RNAmelt/> to try it. The source for the page is
215
+ `index.html` in the [repository](https://github.com/tspich/RNAmelt).
216
+
217
+ ## Development
218
+
219
+ ```bash
220
+ git clone https://github.com/tspich/RNAmelt
221
+ cd RNAmelt
222
+ pip install -e '.[plots]'
223
+
224
+ pytest tests/ # or: python -m unittest discover tests
225
+ python -m build # sdist + wheel into dist/
226
+ ```
227
+
228
+ Module layering is strict: `functions` → `methods` → `analysis_melting` →
229
+ `api` → `__main__` / browser. `functions` stays stateless. `plots` is
230
+ lazy-imported so the browser bundle never pulls matplotlib.
231
+
232
+ ## License
233
+
234
+ [MIT](LICENSE).
235
+
236
+ ## Links
237
+
238
+ - Source: <https://github.com/tspich/RNAmelt>
239
+ - Issues: <https://github.com/tspich/RNAmelt/issues>
240
+ - Live demo: <https://tspich.github.io/RNAmelt/>
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "rnamelt"
7
+ version = "0.1.0"
8
+ description = "Two-state thermodynamic analysis (ΔH, ΔS, ΔG, Tm) of RNA melting curves"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "tspich" },
14
+ { name = "RaumZeit" },
15
+ ]
16
+ keywords = ["rna", "melting curve", "thermodynamics"]
17
+ dependencies = [
18
+ "numpy>=1.23",
19
+ "pandas>=1.5",
20
+ "scipy>=1.10",
21
+ ]
22
+
23
+ [project.optional-dependencies]
24
+ plots = ["matplotlib>=3.5"]
25
+
26
+ [project.scripts]
27
+ rnamelt = "rnamelt.__main__:main"
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/tspich/RNAmelt"
31
+ Issues = "https://github.com/tspich/RNAmelt/issues"
32
+
33
+ [tool.hatch.build.targets.wheel]
34
+ packages = ["rnamelt"]
35
+
36
+ [tool.hatch.build.targets.sdist]
37
+ include = [
38
+ "rnamelt",
39
+ "README.md",
40
+ "pyproject.toml",
41
+ ]
@@ -0,0 +1,54 @@
1
+ """rnamelt — RNA / DNA melting-curve thermodynamic analysis.
2
+
3
+ Public API:
4
+ MeltAnalysis — class façade
5
+ analyze_single, analyze_multi, analyze_concentration — DataFrame in
6
+ analyze_csv — path in
7
+ """
8
+
9
+ from rnamelt.api import (
10
+ MeltAnalysis,
11
+ analyze_concentration,
12
+ analyze_csv,
13
+ analyze_multi,
14
+ analyze_single,
15
+ )
16
+ from rnamelt.methods import FIT_INIT_DEFAULTS, SOLVER_DEFAULTS, VH_DEFAULTS
17
+ from rnamelt.results import (
18
+ BatchResult,
19
+ ConcentrationCurve,
20
+ ConcentrationResult,
21
+ ConcentrationSeries,
22
+ FitFailed,
23
+ FullFit,
24
+ MultiColumnResult,
25
+ MultiResult,
26
+ SingleResult,
27
+ VanHoffFit,
28
+ )
29
+
30
+ ANALYSES = [
31
+ "rnamelt.analysis_melting",
32
+ ]
33
+
34
+ __all__ = [
35
+ "MeltAnalysis",
36
+ "analyze_single",
37
+ "analyze_multi",
38
+ "analyze_concentration",
39
+ "analyze_csv",
40
+ "SingleResult",
41
+ "MultiResult",
42
+ "MultiColumnResult",
43
+ "ConcentrationResult",
44
+ "ConcentrationCurve",
45
+ "ConcentrationSeries",
46
+ "BatchResult",
47
+ "VanHoffFit",
48
+ "FullFit",
49
+ "FitFailed",
50
+ "SOLVER_DEFAULTS",
51
+ "VH_DEFAULTS",
52
+ "FIT_INIT_DEFAULTS",
53
+ "ANALYSES",
54
+ ]