scadnano documentation

scadnano

The scadnano Python module is a library for describing synthetic DNA nanostructures (e.g., DNA origami). Installation instructions are at the GitHub repository.

The scadnano project is developed and maintained by the UC Davis Molecular Computing group. Note that cadnano is a separate project, developed and maintained by the Douglas lab at UCSF.

This module is used to write Python scripts creating files readable by scadnano, a web application useful for displaying and manually editing synthetic DNA nanostructures. The purpose of this module is to help automate some of the task of creating DNA designs, as well as making large-scale changes to them that are easier to describe programmatically than to do by hand in scadnano.

If you find scadnano useful in a scientific project, please cite its associated paper:

scadnano: A browser-based, scriptable tool for designing DNA nanostructures.
David Doty, Benjamin L Lee, and Tristan Stérin.
DNA 2020: Proceedings of the 26th International Conference on DNA Computing and Molecular Programming

This document describes the API for the scadnano Python package, see the repository for additional documentation, such as installation instructions. There is separate documentation for the scadnano web interface.

This library uses typing hints from the Python typing library. (https://docs.python.org/3/library/typing.html) Each function and method indicate intended types of the parameters. However, due to Python’s design, these types are not enforced at runtime. It is suggested to use a static analysis tool such as that provided by an IDE such as PyCharm (https://www.jetbrains.com/pycharm/) to see warnings when the typing rules are violated. Such warnings probably indicate an erroneous usage.

Most of the classes in this module are Python dataclasses (https://docs.python.org/3/library/dataclasses.html) whose fields show up in the documentation. Their types are listed in parentheses after the name of the class; for example Color has int fields Color.r, Color.g, Color.b. In general it is safe to read these fields directly, but not to write to them directly. Setter methods (named set_<fieldname>) are provided for fields where it makes sense to set it to another value than it had originally. However, due to Python naming conventions for dataclass fields and property setters, it is not straightforward to enforce that the fields cannot be written, so the user must take care not to set them.

class scadnano.Color(r: Union[int, NoneType] = None, g: Union[int, NoneType] = None, b: Union[int, NoneType] = None, hex_string: dataclasses.InitVar = None)
r: Optional[int] = None

Red component: 0-255.

Optional if Color.hex is given.

g: Optional[int] = None

Green component: 0-255.

Optional if Color.hex is given.

b: Optional[int] = None

Blue component: 0-255.

Optional if Color.hex is given.

hex_string: dataclasses.InitVar = None

Hex color preceded by # sign, e.g., “#ff0000” is red.

Optional if Color.r, Color.g, Color.b are all given.

class scadnano.ColorCycler

Calling next(color_cycler) on a ColorCycler named color_cycler returns a the next Color from a fixed size list, cycling after reaching the end of the list.

To choose new colors, set color_cycler.colors to a new list of Color’s.

property colors

The colors that are cycled through when calling next() on some ColorCycler.

scadnano.default_scaffold_color = Color(r=0, g=102, b=204)

Default color for scaffold strand(s).

scadnano.default_strand_color = Color(r=0, g=0, b=0)

Default color for non-scaffold strand(s).

class scadnano.Grid(value)

Represents default patterns for laying out helices in the side view. Each Grid except Grid.none has an interpretation of a “grid position”, which is a 2D integer coordinate (h, v). (scadnano also allows a 3rd coordinate (h, v, b) specifying a “base offset” at which to position the start of the Helix, which is not relevant for the side view but will eventually be supported to adjust the main view.)

square = 'square'

Square lattice. Increasing h moves right and increasing v moves down. (i.e., “computer screen coordinates” rather than Cartesian coordinates where positive y is up.)

hex = 'hex'

Hexagonal lattice. Uses the “odd-q horizontal layout” coordinate system described here: https://www.redblobgames.com/grids/hexagons/. Incrementing v moves down. Incrementing h moves down and to the right if h is even, and moves up and to the right if h is odd.

honeycomb = 'honeycomb'

Honeycomb lattice. This consists of all the hex lattice positions except where honeycomb lattice disallows grid positions (h, v) with v even and h a multiple of 3 or v odd and h = 1 + a multiple of 3.

However, we use the same convention as cadnano for encoding hex coordinates see misc/cadnano-format-specs/v2.txt. That convention is different from simply excluding coordinates from the hex lattice.

none = 'none'

No fixed grid.

scadnano.DNA_base_wildcard = '?'

Symbol to insert when a DNA sequence has been assigned to a strand through complementarity, but some regions of the strand are not bound to the strand that was just assigned. Also used in case the DNA sequence assigned to a strand is too short; the sequence is padded with DNA_base_wildcard to make its length the same as the length of the strand.

class scadnano.M13Variant(value)

Variants of M13mp18 viral genome. “Standard” variant is p7249. Other variants are longer.

p7249 = 'p7249'

“Standard” variant of M13mp18; 7249 bases long, available from, for example

https://www.tilibit.com/collections/scaffold-dna/products/single-stranded-scaffold-dna-type-p7249

https://www.neb.com/products/n4040-m13mp18-single-stranded-dna

http://www.bayoubiolabs.com/biochemicat/vectors/pUCM13/

p7560 = 'p7560'

Variant of M13mp18 that is 7560 bases long. Available from, for example

https://www.tilibit.com/collections/scaffold-dna/products/single-stranded-scaffold-dna-type-p7560

p8064 = 'p8064'

Variant of M13mp18 that is 8064 bases long. Available from, for example

https://www.tilibit.com/collections/scaffold-dna/products/single-stranded-scaffold-dna-type-p8064

scadnano.m13(rotation: int = 5587, variant: scadnano.M13Variant = <M13Variant.p7249: 'p7249'>) → str

The M13mp18 DNA sequence (commonly called simply M13).

By default, starts from cyclic rotation 5587 (with 0-based indexing; commonly this is called rotation 5588, which assumes that indexing begins at 1), as defined in GenBank.

By default, returns the “standard” variant of consisting of 7249 bases, sold by companies such as Tilibit. and New England Biolabs

The actual M13 DNA strand itself is circular, so assigning this sequence to the scaffold Strand in a Design means that the “5’ end” of the scaffold Strand (which is a fiction since the actual circular DNA strand has no endpoint) will have the sequence starting at position 5587 starting at the displayed 5’ in scadnano, assigned until the displayed 3’ end. Assuming the displayed scaffold Strand has length \(n < 7249\), then a loopout of length \(7249 - n\) consisting of the undisplayed bases will be present in the actual DNA structure. For a more detailed discussion of why this particular rotation of M13 is chosen, see Supplementary Note S8 in [Folding DNA to create nanoscale shapes and patterns. Paul W. K. Rothemund, Nature 440:297-302 (2006)].

Parameters
  • rotation – rotation of circular strand. Valid values are 0 through length-1.

  • variant – variant of M13 strand to use

Returns

M13 strand sequence

class scadnano.Modification(display_text: str, id: str = 'WARNING: no id assigned to modification', idt_text: Optional[str] = None)

Base class of modifications (to DNA sequences, e.g., biotin or Cy3). Use Modification3Prime, Modification5Prime, or ModificationInternal to instantiate.

display_text: str

Short text to display in the web interface as an “icon” visually representing the modification, e.g., 'B' for biotin or 'Cy3' for Cy3.

id: str = 'WARNING: no id assigned to modification'

Representation as a string; used to write in Strand json representation, while the full description of the modification is written under a global key in the Design. If not specified, but Modification.idt_text is specified, then it will be set equal to that.

idt_text: Optional[str] = None

IDT text string specifying this modification (e.g., ‘/5Biosg/’ for 5’ biotin). optional

class scadnano.Modification5Prime(display_text: str, id: str = 'WARNING: no id assigned to modification', idt_text: Optional[str] = None)

5’ modification of DNA sequence, e.g., biotin or Cy3.

class scadnano.Modification3Prime(display_text: str, id: str = 'WARNING: no id assigned to modification', idt_text: Optional[str] = None)

3’ modification of DNA sequence, e.g., biotin or Cy3.

class scadnano.ModificationInternal(display_text: str, id: str = 'WARNING: no id assigned to modification', idt_text: Optional[str] = None, allowed_bases: Optional[FrozenSet[str]] = None)

Internal modification of DNA sequence, e.g., biotin or Cy3.

allowed_bases: Optional[FrozenSet[str]] = None

If None, then this is an internal modification that goes between bases. If instead it is a list of bases, then this is an internal modification that attaches to a base, and this lists the allowed bases for this internal modification to be placed at. For example, internal biotins for IDT must be at a T. If any base is allowed, it should be ['A','C','G','T'].

class scadnano.Position3D(x: float = 0, y: float = 0, z: float = 0)

Position (x,y,z) in 3D space.

x: float = 0

x-coordinate of position. Increasing x moves right in the side view and out of the screen in the main view.

y: float = 0

y-coordinate of position. Increasing y moves down in the side and main views, i.e., “screen coordinates”. (though this can be rotated to Cartesian coordinates, where y goes up, by selecting “invert y/z axes” in the View menu of scadnano.)

z: float = 0

z-coordinate of position. Increasing z moves right in the main view and into the screen in the side view.

class scadnano.HelixGroup(position: scadnano.Position3D = Position3D(x=0, y=0, z=0), pitch: float = 0, yaw: float = 0, roll: float = 0, helices_view_order: Optional[List[int]] = None, grid: scadnano.Grid = <Grid.none: 'none'>)

Represents a set of properties to apply to a specific group of Helix’s in the Design.

A HelixGroup is useful for grouping together helices that should all be in parallel, as part of a design where different groups are not parallel. In particular, each HelixGroup can be given its own 3D position and pitch/yaw/roll orientation angles. Each HelixGroup does not actually contain its helices; they are associated through the field Helix.group, which is a string representing a key in the dict groups specified in the constructor for Design.

If there are HelixGroup’s explicitly specified, then the field Design.grid is ignored. Each HelixGroup has its own grid, and the fields Helix.position or Helix.grid_position are considered relative to the origin of that HelixGroup (i.e., the value HelixGroup.position). Although it is possible to assign a Helix in a HelixGroup a non-zero Helix.pitch or Helix.yaw, the most common use case is that all helices in a group are parallel, so they all have these angles equal to 0 (since they are unrotated relative to each other along the pitch and yaw planes).

position: scadnano.Position3D = Position3D(x=0, y=0, z=0)

The “origin” of this HelixGroup.

pitch: float = 0

Same meaning as Helix.pitch, applied to every Helix in the group.

yaw: float = 0

Same meaning as Helix.yaw, applied to every Helix in the group.

roll: float = 0

Same meaning as Helix.roll, applied to every Helix in the group.

helices_view_order: Optional[List[int]] = None

Same meaning as Design.helices_view_order, applied to only the Helix’s in the group.

grid: scadnano.Grid = 'none'

Same meaning as Design.grid, enforced only on the Helix’s in the group.

helices_view_order_inverse(idx: int) → int

Given a Helix.idx in this HelixGroup, return its view order.

Parameters

idx – index of Helix in this HelixGroup

Returns

view order of the Helix

Raises

ValueError – if idx is not the index of a Helix in this HelixGroup

class scadnano.Helix(max_offset: Optional[int] = None, min_offset: int = 0, major_tick_start: Optional[int] = None, major_tick_distance: Optional[int] = None, major_tick_periodic_distances: Optional[List[int]] = None, major_ticks: Optional[List[int]] = None, grid_position: Optional[Tuple[int, int]] = None, position: Optional[scadnano.Position3D] = None, pitch: float = 0, roll: float = 0, yaw: float = 0, idx: Optional[int] = None, group: str = 'default_group', _domains: List[scadnano.Domain] = <factory>)

Represents a “helix” where Domain’s could go. Technically a Helix can contain no Domain’s. More commonly, some partial regions of it may have only 1 or 0 Domain’s. So it is best thought of as a “potential” double-helix.

It has a 1-dimensional integer coordinate system given by “offsets”, integers between Helix.min_offset (inclusive) and Helix.max_offset (exclusive). At any valid offset for this Helix, at most two Domain’s may share that offset on this Helix, and if there are exactly two, then one must have Domain.forward = true and the other must have Domain.forward = false.

Once part of a Design, a Helix has an index (accessible via Helix.idx() once the Design is created) representing its order in the list of all Helix’s. This index is how a Domain is associated to the Helix via the integer index Domain.helix.

max_offset: Optional[int] = None

Maximum offset (exclusive) of Domain that can be drawn on this Helix.

Optional field. If unspecified, it is calculated when the Design is instantiated as the largest Domain.end offset of any Domain in the design.

min_offset: int = 0

Minimum offset (inclusive) of Domain that can be drawn on this Helix.

Optional field. Default value 0.

major_tick_start: Optional[int] = None

Offset of first major tick when not specifying Helix.major_ticks. Used in combination with either Helix.major_tick_distance or Helix.major_tick_periodic_distances.

Optional field. If not specified, is initialized to value Helix.min_offset.

major_tick_distance: Optional[int] = None

Distance between major ticks (bold) delimiting boundaries between bases. Major ticks will appear in the visual interface at positions

Optional field. If 0 then no major ticks are drawn. If not specified then the default value is assumed. If the grid is Grid.square then the default value is 8. If the grid is Grid.hex or Grid.honeycomb then the default value is 7.

major_tick_periodic_distances: Optional[List[int]] = None

Periodic distances between major ticks. For example, setting Helix.major_tick_periodic_distances = [2, 3] and Helix.major_tick_start = 10 means that major ticks will appear at 12, 15, 17, 20, 22, 25, 27, 30, …

Optional field. Helix.major_tick_distance is equivalent to the setting Helix.major_tick_periodic_distances = [Helix.major_tick_distance].

major_ticks: Optional[List[int]] = None

If not None, overrides Helix.major_tick_distance to specify a list of offsets at which to put major ticks.

grid_position: Optional[Tuple[int, int]] = None

(h,v) position of this helix in the side view grid, if Grid.square, Grid.hex , or Grid.honeycomb is used in the Design containing this helix. h and v are in units of “helices”: incrementing h moves right one helix in the grid and incrementing v moves down one helix in the grid. In the case of the hexagonal lattice, The convention is that incrementing v moves down and to the right if h is even, and moves down and to the left if h is odd. This is the “odd-q” coordinate system here: https://www.redblobgames.com/grids/hexagons/) However, the default y position in the main view for helices does not otherwise depend on grid_position. The default is to list the y-coordinates in order by helix idx.

Default is h = 0, v = index of Helix in Design.helices.

In the case of the honeycomb lattice, we use the same convention as cadnano for encoding hex coordinates, see misc/cadnano-format-specs/v2.txt. That convention is different from simply excluding coordinates from the hex lattice.

position: Optional[scadnano.Position3D] = None

Position (x,y,z) of this Helix in 3D space.

Must be None if Helix.grid_position is specified.

pitch: float = 0

Angle in the main view plane; 0 means pointing to the right (min_offset on left, max_offset on right). Rotation is clockwise in the main view. See https://en.wikipedia.org/wiki/Aircraft_principal_axes Units are degrees.

roll: float = 0

Angle around the center of the helix; 0 means pointing straight up in the side view. Rotation is clockwise in the side view. See https://en.wikipedia.org/wiki/Aircraft_principal_axes Units are degrees.

yaw: float = 0

Third angle for orientation besides Helix.pitch and Helix.roll. Not visually displayed in scadnano, but here to support more general 3D applications. See https://en.wikipedia.org/wiki/Aircraft_principal_axes Units are degrees.

idx: Optional[int] = None

Index of this Helix.

Optional if no other Helix specifies a value for idx. Default is the order of the Helix is listed in constructor for Design.

group: str = 'default_group'

Name of the HelixGroup to which this Helix belongs.

calculate_major_ticks(grid: scadnano.Grid) → List[int]

Calculates full list of major tick marks, whether using default_major_tick_distance (from Design), Helix.major_tick_distance, or Helix.major_ticks. They are used in reverse order to determine precedence. (e.g., Helix.major_ticks overrides Helix.major_tick_distance, which overrides default_major_tick_distance from Design.

property domains

Return Domain’s on this Helix. Assigned when a Design is created using this Helix.

Returns

Domain’s on this helix

class scadnano.Domain(helix: int, forward: bool, start: int, end: int, deletions: List[int] = <factory>, insertions: List[Tuple[int, int]] = <factory>, name: Optional[str] = None, label: Optional[DomainLabel] = None)

A maximal portion of a Strand that is continguous on a single Helix. A Strand contains a list of Domain’s (and also potentially Loopout’s).

helix: int

index of the Helix on which this Domain resides.

forward: bool

Whether the strand “points” forward (i.e., its 3’ end has a larger offset than its 5’ end). If Domain.forward is True, then Domain.start is the 5’ end of the Domain and Domain.end is the 3’ end of the Domain. If Domain.forward is False, these roles are reversed.

start: int

The smallest offset position of any base on this Domain (3’ end if Domain.forward = False, 5’ end if Domain.forward = True).

end: int

1 plus the largest offset position of any base on this Domain (5’ end if Domain.forward = False, 3’ end if Domain.forward = True). Note that the set of base offsets occupied by this Domain is {start, start+1, …, end-1}, i.e., inclusive for Strand.start but exclusive for Strand.end, the same convention used in Python for slices of lists and strings. (e.g., "abcdef"[1:3] == "bc")

Some methods (such as Domain.dna_sequence_in()) use the convention of being inclusive on both ends and are marked with the word “INCLUSIVE”. (Such a convention is easier to reason about when there are insertions and deletions.)

deletions: List[int]

List of positions of deletions on this Domain.

insertions: List[Tuple[int, int]]

List of (position,num_insertions) pairs on this Domain.

This is the number of extra bases in addition to the base already at this position. The total number of bases at this offset is num_insertions+1.

name: Optional[str] = None

Optional name to give this Domain.

This is used to interoperate with the dsd DNA sequence design package.

label: Optional[DomainLabel] = None

Generic “label” object to associate to this Domain.

Useful for associating extra information with the Domain that will be serialized, for example, for DNA sequence design. It must be an object (e.g., a dict or primitive type such as str or int) that is naturally JSON serializable. (Calling json.dumps on the object should succeed without having to specify a custom encoder.)

strand()scadnano.Strand
Returns

The Strand that contains this Loopout.

set_name(name: str) → None

Sets name of this Domain.

set_label(label: DomainLabel) → None

Sets label of this Domain.

offset_5p() → int

5’ offset of this Domain, INCLUSIVE.

offset_3p() → int

3’ offset of this Domain, INCLUSIVE.

contains_offset(offset: int) → bool

Indicates if offset is the offset of a base on this Domain.

Note that offsets refer to visual portions of the displayed grid for the Helix. If for example, this Domain starts at position 0 and ends at 10, and it has 5 deletions, then it contains the offset 7 even though there is no base 7 positions from the start.

dna_length() → int

Number of bases in this Domain.

dna_length_in(left: int, right: int) → int

Number of bases in this Domain between offsets left and right (INCLUSIVE).

visual_length() → int

Distance between Domain.start offset and Domain.end offset.

This can be more or less than the Domain.dna_length() due to insertions and deletions.

dna_sequence() → Optional[str]

Return DNA sequence of this Domain, or None if no DNA sequence has been assigned to this Domain’s Strand.

dna_sequence_in(offset_left: int, offset_right: int) → Optional[str]

Return DNA sequence of this Domain in the interval of offsets given by [offset_left, offset_right], INCLUSIVE, or None if no DNA sequence has been assigned to this Domain’s Strand.

WARNING: This is inclusive on both ends, unlike other parts of this API where the right endpoint is exclusive. This is to make the notion well-defined when one of the endpoints is on an offset with a deletion or insertion.

get_seq_start_idx() → int

Starting DNA subsequence index for first base of this Domain on its Parent Strand’s DNA sequence.

domain_offset_to_strand_dna_idx(offset: int, offset_closer_to_5p: bool) → int

Convert from offset on this Domain’s Helix to string index on the parent Strand’s DNA sequence.

If offset_closer_to_5p is True, (this only matters if offset contains an insertion) then the only leftmost string index corresponding to this offset is included, otherwise up to the rightmost string index (including all insertions) is included.

overlaps(other: scadnano.Domain) → bool

Indicates if this Domain’s set of offsets (the set \(\{x \in \mathbb{N} \mid\) self.start \(\leq x \leq\) self.end \(\}\)) has nonempty intersection with those of other, and they appear on the same helix, and they point in opposite directions.

overlaps_illegally(other: scadnano.Domain) → bool

Indicates if this Domain’s set of offsets (the set \(\{x \in \mathbb{N} \mid\) self.start \(\leq x \leq\) self.end \(\}\)) has nonempty intersection with those of other, and they appear on the same helix, and they point in the same direction.

compute_overlap(other: scadnano.Domain) → Tuple[int, int]

Return [left,right) offset indicating overlap between this Domain and other.

Return (-1,-1) if they do not overlap (different helices, or non-overlapping regions of the same helix).

insertion_offsets() → List[int]

Return offsets of insertions (but not their lengths).

class scadnano.Loopout(length: int, name: Optional[str] = None, label: Optional[DomainLabel] = None)

Represents a single-stranded loopout on a Strand.

One could think of a Loopout as a type of Domain, but none of the fields of Domain make sense for Loopout, so they are not related to each other in the type hierarchy. It is interpreted that a Loopout is a single-stranded region bridging two Domain’s that are connected to Helix’s. It is illegal for two consecutive Domain’s to both be Loopout’s, or for a Loopout to occur on either end of the Strand (i.e., each Strand must begin and end with a Domain).

For example, one use of a loopout is to describe a hairpin (a.k.a., stem-loop). The following creates a Strand that represents a hairpin with a stem length of 10 and a loop length of 5.

import scadnano as sc

domain_f = sc.Domain(helix=0, forward=True, start=0, end=10)
loop = sc.Loopout(length=5)
domain_r = sc.Domain(helix=0, forward=False, start=0, end=10)
hairpin = sc.Strand([domain_f, loop, domain_r])

It can also be created with chained method calls

import scadnano as sc

design = sc.Design(helices=[sc.Helix(max_offset=10)])
design.strand(0,0).move(10).loopout(0,5).move(-10)
length: int

Length (in DNA bases) of this Loopout.

name: Optional[str] = None

Optional name to give this Loopout.

This is used to interoperate with the dsd DNA sequence design package.

label: Optional[DomainLabel] = None

Generic “label” object to associate to this Loopout.

Useful for associating extra information with the Loopout that will be serialized, for example, for DNA sequence design. It must be an object (e.g., a dict or primitive type such as str or int) that is naturally JSON serializable. (Calling json.dumps on the object should succeed without having to specify a custom encoder.)

strand()scadnano.Strand
Returns

The Strand that contains this Loopout.

set_name(name: str) → None

Sets name of this Loopout.

set_label(label: Optional[DomainLabel]) → None

Sets label of this Loopout.

dna_length() → int

Length of this Loopout; same as field Loopout.length.

dna_sequence() → Optional[str]

Return DNA sequence of this Loopout, or None if no DNA sequence has been assigned to the Strand of this Loopout.

get_seq_start_idx() → int

Starting DNA subsequence index for first base of this Loopout on its Strand’s DNA sequence.

scadnano.wc(seq: str) → str

Return reverse Watson-Crick complement of seq.

class scadnano.IDTFields(scale: str = '25nm', purification: str = 'STD', plate: Optional[str] = None, well: Optional[str] = None)

Data required when ordering DNA strands from the synthesis company IDT (Integrated DNA Technologies). This data is used when automatically generating files used to order DNA from IDT.

When exporting to IDT files via Design.write_idt_plate_excel_file() or Design.write_idt_bulk_input_file(), the field Strand.name is used for the name if it exists, otherwise a reasonable default is chosen.

scale: str = '25nm'

Synthesis scale at which to synthesize the strand (third field in IDT bulk input: https://www.idtdna.com/site/order/oligoentry). Choices supplied by IDT at the time this was written: "25nm", "100nm", "250nm", "1um", "5um", "10um", "4nmU", "20nmU", "PU", "25nmS".

Optional field.

purification: str = 'STD'

Purification options (fourth field in IDT bulk input: https://www.idtdna.com/site/order/oligoentry). Choices supplied by IDT at the time this was written: "STD", "PAGE", "HPLC", "IEHPLC", "RNASE", "DUALHPLC", "PAGEHPLC".

Optional field.

plate: Optional[str] = None

Name of plate in case this strand will be ordered on a 96-well or 384-well plate.

Optional field, but non-optional if IDTField.well is not None.

well: Optional[str] = None

Well position on plate in case this strand will be ordered on a 96-well or 384-well plate.

Optional field, but non-optional if IDTField.plate is not None.

class scadnano.StrandBuilder(design: scadnano.Design[StrandLabel, DomainLabel], helix: int, offset: int)

Represents a Strand that is being built in an existing Design.

This is an intermediate object created when using chained method building by calling Design.strand(), for example

design.strand(0, 0).to(10).cross(1).to(5).with_modification_5p(mod.biotin_5p).as_scaffold()

StrandBuilder should generally not be created directly. Although it is convenient to use chained method calls, it is also sometimes useful to assign the StrandBuilder object into a variable and then call the methods on that variable. For example, this code is equivalent to the above line:

strand_builder = design.strand(0, 0)
strand_builder.to(10)
strand_builder.cross(1)
strand_builder.to(5)
strand_builder.with_modification_5p(mod.biotin_5p)
strand_builder.as_scaffold()
cross(helix: int, offset: Optional[int] = None, move: Optional[int] = None)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Add crossover. To have any effect, must be followed by call to StrandBuilder.to() or StrandBuilder.move().

Parameters
  • helixHelix to crossover to

  • offset – new offset on helix. If not specified, defaults to current offset. (i.e., a “vertical” crossover) Mutually excusive with move.

  • move – Relative distance to new offset on helix from current offset. If not specified, defaults to using parameter offset. Mutually excusive with offset.

Returns

self

loopout(helix: int, length: int, offset: Optional[int] = None, move: Optional[int] = None)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Like StrandBuilder.cross(), but creates a Loopout instead of a crossover.

Parameters
  • helixHelix to crossover to

  • length – length of Loopout to add

  • offset – new offset on helix. If not specified, defaults to current offset. (i.e., a “vertical” loopout) Mutually excusive with move.

  • move – Relative distance to new offset on helix from current offset. If not specified, defaults to using parameter offset. Mutually excusive with offset.

Returns

self

move(delta: int)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Extends this StrandBuilder on the current helix to offset given by the current offset plus delta, which adds a new Domain to the Strand being built. This is a “relative move”, whereas StrandBuilder.to() and StrandBuilder.update_to() are “absolute moves”.

This updates the underlying Design with a new Domain, and if StrandBuilder.loopout() was last called on this StrandBuilder, also a new Loopout.

If two instances of StrandBuilder.move() are chained together, this creates two domains on the same helix. The two offsets must move in the same direction. In other words, if we call .move(o1).move(o2), then o1 and o2 must be either both negative or both positive.

Parameters

delta – Distance to new offset to extend to, compared to current offset. If less than current offset, the new Domain is reverse, otherwise it is forward.

Returns

self

to(offset: int)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Extends this StrandBuilder on the current helix to offset offset, which adds a new Domain to the Strand being built. This is an “absolute move”, whereas StrandBuilder.move() is a “relative move”.

This updates the underlying Design with a new Domain, and if StrandBuilder.loopout() was last called on this StrandBuilder, also a new Loopout.

If two instances of StrandBuilder.to() are chained together, this creates two domains on the same helix. The two offsets must move in the same direction. In other words, if the starting offset is s, and we call .to(o1).to(o2), then either s < o1 < o2 or o2 < o1 < s must be true.

To simply change the current offset after calling StrandBuilder.to(), without creating a new Domain, call StrandBuilder.update_to() instead.

Parameters

offset – new offset to extend to. If less than current offset, the new Domain is reverse, otherwise it is forward.

Returns

self

update_to(offset: int)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Like StrandBuilder.to(), but changes the current offset without creating a new Domain. So unlike StrandBuilder.to(), several consecutive calls to StrandBuilder.update_to() are equivalent to only making the final call. This is an “absolute move”, whereas StrandBuilder.move() is a “relative move”.

If StrandBuilder.cross() or StrandBuilder.loopout() was just called, then StrandBuilder.to() and StrandBuilder.update_to() have the same effect.

Parameters

offset – new offset to extend to. If less than offset of the last call to StrandBuilder.cross() or StrandBuilder.loopout(), the new Domain is reverse, otherwise it is forward.

Returns

self

as_circular()scadnano.StrandBuilder[StrandLabel, DomainLabel]

Makes Strand being built circular.

Returns

self

as_scaffold()scadnano.StrandBuilder[StrandLabel, DomainLabel]

Makes Strand being built a scaffold.

Returns

self

with_idt(scale: str = '25nm', purification: str = 'STD', plate: Optional[str] = None, well: Optional[str] = None)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Gives IDTFields value to Strand being built. Only a name is required; other fields are given reasonable default values.

Parameters
Returns

self

with_modification_5p(mod: scadnano.Modification5Prime)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Sets Strand being built to have given 5’ modification.

Parameters

mod – 5’ modification

Returns

self

with_modification_3p(mod: scadnano.Modification3Prime)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Sets Strand being built to have given 3’ modification.

Parameters

mod – 3’ modification

Returns

self

with_modification_internal(idx: int, mod: scadnano.ModificationInternal, warn_on_no_dna: bool)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Sets Strand being built to have given internal modification.

Parameters
  • idx – idx along DNA sequence of internal modification

  • mod – internal modification

  • warn_on_no_dna – whether to print warning to screen if DNA has not been assigned

Returns

self

with_color(color: scadnano.Color)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Sets Strand being built to have given color.

Parameters

color – color to set for Strand

Returns

self

with_sequence(sequence: str, assign_complement: bool = True)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Assigns sequence as DNA sequence of the Strand being built. This should be done after the Strand’s structure is done being built, e.g.,

design.strand(0, 0).to(10).cross(1).to(5).with_sequence('AAAAAAAAAACGCGC')
Parameters
  • sequence – the DNA sequence to assign to the Strand

  • assign_complement – whether to automatically assign the complement to existing Strand’s bound to this Strand. This has the same meaning as the parameter assign_complement in Design.assign_dna().

Returns

self

with_domain_sequence(sequence: str, assign_complement: bool = True)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Assigns sequence as DNA sequence of the most recently created Domain in the Strand being built. This should be called immediately after a Domain is created via a call to StrandBuilder.to(), StrandBuilder.update_to(), or StrandBuilder.loopout(), e.g.,

design.strand(0, 5).to(8).with_domain_sequence('AAA')\
    .cross(1).to(5).with_domain_sequence('TTT')\
    .loopout(2, 4).with_domain_sequence('CCCC')\
    .to(10).with_domain_sequence('GGGGG')
Parameters
  • sequence – the DNA sequence to assign to the Domain

  • assign_complement – whether to automatically assign the complement to existing Strand’s bound to this Strand. This has the same meaning as the parameter assign_complement in Design.assign_dna().

Returns

self

with_name(name: str)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Assigns name as name of the Strand being built.

design.strand(0, 0).to(10).cross(1).to(5).with_name('scaffold')
Parameters

name – name to assign to the Strand

Returns

self

with_label(label: StrandLabel)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Assigns label as label of the Strand being built.

design.strand(0, 0).to(10).cross(1).to(5).with_label('scaffold')
Parameters

label – label to assign to the Strand

Returns

self

with_domain_name(name: str)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Assigns name as of the most recently created Domain or Loopout in the Strand being built. This should be called immediately after a Domain is created via a call to StrandBuilder.to(), StrandBuilder.update_to(), or StrandBuilder.loopout(), e.g.,

design.strand(0, 0).to(10).with_domain_name('dom1*').cross(1).to(5).with_domain_name('dom1')
Parameters

name – name to assign to the most recently created Domain or Loopout

Returns

self

with_domain_label(label: DomainLabel)scadnano.StrandBuilder[StrandLabel, DomainLabel]

Assigns label as label of the most recently created Domain or Loopout in the Strand being built. This should be called immediately after a Domain is created via a call to StrandBuilder.to(), StrandBuilder.update_to(), or StrandBuilder.loopout(), e.g.,

design.strand(0, 5).to(8).with_domain_label('domain 1')\
    .cross(1).to(5).with_domain_label('domain 2')\
    .loopout(2, 4).with_domain_label('domain 3')\
    .to(10).with_domain_label('domain 4')
Parameters

label – label to assign to the Domain or Loopout

Returns

self

class scadnano.Strand(domains: List[Union[scadnano.Domain[DomainLabel], scadnano.Loopout[DomainLabel]]], circular: bool = False, dna_sequence: Optional[str] = None, color: Optional[scadnano.Color] = None, idt: Optional[scadnano.IDTFields] = None, is_scaffold: bool = False, modification_5p: Optional[scadnano.Modification5Prime] = None, modification_3p: Optional[scadnano.Modification3Prime] = None, modifications_int: Dict[int, scadnano.ModificationInternal] = <factory>, name: Optional[str] = None, label: Optional[StrandLabel] = None)

Represents a single strand of DNA.

Each maximal portion that is continguous on a single Helix is a Domain. Crossovers from one Helix to another are implicitly from the 3’ end of one of this Strand’s Domain’s to the 5’ end of the next Domain.

A portion of the Strand not associated to any Helix is represented by a Loopout. Two Loopout’s cannot occur consecutively on a Strand, nor can a Strand contain only a Loopout but no Domain.

One can set the strand to be a scaffold in the constructor:

import scadnano as sc

scaffold_domains = [ ... ]
scaffold_strand = sc.Strand(domains=scaffold_domains, is_scaffold=True)

or by calling Strand.set_scaffold() on the Strand object:

import scadnano as sc

scaffold_domains = [ ... ]
scaffold_strand = sc.Strand(domains=scaffold_domains)
scaffold_strand.set_scaffold()

Both will give the strand the same color that cadnano uses for the scaffold.

domains: List[Union[scadnano.Domain[DomainLabel], scadnano.Loopout[DomainLabel]]]

Domain’s (or Loopout’s) composing this Strand. Each Domain is contiguous on a single Helix and could be either single-stranded or double-stranded, whereas each Loopout is single-stranded and has no associated Helix.

circular: bool = False

If True, this Strand is circular and has no 5’ or 3’ end. Although there is still a first and last Domain, we interpret there to be a crossover from the 3’ end of the last domain to the 5’ end of the first domain, and any circular permutation of Strand.domains should result in a functionally equivalent Strand. It is illegal to have a Modification5Prime or Modification3Prime on a circular Strand.

dna_sequence: Optional[str] = None

Do not assign directly to this field. Always use Design.assign_dna (for complementarity checking) or Strand.set_dna_sequence (without complementarity checking, to allow mismatches).

color: Optional[scadnano.Color] = None

Color to show this strand in the main view. If not specified in the constructor, a color is assigned by cycling through a list of defaults given by ColorCycler.colors()

idt: Optional[scadnano.IDTFields] = None

Fields used when ordering strands from the synthesis company IDT (Integrated DNA Technologies, Coralville, IA). If present (i.e., not equal to None) then the method Design.write_idt_bulk_input_file() can be called to automatically generate an text file for ordering strands in test tubes: https://www.idtdna.com/site/order/oligoentry, as can the method Design.write_idt_plate_excel_file() for writing a Microsoft Excel file that can be uploaded to IDT’s website for describing DNA sequences to be ordered in 96-well or 384-well plates.

is_scaffold: bool = False

Indicates whether this Strand is a scaffold for a DNA origami. If any Strand in a Design is a scaffold, then the design is considered a DNA origami design.

modification_5p: Optional[scadnano.Modification5Prime] = None

5’ modification; None if there is no 5’ modification. Illegal to have if Strand.circular is True.

modification_3p: Optional[scadnano.Modification3Prime] = None

3’ modification; None if there is no 3’ modification. Illegal to have if Strand.circular is True.

modifications_int: Dict[int, scadnano.ModificationInternal]

Modification’s to the DNA sequence (e.g., biotin, Cy3/Cy5 fluorphores). Maps offset to modification. If the internal modification is attached to a base (e.g., internal biotin, /iBiodT/ from IDT), then the offset is that of the base. If it goes between two bases (e.g., internal Cy3, /iCy3/ from IDT), then the offset is that of the previous base, e.g., to put a Cy3 between bases at offsets 3 and 4, the offset should be 3. So for an internal modified base on a sequence of length n, the allowed offsets are 0,…,n-1, and for an internal modification that goes between bases, the allowed offsets are 0,…,n-2.

name: Optional[str] = None

Optional name to give the strand. If specified it is shown on mouseover in the scadnano web interface.

This is used to interoperate with the dsd DNA sequence design package.

label: Optional[StrandLabel] = None

Generic “label” object to associate to this Strand.

Useful for associating extra information with the Strand that will be serialized, for example, for DNA sequence design. It must be an object (e.g., a dict or primitive type such as str or int) that is naturally JSON serializable. (Calling json.dumps on the object should succeed without having to specify a custom encoder.)

rotate_domains(rotation: int, forward: bool = True) → None

“Rotates” the strand by replacing domains with a circular rotation, e.g., if the domains are

A, B, C, D, E, F

then strand.rotate_domains(2) makes the Strand have the same domains, but in this order:

E, F, A, B, C, D

and strand.rotate_domains(2, forward=False) makes

C, D, E, F, A, B

Parameters
  • rotation – Amount to rotate domains.

  • forward – Whether to move domains forward (wrapping off 3’ end back to 5’ end) or backward (wrapping off 5’ end back to 3’ end).

set_scaffold(is_scaf: bool = True) → None

Sets this Strand as a scaffold. Alters color to default scaffold color.

If is_scaf == False, sets this strand as not a scaffold, and leaves the color alone.

set_name(name: str) → None

Sets name of this Strand.

set_label(label: Any) → None

Sets label of this Strand.

set_color(color: scadnano.Color) → None

Sets color of this Strand.

set_circular(circular: bool = True) → None

Sets this to be a circular Strand (or non-circular if optional parameter is False).

Parameters

circular – whether to make this Strand circular (True) or linear (False)

Raises

StrandError – if this Strand has a 5’ or 3’ modification

set_linear() → None

Makes this a linear (non-circular) Strand. Equivalent to calling self.set_circular(False).

set_domains(domains: Iterable[Union[scadnano.Domain[DomainLabel], scadnano.Loopout[DomainLabel]]]) → None

Sets the Domain’s/Loopout’s of this Strand to be domains, which can contain a mix of Domain’s and Loopout’s, just like the field Strand.domains.

Parameters

domains – The new sequence of Domain’s/Loopout’s to use for this Strand.

Raises

StrandError – if domains has two consecutive Loopout’s, consists of just a single Loopout’s, or starts or ends with a Loopout

idt_export_name(unique_names: bool = False) → str
Parameters

unique_names – If True and default name is used, enforces that strand names must be unique by encoding the forward/reverse Boolean into the name. If False (the default), uses cadnano’s exact naming convention, which allows two strands to have the same default name, if they begin and end at the same (helix,offset) pair (but point in opposite directions at each). Has no effect if Strand.idt or Strand.name are defined; if those are used, they must be explicitly set to be unique.

Returns

If Strand.name is not None, return Strand.name, otherwise return the result of Strand.default_export_name() with parameter unique_names.

default_export_name(unique_names: bool = False) → str

Returns a default name to use when exporting the DNA sequence. Uses cadnano’s naming convention of, for example ‘ST2[5]4[10]’ to indicate a strand that starts at helix 2, offset 5, and ends at helix 4, offset 10. Note that this naming convention is not unique: two strands in the system could share this name. To ensure it is unique, set the parameter unique_names to True, which will modify the name with forward/reverse information from the first domain that uniquely identifies the strand, e.g., ‘ST2[5]F4[10]’ or ‘ST2[5]R4[10]’.

If the strand is a scaffold (i.e., if Strand.is_scaffold is True), then the name will begin with ‘SCAF’ instead of ‘ST’.

Parameters

unique_names – If True, enforces that strand names must be unique by encoding the forward/reverse Boolean into the name. If False (the default), uses cadnano’s exact naming convention, which allows two strands to have the same default name, if they begin and end at the same (helix,offset) pair (but point in opposite directions at each).

Returns

default name to export (used, for example, by idt DNA export methods Design.write_idt_plate_excel_file() and Design.write_idt_bulk_input_file() if Strand.name and Strand.idt.name are both not set)

set_modification_5p(mod: Optional[scadnano.Modification5Prime] = None) → None

Sets 5’ modification to be mod. mod cannot be non-None if Strand.circular is True.

set_modification_3p(mod: Optional[scadnano.Modification3Prime] = None) → None

Sets 3’ modification to be mod. mod cannot be non-None if Strand.circular is True.

remove_modification_5p() → None

Removes 5’ modification.

remove_modification_3p() → None

Removes 3’ modification.

set_modification_internal(idx: int, mod: scadnano.ModificationInternal, warn_on_no_dna: bool = True) → None

Adds internal modification mod at given DNA index idx.

remove_modification_internal(idx: int) → None

Removes internal modification at given DNA index idx.

first_domain()scadnano.Domain

First domain on this Strand.

last_domain()scadnano.Domain

Last domain on this Strand.

set_dna_sequence(sequence: str) → None

Set this Strand’s DNA sequence to seq WITHOUT checking for complementarity with overlapping Strand’s or automatically assigning their sequences. To assign a sequence to a Strand and have the overlapping Strand’s automatically have the appropriate Watson-Crick complements assigned, use Design.assign_dna.

All whitespace in sequence is removed, and lowercase bases ‘a’, ‘c’, ‘g’, ‘t’ are converted to uppercase.

sequence, after all whitespace is removed, must be exactly the same length as Strand.dna_length(). Wildcard symbols (DNA_case_wildcard) are allowed to leave part of the DNA unassigned.

dna_length() → int

Return sum of DNA length of Domain’s and Loopout’s of this Strand.

bound_domains() → List[scadnano.Domain]

Domain’s of this Strand that are not Loopout’s.

offset_5p() → int

5’ offset of this entire Strand, INCLUSIVE.

offset_3p() → int

3’ offset of this entire Strand, INCLUSIVE.

overlaps(other: scadnano.Strand) → bool

Indicates whether self overlaps other_strand, meaning that the set of offsets occupied by self has nonempty intersection with those occupied by other_strand.

assign_dna_complement_from(other: scadnano.Strand) → None

Assuming a DNA sequence has been assigned to other, assign its Watson-Crick complement to the portions of this Strand that are bound to other.

Generally this is not called directly; use Design.assign_dna() to assign a DNA sequence to a Strand. The method Design.assign_dna() will calculate which other Strand’s need to be assigned via Strand.assign_dna_complement_from().

However, it is permitted to assign the field Strand.dna_sequence directly via the method Strand.set_dna_sequence(). This is used, for instance, to assign a DNA sequence to a Strand bound to another Strand with an assigned DNA sequence where they overlap. In this case no error checking about sequence complementarity is done. This can be used to intentionally assign mismatching DNA sequences to Strand’s that are bound on a Helix.

dna_index_start_domain(domain: Union[scadnano.Domain, scadnano.Loopout]) → int

Returns index in DNA sequence of domain, e.g., if there are five domains

012 3 45 678 9 AAA-C-GG-TTT-ACGT

Then their indices, respectively in order, are 0, 3, 4, 6, 9.

Parameters

domain

any

to find the start DNA index of

Returns

index (within DNA sequence string) of substring of DNA starting with given Domain

first_bound_domain()scadnano.Domain

First Domain (i.e., not a Loopout) on this Strand.

Currently the first and last strand must not be Loopout’s, so this should return the same domain as Strand.first_domain(), but in case an initial or final Loopout is supported in the future, this method is provided.

last_bound_domain()scadnano.Domain

Last Domain (i.e., not a Loopout) on this Strand.

Currently the first and last strand must not be Loopout’s, so this should return the same domain as Strand.first_domain(), but in case an initial or final Loopout is supported in the future, this method is provided.

reverse() → None

Reverses “polarity” of this Strand.

Does NOT check whether this keeps the Design legal, so be cautious in calling this method directly. To reverse every Strand, called Design.reverse_all(). If the design was legal before, it will be legal after calling that method.

no_modifications_version()scadnano.Strand
Returns

version of this Strand with no DNA modifications.

class scadnano.StrandOrder(value)

Which part of a Strand to use for sorting in the key function returned by strand_order_key_function().

five_prime = 0

5’ end of the strand

three_prime = 1

3’ end of the strand

five_or_three_prime = 2

Either 5’ end or 3’ end is used, whichever is first according to the sort order.

top_left_domain = 3

The start offset of the “top-left” Domain of the Strand: the Domain whose Domain.helix is minimal, and, among all such Domain’s, the one with minimal Domain.start.

scadnano.strand_order_key_function(*, column_major: bool = True, strand_order: scadnano.StrandOrder) → Callable[[scadnano.Strand], Any]

Returns a key function indicating a sorted order for Strand’s. Useful as a parameter for Design.().

Parameters
  • column_major – If true, column major order is used: ordered by base offset first, then by helix. Otherwise row-major order is used: ordered by helix first, then by base offset.

  • strand_order – Which part of the strand to use as a key for the sorted order. See StrandOrder for definitions.

Returns

A key function that can be passed to Design.() to specify a sorted order for the Strand’s.

exception scadnano.IllegalDesignError(the_cause: str)

Indicates that some aspect of the Design object is illegal.

exception scadnano.StrandError(strand: scadnano.Strand, the_cause: str)

Indicates that the Design is illegal due to some specific Strand. Information about the Strand is embedded in the error message when this exception is raised that helps to identify which Strand caused the problem.

class scadnano.PlateType(value)

Represents two different types of plates in which DNA sequences can be ordered.

wells96 = 96

96-well plate.

wells384 = 384

384-well plate.

class scadnano.Geometry(rise_per_base_pair: float = 0.332, helix_radius: float = 1.0, bases_per_turn: float = 10.5, minor_groove_angle: float = 150.0, inter_helix_gap: float = 1.0)

Parameters controlling some geometric visualization/physical aspects of Design.

rise_per_base_pair: float = 0.332

Distance in nanometers between two adjacent base pairs along the length of a DNA double helix.

helix_radius: float = 1.0

Radius of a DNA helix in nanometers.

bases_per_turn: float = 10.5

Number of DNA base pairs in a full turn of DNA.

minor_groove_angle: float = 150.0

Minor groove angle in degrees.

inter_helix_gap: float = 1.0

Gap between helices in nanometers (due to electrostatic repulsion; needed to display to scale).

class scadnano.Design(*, helices: Optional[Union[List[scadnano.Helix], Dict[int, scadnano.Helix]]] = None, groups: Optional[Dict[str, scadnano.HelixGroup]] = None, strands: Optional[List[scadnano.Strand]] = None, grid: Optional[scadnano.Grid] = None, helices_view_order: Optional[List[int]] = None, geometry: Optional[scadnano.Geometry] = None)

Object representing the entire design of the DNA structure.

automatically_assign_color: bool = True

If automatically_assign_color = False, then for any Strand such that Strand.color = None, do not automatically assign a Color to it. In this case color will be set to its default of None and will not be written to the JSON with Design.write_scadnano_file() or Design.to_json().

strands: List[scadnano.Strand[StrandLabel, DomainLabel]]

All of the Strand’s in this Design.

Required field.

geometry: scadnano.Geometry

Controls some geometric/physical aspects of this Design.

groups: Dict[str, scadnano.HelixGroup] = None

HelixGroup’s in this Design.

helices: Dict[int, scadnano.Helix] = None

All of the Helix’s in this Design. This is a dictionary mapping index to the Helix with that index; if helices have indices 0, 1, …, num_helices-1, then this can be used as a list of Helices.

Optional field. If not specified, then the number of helices will be just large enough to store the largest index Domain.helix stored in any Domain in Design.strands.

property helices_view_order

Return helices_view_order of this Design if no HelixGroup’s are being used, otherwise raise a ValueError.

Returns

helices_view_order of this Design

property grid

Return grid of this Design if no HelixGroup’s are being used, otherwise raise a ValueError.

Returns

grid of this Design

set_grid(grid: scadnano.Grid) → None

Sets the grid of the default HelixGroup, if the default is being used, otherwise raises an exception.

Parameters

grid – new grid to set for the (only) HelixGroup in this Design

Raises

IllegalDesignError – if there is more than one HelixGroup in this Design

helices_idxs_in_group(group_name: str) → List[int]

Indexes of Helix’s in this group. Must be associated with a Design for this to work.

Parameters

group_name – name of group

Returns

list of indices of Helix’s in this HelixGroup

static from_scadnano_file(filename: str)scadnano.Design

Loads a Design from the file with the given name.

Parameters

filename – name of the file with the design. Should be a JSON file ending in .dna

Returns

Design described in the file

static from_scadnano_json_str(json_str: str)scadnano.Design

Loads a Design from the given JSON string.

Parameters

json_str – JSON description of the Design

Returns

Design described in the JSON string

static from_scadnano_json_map(json_map: dict)scadnano.Design

Loads a Design from the given JSON object (i.e., Python object obtained by calling json.loads(json_str) from a string representing contents of a JSON file.

Parameters

json_map – map describing the Design; should be JSON serializable via encode(json_map)

Returns

Design described in the object

property scaffold

Returns the first scaffold in this Design, if there is one, or None otherwise.

static from_cadnano_v2(directory: Optional[str] = None, filename: Optional[str] = None, json_dict: Optional[dict] = None)scadnano.Design

Creates a Design from a cadnano v2 file.

strand(helix: int, offset: int)scadnano.StrandBuilder

Used for chained method building by calling Design.strand() to build the Strand domain by domain, in order from 5’ to 3’. For example

design.strand(0, 7).to(10).cross(1).to(5).cross(2).to(15)

This creates a Strand in this Design equivalent to

design.add_strand(Strand([
    sc.Domain(0, True, 7, 10),
    sc.Domain(1, False, 5, 10),
    sc.Domain(2, True, 5, 15),
]))

Loopouts can also be included:

design.strand(0, 7).to(10).cross(1).to(5).loopout(2, 3).to(15)

This creates a Strand in this Design equivalent to

design.add_strand(Strand([
    sc.Domain(0, True, 7, 10),
    sc.Domain(1, False, 5, 10),
    sc.Loopout(3),
    sc.Domain(2, True, 5, 15),
]))

Each call to Design.strand(), StrandBuilder.cross(), StrandBuilder.loopout(), StrandBuilder.to() StrandBuilder.update_to(), returns a StrandBuilder object.

Each call to StrandBuilder.to(), StrandBuilder.update_to(), or StrandBuilder.loopout() modifies the Design by replacing the Strand with an updated version.

See the documentation for StrandBuilder for the methods available to call in this way.

Parameters
  • helix – starting Helix

  • offset – starting offset on helix

Returns

StrandBuilder object representing the partially completed Strand

assign_m13_to_scaffold(rotation: int = 5587, variant: scadnano.M13Variant = <M13Variant.p7249: 'p7249'>) → None

Assigns the scaffold to be the sequence of M13: m13() with the given rotation and M13Variant.

Raises IllegalDesignError if the number of scaffolds is not exactly 1.

to_cadnano_v2() → Dict[str, Any]

Converts the design to the cadnano v2 format. Please see the spec misc/cadnano-format-specs/v2.txt for more info on that format.

set_helices_view_order(helices_view_order: List[int]) → None

Sets helices_view_order.

Parameters

helices_view_order – new view order of helices

strands_starting_on_helix(helix: int) → List[scadnano.Strand]

Return list of Strand’s that begin (have their 5’ end) on the Helix with index helix.

strands_ending_on_helix(helix: int) → List[scadnano.Strand]

Return list of Strand’s that finish (have their 3’ end) on the Helix with index helix.

domain_at(helix: int, offset: int, forward: bool) → Optional[scadnano.Domain]

Return Domain that overlaps offset on helix with idx helix and has Domain.forward = True, or None if there is no such Domain.

Parameters
  • helix – TODO

  • offset – TODO

  • forward – TODO

Returns

TODO

domains_at(helix: int, offset: int) → List[scadnano.Domain]

Return list of Domain’s that overlap offset on helix with idx helix.

If constructed properly, this list should have 0, 1, or 2 elements.

add_strand(strand: scadnano.Strand) → None

Add strand to this design.

remove_strand(strand: scadnano.Strand) → None

Remove strand from this design.

append_domain(strand: scadnano.Strand, domain: Union[scadnano.Domain, scadnano.Loopout]) → None

Same as Design.insert_domain, but inserts at end.

Parameters
insert_domain(strand: scadnano.Strand, order: int, domain: Union[scadnano.Domain, scadnano.Loopout]) → None

Insert Domain into strand at index given by order. Uses same indexing as Python lists, e.g., design.insert_domain(strand, domain, 0) inserts domain as the new first Domain.

remove_domain(strand: scadnano.Strand, domain: Union[scadnano.Domain, scadnano.Loopout]) → None

Remove Domain from strand.

to_json(suppress_indent: bool = True) → str

Return string representing this Design, suitable for reading by scadnano if written to a JSON file ending in extension .sc

add_deletion(helix: int, offset: int) → None

Adds a deletion to every scadnano.Strand at the given helix and base offset.

add_insertion(helix: int, offset: int, length: int) → None

Adds an insertion with the given length to every scadnano.Strand at the given helix and base offset, with the given length.

set_start(domain: scadnano.Domain, start: int) → None

Sets Domain.start to start.

set_end(domain: scadnano.Domain, end: int) → None

Sets Domain.end to end.

move_strand_offsets(delta: int) → None

Moves all strands backward (if delta < 0) or forward (if delta > 0) by delta.

move_strands_on_helices(delta: int) → None

Moves all strands up (if delta < 0) or down (if delta > 0) by the number of helices given by delta.

assign_dna(strand: scadnano.Strand, sequence: str, assign_complement: bool = True, domain: Optional[Union[scadnano.Domain, scadnano.Loopout]] = None, check_length: bool = False) → None

Assigns sequence as DNA sequence of strand.

If any scadnano.Strand is bound to strand, it is assigned the reverse Watson-Crick complement of the relevant portion, and any remaining portions of the other strand that have not already been assigned a DNA sequence are assigned to be the symbol DNA_base_wildcard.

Before assigning, sequence is first forced to be the same length as strand as follows: If sequence is longer, it is truncated. If sequence is shorter, it is padded with DNA_base_wildcard’s. This can be disabled by setting check_length to True, in which case the method raises an IllegalDesignError if the lengths do not match.

All whitespace in sequence is removed, and lowercase bases ‘a’, ‘c’, ‘g’, ‘t’ are converted to uppercase.

Parameters
  • strandStrand to assign DNA sequence to

  • sequence – string of DNA bases to assign

  • assign_complement – Whether to assign the complement DNA sequence to any Strand that is bound to this one (default True)

  • domainDomain on strand to assign. If None, then the whole Strand is given a DNA sequence. Otherwise, only domain is assigned, and the rest of the Domain’s on strand are left alone (either keeping their DNA sequence, or being assigned DNA_base_wildcard if no DNA sequence was previously assigned.) If domain is specified, then len(sequence) must be least than or equal to the number of bases on domain. (i.e., domain.dna_length())

  • check_length – If True, raises IllegalDesignError if length of Strand or Domain being assigned to does not match the length of the DNA sequence.

Raises

IllegalDesignError – If check_length is True and the length of Strand or Domain being assigned to does not match the length of the DNA sequence.

to_idt_bulk_input_format(delimiter: str = ',', key: Optional[Callable[[scadnano.Strand], Any]] = None, warn_duplicate_name: bool = False, only_strands_with_idt: bool = False, export_scaffold: bool = False, export_non_modified_strand_version: bool = False) → str

Called by Design.write_idt_bulk_input_file() to determine what string to write to the file. This function can be used to get the string directly without creating a file.

Parameters have the same meaning as in Design.write_idt_bulk_input_file().

Returns

string that is written to the file in the method Design.write_idt_bulk_input_file().

write_idt_bulk_input_file(*, directory: str = '.', filename: Optional[str] = None, key: Optional[Callable[[scadnano.Strand], Any]] = None, extension: Optional[str] = None, delimiter: str = ',', warn_duplicate_name: bool = True, only_strands_with_idt: bool = False, export_scaffold: bool = False, export_non_modified_strand_version: bool = False) → None

Write .idt text file encoding the strands of this Design with the field Strand.idt, suitable for pasting into the “Bulk Input” field of IDT (Integrated DNA Technologies, Coralville, IA, https://www.idtdna.com/), with the output file having the same name as the running script but with .py changed to .idt, unless filename is explicitly specified. For instance, if the script is named my_origami.py, then the sequences will be written to my_origami.idt. If filename is not specified but extension is, then that extension is used instead of idt. At least one of filename or extension must be None.

The string written is that returned by Design.to_idt_bulk_input_format().

Parameters
  • directory – specifies a directory in which to place the file, either absolute or relative to the current working directory. Default is the current working directory.

  • filename – optinoal custom filename to use (instead of currently running script)

  • key

    key function used to determine order in which to output strand sequences. Some useful defaults are provided by strand_order_key_function()

  • extension – alternate filename extension to use (instead of idt)

  • delimiter – is the symbol to delimit the four IDT fields name,sequence,scale,purification.

  • warn_duplicate_name – if True prints a warning when two different Strand’s have the same IDTField.name and the same Strand.dna_sequence. An IllegalDesignError is raised (regardless of the value of this parameter) if two different Strand’s have the same name but different sequences, IDT scales, or IDT purifications.

  • only_strands_with_idt – If False (the default), all non-scaffold sequences are output, with reasonable default values chosen if the field Strand.idt is missing. (though scaffold is included if export_scaffold is True). If True, then strands lacking the field Strand.idt will not be exported.

  • export_scaffold – If False (the default), scaffold sequences are not exported. If True, scaffold sequences on strands output according to only_strands_with_idt (i.e., scaffolds will be exported, unless they lack the field Strand.idt and only_strands_with_idt is True).

  • export_non_modified_strand_version – For any Strand with a Modification, also export a version of the Strand without any modifications. The name for this Strand is the original name with ‘_nomods’ appended to it.

write_idt_plate_excel_file(*, directory: str = '.', filename: Optional[str] = None, key: Optional[Callable[[scadnano.Strand], Any]] = None, warn_duplicate_name: bool = False, only_strands_with_idt: bool = False, export_scaffold: bool = False, use_default_plates: bool = True, warn_using_default_plates: bool = True, plate_type: scadnano.PlateType = <PlateType.wells96: 96>, export_non_modified_strand_version: bool = False) → None

Write .xls (Microsoft Excel) file encoding the strands of this Design with the field Strand.idt, suitable for uploading to IDT (Integrated DNA Technologies, Coralville, IA, https://www.idtdna.com/) to describe a 96-well or 384-well plate (https://www.idtdna.com/site/order/plate/index/dna/), with the output file having the same name as the running script but with .py changed to .xls, unless filename is explicitly specified. For instance, if the script is named my_origami.py, then the sequences will be written to my_origami.xls.

Parameters
  • directory – specifies a directory in which to place the file, either absolute or relative to the current working directory. Default is the current working directory.

  • filename – custom filename if default (explained above) is not desired

  • key

    key function used to determine order in which to output strand sequences. Some useful defaults are provided by strand_order_key_function()

  • warn_duplicate_name – if True prints a warning when two different Strand’s have the same IDTField.name and the same Strand.dna_sequence. An IllegalDesignError is raised (regardless of the value of this parameter) if two different Strand’s have the same name but different sequences, IDT scales, or IDT purifications.

  • only_strands_with_idt – If False (the default), all non-scaffold sequences are output, with reasonable default values chosen if the field Strand.idt is missing. (though scaffold is included if export_scaffold is True). If True, then strands lacking the field Strand.idt will not be exported. If False, then use_default_plates must be True.

  • export_scaffold – If False (the default), scaffold sequences are not exported. If True, scaffold sequences on strands output according to only_strands_with_idt (i.e., scaffolds will be exported, unless they lack the field Strand.idt and only_strands_with_idt is True).

  • use_default_plates – Use default values for plate and well (ignoring those in idt fields, which may be None). If False, each Strand to export must have the field Strand.idt, so in particular the parameter only_strands_with_idt must be True.

  • warn_using_default_plates – specifies whether, if use_default_plates is True, to print a warning for strands whose Strand.idt has the fields IDTFields.plate and IDTFields.well, since use_default_plates directs these fields to be ignored.

  • plate_type – a PlateType specifying whether to use a 96-well plate or a 384-well plate if the use_default_plates parameter is True. Ignored if use_default_plates is False, because in that case the wells are explicitly set by the user, who is free to use coordinates for either plate type.

  • export_non_modified_strand_version – For any Strand with a Modification, also export a version of the Strand without any modifications. The name for this Strand is the original name with ‘_nomods’ appended to it.

write_scadnano_file(directory: str = '.', filename: Optional[str] = None, extension: Optional[str] = None) → None

Write .sc file representing this Design, suitable for reading by scadnano, with the output file having the same name as the running script but with .py changed to .sc, unless filename is explicitly specified. For instance, if the script is named my_origami.py, then the design will be written to my_origami.sc. If extension is specified (but filename is not), then the design will be written to my_origami.<extension>

directory specifies a directory in which to place the file, either absolute or relative to the current working directory. Default is the current working directory.

The string written is that returned by Design.to_json().

Parameters
  • directory – directory in which to put file (default: current working directory)

  • filename – filename (default: name of script with .py replaced by .sc). Mutually exclusive with extension

  • extension – extension for filename (default: .sc) Mutually exclusive with filename

export_cadnano_v2(directory: str = '.', filename: Optional[str] = None) → None

Write .json file representing this Design, suitable for reading by cadnano v2, with the output file having the same name as the running script but with .py changed to .json, unless filename is explicitly specified. For instance, if the script is named my_origami.py, then the design will be written to my_origami.json.

directory specifies a directory in which to place the file, either absolute or relative to the current working directory. Default is the current working directory.

The string written is that returned by Design.to_cadnano_v2().

add_nick(helix: int, offset: int, forward: bool, new_color: bool = True) → None

Add nick to Domain on Helix with index helix, in direction given by forward, at offset offset. The two Domain’s created by this nick will have 5’/3’ ends at offsets offset and offset-1.

For example, if there is a Domain with Domain.helix = 0, Domain.forward = True, Domain.start = 0, Domain.end = 10, then calling add_nick(helix=0, offset=5, forward=True) will split it into two Domain’s, with one domains having the fields Domain.helix = 0, Domain.forward = True, Domain.start = 0, Domain.end = 5, (recall that Domain.end is exclusive, meaning that the largest offset on this Domain is 4 = offset-1) and the other domain having the fields Domain.helix = 0, Domain.forward = True, Domain.start = 5, Domain.end = 10.

If the Strand is circular, then it will be made linear with the 5’ and 3’ ends at the nick position, modified in place. Otherwise, this Strand will be deleted from the design, and two new Strand’s will be added.

Parameters
  • helix – index of helix where nick will occur

  • offset – offset to nick (nick will be between offset and offset-1)

  • forward – forward or reverse Domain on helix at offset?

  • new_color – whether to assign a new color to one of the Strand’s resulting from the nick. If False, both Strand’s created have the same color as the original If True, one Strand keeps the same color as the original and the other is assigned a new color

ligate(helix: int, offset: int, forward: bool) → None

Reverse operation of Design.add_nick(). “Ligates” a nick between two adjacent Domain’s in the same direction on a Helix with index helix, in direction given by forward, at offset offset.

For example, if there are a Domain’s with Domain.helix = 0, Domain.forward = True, Domain.start = 0, Domain.end = 5, (recall that Domain.end is exclusive, meaning that the largest offset on this Domain is 4 = offset-1) and the other domain having the fields Domain.helix = 0, Domain.forward = True, Domain.start = 5, Domain.end = 10. then calling ligate(helix=0, offset=5, forward=True) will combine them into one Domain, having the fields Domain.helix = 0, Domain.forward = True, Domain.start = 0, Domain.end = 10.

If the Domain’s are on the same Strand (i.e., they are the 5’ and 3’ ends of that Strand, which is necessarily linear), then the Strand is made is circular in place, Otherwise, the two Strand’s of each Domain will be joined into one, replacing the previous strand on the 5’-most side of the nick (i.e., the one whose 3’ end terminated at the nick), and deleting the other strand.

Parameters
  • helix – index of helix where nick will be ligated

  • offset – offset to ligate (nick to ligate must be between offset and offset-1)

  • forward – forward or reverse Domain on helix at offset?

add_half_crossover(helix: int, helix2: int, offset: int, forward: bool, offset2: Optional[int] = None, forward2: Optional[bool] = None) → None

Add a half crossover from helix helix at offset offset to helix2, on the strand with Strand.forward = forward.

Unlike Design.add_full_crossover(), which automatically adds a nick between the two half-crossovers, to call this method, there must already be nicks adjacent to the given offsets on the given helices. (either on the left or right side)

If the crossover is within a Strand, i.e., between its 5’ and ‘ ends, the Strand will simply be made circular, modifying it in place. Otherwise, the old two Strand’s will be deleted, and a new Strand added.

Parameters
  • helix – index of one helix of half crossover

  • helix2 – index of other helix of half crossover

  • offset – offset on helix at which to add half crossover

  • forward – direction of Strand on helix to which to add half crossover

  • offset2 – offset on helix2 at which to add half crossover. If not specified, defaults to offset

  • forward2 – direction of Strand on helix2 to which to add half crossover. If not specified, defaults to the negation of forward

add_full_crossover(helix: int, helix2: int, offset: int, forward: bool, offset2: Optional[int] = None, forward2: Optional[bool] = None) → None

Adds two half-crossovers, one at offset and another at offset-1. Other arguments have the same meaning as in Design.add_half_crossover(). A nick is automatically added on helix helix between offset and offset-1 if one is not already present, and similarly for offset2 on helix helix2.

Parameters
  • helix – index of one helix of half crossover

  • helix2 – index of other helix of half crossover

  • offset – offset on helix at which to add half crossover

  • forward – direction of Strand on helix to which to add half crossover

  • offset2 – offset on helix2 at which to add half crossover. If not specified, defaults to offset

  • forward2 – direction of Strand on helix2 to which to add half crossover. If not specified, defaults to the negation of forward

inline_deletions_insertions() → None

Converts deletions and insertions by “inlining” them. Insertions and deletions are removed, and their domains have their lengths altered. Also, major tick marks on the helices will be shifted to preserve their adjacency to bases already present. For example, if there are major tick marks at 0, 8, 18, 24, and a deletion between 0 and 8:

0      8         18    24    30
|--X---|---------|-----|------

then the domain is shortened by 1, the tick marks become 0, 7, 15, 23, and the helix’s maximum offset is shrunk by 1:

0     7         17    23    29
|-----|---------|-----|------

Similarly, if there are insertions (in the example below, the “2” represents an insertion of length 2, which represents 3 total bases), they are expanded

0      8         18    24    30
|--2---|---------|-----|------

then the domain is lengthened by 3:

0        10        20    26    32
|--------|---------|-----|------

And it works if there are both insertions and deletions:

0      8         18    24    30
|--2---|---------|--X--|------

then the domain is lengthened by 3:

0        10        20   25    31
|--------|---------|----|------

We assume that a major tick mark appears just to the LEFT of the offset it encodes, so the minimum and maximum offsets for tick marks are respectively the helix’s minimum offset and 1 plus its maximum offset, the latter being just to the right of the last offset on the helix.

reverse_all() → None

Reverses “polarity” of every Strand in this Design.

No attempt is made to make any assigned DNA sequences match by reversing or rearranging them. Every Strand keeps the same DNA sequence it had before (unreversed), if one was assigned. It is recommended to assign/reassign DNA sequences after doing this operation.

strand_with_name(name: str) → Optional[scadnano.Strand]
Parameters

name – name of a Strand.

Returns

the Strand with name name, or None if no Strand in the Design has that name.

origami_rectangle

The origami_rectangle module defines the function origami_rectangle.create() for creating a DNA origami rectangle using the scadnano module.

class origami_rectangle.NickPattern(value)

Represents options for where to place nicks between staples.

staggered = 1

A nick appears in a given helix and column if the parity of the helix and column match (both even or both odd).

staggered_opposite = 2

A nick appears in a given helix and column if the parity of the helix and column don’t match (one is even and the other is odd).

CURRENTLY UNSUPPORTED.

even = 3

A nick appears in every column and only even-index helices.

CURRENTLY UNSUPPORTED.

odd = 4

A nick appears in every column and only odd-index helices.

CURRENTLY UNSUPPORTED.

origami_rectangle.staggered = <NickPattern.staggered: 1>

Convenience reference defined so one can type origami_rectangle.staggered instead of origami_rectangle.NickPattern.staggered.

origami_rectangle.staggered_opposite = <NickPattern.staggered_opposite: 2>

Convenience reference defined so one can type origami_rectangle.staggered_opposite instead of origami_rectangle.NickPattern.staggered_opposite.

CURRENTLY UNSUPPORTED.

origami_rectangle.even = <NickPattern.even: 3>

Convenience reference defined so one can type origami_rectangle.even instead of origami_rectangle.NickPattern.even.

CURRENTLY UNSUPPORTED.

origami_rectangle.odd = <NickPattern.odd: 4>

Convenience reference defined so one can type origami_rectangle.odd instead of origami_rectangle.NickPattern.odd.

CURRENTLY UNSUPPORTED.

origami_rectangle.create(*, num_helices: int, num_cols: int, assign_seq: bool = True, seam_left_column: int = -1, nick_pattern: origami_rectangle.NickPattern = <NickPattern.staggered: 1>, twist_correction_deletion_spacing: int = 0, twist_correction_start_col: int = 1, twist_correction_deletion_offset: int = -1, num_flanking_columns: int = 1, num_flanking_helices: int = 0, custom_scaffold: Optional[str] = None, edge_staples: bool = True, scaffold_nick_offset: int = -1)scadnano.Design

Creates a DNA origami rectangle with a given number of helices and “columns” (16-base-wide region in each helix). The columns include the 16-base regions on the end where potential “edge staples” go, as well as the two-column-wide “seam” region in the middle.

Below is an example diagram of the staples created by this function.

Consider for example the function call create(num_helices=8, num_cols=10, nick_pattern=origami_rectangle.staggered). The scaffold strand resulting from this call is shown below:

  #       C0       #       C1       #       C2       #       C3       #       C4       #       C5       #       C6       #       C7       #       C8       #       C9       #
H0 +--------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------+
   |                                                                                                                                                                       |
H1 +--------------- ---------------- ---------------- ---------------- ---------------+ +--------------- ---------------- ---------------- ---------------- ---------------+
                                                                                      | |
H2 +--------------- ---------------- ---------------- ---------------- ---------------+ +--------------- ---------------- ---------------- ---------------- ---------------+
   |                                                                                                                                                                       |
H3 +--------------- ---------------- ---------------- ---------------- ---------------+ +--------------- ---------------- ---------------- ---------------- ---------------+
                                                                                      | |
H4 +--------------- ---------------- ---------------- ---------------- ---------------+ +--------------- ---------------- ---------------- ---------------- ---------------+
   |                                                                                                                                                                       |
H5 +--------------- ---------------- ---------------- ---------------- ---------------+ +--------------- ---------------- ---------------- ---------------- ---------------+
                                                                                      | |
H6 +--------------- ---------------- ---------------- ---------------- ---------------+ +--------------- ---------------- ---------------- ---------------- ---------------+
   |                                                                                                                                                                       |
H7 +--------------- ---------------- ---------------- ---------------- ---------------] <--------------- ---------------- ---------------- ---------------- ---------------+

Helix indices are labelled H0, H1, … and column indices are labeled C0, C1, … Each single symbol -, +, <, >, [, ], + represents one DNA base, so each column is 16 bases wide. The # is a visual delimiter between columns and does not represent any bases, nor do spaces between the base-representing symbols. The 5’ end of a strand is indicated with [ or ] and the 3’ end is indicated with > or <. A crossover is indicated with

+
|
+

Below are the staples resulting from this same call.

  #       C0       #       C1       #       C2       #       C3       #       C4       #       C5       #       C6       #       C7       #       C8       #       C9       #
H0 <--------------+ +--------------- -------]<------+ +--------------- -------]<------+ +--------------- -------]<------+ +--------------- -------]<------+ +--------------]
                  | |                               | |                                                                 | |                               | |                               
H1 [--------------+ +------>[------+ +--------------+ +------>[------+ +--------------+ +------>[------+ +--------------+ +------>[------+ +--------------+ +-------------->
                                   | |                               | |                               | |                               | |                               
H2 <--------------+ +--------------+ +------]<------+ +--------------+ +------]<------+ +--------------+ +------]<------+ +--------------+ +------]<------+ +--------------]
                  | |                               | |                                                                 | |                               | |                               
H3 [--------------+ +------>[------+ +--------------+ +------>[------+ +--------------+ +------>[------+ +--------------+ +------>[------+ +--------------+ +-------------->
                                   | |                               | |                               | |                               | |                               
H4 <--------------+ +--------------+ +------]<------+ +--------------+ +------]<------+ +--------------+ +------]<------+ +--------------+ +------]<------+ +--------------]
                  | |                               | |                                                                 | |                               | |                               
H5 [--------------+ +------>[------+ +--------------+ +------>[------+ +--------------+ +------>[------+ +--------------+ +------>[------+ +--------------+ +-------------->
                                   | |                               | |                               | |                               | |                               
H6 <--------------+ +--------------+ +------]<------+ +--------------+ +------]<------+ +--------------+ +------]<------+ +--------------+ +------]<------+ +--------------]
                  | |                               | |                                                                 | |                               | |                               
H7 [--------------+ +------>[------- ---------------+ +------>[------- ---------------+ +------>[------- ---------------+ +------>[------- ---------------+ +-------------->

The seam crosses columns C4 and C5. The left and right edge staples respectively are in columns C0 and C9.

Prints warning if number of bases exceeds 7249 (length of standard M13 scaffold strand), but does not otherwise cause an error.

Here’s an example of using origami_rectangle.create to create a design for a 16-helix rectangle and write it to a file readable by scadnano. (By default the output file name is the same as the script calling Design.write_scadnano_file() but with the extension .py changed to .dna.)

import origami_rectangle as rect

# XXX: ensure num_cols is even since we divide it by 2
design = rect.create(num_helices=16, num_cols=24, nick_pattern=rect.staggered)
design.write_scadnano_file()

However, we caution that create() is not intended to be very extensible for creating many different types of DNA origami. It is more intended as an example whose source code can be an efficient reference to learn the scadnano API.

Parameters
  • num_helices – number of helices. must be even.

  • num_cols – number of “columns” as defined above. must be even and at least 4.

  • assign_seq – whether to assign a DNA sequence to the scaffold. If True, uses custom_scaffold if it is not None, or M13 otherwise.

  • seam_left_column – specifies the location of the seam. (i.e., scaffold crossovers in the middle of the origami.) If positive, the seam occupies two columns, and seam_left_column specifies the column on the left. To make the crossover geometry work out, a nonnegative seam_left_column must be even, greater than 0, and less than num_helices - 2. If negative, it is calculated automatically to be roughly in the middle.

  • nick_pattern – describes whether nicks between staples should be “staggered” or not. See origami_rectangle.NickPattern for details.

  • twist_correction_deletion_spacing – If twist_correction_deletion_spacing > 0, adds deletions between crossovers in one out of every twist_correction_deletion_spacing columns. See this paper for an explanation of twist correction in DNA origami: Programmable molecular recognition based on the geometry of DNA nanostructures, Sungwook Woo and Paul W. K. Rothemund, Nature Chemistry, volume 3, pages 620–627 (2011) https://doi.org/10.1038/nchem.1070

  • twist_correction_start_col – ignored if twist_correction_deletion_spacing <= 0, otherwise it indicates the column at which to put the first deletions. Default = 1.

  • twist_correction_deletion_offset – the relative offset of the deletion, relative to the left side of the column.

  • num_flanking_columns – the number of empty columns on the helix on each side of the origami.

  • num_flanking_helices – the number of empty helices above and below the origami.

  • custom_scaffold – the scaffold sequence to use. If set to None, the standard 7249-base M13 is used: scadnano.m13().

  • edge_staples – indicates whether to include the edge staples. (Leaving them out prevents multiple origami rectangles from polymerizing in solution due to base stacking interactions on the left and right edges of the origami rectangle.)

  • scaffold_nick_offset – the position of the “nick” on the scaffold (the M13 scaffold is circular, so for such a scaffold this really represents where any unused and undepicted bases of the scaffold will form a loop-out). If negative (default value) then it will be chosen to be along the origami seam.

Returns

a Design representing a DNA origami rectangle

Interoperability - cadnano v2

Scadnano provides function to convert design to and from cadnano v2:

  • DNADesign.from_cadnano_v2() will create a scadnano DNADesign from a cadnanov2 json file.

  • DNADesign.export_cadnano_v2() will produce a cadnanov2 json file from a scadnano design.

Important

All cadnanov2 designs can be imported to scadnano. However not all scadnano designs can be imported to cadnanov2, to be importable to cadnanov2 a scadnano design need to comply with the following points:

  • The design cannot feature any Loopout as it is not a concept that exists in cadnanov2.

  • Following cadnanov2 conventions, helices with even number must have their scaffold going forward and helices with odd number backward.

Also note that maximum helices offsets can be altered in a scadnano to cadnanov2 conversion as cadnanov2 needs max offsets to be a multiple of 21 in the hex grid and 32 in the rectangular grid. The conversion algorithm will choose the lowest multiple of 21 or 32 which fits the entire design.

The cadnanov2 json format does not embed sequences hence they will be lost after conversion.

Indices and tables