3

What is a good way to draw a dynamic programming such as this one (with the path) in python? Dynamic programming table

I have looked online and I see pygame but is that really the best option for this sort of technical drawing?

One option might be to use matplotlib using something like

import matplotlib.pylab as plt
plt.figure()
col_labels=['col1','col2','col3']
row_labels=['row1','row2','row3']
table_vals=[[11,12,13],[21,22,23],[31,32,33]]

the_table = plt.table(cellText=table_vals,
                  colWidths = [0.1]*3,
                  rowLabels=row_labels,
                  colLabels=col_labels,
                  loc='center right')
plt.text(12,3.4,'Table Title',size=8)

plt.show()

How can I draw the line on the table?

4
  • What's wrong with PyGame? The name? Commented Feb 28, 2014 at 20:09
  • @IgnacioVazquez-Abrams Isn't pygame about interactivity? I just want to draw a picture. Commented Feb 28, 2014 at 20:10
  • Yes, but showing an image is a form of interactivity, limited as it may be. Commented Feb 28, 2014 at 20:11
  • It can be, but it doesn't have to. I would maybe try and use matplotlib. Draw some sort of tabular plot with imshow(), create custom labels for the axes and then draw that line above all. Commented Feb 28, 2014 at 20:13

1 Answer 1

9
+50

The following code yields an approximation of the figure you want, using native Matplotlib tables:

import matplotlib.pylab as plt
import numpy as np

def get_coord(table, irow, icol):
    # get coordinates of a cell. This seems to work, don't ask why.
    cell = table.get_celld()[irow+1,icol] # row 0 is column headers
    box = cell.get_bbox().get_points() # [[x0, y0],[x1, y1]]
    xc, yc = box.mean(axis=0) # get center
    return xc, yc

col_labels=['G','A','T','C','C']
row_labels= ['G','T','G','C','C']
table_vals= [
    ['x','','','',''],
    ['','','x','',''],
    ['x','','','',''],
    ['','','','x','x'],
    ['','','','x','x']]
line = [(0,0), (0,1), (1,2), (2,2), (3,3), (4,4)]    

# draw table
the_table = plt.table(cellText=table_vals,
    colWidths = [0.1]*len(col_labels),
    rowLabels=row_labels, colLabels=col_labels,
    cellLoc = 'center', rowLoc = 'center', bbox=[.1,.1,.8,.8])
plt.draw() # lay out table, so that cell coordinates are calculated

# look up line coordinates
x = []; y = []
for irow, icol in line:
    xc, yc = get_coord(the_table, irow, icol)
    x.append(xc)
    y.append(yc)

# draw line    
plt.plot(x, y, 'r', linewidth = 5, alpha=0.5)
plt.xlim([0,1])
plt.ylim([0,1])
plt.show()

Result:

table1

Note that the result is not extremely beautiful, I could for example not figure out how to change the width of the column with row-labels. There is also the issue that the table is drawn in 'figure coordinates', while the line is drawn in 'data-coordinates', so if you zoom in the line and the table no longer overlap. I struggled for quite some time with these tables, but in my opinion they are quite a PITA to work with and the resulting code is hard to understand.

My preferred solution is to just draw the table by hand:

import matplotlib.pylab as plt
import numpy as np

col_labels=['G','A','T','C','C']
row_labels= ['G','T','G','C','C']
table_vals= [
    ['X','','','',''],
    ['','','X','',''],
    ['X','','','',''],
    ['','','','X','X'],
    ['','','','X','X']]
line = np.array([
    [0, 1, 2, 2, 3, 4],
    [0, 0, 1, 2, 3, 4]])    
ncol = len(col_labels)
nrow = len(row_labels)

# draw grid lines
plt.plot(np.tile([0, ncol+1], (nrow+2,1)).T, np.tile(np.arange(nrow+2), (2,1)),
    'k', linewidth=3)
plt.plot(np.tile(np.arange(ncol+2), (2,1)), np.tile([0, nrow+1], (ncol+2,1)).T,
    'k', linewidth=3)

# plot labels
for icol, col in enumerate(col_labels):
    plt.text(icol + 1.5, nrow + 0.5, col, ha='center', va='center')
for irow, row in enumerate(row_labels):
    plt.text(0.5, nrow - irow - 0.5, row, ha='center', va='center')

# plot table content
for irow, row in enumerate(table_vals):
    for icol, cell in enumerate(row):
        plt.text(icol + 1.5, nrow - irow - 0.5, cell, ha='center', va='center')

# plot line
plt.plot(line[0] + 1.5, nrow - line[1] - 0.5, 'r', linewidth = 5, alpha = 0.5)

plt.axis([-0.5, ncol + 1.5, -0.5, nrow+1.5])
plt.show()

with result:

table2

This looks much nicer, and the code is straightforward to understand. You might want to adjust some line-widths and font-sizes to your own taste, and hide the axis.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much! You second solution looks great.
Hey guy, how i can color one square of this table?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.