├── README.md ├── assign_sequences.py └── cadnano-beadcatchers.py /README.md: -------------------------------------------------------------------------------- 1 | # cadnano-scripts 2 | 3 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/basnijholt/cadnano-scripts?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -------------------------------------------------------------------------------- /assign_sequences.py: -------------------------------------------------------------------------------- 1 | 2 | # coding: utf-8 3 | 4 | ## Define functions 5 | 6 | # In[5]: 7 | 8 | import sys 9 | import pickle 10 | import copy # !! Not used 11 | import json 12 | 13 | ## !! DEFINE MODULE LEVEL CONSTANTS AT THE TOP. 14 | 15 | def load_json(file_name, period=32): 16 | """ 17 | Loads a .json file in the correct way, so it can still be read by cadnano2. 18 | 19 | Parameters 20 | ---------- 21 | file_name : str 22 | The name and location of the *.json file 23 | period : int 24 | The period of repeating segments of the staples, in the square lattice this is by default 32. 25 | 26 | Returns 27 | ------- 28 | data : list 29 | all data that is loaded from the *.json file 30 | vstrands : list 31 | vstrands data 32 | num_helices : int 33 | number of helices in the design 34 | num_bases : int 35 | number of bases in the design 36 | idx : dict 37 | polarity 38 | period 39 | 40 | Example 41 | ------- 42 | data, vstrands, num_helices, num_bases, idx, polarity, per = load_json('ruler_design_12nov_1353.json') 43 | """ 44 | with open(file_name) as f: 45 | data = json.load(f) 46 | 47 | vstrands = data['vstrands'] # !! vstrands also in outer script. 48 | num_helices = len(vstrands) 49 | num_bases = len(vstrands[0]['scaf']) 50 | idx = {} #Generate dictionary for translating helix_num to vstrand_num 51 | polarity = {} 52 | for helix_num in range(num_helices): 53 | idx[vstrands[helix_num]['num']] = helix_num 54 | polarity[helix_num] = vstrands[idx[helix_num]]['col'] + vstrands[idx[helix_num]]['row'] 55 | return data, vstrands, num_helices, num_bases, idx, polarity, period, file_name 56 | 57 | def save_json(file_name): 58 | """ 59 | Saves the .json file in the correct way, so it can still be read by cadnano2. 60 | 61 | Parameters 62 | ---------- 63 | file_name : str 64 | The name and location of the *.json file 65 | """ 66 | data['vstrands'] = vstrands # !! Accessing global variables 67 | with open(file_name, 'wb') as outfile: 68 | json.dump(data, outfile) 69 | 70 | 71 | def comp_seq_FN(raw_sequence): 72 | """ 73 | Returns the complementary sequence and makes all characters in uppercase. 74 | """ 75 | uppercase = {'a':'A', 'A':'A', 'c':'C', 'C':'C', 'g':'G', 'G':'G', 't':'T', 'T':'T'} 76 | complement = {'a':'T', 'A':'T', 'c':'G', 'C':'G', 'g':'C', 'G':'C', 't':'A', 'T':'A'} 77 | antisense_seq = '' 78 | for letter in raw_sequence: 79 | if letter in uppercase: 80 | antisense_seq = complement[letter] + antisense_seq 81 | return antisense_seq 82 | 83 | def stap_color_string_FN(stap_color_int): 84 | return color_dc[stap_color_int] # !! Accessing global variables 85 | 86 | def initVars(): 87 | """ 88 | Initialization of variables, gives the colors a name and initiates the null_bp 89 | 90 | Example 91 | ------- 92 | stap_color_dc, null_bp = initVars() 93 | """ 94 | null_bp = [-1, -1] # !! Redefining global variables 95 | # Do this in a single statement: 96 | stap_color_dc = {} 97 | stap_color_dc[13369344] = 'red' 98 | stap_color_dc[16204552] = 'red orange' 99 | stap_color_dc[16225054] = 'light orange' 100 | stap_color_dc[11184640] = 'olive' 101 | stap_color_dc[5749504] = 'light green' 102 | stap_color_dc[29184] = 'dark green' 103 | stap_color_dc[243362] = 'cyan' 104 | stap_color_dc[1507550] = 'blue' 105 | stap_color_dc[7536862] = 'purple' 106 | stap_color_dc[12060012] = 'magenta' 107 | stap_color_dc[3355443] = 'dark gray' 108 | stap_color_dc[8947848] = 'light gray' 109 | return stap_color_dc, null_bp 110 | 111 | def openPickledFile(f): 112 | """ Loads a pickled file """ 113 | input_file = file(f, 'r') # DONT USE file() !! 114 | loaded_txt = pickle.load(input_file) 115 | input_file.close() 116 | return loaded_txt 117 | 118 | def openFile(f): 119 | """" Opens a txt file in standard format. """ 120 | input_file = file(f, 'r') # DONT USE file() !! 121 | loaded_txt = input_file.read() 122 | input_file.close() 123 | return loaded_txt 124 | 125 | def give_sequences(cadnano_file): 126 | data, vstrands, num_vstrands, num_helix_bases, idx, polarity, per, json_f = load_json(cadnano_file) 127 | seq_counter_dc = {} 128 | for seq_length in seq_dc.keys(): 129 | seq_counter_dc[seq_length] = 0 130 | 131 | #Generate arrays for stap paths and scaf paths 132 | scaf_path_ra = [] 133 | stap_path_ra = [] 134 | for vstrand_num in range(num_vstrands): 135 | for helix_base_num in range(num_helix_bases): 136 | for [parity, path_ra] in [['scaf', scaf_path_ra], ['stap', stap_path_ra]]: 137 | [prev_helix_num, prev_helix_base_num, next_helix_num, next_helix_base_num] = vstrands[vstrand_num][parity][helix_base_num] 138 | if ([prev_helix_num, prev_helix_base_num] == null_bp) and ([next_helix_num, next_helix_base_num] != null_bp): 139 | sub_ra = [] 140 | curr_helix_num, curr_helix_base_num = vstrands[vstrand_num]['num'], helix_base_num 141 | end_of_strand = False 142 | while not end_of_strand: 143 | sub_ra.append([curr_helix_num, curr_helix_base_num]) 144 | [curr_helix_num, curr_helix_base_num] = vstrands[idx[curr_helix_num]][parity][curr_helix_base_num][2:] 145 | end_of_strand = [curr_helix_num, curr_helix_base_num] == null_bp 146 | path_ra.append(sub_ra) 147 | 148 | #Determine length of maxiscaf 149 | maxiscaf_path_ra = [] 150 | for sub_ra in scaf_path_ra: 151 | if len(sub_ra) > len(maxiscaf_path_ra): 152 | maxiscaf_path_ra = sub_ra 153 | maxiscaf_length = 0 154 | for [helix_num, helix_base_num] in maxiscaf_path_ra: 155 | maxiscaf_length += 1 + vstrands[idx[helix_num]]['skip'][helix_base_num] + vstrands[idx[helix_num]]['loop'][helix_base_num] 156 | if vstrands[idx[helix_num]]['scaf'][helix_base_num][2] not in [helix_num, -1]: 157 | if square_lattice and [helix_num, helix_base_num] not in no_loop_exception_ra: 158 | if (helix_base_num - helix_num%2)%8 == 7: 159 | maxiscaf_length += on_lattice_xover_scaf_loop_length 160 | else: 161 | maxiscaf_length += off_lattice_xover_scaf_loop_length 162 | 163 | if len(maxiscaf_seq) < maxiscaf_length: 164 | print "Error: ", maxiscaf_seq_filename, "only has ", len(maxiscaf_seq), "bases, whereas", maxiscaf_length, "bases are required for", json_filename, "." 165 | sys.exit() 166 | 167 | print "According to", json_f, ", the maxiscaf length should be", maxiscaf_length 168 | print "The maxiscaf sequence length in ", maxiscaf_seq_filename, "is", len(maxiscaf_seq) 169 | seq_dc[maxiscaf_length] = [maxiscaf_seq] 170 | seq_counter_dc[maxiscaf_length] = 0 171 | print 172 | 173 | #Assign scaf base sequences 174 | sub_ra = ['.' for i in range(num_helix_bases)] 175 | scaf_base_seq_dc = {} 176 | for vstrand_num in range(num_vstrands): 177 | scaf_base_seq_dc[vstrands[vstrand_num]['num']] = sub_ra[:] 178 | for sub_ra in scaf_path_ra: 179 | seq_length = 0 180 | for [helix_num, helix_base_num] in sub_ra: 181 | seq_length += 1 + vstrands[idx[helix_num]]['skip'][helix_base_num] + vstrands[idx[helix_num]]['loop'][helix_base_num] 182 | if vstrands[idx[helix_num]]['scaf'][helix_base_num][2] not in [helix_num, -1]: 183 | if square_lattice and [helix_num, helix_base_num] not in no_loop_exception_ra: 184 | if (helix_base_num - helix_num%2)%8 == 7: 185 | seq_length += on_lattice_xover_scaf_loop_length 186 | else: 187 | seq_length += off_lattice_xover_scaf_loop_length 188 | seq = seq_dc[seq_length][seq_counter_dc[seq_length]] 189 | seq_counter_dc[seq_length] += 1 190 | seq_pointer = 0 191 | for [helix_num, helix_base_num] in sub_ra: 192 | base_length = 1 + vstrands[idx[helix_num]]['skip'][helix_base_num] + vstrands[idx[helix_num]]['loop'][helix_base_num] 193 | scaf_base_seq_dc[helix_num][helix_base_num] = seq[seq_pointer:seq_pointer + base_length] 194 | seq_pointer += base_length 195 | if vstrands[idx[helix_num]]['scaf'][helix_base_num][2] not in [helix_num, -1]: 196 | if square_lattice and [helix_num, helix_base_num] not in no_loop_exception_ra: 197 | if (helix_base_num - helix_num%2)%8 == 7: 198 | seq_pointer += on_lattice_xover_scaf_loop_length 199 | else: 200 | seq_pointer += off_lattice_xover_scaf_loop_length 201 | 202 | #Print vstrand sequences 203 | for vstrand_num in range(num_vstrands): 204 | helix_num = vstrands[vstrand_num]['num'] 205 | if helix_num < 10: 206 | helix_num_string = '0' + str(helix_num) 207 | else: 208 | helix_num_string = str(helix_num) 209 | print helix_num_string, ''.join(scaf_base_seq_dc[helix_num]) 210 | 211 | #Set up stap_color_ra to help with matching caDNAno colors to staple strands 212 | sub_ra = [-1 for i in range(num_helix_bases)] 213 | stap_color_ra = [sub_ra[:] for vstrand_num in range(num_vstrands)] 214 | for vstrand_num in range(num_vstrands): 215 | for [helix_base_num, stap_color_int] in vstrands[vstrand_num]['stap_colors']: 216 | stap_color_ra[vstrand_num][helix_base_num] = stap_color_int 217 | 218 | #Generate staple strand output 219 | stap_output_ra = [] 220 | for sub_ra in stap_path_ra: 221 | seq = '' 222 | for [helix_num, helix_base_num] in sub_ra: 223 | seq += comp_seq_FN(scaf_base_seq_dc[helix_num][helix_base_num]) 224 | start_pointer = sub_ra[0] 225 | end_pointer = sub_ra[-1] 226 | [first_helix_num, first_helix_base_num] = start_pointer 227 | stap_color_int = stap_color_ra[idx[first_helix_num]][first_helix_base_num] 228 | stap_output_ra.append([stap_color_dc[stap_color_int], len(seq), start_pointer, end_pointer, seq]) 229 | 230 | #Generate scaffold strand output 231 | scaf_output_ra = [] 232 | for sub_ra in scaf_path_ra: 233 | seq = '' 234 | for [helix_num, helix_base_num] in sub_ra: 235 | seq += scaf_base_seq_dc[helix_num][helix_base_num] 236 | start_pointer = sub_ra[0] 237 | end_pointer = sub_ra[-1] 238 | scaf_output_ra.append([len(seq), start_pointer, end_pointer, seq]) 239 | 240 | 241 | #Sort staple strands according to caDNAno color 242 | sorted_stap_output_ra = sorted(stap_output_ra, key = lambda stap_output:stap_output[0]) 243 | return scaf_output_ra, sorted_stap_output_ra, vstrands 244 | 245 | def print_sequences(): 246 | print 247 | print 248 | #Print sorted staple strand sequences with annotations 249 | for sub_ra in sorted_stap_output_ra: 250 | seq = sub_ra[-1] 251 | note = 'stap strand\t' + str(sub_ra[0]) + '\t' + str(sub_ra[1]) + 'mer\t' + str(sub_ra[2]) + '\t' + 'start\t' + str(sub_ra[3]) + '\t' + 'end' 252 | seq_note = seq + '\t' + note 253 | print seq_note 254 | 255 | #Print short scaffold-parity strand sequences with annotations 256 | for sub_ra in scaf_output_ra: 257 | seq = sub_ra[-1] 258 | if len(seq) < 100: 259 | note = ' short scaf strand\t' + str(sub_ra[0]) + 'mer\t' + str(sub_ra[1]) + '\t' + 'start\t' + str(sub_ra[2]) + '\t' + 'end' 260 | seq_note = seq + '\t' + note 261 | print seq_note 262 | 263 | #Print additional miscellaneous information 264 | num_stap_bases = 0 265 | for sub_ra in sorted_stap_output_ra: 266 | seq = sub_ra[-1] 267 | num_stap_bases += len(seq) 268 | print "number of stap bases is", num_stap_bases 269 | 270 | 271 | num_short_scaf_bases = 0 272 | for sub_ra in scaf_output_ra[1:]: 273 | seq = sub_ra[-1] 274 | num_short_scaf_bases += len(seq) 275 | print "number of short scaf bases is", num_short_scaf_bases 276 | 277 | 278 | ## Settings and files 279 | 280 | # In[6]: 281 | 282 | ################################################################# 283 | #adjustable parameters 284 | square_lattice = True #Set to False if honeycomb lattice is used 285 | on_lattice_xover_scaf_loop_length = 2 #ssDNA loops at scaffold crossovers placed on the square lattice points? 286 | off_lattice_xover_scaf_loop_length = 0 #ssDNA loops at scaffold crossovers placed off the square lattice points? 287 | no_loop_exception_ra = [[17, 24], [16, 247]] #no scaffold loops allowed after the indicated base pointer positions 288 | prefix = 'outputfile\t' #Annotation prefix 289 | 290 | #Read files 291 | ##Need to read in designed sequences for every length of scaffold strand in the caDNAno json file, 292 | ##otherwise an error will occur 293 | seq_dc = openPickledFile('130126_1127_designed_seqs_05-69.txt') 294 | stap_color_dc, null_bp = initVars() #initialize variables 295 | maxiscaf_seq_filename = 'p7308_cadnanoversion.txt' 296 | maxiscaf_seq = openFile(maxiscaf_seq_filename) #Import maxiscaf seq 297 | maxiscaf_seq = comp_seq_FN(comp_seq_FN(maxiscaf_seq)) 298 | maxiscaf_seq = maxiscaf_seq[30:] + maxiscaf_seq[:30] 299 | 300 | 301 | ## Ruler + handles 302 | 303 | # In[8]: 304 | 305 | scaf_output_ra, sorted_stap_output_ra, vstrands = give_sequences('ruler_output.json') 306 | eight_mers = openPickledFile('141110_1628_ortho_8mers_2303.txt') 307 | handle_color = {'cyan' : [0, 5], 'blue' : [1, 6], 'red orange' : [2, 7], 'light gray' : [3, 8], 'magenta' : [4, 9]} 308 | 309 | for color, seqidx in handle_color.items(): 310 | for row in sorted_stap_output_ra: 311 | if row[0] == color and row[3][0] in (0, 1): 312 | # Add 'TT' to staple seq: 313 | row[-1] += 'TT' + eight_mers[seqidx[row[3][0]]] 314 | 315 | print_sequences() 316 | 317 | 318 | ## Plate 319 | 320 | # In[10]: 321 | 322 | scaf_output_ra, sorted_stap_output_ra, vstrands = give_sequences('7x3_output.json') 323 | eight_mers = openPickledFile('141110_1628_ortho_8mers_2303.txt') 324 | handle_color = {56 : [0, 5], 88 : [1, 6], 120 : [2, 7], 152 : [3, 8], 184 : [4, 9]} 325 | 326 | print "before adding handles" 327 | # print_sequences() 328 | helix_to_handle_seq_idx = {16: 0, 18: 1} 329 | for end_num, seqidx in handle_color.items(): 330 | for row in sorted_stap_output_ra: 331 | # row[3] is cadnano_start coordinate (helix, basenum), e.g. [2, 200] 332 | if row[3][1] == end_num and row[3][0] in (16, 18): 333 | row[-1] += 'TTTT' + comp_seq_FN(eight_mers[seqidx[0 if row[3][0] == 16 else 1]]) 334 | 335 | print "after adding handles" 336 | print_sequences() 337 | -------------------------------------------------------------------------------- /cadnano-beadcatchers.py: -------------------------------------------------------------------------------- 1 | 2 | # coding: utf-8 3 | 4 | # Functions: 5 | # - load_json(file_name, period=32) 6 | # - save_json(file_name) 7 | # - removeCrossover(helix_num, start, step, num) 8 | # - insertBreak(helix_num, start, step, num) 9 | # - insertDeletions(start, step) 10 | # - findStaples() 11 | # - colorCycle(i) 12 | # - resetColor() 13 | # - colorBased_on_helix() 14 | # - stapleLength() 15 | # - removeAllStaples() 16 | # - joinStaple() 17 | # - removeStaples(helix_num, start, step, num) 18 | # - insertScaffCrossover(up_helix, bot_helix, base_num) 19 | # - forcePath(helix_num, start, stop) 20 | 21 | # In[37]: 22 | 23 | import matplotlib.pyplot as plt 24 | import numpy as np 25 | import json 26 | 27 | def load_json(file_name, period=32): 28 | """ 29 | Loads a .json file in the correct way, so it can still be read by cadnano2. 30 | 31 | Parameters 32 | ---------- 33 | file_name : str 34 | The name and location of the *.json file 35 | period : int 36 | The period of repeating segments of the staples, in the square lattice this is by default 32. 37 | 38 | Returns 39 | ------- 40 | data : list 41 | all data that is loaded from the *.json file 42 | vstrands : list 43 | vstrands data 44 | num_helices : int 45 | number of helices in the design 46 | num_bases : int 47 | number of bases in the design 48 | idx : dict 49 | polarity 50 | period 51 | 52 | Example 53 | ------- 54 | data, vstrands, num_helices, num_bases, idx, polarity, per = load_json('ruler_design_12nov_1353.json') 55 | """ 56 | with open(file_name) as f: 57 | data = json.load(f) 58 | 59 | vstrands = data['vstrands'] 60 | num_helices = len(vstrands) 61 | num_bases = len(vstrands[0]['scaf']) 62 | idx = {} 63 | polarity = {} 64 | for helix_num in range(num_helices): 65 | idx[vstrands[helix_num]['num']] = helix_num 66 | polarity[helix_num] = vstrands[idx[helix_num]]['col'] + vstrands[idx[helix_num]]['row'] 67 | return data, vstrands, num_helices, num_bases, idx, polarity, period 68 | 69 | def save_json(file_name): 70 | """ 71 | Saves the .json file in the correct way, so it can still be read by cadnano2. 72 | 73 | Parameters 74 | ---------- 75 | file_name : str 76 | The name and location of the *.json file 77 | """ 78 | data['vstrands'] = vstrands 79 | with open(file_name, 'wb') as outfile: 80 | json.dump(data, outfile) 81 | 82 | def removeCrossover(strand, start, step, num, side='left'): 83 | """ 84 | Removes a crossover of the staple strands. 85 | 86 | Parameters 87 | ---------- 88 | strand : int 89 | the strand number of one the two strands of which you want to remove the crossover 90 | start : int 91 | the number of the basepair 92 | step : int 93 | the step interval of repeating pattern 94 | num : int 95 | number of times the pattern repeats 96 | side : string 97 | the side at which the staple makes the crossover, ___| is right, |___ is left 98 | """ 99 | if (idx[strand]%2 == 0) and (side == 'left') or (idx[strand]%2 != 0) and (side == 'right'): 100 | next_strand = vstrands[idx[strand]]['stap'][start][2] 101 | # if the first strand is (even & left) or (odd & right): 102 | for i in range(num): 103 | vstrands[idx[strand]]['stap'][start+i*step][2:] = [-1, -1] 104 | vstrands[idx[next_strand]]['stap'][start+i*step][:2] = [-1, -1] 105 | else: 106 | next_strand = vstrands[idx[strand]]['stap'][start][0] 107 | for i in range(num): 108 | vstrands[idx[strand]]['stap'][start+i*step][:2] = [-1, -1] 109 | vstrands[idx[next_strand]]['stap'][start+i*step][2:] = [-1, -1] 110 | 111 | def insertBreak(helix_num, start, step, num, strand='stap'): 112 | """ 113 | Inserts a break in the staple strand. 114 | 115 | Parameters 116 | ---------- 117 | strand : int 118 | the strand number of where you want to insert a break 119 | start : int 120 | the number of the basepair 121 | step : int 122 | the step interval of repeating pattern 123 | num : int 124 | number of times the pattern repeats 125 | """ 126 | if polarity[idx[helix_num]] % 2 == 0: 127 | for i in range(num): 128 | vstrands[idx[helix_num]][strand][start+i*step][:2] = [-1, -1] 129 | vstrands[idx[helix_num]][strand][start+1+i*step][2:] = [-1, -1] 130 | else: 131 | for i in range(num): 132 | vstrands[idx[helix_num]][strand][start+i*step][2:] = [-1, -1] 133 | vstrands[idx[helix_num]][strand][start+1+i*step][:2] = [-1, -1] 134 | 135 | def insertScaffBreak(helix_num, start, step, num): 136 | """ 137 | Inserts a break in the scaffold strand. 138 | 139 | Parameters 140 | ---------- 141 | strand : int 142 | the strand number of where you want to insert a break 143 | start : int 144 | the number of the basepair 145 | step : int 146 | the step interval of repeating pattern 147 | num : int 148 | number of times the pattern repeats 149 | """ 150 | return insertBreak(helix_num, start, step, num, strand='scaf') 151 | 152 | def insertDeletions(start, step, num): 153 | """ 154 | Inserts a deletion at every 'step' bases and starts at 'start'. 155 | 156 | Parameters 157 | ---------- 158 | start : int 159 | base at which the first deletion is made 160 | step : int 161 | the distance between the deletions, in a square lattice this is 48 to compensate the undertwist. 162 | """ 163 | for helix_num in idx: 164 | if vstrands[idx[helix_num]]['scaf'][num_bases/2] != [-1, -1, -1, -1]: 165 | for i in range(num): 166 | vstrands[idx[helix_num]]['skip'][start+i*step] = -1 167 | 168 | def findStaples(): 169 | """ 170 | Finds the beginning points of all staples 171 | 172 | Returns 173 | ------- 174 | staples : list 175 | A list of tuples with the num_helix and the num_base where 176 | the staple starts [(num_helix, num_base), (0, 154), (1, 14), ..., (14, 158)] 177 | num_staples : int 178 | Number of staples in the design 179 | 180 | Example 181 | ------- 182 | staples, num_staples = findStaples() 183 | returns the list and number of staples 184 | """ 185 | # Create a list of two-tuples describing the start of all staples. 186 | staples = [(helix_num, base_num) for helix_num in idx 187 | for base_num, staple in enumerate(vstrands[idx[helix_num]]['stap']) 188 | if staple[:2] == [-1, -1] and staple[2:] != [-1, -1]] 189 | return staples 190 | 191 | def colorCycle(i): 192 | """ 193 | This funtion returns a color, and loops back to the first one when it reaches the last one. 194 | """ 195 | colors = [13369344, 243362, 1507550, 16204552, 8947848, 12060012, 29184, 5749504, 7536862, 3355443, 11184640, 16225054] 196 | return colors[i%len(colors)] 197 | 198 | def resetColor(): 199 | """ 200 | Resets all staples to the color grey 201 | """ 202 | staples = findStaples() 203 | # empty all lists, so no color data remains 204 | for helix_num in idx: 205 | vstrands[idx[helix_num]]['stap_colors'] = [] 206 | # create nested lists with color data, all in grey. 207 | for helix_num, base_num in staples: 208 | # idx is a dict that maps "user interface" indices to vstand indices. 209 | vstrands[idx[helix_num]]['stap_colors'].append([base_num, 8947848]) 210 | 211 | 212 | def colorBased_on_helix(): 213 | """ 214 | This funtions gives each staple that starts on the same helix, the same color. 215 | 216 | Dependends 217 | ---------- 218 | resetColor() 219 | findStaples() 220 | """ 221 | resetColor() 222 | for helix_num in idx: 223 | num_staples = len(vstrands[idx[helix_num]]['stap_colors']) 224 | for staple_num in range(num_staples): 225 | vstrands[idx[helix_num]]['stap_colors'][staple_num][1] = colorCycle(helix_num) 226 | 227 | def colorBased_on_length(): 228 | """ 229 | This funtions gives each staple that starts on the same helix, the same color. 230 | 231 | Dependends 232 | ---------- 233 | resetColor() 234 | findStaples() 235 | stapleLength() 236 | findStaples() 237 | """ 238 | resetColor() 239 | staple_info = stapleLength() 240 | bins = np.array([0, 32, 40, 41, 47, 49, 1000]) 241 | inds = np.digitize(staple_info[:, 0], bins) 242 | i = 0 243 | for helix_num in idx: 244 | for color in vstrands[idx[helix_num]]['stap_colors']: 245 | # color = base_num, color_code 246 | color[1] = colorCycle(inds[i]) 247 | i += 1 248 | 249 | 250 | def stapleLength(plot=0): 251 | """ 252 | Returns an array with the lengths of the staples in the structure and a histogram with the lengths of the staples. 253 | 254 | Parameters 255 | ---------- 256 | plot : int 257 | Use stapleLength(plot=1) to plot a histogram or stapleLength() for no plot. 258 | 259 | Dependends 260 | ---------- 261 | findStaples() 262 | 263 | Returns 264 | ------- 265 | staple_info : array_like 266 | An array with the lengths of all staples [staple_length helix_num base_num] 267 | histogram : plot 268 | A plot with the staple lengths vs. the frequency 269 | """ 270 | staples, num_staples = findStaples() 271 | staples_length = [] 272 | staple_info = np.zeros((num_staples, 6), dtype=int) 273 | for staple_num in range(num_staples): 274 | helix_num = staples[staple_num][0] 275 | base_num = staples[staple_num][1] 276 | staple = vstrands[idx[helix_num]]['stap'][base_num] 277 | staple_info[staple_num, 1] = helix_num 278 | staple_info[staple_num, 2] = base_num 279 | i = 1 280 | while staple[2:] != [-1, -1] and i < 1000: # the < 1000 is just for debugging 281 | last_helix = vstrands[idx[helix_num]]['stap'][base_num][0] 282 | next_helix = vstrands[idx[helix_num]]['stap'][base_num][2] 283 | prev_base = vstrands[idx[helix_num]]['stap'][base_num][1] 284 | next_base = vstrands[idx[helix_num]]['stap'][base_num][3] 285 | helix_num = next_helix 286 | base_num = next_base 287 | staple = vstrands[idx[next_helix]]['stap'][next_base] 288 | i += 1 289 | staple_info[staple_num,0] = i 290 | if plot == 1: 291 | plt.hist(staple_info[:,0], bins= 10) 292 | plt.title("Staple length") 293 | plt.xlabel("Length") 294 | plt.ylabel("Frequency") 295 | plt.show() 296 | return staple_info 297 | 298 | def removeAllStaples(): 299 | """ 300 | This removes all Staples from the structure. 301 | """ 302 | for helix_num in idx: 303 | for base_num in range(num_bases): 304 | vstrands[idx[helix_num]]['stap'][base_num] = [-1, -1, -1, -1] 305 | 306 | def joinStaple(helix_num, start, step, num): 307 | """ 308 | Joins a break between two staples. 309 | 310 | Parameters 311 | ---------- 312 | helix_num : int 313 | the strand number of where you want to join the staples 314 | start : int 315 | the number of the basepair 316 | step : int 317 | the step interval of repeating pattern 318 | num : int 319 | number of times the pattern repeats 320 | """ 321 | for i in range(num): 322 | if polarity[idx[helix_num]]%2 == 0: 323 | vstrands[idx[helix_num]]['stap'][start+i*step][:2]= [idx[helix_num],start+1+i*step] 324 | vstrands[idx[helix_num]]['stap'][start+1+i*step][2:]= [idx[helix_num],start+i*step] 325 | else: 326 | vstrands[idx[helix_num]]['stap'][start+i*step][2:]= [idx[helix_num],start+1+i*step] 327 | vstrands[idx[helix_num]]['stap'][start+1+i*step][:2]= [idx[helix_num],start+i*step] 328 | 329 | def removeStaples(helix_num, start, step, num): 330 | """ 331 | Removes staples. 332 | 333 | Parameters 334 | ---------- 335 | strand : int 336 | the strand number of where you want the staples removed 337 | start : int 338 | the number of the basepair where the staple starts. Start at the leftmost base. 339 | step : int 340 | the step interval of repeating pattern 341 | num : int 342 | number of times the pattern repeats 343 | """ 344 | for i in range(num): 345 | staple = vstrands[idx[helix_num]]['stap'] 346 | base_num = start+i*step 347 | if polarity[idx[helix_num]]%2!=0: 348 | while staple[base_num][2:] != [-1, -1]: 349 | staple[base_num] = [-1, -1, -1, -1] 350 | base_num += 1 351 | staple[base_num] = [-1, -1, -1, -1] 352 | else: 353 | while staple[base_num][:2] != [-1, -1]: 354 | staple[base_num] = [-1, -1, -1, -1] 355 | base_num += 1 356 | staple[base_num] = [-1, -1, -1, -1] 357 | 358 | def insertScaffCrossover(up_helix, bot_helix, base_num): 359 | """ 360 | Inserts a scaffold crossover between up_helix and bot_helix. 361 | 362 | Parameters 363 | ---------- 364 | up_helix : int 365 | The number of the top helix. 366 | bot_helix : int 367 | The number of the bottom helix. 368 | base_num : int 369 | The number of the left base. 370 | """ 371 | if polarity[idx[up_helix]]%2 != 0: 372 | vstrands[idx[up_helix]]['scaf'][base_num][:2]= [bot_helix, base_num] 373 | vstrands[idx[up_helix]]['scaf'][base_num+1][2:]= [bot_helix, base_num+1] 374 | 375 | vstrands[idx[bot_helix]]['scaf'][base_num][2:]= [up_helix, base_num] 376 | vstrands[idx[bot_helix]]['scaf'][base_num+1][:2]= [up_helix, base_num+1] 377 | else: 378 | vstrands[idx[up_helix]]['scaf'][base_num][2:]= [bot_helix, base_num] 379 | vstrands[idx[up_helix]]['scaf'][base_num+1][:2]= [bot_helix, base_num+1] 380 | 381 | vstrands[idx[bot_helix]]['scaf'][base_num][:2]= [up_helix, base_num] 382 | vstrands[idx[bot_helix]]['scaf'][base_num+1][2:]= [up_helix, base_num+1] 383 | 384 | def forcePath(helix_num, start, stop): 385 | """ 386 | Forces a path between staples on the same helix 387 | 388 | Parameters 389 | ---------- 390 | helix_num : int 391 | The number of the helix 392 | start : int 393 | number of the base of the 3' (or 5') end 394 | stop : int 395 | number of the base of the 5' (or 3') end 396 | 397 | Example 398 | ------- 399 | forcePath(6, 19, 210) 400 | >>>> forces path between staple on base 19 and 210 on helix number 6 401 | """ 402 | if polarity[idx[helix_num]]%2 != 0: 403 | vstrands[idx[helix_num]]['stap'][start][:2] = [helix_num, stop] 404 | vstrands[idx[helix_num]]['stap'][stop][2:] = [helix_num, start] 405 | else: 406 | vstrands[idx[helix_num]]['stap'][start][2:] = [helix_num, stop] 407 | vstrands[idx[helix_num]]['stap'][stop][:2] = [helix_num, start] 408 | 409 | 410 | ## Plate design (Incl. William's edits 4 nov) 411 | 412 | # In[61]: 413 | 414 | data, vstrands, num_helices, num_bases, idx, polarity, per = load_json('7x3_input.json') 415 | ############################################## 416 | 417 | for i in [9, 11, 13]: 418 | removeCrossover(i, 39, per, 6, 'right') 419 | 420 | for i in [7, 9, 11]: 421 | removeCrossover(i, 55, per, 6, 'right') 422 | 423 | for i in [0, 2, 4, 6]: 424 | insertBreak(i, 39, per, 6) 425 | 426 | for i in [14, 16, 18, 20]: 427 | insertBreak(i, 23, per, 6) 428 | 429 | for i in [2, 4]: 430 | removeCrossover(i, 23, 1, 1, 'right') 431 | 432 | for i in [9, 11, 13]: 433 | insertScaffBreak(i, 64, 48, 3) 434 | 435 | for i in [0, 5, 9, 11, 13, 14]: 436 | forcePath(i, 16, 207) 437 | 438 | for i in [1, 3, 5, 15, 17, 19]: 439 | insertScaffCrossover(i, i+1, 127) 440 | 441 | insertScaffCrossover(7, 20, 119) 442 | insertBreak(5, 23, 1, 1) 443 | insertBreak(7, 23, 1, 1) 444 | 445 | # script doesn't work with forcePath between different helices. 446 | vstrands[6]['stap'][19] = [6, 20, 6, 210] 447 | vstrands[7]['stap'][19] = [7, 210, 7, 20] 448 | vstrands[7]['stap'][210] = [7, 209, 7, 19] 449 | vstrands[6]['stap'][210] = [6, 19, 6, 209] 450 | 451 | resetColor() 452 | insertDeletions(20, 48, 4) 453 | 454 | ############################################## 455 | # color the staples purple that need to be made longer 456 | for i in range(1, len(vstrands[20]['stap_colors'])): 457 | vstrands[20]['stap_colors'][i][1] = colorCycle(8) 458 | for i in range(1, len(vstrands[18]['stap_colors'])): 459 | if i%2 == 0: 460 | vstrands[18]['stap_colors'][i][1] = colorCycle(8) 461 | 462 | # color the staples for the DNA-bead attachment sites in orange 463 | for i in range(len(vstrands[0]['stap_colors'])-1): 464 | vstrands[0]['stap_colors'][i][1] = colorCycle(11) 465 | for i in range(len(vstrands[2]['stap_colors'])): 466 | if i%2 == 1: 467 | vstrands[2]['stap_colors'][i][1] = colorCycle(11) 468 | 469 | # color the staples that need to be omitted in the first step green 470 | for i in [2, 4, 6, 14, 16, 18, 20]: 471 | vstrands[idx[i]]['stap_colors'][0][1] = colorCycle(7) 472 | for i in [2, 4, 14, 16, 18]: 473 | vstrands[idx[i]]['stap_colors'][-1][1] = colorCycle(7) 474 | ############################################## 475 | 476 | save_json('7x3_output.json') 477 | 478 | 479 | ## Ruler design 480 | 481 | # In[59]: 482 | 483 | data, vstrands, num_helices, num_bases, idx, polarity, per = load_json('ruler_input.json') 484 | insertBreak(0,47,32,107) 485 | insertBreak(1,47,32,107) 486 | insertDeletions(60, 48, 72) 487 | resetColor() 488 | for i in range(len(vstrands[0]['stap_colors'])): 489 | vstrands[0]['stap_colors'][i-1][1] = colorCycle(i%6) 490 | vstrands[1]['stap_colors'][i][1] = colorCycle(i%6) 491 | 492 | save_json('ruler_output.json') 493 | --------------------------------------------------------------------------------