In [1]:
import pytabular as pytab
import numpy as np
Next, we will create some data. The data will be a list of rows, which are themselves lists. We could also have made these an array or dataframe. Each element in the row will be a cell in the table.
In [2]:
header = [['', 'Treated', '', 'Control', ''],
['Measure', 'Male', 'Female', 'Male', 'Female']]
measures = ['var{}'.format(i) for i in xrange(10)]
data = np.random.randn(10,4).tolist()
data = [[measures[i]] + data[i] for i in xrange(10)]
data = header + data
for row in data:
print(row)
Creating a PyTabular object from this data is easy. From there, we can manipulate the table to customize the layout and look of the cells.
In [3]:
tabular = pytab.Tabular(data)
print('Shape:', tabular.shape)
print(tabular)
Operate on the table using methods. Methods will either operate on the whole table or on the specific selection you make from the table. Make a selection using Python's slice syntax. Some examples include:
Select the cell in the upper-left:
tabular[0,0]
Select the 2nd row:
tabular[1]
Select the 1st column:
tabular[:,0]
Select cells in the first row, the 2nd column to the last:
tabular[:,1:]
Select cells in the 3rd column, from the 2nd to the 4th row:
tabular[1:4,2]
Built-in methods either operate by-cell or to the table. Table methods, like set_tab_alignment
operate on the whole table and should not be used on a selection. Other methods, like set_bold
and merge
operate on selections of the table. set_bold
does the same thing to each cell in the selection. However, merge
is a special function which we will explore next.
In [4]:
tabular[0,1:3].merge() #merges cells in row 0, columns 1 and 2
tabular[0,3:].merge() #merges cells in row 0, columns 3 and 4
print(tabular)
Now let's add some horizontal lines with set_lines
option. set_lines(lines, narrow)
takes two parameters:
lines: number of lines to place below
narrow: a string to tell cmidrule whether or not to shorten the line on either side of the cell, use 'r' to shorten on the right, 'l' for left and 'lr' on both
When using set_lines
on merged cells, will produce a horizontal line extending across all of the cells merged together.
In [5]:
tabular[0,1:3].set_lines(lines=1, narrow='lr')
tabular[0,3:].set_lines(lines=2, narrow='lr')
print(tabular)
And we will add a horizontal line below the 2nd row.
In [6]:
tabular[1].set_lines(2)
print(tabular)
As-is, the data in the cells is shown with too many significant digits and it is overwhelming. While we allow the user to pass in any formatter (a function which takes a cell value and returns a formatted value as a string), we provide some built-in formatters:
set_digits
sets the number of significant digits displayed in cells
In [7]:
tabular[2:,1:].set_digits(3)
print(tabular)
In [8]:
# obs = a column of data we forgot about
obs = np.array(['', 'Observations'] + np.random.randint(500, 100000, 10).tolist()).reshape((-1,1))
add = pytab.Tabular(obs)
print(add.shape)
print(tabular.shape)
We will use hstack
to stack additional columns to the right of our previous table. NOTE: Use vstack
to tack on an additional row.
In [9]:
newtabular = pytab.hstack(tabular, add)
print(newtabular)
Notice that all of the formatting we have just done has gone away. The cells have reverted to their default values so as to not cause any conflicts with data in the cells. Its a good idea then to add tables before you do formatting. We can repeat all of the previous steps.
In [10]:
newtabular[0,1:3].merge() #merges cells in row 0, columns 1 and 2
newtabular[0,3:-1].merge() #merges cells in row 0, columns 3 and 4
newtabular[0,1:3].set_lines(lines=1, narrow='lr')
newtabular[0,3:-1].set_lines(lines=2, narrow='lr')
newtabular[1].set_lines(2)
newtabular[2:,1:-1].set_digits(3)
print(newtabular)
But notice that the right-most column contains very large integers. Included in PyTabular is a formatter for integers. Let's try it out! Remember you can define your own custom formatters use the set_formatter
as well.
In [11]:
newtabular[2:,-1].set_formatter(pytab.format_int)
print(newtabular)
PyTabular contains many methods for customizing the look of your tables. Using a method on a table selection will apply that method to all of the cells in the selection.
set_bold
set_emph
set_fontsize
set_color
In [12]:
newtabular[0].set_bold() #bolds all cells in first row
newtabular[1].set_emph() #italicizes cell in 2nd row
newtabular[0].set_fontsize('Large') #Huge fontsize for cells in first row
newtabular[2:,1:].set_alignment('r') #right align the cells containing numbers
newtabular[2:,0].set_alignment('l|') #left align and add vertical line to right
newtabular[5].set_color(color='gray',opacity=40) #highlight the cells in the 6th row
newtabular[1].set_rotation(45) #rotate the content in row 2 45 degrees
newtabular[1].set_space_below('0.3cm') #puts space below the 2nd row
newtabular[2].set_space_above('0.3cm') #puts space above the 3nd row
print(newtabular)
In [13]:
# Set the spacing between columns by specifying a custom tabular string
# i.e. the string "cccccc" in "\being{tabular}{cccccc}"
newtabular.set_tab_alignment('cp{2cm}p{2cm}p{2cm}p{2cm}p{2cm}')
print(newtabular)
Casting as other table types will nest the tabular environment inside a table environment, or, in the case of Longtables, change from the tabu environment to the longtabu environment.
In both cases, additional table methods become available. These include set_caption
, set_label
,
and set_location
.
Table Environments:
table
environment)LongTable (LateX longtabu
environment)
The LongTable
class allows the table to overflow on multiple pages.
It has an method set_repeats
where the user can specify which rows
to repeat on every page.
In [14]:
table = pytab.Table(newtabular)
In [15]:
print(table)
In [16]:
longtable = pytab.LongTable(newtabular)
print(longtable)
set_caption
: give table a captionset_label
: give table a labelset_location
: justify the table center='c', left='l' or right='r'add_note
: add a footnote to the tableLongTable Only:
set_repeats
: tell LateX how many rows to repeat at the top of each page;
this usually is the number of header rows in your table
In [17]:
table.set_caption('A Table with Numbers')
table.set_label('tab:table1')
table.set_location('l')
table.add_note('This is a footnote')
table.add_note('This is another footnote')
table.add_note('[1]This footnote has a superscript')
print(table)
In [18]:
longtable.set_repeats(2)
longtable.add_note('Footnote for a long table.')
print(longtable)
In [19]:
longtable.add_environment('landscape')
print(longtable)
In [20]:
longtable.set_indent(0)
print(longtable)
In [21]:
longtable.set_indent(4)
print(longtable)
In [22]:
table[-2,0].set_content('$R^2$') #changing the content cell in the 2nd to last row, first column
table[-2:,0].merge(force=True) #merging over contents (must specify force=True)
table[-2:,1:].merge(force=True) #merging the data together (across rows and columns)
table[-2,1].set_alignment('c')
print(table)
You may have noticed the special character warnings above. PyTabular is not smart, and if you use special characters (e.g. '&', '%', '#', '_', '{', '}', '$', '\', '~', '^') in a cell it will not fix the cell if you have used special characters inappropriately. However, it will warn you when it spots these characters and you can remove these characters using the remove_character
method. Otherwise, we trust you know LateX well enough to use these special characters correctly.