Displaying tabulated data

This page contains several examples how to use the classes in finesse.utilities.tables

The first class is Table. It is intended for already readable data, that means strings or objects with a useful __str__ method.

import numpy as np
import finesse
from finesse.utilities.tables import Table, NumberTable

data = [['a', 'b', 'c'],
        [1,2,3],
        [4,5,6]
       ]
tab = Table(data)

The table can be displayed with pretty printing or as html. The print method will prefer html display if thwat is supported and fall back to a sring representation if not. Calling the built-in print function always uses the string version.

tab.print()
abc
123
456
print(tab)
┌───┬───┬───┐
│ a │ b │ c │
╞═══╪═══╪═══╡
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
└───┴───┴───┘

By default the first row is considered a header. This can also be enabled for the first column or disabled.

print(Table(data, headerrow=True, headercolumn=True))
┌───╥───┬───┐
│ a ║ b │ c │
╞═══╬═══╪═══╡
│ 1 ║ 2 │ 3 │
├───╫───┼───┤
│ 4 ║ 5 │ 6 │
└───╨───┴───┘

print(Table(data, headerrow=False, headercolumn=True))
┌───╥───┬───┐
│ a ║ b │ c │
├───╫───┼───┤
│ 1 ║ 2 │ 3 │
├───╫───┼───┤
│ 4 ║ 5 │ 6 │
└───╨───┴───┘

print(Table(data, headerrow=False, headercolumn=True))
┌───╥───┬───┐
│ a ║ b │ c │
├───╫───┼───┤
│ 1 ║ 2 │ 3 │
├───╫───┼───┤
│ 4 ║ 5 │ 6 │
└───╨───┴───┘

The textcolor, backgroundcolor and the text alignment can be changed. They can be specified in four different ways:

  1. A single value that will be applied to all cells

  2. One value per row in a nested list

  3. One value per column in a nested list

  4. A value for every cell in an array with the same dimensions as the data

The colors must be defined as RGB values, possible alignments are “left”, “right” and “center”.

red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)

Table(data, color=red)
abc
123
456
Table(data,
color=[
    [red],
    [green],
    [blue]
])
abc
123
456
Table(data,
    color=[
        [red, green, blue]
    ])
abc
123
456
Table(data,
color=[
    [red, green, blue],
    [blue, green, red],
    [green, red, blue]
])
abc
123
456
Table(data, backgroundcolor=green)
abc
123
456

If any number of the RGB triple is smaller than zero, it is treated as if no color was given.

Table(data,
color=[
    [blue, (-1,0,0), red]
])
abc
123
456
tab=Table([['abc','def','ghi'],['x','y','z']], alignment=[['left','right','center']])
print(tab)
tab.print()
┌─────┬─────┬─────┐
│ abc │ def │ ghi │
╞═════╪═════╪═════╡
│ x   │   y │  z  │
└─────┴─────┴─────┘

abcdefghi
xyz

It is also possible to generate latex code for the table.

print(tab.latex())
\begin{table}
\begin{tabular}{|l|r|c|}
\hline
abc & def & ghi\\
\hline
x & y & z\\
\hline
\end{tabular}
\end{table}

If the table cells have colored text, the xcolor package must be used in the latex file, the backgroundcolor is not used.

For handling different alignments in a column the multicolumn command is used.

tab = Table(
        [
            ['abc','def','ghi'],
            ['x','y','z']
        ],
        color=[
            [red, green, blue],
            [blue, green, red]
            ],
        alignment=[
            ['left','right','center'],
            ['right', 'left', 'center']
        ]
)
print(tab.latex())
\begin{table}
\definecolor{color000000255}{RGB}{000, 000, 255}
\definecolor{color000255000}{RGB}{000, 255, 000}
\definecolor{color255000000}{RGB}{255, 000, 000}
\begin{tabular}{|l|r|c|}
\hline
\textcolor{color255000000}{abc} & \textcolor{color000255000}{def} & \textcolor{color000000255}{ghi}\\
\hline
\multicolumn{1}{|r|}{\textcolor{color000000255}{x}} & \multicolumn{1}{|l|}{\textcolor{color000255000}{y}} & \textcolor{color255000000}{z}\\
\hline
\end{tabular}
\end{table}

You can also save the data of the table as a csv file using the syntax of the csv package. The file will not contain any formatting or color information. The function returns the used csv writer, so you can write further data to the file.

import sys
tab.write_csv(sys.stdout)
abc,def,ghi
x,y,z
<_csv.writer at 0x7f5c12b0af20>

If you want to process some other data as a table or change how something is shown, you can create a new class inheriting from Table and overload the necessary methods. One such class already exists: NumberTable. It displays data only containing numbers with string headers.

data = np.random.random((2,3))
NumberTable(data)
0.21744587489523870.134943543013858580.8513928282944735
0.51866428341080460.0198171476626884950.016991514135458186
NumberTable(data, colnames=['a','b','c'])
abc
0.21744587489523870.134943543013858580.8513928282944735
0.51866428341080460.0198171476626884950.016991514135458186
NumberTable(data, rownames=['x','y'])
x0.21744587489523870.134943543013858580.8513928282944735
y0.51866428341080460.0198171476626884950.016991514135458186
NumberTable(data, rownames=['x','y'], colnames=['a','b','c'])
abc
x0.21744587489523870.134943543013858580.8513928282944735
y0.51866428341080460.0198171476626884950.016991514135458186

You can format the numbers in several wayswith a python formatting string or a function that transforms numbers to strings. These can be given for every cell at once, column- or row-wise or for every cell individually.

print(
    NumberTable(
        data,
        numfmt='{:.5g}'
    )
)
┌─────────┬──────────┬──────────┐
│ 0.21745 │  0.13494 │  0.85139 │
├─────────┼──────────┼──────────┤
│ 0.51866 │ 0.019817 │ 0.016992 │
└─────────┴──────────┴──────────┘

print(
    NumberTable(
        data,
        numfmt=lambda x: round(x,2)
    )
)
┌──────┬──────┬──────┐
│ 0.22 │ 0.13 │ 0.85 │
├──────┼──────┼──────┤
│ 0.52 │ 0.02 │ 0.02 │
└──────┴──────┴──────┘

print(
    NumberTable(
        data,
        numfmt=[
            ['{:.5g}','{:.2g}','{:.1g}']
        ]
    )
)
┌─────────┬──────┬──────┐
│ 0.21745 │ 0.13 │  0.9 │
├─────────┼──────┼──────┤
│ 0.51866 │ 0.02 │ 0.02 │
└─────────┴──────┴──────┘

print(
    NumberTable(
        data,
        numfmt=[
            ['{:.5g}'],
            ['{:.2g}']
        ]
    )
)
┌─────────┬─────────┬─────────┐
│ 0.21745 │ 0.13494 │ 0.85139 │
├─────────┼─────────┼─────────┤
│    0.52 │    0.02 │   0.017 │
└─────────┴─────────┴─────────┘

print(
    NumberTable(
        data,
        numfmt=[
            ['{:.5g}','{:.2g}','{:.1g}'],
            ['{:.1e}',lambda x: round(x,2), lambda x: str(x**2)]
        ]
    )
)
┌─────────┬──────┬────────────────────────┐
│ 0.21745 │ 0.13 │                    0.9 │
├─────────┼──────┼────────────────────────┤
│ 5.2e-01 │ 0.02 │ 0.00028871155261547533 │
└─────────┴──────┴────────────────────────┘

You can also color the numbers and their background by applying a function to the data array. It has to have the structure of a matplotlib colormap.

import matplotlib as mpl
cmap1 = mpl.cm.get_cmap('viridis')
cmap2 = mpl.cm.get_cmap('Greys')
tab = NumberTable(
    data,
    rownames=['x','y'],
    colnames=['a','b','c'],
    numfmt='{:.5g}',
    colfunc = cmap1,
    bgcolfunc = cmap2
)
tab.print()
abc
x0.217450.134940.85139
y0.518660.0198170.016992

As the colormaps expect values between 0 and 1, you can provide a normalization function.

NumberTable(
    [[200,500,-300]],
    colfunc=cmap1,
    norm=mpl.colors.Normalize(vmin=-300, vmax=500))
200500-300

As NumberTable is a child class of Table, it has the same display functions.

print(tab.latex())
\begin{table}
\definecolor{color031148140}{RGB}{031, 148, 140}
\definecolor{color046046046}{RGB}{046, 046, 046}
\definecolor{color063072137}{RGB}{063, 072, 137}
\definecolor{color070007090}{RGB}{070, 007, 090}
\definecolor{color070008092}{RGB}{070, 008, 092}
\definecolor{color071047125}{RGB}{071, 047, 125}
\definecolor{color145145145}{RGB}{145, 145, 145}
\definecolor{color155217060}{RGB}{155, 217, 060}
\definecolor{color223223223}{RGB}{223, 223, 223}
\definecolor{color238238238}{RGB}{238, 238, 238}
\definecolor{color253253253}{RGB}{253, 253, 253}
\begin{tabular}{|c|c|c|c|}
\hline
 & a & b & c\\
\hline
x & \multicolumn{1}{|r|}{\textcolor{color063072137}{0.21745}} & \multicolumn{1}{|r|}{\textcolor{color071047125}{0.13494}} & \multicolumn{1}{|r|}{\textcolor{color155217060}{0.85139}}\\
\hline
y & \multicolumn{1}{|r|}{\textcolor{color031148140}{0.51866}} & \multicolumn{1}{|r|}{\textcolor{color070008092}{0.019817}} & \multicolumn{1}{|r|}{\textcolor{color070007090}{0.016992}}\\
\hline
\end{tabular}
\end{table}
tab.write_csv(sys.stdout);
,a,b,c
x,0.21745,0.13494,0.85139
y,0.51866,0.019817,0.016992

These classes are used in finesse by several functions to display information. For example the distances matrix of a model can be shown in table format. The function supports keyword arguments for NumberTable to customize the table.

model = finesse.Model()
model.parse("""
### L0 -> BS -> YARM of ET-LF
# input
l L0 P=1
s l0 L0.p1 BS.p1 L=10

# Main beam splitter
bs BS T=0.5 L=37.5u alpha=60
s BSsub1 BS.p3 BSAR1.p1 L=0.07478 nr=&nsilica
s BSsub2 BS.p4 BSAR2.p1 L=0.07478 nr=&nsilica
bs BSAR1 R=50u L=0 alpha=-36.6847
bs BSAR2 R=50u L=0 alpha=36.6847

# Y arm telescope
s lBS_ZM1 BS.p2 ZM1.p1 L=70
bs ZM1 T=250u L=37.5u Rc=-50
s lZM1_ZM2 ZM1.p2 ZM2.p1 L=50
bs ZM2 T=0 L=37.5u Rc=-82.5
s lZM2_ITMlens ZM2.p2 ITM_lens.p1 L=52.5

lens ITM_lens 75
s lITM_th2 ITM_lens.p2 ITMAR.p1 L=0

# Y arm input mirror
m ITMAR R=0 L=20u
s ITMsub ITMAR.p2 ITM.p1 L=0.2 nr=&nsilicon
m ITM T=7000u L=37.5u Rc=-5580

# Y arm length
s l_arm ITM.p2 ETM.p1 L=10k

# Y arm end mirror
m ETM T=6u L=37.5u Rc=5580
s ETMsub ETM.p2 ETMAR.p1 L=0.2 nr=&nsilicon
m ETMAR R=0 L=500u

# SRM
s lBS_SRM BSAR2.p3 SRM.p1 L=10

m SRM T=0.2 L=0 Rc=-9410
s SRMsub SRM.p2 SRMAR.p1 L=0.0749 nr=&nsilicon
m SRMAR R=0 L=50n

# cavities
cav cavARM ITM.p2
cav cavSRC SRM.p1 ITM.p1.i

var nsilica 1.44963098985906
var nsilicon 3.42009

lambda(1550n)
""")

ps = model.propagate_beam(model.ITM.p1.o, model.SRM.p1.i)

import matplotlib as mpl
cmap = mpl.cm.get_cmap('viridis')
norm = mpl.colors.Normalize(vmin=-200, vmax=200)

tab = ps.distances_matrix_table(
    colfunc = cmap,
    norm = norm
    )
tab.print()
ITMITMARITM_lensZM2ZM1BSBSAR2SRM
ITM0 m200 mm200 mm52.7 m102.7 m172.7 m172.77 m182.77 m
ITMAR-200 mm0 m0 m52.5 m102.5 m172.5 m172.57 m182.57 m
ITM_lens-200 mm0 m0 m52.5 m102.5 m172.5 m172.57 m182.57 m
ZM2-52.7 m-52.5 m-52.5 m0 m50 m120 m120.07 m130.07 m
ZM1-102.7 m-102.5 m-102.5 m-50 m0 m70 m70.075 m80.075 m
BS-172.7 m-172.5 m-172.5 m-120 m-70 m0 m74.78 mm10.075 m
BSAR2-172.77 m-172.57 m-172.57 m-120.07 m-70.075 m-74.78 mm0 m10 m
SRM-182.77 m-182.57 m-182.57 m-130.07 m-80.075 m-10.075 m-10 m0 m