Protein is Good for You, part 2 (Matt Gertz)

In yesterday’s blog post, I walked through an engine for translating DNA to its amino acid results via messenger RNA.  In today’s blog, we’ll work on the visualization using WPF StackPanels.  (This example requires VS2008, although it could certainly be written in WinForms as well with just a little bit of extra work.)

Caution:  The point of this blog is to demonstrate StackPanels, and specifically how you can control their orientation and nesting.  Consequently, for the sake of that argument, I’m creating a lot of text objects (one for each base and each amino) and nesting them to demonstrate this.  For a really robust program, I would ditch the extra objects and just do owner draw directly.  In other words, don’t use this example on enormous 20000-sequence strands of DNA, as neither you nor your PC would like the performance results.


In the last post, I added a ScrollViewer to the Window, changed it to scroll horizontally instead of vertically, but otherwise left it alone.  Now we’ll dig into the details of how we’ll populate it with StackPanels. 

StackPanels expose a very easy way to organize a set of drawable objects on the screen.  StackPanels expose a Children collection, and when you add objects to the that collection, they’ll display in the order you add them and in the direction you specify.  What’s really cool is that StackPanels will nest with each other, and I’ll take advantage of that fact by creating three StackPanels that organize information horizontally (one each for DNA, mRNA, and aminos), and then adding them to a parent StackPanel so that they line up with each other.  I’ll then add the parent StackPanel to the ScrollViewer so that the alignment of all three sub-panels can be seen.

Each of the sub-panels will contain one of more text objects which either contain the abbreviation of a base, the abbreviation of an amino, or blank space (representing unused intron material).  Aminos correspond to three bases, and so those text objects need to be three times wider.  I’ll create some helper functions to return the appropriate text objects:

    Const baseWidth As Integer = 16


    Private Function DrawBase(ByVal base As Char) As TextBlock

        Dim baseTextBlock As New TextBlock

        Select Case base ‘ Switch for colors

            Case “C”

                baseTextBlock.Background = Brushes.LightSalmon

            Case “G”

                baseTextBlock.Background = Brushes.LightGoldenrodYellow

            Case “A”

                baseTextBlock.Background = Brushes.LightGreen

            Case “T”

                baseTextBlock.Background = Brushes.LightSkyBlue

            Case “U”

                baseTextBlock.Background = Brushes.LightSteelBlue

        End Select


        baseTextBlock.Inlines.Add(New Bold(New Run(base)))

        baseTextBlock.Height = 32

        baseTextBlock.Width = baseWidth

        baseTextBlock.TextAlignment = TextAlignment.Center


        Return baseTextBlock

    End Function


That last function will be used by both DNA and RNA, creating and returning a fixed block of an appropriate color (a different one for each base) 16 x 32 pixels with the base abbreviation (passed into the function) centered within it.  I’ve chosen light colors so that the dark text will show up against the background properly. 

For the amino chains, it’s pretty similar, except that each block is three times wider, to keep the amino lined up with the codon:

    Private Function DrawAmino(ByVal amino As String) As TextBlock

        Dim aminoTextBlock As New TextBlock

        Select Case amino ‘ Switch for colors

            Case “Phe”

                aminoTextBlock.Background = Brushes.AliceBlue

            Case “Leu”

                aminoTextBlock.Background = Brushes.Beige

            Case “Ser”

                aminoTextBlock.Background = Brushes.Cyan

            Case “Tyr”

                aminoTextBlock.Background = Brushes.LightSeaGreen

           ‘ (Etc… the other aminos omitted for brevity’s sake; see final code for full list.)


        End Select

        aminoTextBlock.Inlines.Add(New Bold(New Run(amino)))

        aminoTextBlock.Height = 32

        aminoTextBlock.Width = baseWidth * 3

        aminoTextBlock.TextAlignment = TextAlignment.Center

        Return aminoTextBlock

    End Function

And for empty space, I just pass in the number of spaces required and multiple it by the baseWidth:

    Private Function DrawNoMap(ByVal noMapSize As Integer) As TextBlock

        Dim noMapTextBlock As New TextBlock

        noMapTextBlock.Background = ScrollViewer1.Background

        noMapTextBlock.Height = 32

        noMapTextBlock.Width = baseWidth * noMapSize

        Return noMapTextBlock

    End Function


Now I have the tools; we can put them to good use.  First, let’s create & populate the DNA StackPanel:

    Private Function DrawBases(ByVal s As String) As StackPanel

        ‘ DNA goes here (horizontal orientation):

        Dim myStackPanel As New StackPanel

        myStackPanel.HorizontalAlignment = System.Windows.HorizontalAlignment.Left

        myStackPanel.VerticalAlignment = System.Windows.VerticalAlignment.Top

        myStackPanel.Orientation = Orientation.Horizontal


        ‘Add child elements to the parent StackPanel.

        For i As Integer = 0 To s.Length – 1




        Return myStackPanel

    End Function


This is a simple function that does three things:

(1)    Create a stack panel that has horizontal orientation, containing object that start from the top left.

(2)    Step through each base in the DNA or RNA and add the TextBlock for it created in DrawBase.

(3)    Return the completed StackPanel

I can use this for both DNA and mRNA just by passing in the appropriate string.  Aminos are a bit trickier because I’ve decided to save them as lists of strings rather than one long string (to make it easier to access individual proteins should I wish to expand this program in the future):

    Private Function DrawAminos() As StackPanel

        ‘ Aminos go here (horizontal orientation):

        Dim myStackPanelAminos As New StackPanel

        myStackPanelAminos.HorizontalAlignment = System.Windows.HorizontalAlignment.Left