Easiest way to turn a list into an HTML table in python?

Question:

lets say I have a list like so:

['one','two','three','four','five','six','seven','eight','nine']

and I want to experiment with turning this data into a HTML table of various dimensions:

one     two    three
four    five   six
seven   eight  nine

or

one    four   seven
two    five   eight
three  six    nine

or

one    two   three  four
five   six   seven  eight
nine

Is there a library that can handle this without needing to do crazy list splicing or nested for loops? My google searches reveal that there are a few HTML libraries, but I don’t have the time to go through each one to see if they can handle tables very well. Has anyone ever had to do this? If so how did you do it?

Asked By: priestc

||

Answers:

Well there are several templating libraries around (Genshi is one I like but there are many others).

Alternatively you could do something like:

def print_table(data, row_length):
    print '<table>'
    counter = 0
    for element in data:
        if counter % row_length == 0:
            print '<tr>'
        print '<td>%s</td>' % element
        counter += 1
        if counter % row_length == 0:
            print '</tr>'
    if counter % row_length != 0:
        for i in range(0, row_length - counter % row_length):
            print '<td>&nbsp;</td>'
        print '</tr>'
    print '</table>'
Answered By: Benno

I would decompose your problem into two parts:

  • given a “flat list”, produce a list of sublists where the sublists are of a given length and the overall list may be walked into either a “row major” order (your first and third example) or “column major” (your second example);
  • given a list of sublists with string items, produce an HTML table out of it.

I think the two tasks are really very distinct and there’s nothing to gain (and much to lose) in mushing them up, so I would be astonished if any well-designed library did such mushing.

For point 1, row-major is easy:

def row_major(alist, sublen):      
  return [alist[i:i+sublen] for i in range(0, len(alist), sublen)]

and column-major not that bad:

def col_major(alist, sublen):
  numrows = (len(alist)+sublen-1) // sublen 
  return [alist[i::sublen] for i in range(numrows)]

for example…:

L = ['one','two','three','four','five','six','seven','eight','nine']
for r in row_major(L, 3): print r
print
for r in col_major(L, 3): print r
for r in row_major(L, 4): print r

produces your three desired results (one list per row, not in HTML form yet;-).

The second half of the problem — produce an HTML table from a list of lists of strings:

def html_table(lol):
  print '<table>'
  for sublist in lol:
    print '  <tr><td>'
    print '    </td><td>'.join(sublist)
    print '  </td></tr>'
  print '</table>'

If you want to get it as a single string rather than print it out, change each print into yield and use 'n'.join(html_table(lol)).

Now you have two simple, useful, usable and reusable building blocks — having them separate will come in handy whenever you want to present your data as anything BUT an HTML table, and also whenever the list-of-lists to present as an HTML table comes from any other way of building it. Putting them together is easy to do in your application code, but of course it’s also easy to do a simple “glue routine”, e.g., assuming the yield-based version of html_table and that a single string result is desired:

def list_to_html_table(alist, sublength, column_major=False):
  if column_major:
    lol = col_major(alist, sublength)
  else:
    lol = row_major(alist, sublength)
  return ''.join(html_table(lol))

Isn’t this building-blocks approach really nicer and more pleasant, as well as more productive, than programming in terms of big blobs of mushed-up glue…?-)

Answered By: Alex Martelli

Maybe manipulate template is easier for toy codes, =p

def get_html_tbl(seq, col_count):
    if len(seq) % col_count:
        seq.extend([''] * (col_count - len(seq) % col_count))
    tbl_template = '<table>%s</table>' % ('<tr>%s</tr>' % ('<td>%s</td>' * col_count) * (len(seq)/col_count))
    return tbl_template % tuple(seq)
Answered By: okm

Just for future reference, I implemented a small Python module called simpletable to provide easy HTML table generation. It also that deals with the issue described in this question.

The usage is as simple as below:

import simpletable

test_data = [str(x) for x in range(20)]
formatted_data = simpletable.fit_data_to_columns(test_data, 5)
table = simpletable.SimpleTable(formatted_data)
html_page = simpletable.HTMLPage(table)
html_page.save("test_page.html")

Since it does not require third-party packages, you can just get the code from my repository and use it in your projects.

Answered By: Matheus Portela

Although this has been answered before, here is another solution by using numpy and pandas DataFrame. Since a lot of people are interested in data-science nowadays, I thought solving this using pandas would be fun:

GITHUB SOLUTION:
I have made my solution available at my GitHub Repository which you can also run and explore in Google Colaboratory (I strongly recommend this).

The custom function (generate_html_with_table()) that I used here is available in this Jupyter Notebook.

SOLUTION:
To get your solution run the following:

data = ['one','two','three','four','five','six','seven','eight','nine']
columns = 4                   # Number of Columns
columns_or_rows = columns
column_name_prefix = 'Column' # Prefix for Column headers
span_axis = 1                 # Span along a row (1) or a column (0) first
showOutput = True             # Use False to suppress printing output

# Generate HTML
data_html, data_df = generate_html_with_table(data, columns_or_rows, column_name_prefix, span_axis, showOutput)

OUTPUT:

HTML Generated: 

<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Column_0</th>
      <th>Column_1</th>
      <th>Column_2</th>
      <th>Column_3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>one</td>
      <td>two</td>
      <td>three</td>
      <td>four</td>
    </tr>
    <tr>
      <th>1</th>
      <td>five</td>
      <td>six</td>
      <td>seven</td>
      <td>eight</td>
    </tr>
    <tr>
      <th>2</th>
      <td>nine</td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
  </tbody>
</table>

code_output_with_spanning_along_a_row

Answered By: CypherX

Use tabulate

from tabulate import tabulate

table = [['one','two','three'],['four','five','six'],['seven','eight','nine']]

print(tabulate(table, tablefmt='html'))

Which produces the following output.

<table>
<tbody>
<tr><td>one  </td><td>two  </td><td>three</td></tr>
<tr><td>four </td><td>five </td><td>six  </td></tr>
<tr><td>seven</td><td>eight</td><td>nine </td></tr>
</tbody>
</table>
Answered By: Tomasz

another choice is prettytable:

from prettytable import PrettyTable
pt = PrettyTable()

if you want to generate html format:

print(pt.get_html_string())

if only generate ascii format table:

print(pt.get_string())

pls refer to the official document: https://ptable.readthedocs.io/en/latest/tutorial.html for more option, eg enable different kinds of style.

enjoy.

Answered By: Han.Oliver