Skip to content

Commit

Permalink
Merge pull request #96 from UC-Davis-molecular-computing/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
dave-doty authored Jun 28, 2020
2 parents f54b629 + 293b6d2 commit 17677d9
Show file tree
Hide file tree
Showing 66 changed files with 4,673 additions and 3,389 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: "release"

on:
push:
branches:
- "master"

jobs:
release:
name: "Release"
runs-on: "ubuntu-latest"

steps:
# ...
- name: "Build & test"
run: |
echo "done!"
- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "latest"
prerelease: false
title: "Development Build [TODO: Replace label and number with version number]"
files: |
LICENSE.txt
100 changes: 98 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,19 @@ This module is used to write Python scripts outputting `.dna` files readable by

Early versions of this project didn't have well-defined versions. However, we will try to announce breaking changes (and possibly new features) under the [GitHub releases page](https://github.com/UC-Davis-molecular-computing/scadnano-python-package/releases). The version numbers in this Python library repo and the [web interface repo](https://github.com/UC-Davis-molecular-computing/scadnano/releases) won't always advance at the same time. However, when a breaking change is made, this will increment the minor or major version numbers in both libraries (version numbers are major.minor.patch, i.e., version 0.9.2 has minor version number 9).





## Reporting issues

Please report issues in the web interface at the [scadnano web interface GitHub repository](https://github.com/UC-Davis-molecular-computing/scadnano/issues), and report issues in the Python scripting library at the [scadnano Python package GitHub repository](https://github.com/UC-Davis-molecular-computing/scadnano-python-package/issues).






## Installation

The scadnano Python package requires Python version 3.7 or later. If you do not have that version (or later) of Python installed, follow [this link](https://www.python.org/downloads/) to install it.
Expand Down Expand Up @@ -55,7 +64,94 @@ Once Python is installed, there are two ways you can install the scadnano Python
* *optional*: [origami_rectangle.py](https://raw.githubusercontent.com/UC-Davis-molecular-computing/scadnano-python-package/master/scadnano/origami_rectangle.py); This can help create origami rectangles, but it is not necessary to use scadnano.
* *optional*: [_version.py](https://raw.githubusercontent.com/UC-Davis-molecular-computing/scadnano-python-package/master/scadnano/_version.py) This ensures that the current version number is written into any `.dna` files written by the library; otherwise it may be out of date. (Which should not matter for the most part.)
Unfortunately, the scadnano package uses the Python package [xlwt](https://pypi.org/project/xlwt/) to write Excel files, so in order to call the method [`DNADesign.write_idt_plate_excel_file()`](https://scadnano-python-package.readthedocs.io/#scadnano.scadnano.DNADesign.write_idt_plate_excel_file) to export an Excel file with DNA sequences, xlwt must be installed. To install, type `pip install xlwt` at the command line.
The scadnano package uses the Python package [xlwt](https://pypi.org/project/xlwt/) to write Excel files, so in order to call the method [`DNADesign.write_idt_plate_excel_file()`](https://scadnano-python-package.readthedocs.io/#scadnano.scadnano.DNADesign.write_idt_plate_excel_file) to export an Excel file with DNA sequences, xlwt must be installed. To install, type `pip install xlwt` at the command line.







## Example

Consider the following design:

![](https://github.com/UC-Davis-molecular-computing/scadnano/blob/master/doc-images/screenshot-initial.png)

The following Python script produces this design.

```python
import scadnano as sc
import modifications as mod


def main():
# helices
helices = [sc.Helix(max_offset=48), sc.Helix(max_offset=48)]

# left staple
stap_left_domain1 = sc.Domain(helix=1, forward=True, start=8, end=24)
stap_left_domain0 = sc.Domain(helix=0, forward=False, start=8, end=24)
stap_left = sc.Strand(domains=[stap_left_domain1, stap_left_domain0])

# right staple
stap_right_domain0 = sc.Domain(helix=0, forward=False, start=24, end=40)
stap_right_domain1 = sc.Domain(helix=1, forward=True, start=24, end=40)
stap_right = sc.Strand(domains=[stap_right_domain0, stap_right_domain1])
stap_right.set_modification_5p(mod.biotin_5p)

# scaffold
scaf_domain1_left = sc.Domain(helix=1, forward=False, start=8, end=24)
scaf_domain0 = sc.Domain(helix=0, forward=True, start=8, end=40)
loopout = sc.Loopout(length=3)
scaf_domain1_right = sc.Domain(helix=1, forward=False, start=24, end=40)
scaf = sc.Strand(domains=[scaf_domain1_left, scaf_domain0, loopout, scaf_domain1_right], is_scaffold=True)

# whole design
design = sc.DNADesign(helices=helices, strands=[scaf, stap_left, stap_right], grid=sc.square)

# deletions and insertions added to design are added to both strands on a helix
design.add_deletion(helix=1, offset=20)
design.add_insertion(helix=0, offset=14, length=1)
design.add_insertion(helix=0, offset=26, length=2)

# also assigns complement to strands other than scaf bound to it
design.assign_dna(scaf, 'AACGT' * 18)

return design


if __name__ == '__main__':
design = main()
design.write_scadnano_file(directory='output_designs')
```

Running the code above produces the `.dna` JSON file shown in the [web interface README](https://github.com/UC-Davis-molecular-computing/scadnano/blob/master/README.md#terminology). That section explains many of the terms used in the code (domain, helix, loopout, insertion, etc.).


## abbreviated syntax with chained methods
Instead of explicitly creating variables and objects representing each domain in each strand, there is a shorter syntax using chained method calls. Instead of the above, create only the helices first, then create the DNADesign. Then strands can be added using a shorter syntax, to describe how to draw the strand starting at the 5' end and moving to the 3' end.

```python
# helices
helices = [sc.Helix(max_offset=48), sc.Helix(max_offset=48)]

# whole design
design = sc.DNADesign(helices=helices, strands=[], grid=sc.square)

# left staple
design.strand(1, 8).to(24).cross(0).to(8)

# right staple
design.strand(0, 40).to(24).cross(1).to(40).with_modification_5p(mod.biotin_5p)

# scaffold
design.strand(1, 24).to(8).cross(0).to(40).loopout(1, 3).to(24).as_scaffold()
```

Documentation is available in the [API docs](https://scadnano-python-package.readthedocs.io/en/latest/#scadnano.DNADesign.strand).

The code for adding insertions, deletions, and assigning DNA would be the same as in the original script.



Expand All @@ -78,7 +174,7 @@ A [tutorial](https://github.com/UC-Davis-molecular-computing/scadnano-python-pac



## Examples
## Other examples

Several example scripts are located in the
[examples/](https://github.com/UC-Davis-molecular-computing/scadnano-python-package/tree/master/examples) subfolder.
Expand Down
10 changes: 5 additions & 5 deletions examples/24_helix_origami_rectangle_twist_corrected.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ def add_staple_crossovers(design: sc.DNADesign):
start_offset = 24 if helix % 2 == 0 else 40
for offset in range(start_offset, 296, 32):
if offset != 152: # skip crossover near seam
design.add_full_crossover(helix1=helix, helix2=helix + 1, offset1=offset,
forward1=helix % 2 == 1)
design.add_full_crossover(helix=helix, helix2=helix + 1, offset=offset,
forward=helix % 2 == 1)


def add_staple_nicks(design: sc.DNADesign):
Expand Down Expand Up @@ -69,13 +69,13 @@ def add_scaffold_crossovers(design: sc.DNADesign):

# scaffold interior
for helix in range(1, 23, 2):
crossovers.append(sc.Crossover(helix1=helix, helix2=helix + 1, offset1=152, forward1=False))
crossovers.append(sc.Crossover(helix=helix, helix2=helix + 1, offset=152, forward=False))

# scaffold edges
for helix in range(0, 23, 2):
crossovers.append(sc.Crossover(helix1=helix, helix2=helix + 1, offset1=8, forward1=True, half=True))
crossovers.append(sc.Crossover(helix=helix, helix2=helix + 1, offset=8, forward=True, half=True))
crossovers.append(
sc.Crossover(helix1=helix, helix2=helix + 1, offset1=295, forward1=True, half=True))
sc.Crossover(helix=helix, helix2=helix + 1, offset=295, forward=True, half=True))

design.add_crossovers(crossovers)

Expand Down
5 changes: 5 additions & 0 deletions examples/2_staple_2_helix_modifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ def main():
stap_right.set_modification_internal(5, mod.cy3_int)
stap_right.set_modification_3p(mod.biotin_3p)

scaf.set_modification_5p(mod.biotin_5p)
scaf.set_modification_3p(mod.cy3_3p)
scaf.set_modification_internal(5, mod.cy5_int)
scaf.set_modification_internal(32, mod.cy3_int)

return design


Expand Down
44 changes: 44 additions & 0 deletions examples/2_staple_2_helix_origami_deletions_insertions_labels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import scadnano as sc


def main():
# helices
helices = [sc.Helix(max_offset=48), sc.Helix(max_offset=48)]

# left staple
stap_left_ss1 = sc.Domain(helix=1, forward=True, start=8, end=24)
stap_left_ss0 = sc.Domain(helix=0, forward=False, start=8, end=24)
stap_left = sc.Strand(domains=[stap_left_ss1, stap_left_ss0],
label='left staple')

# right staple
stap_right_ss0 = sc.Domain(helix=0, forward=False, start=24, end=40)
stap_right_ss1 = sc.Domain(helix=1, forward=True, start=24, end=40)
stap_right = sc.Strand(domains=[stap_right_ss0, stap_right_ss1],
label='right staple')

# scaffold
scaf_ss1_left = sc.Domain(helix=1, forward=False, start=8, end=24)
scaf_ss0 = sc.Domain(helix=0, forward=True, start=8, end=40)
loopout = sc.Loopout(length=3)
scaf_ss1_right = sc.Domain(helix=1, forward=False, start=24, end=40)
scaf = sc.Strand(domains=[scaf_ss1_left, scaf_ss0, loopout, scaf_ss1_right], is_scaffold=True,
label='scaffold label')

# whole design
design = sc.DNADesign(helices=helices, strands=[scaf, stap_left, stap_right], grid=sc.square)

# deletions and insertions added to design are added to both strands on a helix
design.add_deletion(helix=1, offset=20)
design.add_insertion(helix=0, offset=14, length=1)
design.add_insertion(helix=0, offset=26, length=2)

# also assigns complement to strands other than scaf bound to it
design.assign_dna(scaf, 'AACGT' * 18)

return design


if __name__ == '__main__':
design = main()
design.write_scadnano_file(directory='output_designs')
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import scadnano as sc
import modifications as mod


def main():
# helices
helices = [sc.Helix(max_offset=48), sc.Helix(max_offset=48)]

# whole design
design = sc.DNADesign(helices=helices, strands=[], grid=sc.square)

design.strand(1, 8).to(24).cross(0).to(8) # left staple
design.strand(0, 40).to(24).cross(1).to(40).with_modification_5p(mod.biotin_5p) # right staple
design.strand(1, 24).to(8).cross(0).to(40).loopout(1, 3).to(24).as_scaffold()

# deletions and insertions added to design are added to both strands on a helix
design.add_deletion(helix=1, offset=20)
design.add_insertion(helix=0, offset=14, length=1)
design.add_insertion(helix=0, offset=26, length=2)

# also assigns complement to strands other than scaf bound to it
design.assign_dna(design.scaffold, 'AACGT' * 18)

return design


if __name__ == '__main__':
design = main()
design.write_scadnano_file(directory='output_designs')
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import scadnano as sc


def main():
# helices
helices = [sc.Helix(max_offset=48), sc.Helix(max_offset=48)]

# left staple
stap_left_ss1 = sc.Domain(helix=1, forward=True, start=8, end=24)
stap_left_ss0 = sc.Domain(helix=0, forward=False, start=8, end=24)
stap_left = sc.Strand(domains=[stap_left_ss1, stap_left_ss0])

# right staple
stap_right_ss0 = sc.Domain(helix=0, forward=False, start=24, end=40)
stap_right_ss1 = sc.Domain(helix=1, forward=True, start=24, end=40)
stap_right = sc.Strand(domains=[stap_right_ss0, stap_right_ss1])

# scaffold
scaf_ss1_left = sc.Domain(helix=1, forward=False, start=8, end=24)
scaf_ss0 = sc.Domain(helix=0, forward=True, start=8, end=40)
loopout = sc.Loopout(length=3)
scaf_ss1_right = sc.Domain(helix=1, forward=False, start=24, end=40)
scaf = sc.Strand(domains=[scaf_ss1_left, scaf_ss0, loopout, scaf_ss1_right], is_scaffold=True)

# geometry
geometry = sc.Geometry(z_step=0.2, helix_radius=1.2, inter_helix_gap=1.0)

# whole design
design = sc.DNADesign(helices=helices, strands=[scaf, stap_left, stap_right], grid=sc.square,
geometry=geometry)

# deletions and insertions added to design are added to both strands on a helix
design.add_deletion(helix=1, offset=20)
design.add_insertion(helix=0, offset=14, length=1)
design.add_insertion(helix=0, offset=26, length=2)

# also assigns complement to strands other than scaf bound to it
design.assign_dna(scaf, 'AACGT' * 18)

return design


if __name__ == '__main__':
design = main()
design.write_scadnano_file(directory='output_designs')
42 changes: 21 additions & 21 deletions examples/6_helix_bundle_honeycomb.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,41 +97,41 @@ def add_nicks(design: sc.DNADesign):
def add_crossovers(design: sc.DNADesign):
# staples interior
for offset in range(84, 1246, 42):
design.add_full_crossover(helix1=0, helix2=1, offset1=offset, forward1=False)
design.add_full_crossover(helix1=3, helix2=4, offset1=offset, forward1=True)
design.add_full_crossover(helix=0, helix2=1, offset=offset, forward=False)
design.add_full_crossover(helix=3, helix2=4, offset=offset, forward=True)
for offset in range(56, 1246, 42):
design.add_full_crossover(helix1=1, helix2=2, offset1=offset, forward1=True)
design.add_full_crossover(helix1=4, helix2=5, offset1=offset, forward1=False)
design.add_full_crossover(helix=1, helix2=2, offset=offset, forward=True)
design.add_full_crossover(helix=4, helix2=5, offset=offset, forward=False)
for offset in range(70, 1246, 42):
design.add_full_crossover(helix1=2, helix2=3, offset1=offset, forward1=False)
design.add_full_crossover(helix1=5, helix2=0, offset1=offset, forward1=True)
design.add_full_crossover(helix=2, helix2=3, offset=offset, forward=False)
design.add_full_crossover(helix=5, helix2=0, offset=offset, forward=True)
for offset in range(49, 1245, 42): # extra crossovers 5 - 0 for some reason
design.add_full_crossover(helix1=5, helix2=0, offset1=offset, forward1=True)
design.add_full_crossover(helix=5, helix2=0, offset=offset, forward=True)

# staples edges
design.add_half_crossover(helix1=0, helix2=1, offset1=42, forward1=False)
design.add_half_crossover(helix1=3, helix2=4, offset1=42, forward1=True)
design.add_half_crossover(helix1=0, helix2=5, offset1=1245, forward1=False)
design.add_half_crossover(helix1=2, helix2=3, offset1=1245, forward1=False)
design.add_half_crossover(helix=0, helix2=1, offset=42, forward=False)
design.add_half_crossover(helix=3, helix2=4, offset=42, forward=True)
design.add_half_crossover(helix=0, helix2=5, offset=1245, forward=False)
design.add_half_crossover(helix=2, helix2=3, offset=1245, forward=False)

# scaffold interior
crossovers = []
for offset in range(58, 1250, 42):
crossovers.append(sc.Crossover(helix1=0, helix2=1, offset1=offset, forward1=True))
crossovers.append(sc.Crossover(helix=0, helix2=1, offset=offset, forward=True))
for offset in range(30, 1250, 42):
crossovers.append(sc.Crossover(helix1=1, helix2=2, offset1=offset, forward1=False))
crossovers.append(sc.Crossover(helix=1, helix2=2, offset=offset, forward=False))
for offset in range(54, 1250, 42):
crossovers.append(sc.Crossover(helix1=2, helix2=3, offset1=offset, forward1=True))
crossovers.append(sc.Crossover(helix=2, helix2=3, offset=offset, forward=True))
for offset in range(26, 1250, 42):
crossovers.append(sc.Crossover(helix1=3, helix2=4, offset1=offset, forward1=False))
crossovers.append(sc.Crossover(helix=3, helix2=4, offset=offset, forward=False))

# scaffold edges
crossovers.append(sc.Crossover(helix1=0, helix2=1, offset1=16, forward1=True, half=True))
crossovers.append(sc.Crossover(helix1=2, helix2=3, offset1=12, forward1=True, half=True))
crossovers.append(sc.Crossover(helix1=4, helix2=5, offset1=19, forward1=True, half=True))
crossovers.append(sc.Crossover(helix1=0, helix2=1, offset1=1275, forward1=True, half=True))
crossovers.append(sc.Crossover(helix1=2, helix2=3, offset1=1271, forward1=True, half=True))
crossovers.append(sc.Crossover(helix1=4, helix2=5, offset1=1278, forward1=True, half=True))
crossovers.append(sc.Crossover(helix=0, helix2=1, offset=16, forward=True, half=True))
crossovers.append(sc.Crossover(helix=2, helix2=3, offset=12, forward=True, half=True))
crossovers.append(sc.Crossover(helix=4, helix2=5, offset=19, forward=True, half=True))
crossovers.append(sc.Crossover(helix=0, helix2=1, offset=1275, forward=True, half=True))
crossovers.append(sc.Crossover(helix=2, helix2=3, offset=1271, forward=True, half=True))
crossovers.append(sc.Crossover(helix=4, helix2=5, offset=1278, forward=True, half=True))

design.add_crossovers(crossovers)

Expand Down
Loading

0 comments on commit 17677d9

Please sign in to comment.