Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Double helix generating algorithm

Tags:

python

I'm trying to come up with a good algorithm to create an representation of a right handed DNA string with major and minor grooves using the dash character, for an arbitrary number of characters.

This is what I currently have, using 776 #'s:

  #########                 ##########
    #########                ##########
      #########              ##########
        #########          ##########
          ##########     ##########
            ########## ##########
              ###### ##########
                ## ##########
                 ########## #
               ########## #####
             ########## #########
           ##########    ##########
         ##########        ##########
       ##########           ##########
     ##########             ##########
   ##########               ##########
  ##########               ##########
  ##########             ##########
  ##########           ##########
   ##########        ##########
     ###########   ##########
       ######### ##########
         ##### ##########
           # ##########
           ########## ###
         ########## #######
       ##########  ##########
     ##########      ##########
   ##########          ##########
  ##########             ##########
  ##########               ##########
  ##########                 ##########
   ##########                 ##########
     ##########               ##########
       ##########             ##########
         ##########          ##########
           ##########      ##########
             ##########  ##########
               ####### ##########
                 #### #########
                    ######### #
                  ########## ###
                ########### #######

but the helix doesn't align perfectly when I manually try to repeat the helix via copy/pasting.

A solution that has has the same width as the example above but also has the basepair crossbonds (like in this image or in the scarf pattern below), is also acceptable.

scarf pattern

like image 268
BioGeek Avatar asked Apr 23 '12 14:04

BioGeek


5 Answers

The key to this question is to recognize that you can represent each strand on the helix as a combination of sine waves - one for the periodic portion, and one for the "depth" into the page. Once you've parameterized the problem this way, you can control every aspect of your helix. The example below uses * and # to show the different strands to illustrate the point. If you choose values for the wavelength that do not commensurate with integer values you'll get less then optimal results - but now you can play with inputs to find what you consider the most aesthetically pleasing representation.

from numpy import *

amp = 10
length = 100
wavelength = 20

omega = (2*pi)/wavelength
phi   = wavelength*(0.5)
X = arange(1,length)
Y1 = round_(amp*(sin(omega*X) + 1))
Y2 = round_(amp*(sin(omega*X+phi) + 1))

offset = phi/2
Z1 = sin(omega*X + offset)
Z2 = sin(omega*X + phi + offset)

T1 = " ######### "
T2 = " ********* "
clen = len(T1)

H = zeros((length,amp*2+clen),dtype='str')
H[:,:] = " "

for n,(y1,y2,z1,z2) in enumerate(zip(Y1,Y2,Z1,Z2)):
    H[n,y1:y1+clen] = list(T1)
    H[n,y2:y2+clen] = list(T2)

    # Overwrite if first helix is on top
    if z1>z2: H[n,y1:y1+clen] = list(T1)

for line in H:
    print "".join(line)

These values give:

   *********  #########        
  *********      #########     
 *********         #########   
 *********           ######### 
   *********         ######### 
     *********       ######### 
       *********   #########   
          ****** #########     
              #########        
           ######### ****      
        #########  *********   
     #########      *********  
   #########         ********* 
 #########           ********* 
 #########         *********   
 #########       *********     
   #########   *********       
     ###### *********          
        *********              
      ********* ####           
   *********  #########        
  *********      #########     
 *********         #########   
 *********           ######### 
   *********         ######### 
     *********       ######### 
       *********   #########   
          ****** #########     
              #########        
like image 91
Hooked Avatar answered Oct 01 '22 20:10

Hooked


This ought to give you a decent start:

from math import sin, cos, pi

class RightHelix(object):
    def __init__(self, maxima, minima, period, offset):
        self.mid = 0.5 * (maxima + minima)
        self.mag = 0.5 * (maxima - minima)
        self.k = 2.0 * pi / period
        self.offs = self.k * offset
    def x(self, t):
        return self.mid + self.mag * sin(self.k*t - self.offs)
    def y(self, t):
        return -self.mag * cos(self.k*t - self.offs)

def main():
    rh = RightHelix(33, 7, 20, -2)

    for t in range(40):
        x,y = rh.x(t), rh.y(t)
        print(' '*int(x-0.5) + ('O','X')[y>0])

if __name__=="__main__":
    main()

as given, produces

                           O
                              O
                               O
                                O
                               X
                              X
                           X
                       X
                   X
               X
           X
        X
       X
      X
       O
        O
           O
               O
                   O
                       O
                           O
                              O
                               O
                                O
                               X
                              X
                           X
                       X
                   X
               X
           X
        X
       X
      X
       O
        O
           O
               O
                   O
                       O

(the Xs and Os are just to show that it is, indeed, a right-handed spiral).

like image 42
Hugh Bothwell Avatar answered Oct 02 '22 20:10

Hugh Bothwell


How about this one:

import math

phaseA = math.pi/1.5
phaseB = 0
step = math.pi/20
width = 30  # screen size
breadth = 8  # breadth of DNA single string

x = 0.0
while True:
  x += step
  if x > 30.0: break
  yA = math.sin(x + phaseA)
  zA = math.cos(x + phaseA)
  yB = math.sin(x + phaseB)
  zB = math.cos(x + phaseB)
  if zA > zB:  # which is in front?
    yTop, yBottom = yA, yB
  else:
    yTop, yBottom = yB, yA
  # screenify values:
  yTop    = 1 + int((1.0 + yTop)    / 2.0 * (width-breadth))
  yBottom = 1 + int((1.0 + yBottom) / 2.0 * (width-breadth))
  line = ' ' * yBottom + '#' * breadth + ' ' * (width-yBottom)
  line = list(line)  # make mutable
  line[yTop-1] = ' '
  line[yTop+breadth+1] = ' '
  for i in range(breadth):
    line[yTop+i] = '#'
  print ''.join(line)

It does not use a specific number of hashes for the output, though. Maybe this was one of you requirements, don't know ...

It should produce a repetitive pattern as long as the step value is a whole-numbered fraction of math.pi.

like image 21
Alfe Avatar answered Oct 02 '22 20:10

Alfe


Here's my approach. It's probably not materially different than anyone else's, but I wrote it, so here it goes:

The top half is configuration. The bottom half is action.

from math import cos, sin, pi

length = 50
width = 30
thickness = 10
rotation = 0.15
strands = [0, 2 * pi / 3]
strand_char = "#"

radius = width / 2
for line in range(length):
    output = [" "] * (width + thickness + 2)
    total_rotation = -line * rotation
    sorted_strands = sorted(strands, key=lambda s: cos(total_rotation + s))
    for strand_offset in sorted_strands:
        pos = int(radius * sin(total_rotation + strand_offset) + radius)
        output[pos : pos + thickness + 2] = " " + strand_char * thickness + " "
    print("".join(output))

Output:

                ##########  ##########    
             ##########      ##########   
           ##########         ##########  
         ##########           ##########  
       ##########             ##########  
     ##########               ##########  
    ##########               ##########   
  ##########                ##########    
  ##########               ##########     
 ##########               ##########      
 ##########             ##########        
 ##########           ##########          
 ##########         ##########            
  ##########      ##########              
   ##########  ##########                 
    ######## ##########                   
     ##### ##########                     
       # ##########                       
       ########## #                       
     ########## #####                     
    ########## ########                   
  ##########    ##########                
 ##########       ##########              
 ##########         ##########            
 ##########           ##########          
 ##########             ##########        
 ##########               ##########      
  ##########               ##########     
   ##########                ##########   
    ##########                ##########  
     ##########               ##########  
       ##########             ##########  
         ##########           ##########  
           ##########         ##########  
             ##########      ##########   
                ##########  ##########    
                  ######## ##########     
                    ##### ##########      
                      # ##########        
                      ########## #        
                    ########## #####      
                 ########## #########     
               ##########    ##########   
             ##########       ##########  
           ##########         ##########  
         ##########           ##########  
       ##########             ##########  
     ##########               ##########  
    ##########               ##########   
  ##########                ##########    
like image 25
recursive Avatar answered Oct 02 '22 20:10

recursive


                 ########## ####
               ########## ########
             ##########  ###########
           ##########      ##########
         ##########         ##########
       ##########            #########
     ##########              #########
   ##########               ##########
  ##########               ##########
  ##########             ##########
  ##########           ##########
   ##########        ##########
     ###########   ##########
       ######### ##########
         ##### ##########
           # ##########
           ########## ###
         ########## #######
       ##########  ##########
     ##########      ##########
   ##########          ##########
  ##########             ##########
  ##########               ##########
  ##########                 ##########
   ##########                 ##########
     ##########               ##########
       ##########             ##########
         ##########          ##########
           ##########      ##########
             ##########  ##########
               ####### ##########
                 #### #########
                    ######### #

. . .

Sadly I wanted that to be the sum total of my answer. But I should explain: when you perform changes to tesselations, you need to work with the basic repeating unit (and if you modify the way it tesselates, you have to modify other parts of it, but you aren't doing that). I cut your pattern into what I thought looked like a repeating unit, then copy-pasted it once; when I made a change to the bottom, I made the same change to the top.

<deep thoughts>Sometimes the simplest solutions are found without too much thinking.</deep thoughts>

Nevertheless, you could definitely perform a posterization algorithm on an image of DNA, turning it into a bitmap. (You can do this to an image you have the copyright of.) If you are not beholden to using the same character, you could also use an ascii art generator, of which you can find dozens on the web and in open-source software via some Google searching. That is, however, not in the scope of the StackOverflow FAQ so I won't go much into detail on that, except to link this computer science paper on vector-style ascii-art conversion: http://www.cse.cuhk.edu.hk/~ttwong/papers/asciiart/asciiart.pdf

like image 25
ninjagecko Avatar answered Oct 03 '22 20:10

ninjagecko