dnacurve

DNA curvature analysis.

Dnacurve is a Python library, console script, and web application to calculate the global 3D structure of a B-DNA molecule from its nucleotide sequence according to the dinucleotide wedge model. Local bending angles and macroscopic curvature are calculated at each nucleotide.

Author:

Christoph Gohlke

License:

BSD-3-Clause

Version:

2026.6.9

DOI:

10.5281/zenodo.7135499

Quickstart

Install the dnacurve package and all dependencies from the Python Package Index:

python -m pip install -U "dnacurve[all]"

Print the console script usage:

python -m dnacurve --help

Run the web application:

python -m dnacurve --web

See Examples for using the programming interface.

Source code and support are available on GitHub.

Requirements

This revision was tested with the following requirements and dependencies (other versions may work):

Revisions

2026.6.9

  • Fix code review issues.

  • Use HTML Living Standard in web application.

  • Drop support for Python 3.11, support Python 3.15.

2026.1.8

  • Improve code quality.

2025.12.12

  • Remove unused overlapping_chunks function.

  • Drop support for Python 3.10, support Python 3.14.

2025.5.8

  • Remove deprecated save functions (breaking).

  • Remove doctest command line option.

2025.1.1

  • Improve type hints.

  • Drop support for Python 3.9, support Python 3.13.

2024.5.24

Refer to the CHANGES file for older revisions.

Notes

The algorithms, plots, and PDB format are not meant to be used with very long sequences. By default, sequences are truncated to 510 nucleotides, which can be overridden by the user.

The generated PDB files can be visualized interactively using UCSF Chimera.

Dnacurve.py was derived from DNACG.PAS (c) 1993, and DNACURVE.CPP (c) 1995.

References

  1. Bending and curvature calculations in B-DNA. Goodsell DS, Dickerson RE. Nucleic Acids Res 22, 5497-503, 1994. See also http://mgl.scripps.edu/people/goodsell/research/bend/index.html.

  2. Curved DNA without A-A: experimental estimation of all 16 DNA wedge angles. Bolshoy A et al. Proc Natl Acad Sci USA 88, 2312-6, 1991.

  3. A comparison of six DNA bending models. Tan RK and Harvey SC. J Biomol Struct Dyn 5, 497-512, 1987.

  4. Curved DNA: design, synthesis, and circularization. Ulanovsky L et al. Proc Natl Acad Sci USA 83, 862-6, 1986.

  5. The ten helical twist angles of B-DNA. Kabsch W, Sander C, and Trifonov EN. Nucleic Acids Res 10, 1097-1104, 1982.

  6. Rod models of DNA: sequence-dependent anisotropic elastic modelling of local bending phenomena. Munteanu MG et al. Trends Biochem Sci 23(9), 341-7, 1998.

Examples

>>> from dnacurve import CurvedDNA
>>> cdna = CurvedDNA('ATGCAAATTG' * 5, 'trifonov', name='Example')
>>> cdna.curvature[:, 18:22]
array([[0.58061616, 0.58163338, 0.58277938, 0.583783  ],
       [0.08029914, 0.11292516, 0.07675816, 0.03166286],
       [0.57923902, 0.57580064, 0.57367815, 0.57349872]])
>>> cdna.write_csv('_test.csv')
>>> cdna.write_pdb('_test.pdb')
>>> cdna.plot('_test.png', dpi=120)

License

Copyright (c) 1993-2026, Christoph Gohlke
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

dnacurve module

dnacurve.__version__

Dnacurve version string.

class dnacurve.CurvedDNA(sequence, /, model='trifonov', name='Untitled', curvature_window=10, bend_window=2, curve_window=15, maxlen=MAXLEN)

Bases: object

Calculate, plot or write helix coordinates, local bending and curvature.

Parameters:
  • sequence (Sequence | os.PathLike[Any] | str) – Sequence instance, file name, or nucleotide sequence. See Sequence parameters.

  • model (Model | os.PathLike[Any] | str) – Model instance, file name, class, dict, or name of predefined model. See Model parameters.

  • name (str) – Name of sequence.

  • curvature_window (int) – Window size for calculating curvature.

  • bend_window (int) – Window size for calculating local bend angles.

  • curve_window (int) – Window size for calculating curvature angles.

  • maxlen (int) – Maximum length of sequence.

Notes

Atomic coordinates are centered at origin and oriented such that: (1) helix-axis endpoints lie on x-axis and (2) maximum deviation of DNA- from x-axis is along the z-axis. Coordinates in PDB files are shifted to the positive domain.

The curvature at nucleotide N is one over the radius of a circle passing through helix axis coordinates N-window, N, and N+window, which are separated by one respectively two helix turns. The three points define a triangle. The radius is the product of the length of the triangle sides divided by four times the area of the triangle. A window size of 10 is optimal for B-DNA.

The local bend angle at nucleotide N is the angle between the normal vectors of base pairs N-window and N+window. The window size should be one or two.

The curvature angle at nucleotide N is the angle between the smoothed normal vectors of basepair N-window and N+window. The window size should be in the order of 15.

The curvature and bend values are normalized relative to the DNA curvature in a nucleosome (0.0234).

write_csv(path, /)

Write coordinates and curvature values to CSV file.

Parameters:

path (os.PathLike[Any] | str) – Name of CSV file to write.

Return type:

None

write_pdb(path, /)

Write atomic coordinates to PDB file.

Parameters:

path (os.PathLike[Any] | str) – Name of PDB file to write.

Return type:

None

csv()

Return coordinates and curvature values in CSV format.

Returns:

CSV-formatted string with sequence index, curvature values, and helix axis, phosphate, and normal vector coordinates.

Return type:

str

pdb()

Return atomic coordinates in PDB format.

Returns:

PDB-formatted string with phosphate atom coordinates for both strands of the DNA double helix.

Return type:

str

plot(arg=True, /, dpi=96, figsize=(6.0, 7.5), imageformat=None)

Plot results using matplotlib.

Parameters:
  • arg (str | os.PathLike[Any] | BinaryIO | bool) –

    Specifies how to plot:

    • False: do not plot.

    • True: plot interactively.

    • File name: write the figure to it.

    • Open file: write the figure to it.

  • dpi (int) – Resolution of plot in dots per inch.

  • figsize (tuple[float, float]) – Matplotlib figure size.

  • imageformat (str | None) – Image file format of the figure, such as, ‘png’, ‘pdf’, or ‘svg’.

Return type:

Any

property name: str

Name of sequence.

class dnacurve.Model(model=None, /, **kwargs)

Bases: object

N-mer DNA-bending model.

Transformation parameters and matrices for all oligonucleotides of certain length.

Parameters:
  • model (Model | dict[str, Any] | os.PathLike[Any] | str | None) –

    Specifies type of model:

    • None: Model.STRAIGHT.

    • Model: Model instance.

    • dict: Specifies Model.name, Model.oligo, Model.twist, Model.roll, Model.tilt, and Model.rise.

    • str: Name of predefined model, ‘straight’, ‘aawedge’, ‘trifonov’, ‘desantis’, ‘calladine’, ‘reversed’, ‘nucleosome’, or ‘trinucleotide’.

    • Path: File containing model parameters.

  • **kwargs (Any) –

    Additional arguments to modify model:

    • Model.name

    • Model.oligo

    • Model.twist

    • Model.roll

    • Model.tilt

    • Model.rise

Examples

>>> m = Model('AAWedge')
>>> m = Model('Nucleosome')
>>> m = Model(**Model.STRAIGHT)
>>> m = Model(Model.CALLADINE, name='My Model', rise=4.0)
>>> m.name == 'My Model' and m.rise == 4.0
True
>>> m = Model(
...     name='Test',
...     rise=3.38,
...     oligo='AA AC AG AT CA GG CG GA GC TA'.split(),
...     twist=(34.29,) * 10,
...     roll=(0.0,) * 10,
...     tilt=(0.0,) * 10,
... )
>>> m.write('_test.dat')
>>> m.twist == Model('_test.dat').twist
True
write(path, /)

Write model to file.

Parameters:

path (os.PathLike[Any] | str) – Name of file to write.

Return type:

None

class dnacurve.Sequence(arg, /, name='Untitled', comment='', maxlen=1024 * 1024)

Bases: object

DNA nucleotide sequence.

Parameters:
  • arg (os.PathLike[Any] | str) – Sequence or name of file containing sequence.

  • name (str) – Name of sequence.

  • comment (str) – Single line description of sequence.

  • maxlen (int) – Maximum length of sequence.

Notes

FASTA files must contain >name<space>comment<newline>sequence. SEQ files must contain name<newline>comment<newline>sequence. Nucleotides other than ATCG are ignored.

Examples

>>> Sequence('0AxT-C:G a`t~c&g\t')[:]
'ATCGATCG'
>>> seq = Sequence('ATGCAAATTG' * 5, name='Test')
>>> seq == 'ATGCAAATTG' * 5
True
>>> seq == None
False
>>> seq.write('_test.seq')
>>> seq == Sequence('_test.seq')
True
write(path, /)

Write sequence to file.

Parameters:

path (os.PathLike[Any] | str) – Name of file to write.

Return type:

None

property string: str

Sequence string containing only ATCG.

format(block=10, line=6)

Return string of sequence formatted in blocks and lines.

Parameters:
  • block (int) – Length of blocks.

  • line (int) – Line length.

Return type:

str

dnacurve.chunks(sequence: str, /, size: int = 10) list[str]
dnacurve.chunks(sequence: list[str], /, size: int = 10) list[list[str]]

Return sequence in chunks of size.

Parameters:
  • sequence (str | list[str]) – Sequence to be chunked.

  • size (int) – Length of chunks.

Return type:

list[str] | list[list[str]]

Examples

>>> chunks('ATCG' * 4, 10)
['ATCGATCGAT', 'CGATCG']
dnacurve.complementary(sequence)

Return complementary DNA sequence.

Parameters:

sequence (Sequence | str) – DNA sequence.

Return type:

str

Examples

>>> complementary('AT CG')
'CGAT'
dnacurve.dinuc_window(sequence, size, /)

Return window of nucleotides around each dinucleotide in sequence.

Parameters:
  • sequence (Sequence | str) – Sequence to be windowed.

  • size (int) – Length of window.

Yields:

Oligonucleotide sequence at window or None if window overlaps border.

Return type:

Iterator[str | None]

Examples

>>> list(dinuc_window('ATCG', 2))
['AT', 'TC', 'CG']
>>> list(dinuc_window('ATCG', 3))
['ATC', 'TCG', None]
>>> list(dinuc_window('ATCG', 4))
[None, 'ATCG', None]
dnacurve.dinucleotide_matrix(rise, twist, roll, tilt, /)

Return transformation matrix to move from one nucleotide to next.

Parameters:
  • rise (float) – Displacement along the Z axis.

  • twist (float) – Rotation angle in deg about the Z axis.

  • roll (float) – Rotation angle in deg about the Y axis.

  • tilt (float) – Rotation angle in deg about the X axis.

Returns:

4x4 homogeneous transformation matrix.

Return type:

NDArray[Any]

dnacurve.main(argv=None, /)

Command line usage main function.

Parameters:

argv (list[str] | None) – Command line arguments.

Returns:

Exit code; 0 on success.

Return type:

int

dnacurve.oligonucleotides(length, /, nucleotides='AGCT')

Generate all oligonucleotide sequences of length.

Parameters:
  • length (int) – Length of oligonucleotides to generate.

  • nucleotides (str) – Nucleotides in oligonucleotides.

Yields:

Oligonucleotide sequence of length.

Return type:

Iterator[str]

Examples

>>> ' '.join(oligonucleotides(2))
'AA AG AC AT GA GG GC GT CA CG CC CT TA TG TC TT'
dnacurve.superimpose_matrix(v0, v1, /)

Return matrix to transform given vector set to second vector set.

Parameters:
  • v0 (NDArray[Any]) – Given vector set.

  • v1 (NDArray[Any]) – Target vector set.

Returns:

4x4 homogeneous transformation matrix that best superimposes v0 onto v1 using SVD.

Return type:

NDArray[Any]

dnacurve.unique_oligos(length, /, nucleotides='AGCT')

Generate all unique oligonucleotide sequences of length.

Parameters:
  • length (int) – Length of oligonucleotides to generate.

  • nucleotides (str) – Nucleotides in oligonucleotides.

Yields:

Unique oligonucleotide sequence of length, excluding reverse complements.

Return type:

Iterator[str]

Examples

>>> ' '.join(unique_oligos(2))
'AA AG AC AT GA GG GC CA CG TA'
dnacurve.MAXLEN

Maximum length of sequences to analyze.

dnacurve.MODELS

Predefined models.

dnacurve.web

dnacurve.web.main(url=None, /, *, open_browser=True, debug=False)

Run web application in local Flask server.

Fall back to Python’s CGI server if Flask is not installed.

Parameters:
  • url (str | None) – URL at which the web application is served. The default is http://127.0.0.1:5000/.

  • open_browser (bool) – Open url in web browser.

  • debug (bool) – Enable debug mode.

Return type:

int

dnacurve.web.response(form, /, url, *, template=None, help=None, maxlen=dnacurve.MAXLEN, heads='')

Return HTML document from submitted form data.

Parameters:
  • form (Any) – Flask.request.form or cgi.FieldStorage.

  • url (str) – URL of web application.

  • template (str | None) – HTML page template. The default is dnacurve.web.PAGE.

  • help (str | None) – Help text. The default is dnacurve.web.HELP.

  • maxlen (int) – Maximum length of DNA sequence.

  • heads (str) – Additional HTML page head sections.

Return type:

str