Learning Scientific Programming with Python (2nd edition)

E8.4: DNA diffraction pattern

In an important paper in 1953 [1], Rosalind Franklin published the X-ray diffraction pattern of DNA from calf thymus which displays a characteristic 'X' shape of diffraction spots indicative of a helical structure.

The diffraction pattern of a uniform, continuous helix consists of a series of "layer lines" of spacing $1/p$ in reciprocal space where $p$ is the helix pitch (the height of one complete turn of the helix, measured parallel to its axis). The intensity distribution along the $n$th layer line is proportional to square of the $n$th Bessel function, $J_n(2\pi r R)$, where $r$ is the radius of the helix and $R$ the radial co-ordinate in reciprocal space.

Consider the diffraction pattern of a helix with $p = 34$ Å and $r=10$ Å. The code listing below produces an SVG image of the diffraction pattern of a helix.

References

  1. R. E. Franklin, R. G. Gosling, Nature 171, 740 (1953).
import numpy as np
from scipy.special import jn

# Vertical range of the diffraction pattern: plot nlayer line layers above and
# below the centre horizontal
nlayers = 5
ymin, ymax = -nlayers, nlayers

# Horizontal range of the diffraction pattern, x = 2pi.r.R
xmin, xmax = -10, 10
npts = 4000
x = np.linspace(xmin, xmax, npts)

# Diffraction pattern along each line layer: |Jn(x)|^2
# for n = 0, 1, ..., nlayers-1
layers = np.array([jn(i, x) ** 2 for i in range(nlayers)])

# Obtain the indexes of the maxima in each layer
maxi = [
    (np.diff(np.sign(np.diff(layers[i, :]))) < 0).nonzero()[0] + 1
    for i in range(nlayers)
]

# Create the SVG image, using circles of different radii for diffraction spots
svg_name = "dnadiffraction.svg"
canvas_width = canvas_height = 500
fo = open(svg_name, "w")
print(
    f"""<?xml version="1.0" encoding="utf-8"?>
         <svg xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink"
              width="{canvas_width}"
              height="{canvas_height}"
              style="background: white">""",
    file=fo,
)


def svg_circle(r, cx, cy):
    """Return the SVG mark up for a circle of radius r centred at (cx,cy)."""
    return rf'<circle r="{r}" cx="{cx}" cy="{cy}"/>'


# For each spot in each layer, draw a circle on the canvas. The circle radius
# is the scaled value of the diffraction intensity maximum, with a ceiling
# value of spot_max_radius because the centre spots are very intense
spot_scaling, spot_max_radius = 50, 20
for i in range(nlayers):
    for j in maxi[i]:
        sx = (x[j] - xmin) / (xmax - xmin) * canvas_width
        sy = (i - ymin) / (ymax - ymin) * canvas_height
        spot_radius = min(layers[i, j] * spot_scaling, spot_max_radius)
        print(svg_circle(spot_radius, sx, sy), file=fo)
        if i:
            # The pattern is symmetric about the centre horizontal:
            # duplicate the layers with i > 0
            sy = canvas_height - sy
            print(svg_circle(spot_radius, sx, sy), file=fo)

print(r"</svg>", file=fo)
The simulated diffraction pattern of DNA

The simulated diffraction pattern of DNA.