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.
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:
********* #########
********* #########
********* #########
********* #########
********* #########
********* #########
********* #########
****** #########
#########
######### ****
######### *********
######### *********
######### *********
######### *********
######### *********
######### *********
######### *********
###### *********
*********
********* ####
********* #########
********* #########
********* #########
********* #########
********* #########
********* #########
********* #########
****** #########
#########
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).
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
.
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:
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
######## ##########
##### ##########
# ##########
########## #
########## #####
########## ########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
######## ##########
##### ##########
# ##########
########## #
########## #####
########## #########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ####
########## ########
########## ###########
########## ##########
########## ##########
########## #########
########## #########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########### ##########
######### ##########
##### ##########
# ##########
########## ###
########## #######
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
########## ##########
####### ##########
#### #########
######### #
. . .
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With