import pandas as pd
import toyplot
# Read in Data
= pd.read_csv("../data/gapminder.csv") # Read in the Data gapminder
Chapter 5a - Presenting tables in toyplot
1 Chapter 5a – Presenting Tables in Python (using Toyplot)
Follow along with the code by running cells as you encounter them
Chapter Overview
Styling
8.1. Colouring Alternative Rows
8.2. Adding additional header rows
8.3. Highlighting Minimum and Maximum Rows
8.4. Inserting Whitespace between Groups
Previous versions of this course had tables in Matplotlib as the main content of this chapter. From March 2021 the main content of this chapter will use the package toyplot
. This is not included as part of Anaconda and so must be installed separately.
Content for creating tables in Matplotlib has been moved to Chapter 5b. This is included as some users are unable to install additional packages. Creation of tables in Matplotlib is generally more involved and a fiddly process compared to toyplot
.
toyplot
can also be used to create a variety of other visualisations. It is described as a “kid sized” plotting tool, however as tools like Matplotlib and Seaborn have more support for non-table visualisation we only cover the tables aspect of this package.
Package documentation can be found here – toyplot documentation
Toyplot is the closest package the authors have found to encompassing all of the elements of the ONS and GSS Style Guide. However please note that there may still be elements that are not perfect matches.
2 1. Packages and Data
An alternative to tables in Matplotlib is using the package toyplot
. This is not included as part of Anaconda and so must be installed seperatly.
Let’s start, as always by loading our packages and our data.
This chapter was written using:
- pandas version 1.1.5
- toyplot 0.19.0
Remember you can use the .__version__ attribute (e.g np.__version__ ) to check your version.
More information about the packages is given in Chapter 1.
We’re following standard convention for nicknames, and we’ll also load the gapminder data.
We’re going to use the gapminder data and we’re going to prepare it before we start.
As with other visualisations data preparation is a really important step.
We need to have our data mostly formatted before we visualise it.
Here I’m manipulating my data so that I have the population data for 3 years (1997, 2002 and 2007) for the first five countries in each continent – apart from Oceania, which only comprises of 2 countries in our dataset.
= (gapminder[gapminder["year"].isin([1997, 2002, 2007])] # Filter for the years
select_countries_3y_pop filter(["country", "continent", "year", "pop"]) # .filter *selects* columns
."pop": "int64"}) # Supresses the Scientific Notation of the year columns
.astype({= ["continent","country"],
.pivot_table(index = "year", values = "pop") # Make the data "wider" so each year is a col
columns # Reset our index; so we don't have a multi index
.reset_index() "continent").head()) # Group by the continent and return the first 5 rows for each continent.
.groupby(
= None #Removed the "year" label on the index
select_countries_3y_pop.columns.name
# View the new DataFrame
select_countries_3y_pop
continent | country | 1997 | 2002 | 2007 | |
---|---|---|---|---|---|
0 | Africa | Algeria | 2.907202e+07 | 3.128714e+07 | 3.333322e+07 |
1 | Africa | Angola | 9.875024e+06 | 1.086611e+07 | 1.242048e+07 |
2 | Africa | Benin | 6.066080e+06 | 7.026113e+06 | 8.078314e+06 |
3 | Africa | Botswana | 1.536536e+06 | 1.630347e+06 | 1.639131e+06 |
4 | Africa | Burkina Faso | 1.035284e+07 | 1.225121e+07 | 1.432620e+07 |
52 | Americas | Argentina | 3.620346e+07 | 3.833112e+07 | 4.030193e+07 |
53 | Americas | Bolivia | 7.693188e+06 | 8.445134e+06 | 9.119152e+06 |
54 | Americas | Brazil | 1.685467e+08 | 1.799142e+08 | 1.900106e+08 |
55 | Americas | Canada | 3.030584e+07 | 3.190227e+07 | 3.339014e+07 |
56 | Americas | Chile | 1.459993e+07 | 1.549705e+07 | 1.628474e+07 |
77 | Asia | Afghanistan | 2.222742e+07 | 2.526840e+07 | 3.188992e+07 |
78 | Asia | Bahrain | 5.985610e+05 | 6.563970e+05 | 7.085730e+05 |
79 | Asia | Bangladesh | 1.233153e+08 | 1.356568e+08 | 1.504483e+08 |
80 | Asia | Cambodia | 1.178296e+07 | 1.292671e+07 | 1.413186e+07 |
81 | Asia | China | 1.230075e+09 | 1.280400e+09 | 1.318683e+09 |
110 | Europe | Albania | 3.428038e+06 | 3.508512e+06 | 3.600523e+06 |
111 | Europe | Austria | 8.069876e+06 | 8.148312e+06 | 8.199783e+06 |
112 | Europe | Belgium | 1.019979e+07 | 1.031197e+07 | 1.039223e+07 |
113 | Europe | Bosnia and Herzegovina | 3.607000e+06 | 4.165416e+06 | 4.552198e+06 |
114 | Europe | Bulgaria | 8.066057e+06 | 7.661799e+06 | 7.322858e+06 |
140 | Oceania | Australia | 1.856524e+07 | 1.954679e+07 | 2.043418e+07 |
141 | Oceania | New Zealand | 3.676187e+06 | 3.908037e+06 | 4.115771e+06 |
3 2. Creating a Basic Table
Firstly in Toyplot we create the canvas for our table to sit on. This is similar to create the fig and axes in matplotlib.
The measurements are in pixels, and are entered as width, height. We have used parameter names here - most of the documentation for toyplot does not use them.
Here I have added the parameter style = {"background-color":"gray"}
to demonstrate the area.
= toyplot.Canvas(width=700, height=500, style = {"background-color":"gray" }) canvas
Adding a table to the canvas is simple. canvas.table()
takes an argument for data
which among other things will take a Pandas Data Frame.
# Create the Canvas
= toyplot.Canvas(width=700, height=500)
canvas
# Add the Data
= canvas.table(data = select_countries_3y_pop) table
4 3. Customising Fonts
The table is broken down into several parts. These are table.cells
which acts on all cells, and table.body
which excludes header rows. Within those we can access columns and rows, e.g table.cells.row
and table.cell.column
.
These can then be indexed to make behaviours act on certain instances.
We can set “styles” for text in rows using .lstyle
(L probably standing for letters) This takes a dictionary of a select few CSS methods. Methods of dealing with text can be found in the documentation.
Here we’ve used some of the useful parameters; note that ”fill”
corresponds to text colour.
I’ve set the main text separately to the header rows. Here I’ve used the slicing technique [1:] to select from index 1 through to the end rather than hard coding for the number of rows.
# Create the Canvas
= toyplot.Canvas(width=700, height=500)
canvas
# Add the Data
= canvas.table(data = select_countries_3y_pop)
table
# Header Row Style
0].lstyle = {"font-size":"14px", "font-family":"sans-serif", "font-weight": "bold", "fill": "black"}
table.cells.row[
# Style table text
1:].lstyle = {"font-size":"12px", "font-family":"sans-serif", "fill": "black"} table.cells.row[
5 4. Aligning Columns
By default columns are aligned based on their data type. Numerical data is aligned right, and text based data is aligned in the centre.
I’d like Continent and Country to be aligned left. To do this within the table.cells.columns
I index columns 0 and 1 and set the alignment to be left.
# Create the Canvas
= toyplot.Canvas(width=700, height=500)
canvas
# Add the Data
= canvas.table(data = select_countries_3y_pop)
table
# Header Row Style
0].lstyle = {"font-size":"14px", "font-family":"sans-serif", "font-weight": "bold", "fill": "black"}
table.cells.row[
# Style table text
1:].lstyle = {"font-size":"12px", "font-family":"sans-serif", "fill": "black"}
table.cells.row[
# Set alignment for Continent and Country
0, 1]].align = "left" # [[0,1]] only affects the first 2 columns. table.cells.column[[
6 5. Adjusting column widths and height
We can also do things like manually adjust the width of columns and the height of them as well.
Toyplot naturally attempts to fit the plot or table to the canvas; which gives a nice effect but may need fine tuning.
This looks to have made no difference here - but if we didn’t include it our future gridlines would be in the wrong place.
# Create the Canvas
= toyplot.Canvas(width=700, height=500)
canvas
# Add the Data
= canvas.table(data = select_countries_3y_pop)
table
# Header Row Style
0].lstyle = {"font-size":"14px", "font-family":"sans-serif", "font-weight": "bold", "fill": "black"}
table.cells.row[
# Style table text
1:].lstyle = {"font-size":"12px", "font-family":"sans-serif", "fill": "black"}
table.cells.row[
# Set alignment for Continent and Country
0, 1]].align = "left" # [[0,1]] only affects the first 2 columns.
table.cells.column[[
# Set width for Country Column
1]].width = 150
table.cells.column[[
# Make the header row taller
0]].height = 20 table.cells.row[[
7 6. Setting Grid Lines
We can set up gridlines using table.cells.grid
and then vlines
for vertical lines or hlines
for horizontal lines.
Within the square brackets we specify which rows we want these to apply to. This is given as a list of
[ROW, COLUMNS]
…
is used to represent ALL rows or columns, and a subset of rows or columns can be passed as a list.
In the visualisation I did not want a vertical line at the start or end of my chart – so I passed
[…, [1,2,3,4]]
to have the lines go down ALL rows, but only appear on columns 1:4. Slicing does not work in this instance so they are written out.
# Create the Canvas
= toyplot.Canvas(width=700, height=500)
canvas
# Add the Data
= canvas.table(data = select_countries_3y_pop)
table
# Set alignment for Continent and Country
0, 1]].align = "left" # [[0,1]] only affects the first 2 columns.
table.cells.column[[
# Set width for Country Column
1]].width = 150
table.cells.column[[
# Header Row Style
0].lstyle = {"font-size":"14px", "font-family":"sans-serif", "font-weight": "bold", "fill": "black"}
table.cells.row[
# Style table text
1:].lstyle = {"font-size":"12px", "font-family":"sans-serif", "fill": "black"}
table.cells.row[
# Set up the gridlines
1,2,3,4]]= "single" # ALL rows, columns 1 to 4
table.cells.grid.vlines[..., [1,...] = "single" # ROW 1 , ALL columns
table.cells.grid.hlines[= { "stroke-width": "1", "stroke": "grey"} table.cells.grid.style
8 7. Setting Titles, Subtitles and Captions
While titles can be set directly from the canvas.table
there is more control if these are set as canvas.text()
methods.
These take an x and y argument to specify the location.
The style =
argument takes some basic CSS to define its behaviour. In addition to the ones we’ve talked about before a useful argument is:
text-anchor
- by default this is the middle of the text entered, but can be changed to “start” or “end” to give more control.
The text =
parameter will also allow HTML linking. It is advised to ensure the <a target = “_blank”>
is included to open in a new window rather than your existing Jupyter Notebook.
As the symbols < , > and & are used in XHTML 5 these should be replaced with the codes <
for < , >
for > and &
for & if you wish to use them.
# Create the Canvas
= toyplot.Canvas(width=700, height=500)
canvas
# Add the Data
= canvas.table(data = select_countries_3y_pop)
table
# Set alignment for Continent and Country
0, 1]].align = "left" # [[0,1]] only affects the first 2 columns.
table.cells.column[[
# Set width for Country Column
1]].width = 150
table.cells.column[[
# Header Row Style
0].lstyle = {"font-size":"14px", "font-family":"sans-serif", "font-weight": "bold", "fill": "black"}
table.cells.row[
# Style table text
1:].lstyle = {"font-size":"12px", "font-family":"sans-serif", "fill": "black"}
table.cells.row[
# Set up the gridlines
1,2,3,4]]= "single" # ALL rows, columns 1 to 4
table.cells.grid.vlines[..., [1,...] = "single" # ROW 1 , ALL columns
table.cells.grid.hlines[= { "stroke-width": "1", "stroke": "grey"}
table.cells.grid.style
# Title
= 45, y= 20,
canvas.text(x = "Table 1: Population of select countries over three years",
text = {"font-size":"16px", "font-weight":"bold", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style# Subtitle
= 45, y= 35,
canvas.text(x = "Population for 1997, 2002 and 2007",
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style#Caption
= 510, y= 465,
canvas.text(x = ("<a target='_blank' href='https://www.gapminder.org/'>Source: Gapminder.org</a>"), # A link opens in a new window!
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"}); style
9 8. Styling
9.1 8.1 Colouring Alternative Rows
Colouring alternative rows can be done using table.body.row[].style
.
Here a list comprehension is used to identify the even numbered rows and colours them. Note this is working on the “body” rows – so Africa, Algeria is row 0, which is even and why it is coloured.
# Create the Canvas
= toyplot.Canvas(width=700, height=500)
canvas
# Add the Data
= canvas.table(data = select_countries_3y_pop)
table
# Set alignment for Continent and Country
0, 1]].align = "left" # [[0,1]] only affects the first 2 columns.
table.cells.column[[
# Set width for Country Column
1]].width = 150
table.cells.column[[
# Header Row Style
0].lstyle = {"font-size":"14px", "font-family":"sans-serif", "font-weight": "bold", "fill": "black"}
table.cells.row[
# Style table text
1:].lstyle = {"font-size":"12px", "font-family":"sans-serif", "fill": "black"}
table.cells.row[
# Set up the gridlines
1,2,3,4]]= "single" # ALL rows, columns 1 to 4
table.cells.grid.vlines[..., [1,...] = "single" # ROW 1 , ALL columns
table.cells.grid.hlines[= { "stroke-width": "1", "stroke": "grey"}
table.cells.grid.style
# Title
= 45, y= 20,
canvas.text(x = "Table 1: Population of select countries over three years",
text = {"font-size":"16px", "font-weight":"bold", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style# Subtitle
= 45, y= 35,
canvas.text(x = "Population for 1997, 2002 and 2007",
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style#Caption
= 510, y= 465,
canvas.text(x = ("<a target='_blank' href='https://www.gapminder.org/'>Source: Gapminder.org</a>"), # A link opens in a new window!
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style
# Colour even Rows
= [(each_row % 2 == 0) for each_row in range(len(select_countries_3y_pop))] # This uses list comprehension to highlight odd numbered rows.
rows_to_colour
= {"fill":"#F2F2F2"}; table.body.row[rows_to_colour].style
9.2 8.2 Adding additional header rows
Adding in additional header rows is as simple as passing trows =
in to the canvas.table()
method. Setting this to 2 gives us 2 top rows.
Actions like merging the cells; adding text in to them and formatting can then be done; as seen below.
# Create the Canvas
= toyplot.Canvas(width=700, height=500)
canvas
# Add the Data
= canvas.table(data = select_countries_3y_pop, trows = 2)
table
# Set alignment for Continent and Country
0, 1]].align = "left" # [[0,1]] only affects the first 2 columns.
table.cells.column[[
# Add the text in to the top row and format
= table.top.cell[0, 2:5].merge()
merged = "Year"
merged.data = "center"
merged.align
= table.top.cell[0, 0:2].merge()
merged2 = "Location"
merged2.data = "center"
merged2.align
# Set width for Country Column
1]].width = 150
table.cells.column[[
# Header Row Style
0].lstyle = {"font-size":"14px", "font-family":"sans-serif", "font-weight": "bold", "fill": "black"}
table.cells.row[
# Style table text
1:].lstyle = {"font-size":"12px", "font-family":"sans-serif", "fill": "black"}
table.cells.row[
# Set up the gridlines
1,2,3,4]]= "single" # ALL rows, columns 1 to 4
table.cells.grid.vlines[..., [1,...] = "single" # ROW 1 , ALL columns
table.cells.grid.hlines[= { "stroke-width": "1", "stroke": "grey"}
table.cells.grid.style
# Title
= 45, y= 20,
canvas.text(x = "Table 1: Population of select countries over three years",
text = {"font-size":"16px", "font-weight":"bold", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style# Subtitle
= 45, y= 35,
canvas.text(x = "Population for 1997, 2002 and 2007",
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style#Caption
= 510, y= 465,
canvas.text(x = ("<a target='_blank' href='https://www.gapminder.org/'>Source: Gapminder.org</a>"), # A link opens in a new window!
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style
# Colour even Rows
= [(each_row % 2 == 0) for each_row in range(len(select_countries_3y_pop))] # This uses list comprehension to highlight odd numbered rows.
rows_to_colour
= {"fill":"#F2F2F2"}; table.body.row[rows_to_colour].style
9.3 8.3 Highlighting Minimum and Maximum Rows
We can also highlight minimum and maximum rows.
I’ve created a new data set just for 1997 to show this. It’s also really important to reset the index; we’ve not needed to do this so far but toyplot creates its own index and the two need to match up.
The low and high index are found using a filter and returning the index value. There may be more efficient ways to find this value, but the row value is then passed to the row indexer, and an lstyle applied to colour the text or a style applied to colour the rows. Here one of each has been done for demonstration purposes.
= select_countries_3y_pop[["continent", "country", 1997]]
select_97 =True, drop = True) select_97.reset_index(inplace
# Create the Canvas
= toyplot.Canvas(width=700, height=500)
canvas
# Add the Data
= canvas.table(data = select_97)
table
# Set alignment for Continent and Country
0, 1]].align = "left" # [[0,1]] only affects the first 2 columns.
table.cells.column[[
# Set width for Country Column
1]].width = 150
table.cells.column[[
# Header Row Style
0].lstyle = {"font-size":"14px", "font-family":"sans-serif", "font-weight": "bold", "fill": "black"}
table.cells.row[
# Style table text
1:].lstyle = {"font-size":"12px", "font-family":"sans-serif", "fill": "black"}
table.cells.row[
# Set up the gridlines
1,2,3]]= "single" # ALL rows, columns 1 to 4
table.cells.grid.vlines[..., [1,...] = "single" # ROW 1 , ALL columns
table.cells.grid.hlines[= { "stroke-width": "1", "stroke": "grey"}
table.cells.grid.style
# Title
= 45, y= 20,
canvas.text(x = "Table 1: Population of select countries over three years",
text = {"font-size":"16px", "font-weight":"bold", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style# Subtitle
= 45, y= 35,
canvas.text(x = "Population for 1997, 2002 and 2007",
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style#Caption
= 510, y= 465,
canvas.text(x = ("<a target='_blank' href='https://www.gapminder.org/'>Source: Gapminder.org</a>"), # A link opens in a new window!
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style
# Colour even Rows
= [(each_row % 2 == 0) for each_row in range(len(select_97))] # This uses list comprehension to highlight odd numbered rows.
rows_to_colour
= {"fill":"#F2F2F2"}
table.body.row[rows_to_colour].style
# Find the lowest and highest rows
= select_97[select_97[1997] == select_97[1997].min()].index.values
low_index = select_97[select_97[1997] == select_97[1997].max()].index.values
high_index
# Colour high and low
= { "fill":"blue", "opacity": "0.5"}
table.body.row[low_index].style = {"font-weight":"bold", "fill":"red"} table.body.row[high_index].lstyle
9.4 8.4 Inserting Whitespace between Groups
Gaps can be added in to the data using table.body.gaps.rows
or .columns
The indexes passed should be the ones before the gap, e.g 5 will have a blank line after index 5.
It’s important to note here that the added lines are just white space – they’re not blank lines with their own index. Note the colouring of “even” rows has had to be adjusted here to match previous aesthetics.
# Create the Canvas
= toyplot.Canvas(width=700, height=500)
canvas
# Add the Data
= canvas.table(data = select_97)
table
# Set alignment for Continent and Country
0, 1]].align = "left" # [[0,1]] only affects the first 2 columns.
table.cells.column[[
# Set width for Country Column
1]].width = 150
table.cells.column[[
# Header Row Style
0].lstyle = {"font-size":"14px", "font-family":"sans-serif", "font-weight": "bold", "fill": "black"}
table.cells.row[
# Style table text
1:].lstyle = {"font-size":"12px", "font-family":"sans-serif", "fill": "black"}
table.cells.row[
# Set up the gridlines
1,2,3]]= "single" # ALL rows, columns 1 to 4
table.cells.grid.vlines[..., [1,...] = "single" # ROW 1 , ALL columns
table.cells.grid.hlines[= { "stroke-width": "1", "stroke": "grey"}
table.cells.grid.style
# Title
= 45, y= 20,
canvas.text(x = "Table 1: Population of select countries over three years",
text = {"font-size":"16px", "font-weight":"bold", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style# Subtitle
= 45, y= 35,
canvas.text(x = "Population for 1997, 2002 and 2007",
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style#Caption
= 510, y= 465,
canvas.text(x = ("<a target='_blank' href='https://www.gapminder.org/'>Source: Gapminder.org</a>"), # A link opens in a new window!
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style
# Find the lowest and highest rows
= select_97[select_97[1997] == select_97[1997].min()].index.values
low_index = select_97[select_97[1997] == select_97[1997].max()].index.values
high_index
# Colour high and low
= { "fill":"blue", "opacity": "0.5"}
table.body.row[low_index].style = {"font-weight":"bold", "fill":"red"}
table.body.row[high_index].lstyle
# White space with gaps
= table.body.gaps.rows[[4,9,14,19 ]] = "0.4cm"
a
# Colour "even" Rows
0,2,4,5,7,9, 10, 12,14,15,17,19,20]].style = {"fill":"#F2F2F2"} table.body.row[[
10 9. Grouping a column
Often tables will have a “grouped” column. Rather than the first 5 rows having “Africa” in the continent
column; only the first would. This can make data slightly easier to read; some people find this more attractive. This can also create the illusion of merged cells – similarly to Excel. This solution is one of many ways it could be done; this method avoids multiple indexes which often don’t work well with Matplotlib.
Using the .duplicated()
method on the continent column returns a Boolean series; False
where it’s the first instance of the value; and True
where it’s repeated.
.loc[]
can then be used, passing that Boolean series as the lookup; updating the “continent” column and setting the value of the column (where True
) to blank.
The data then gives the impression of “grouping” the continents together; it’s a fake impression as all that has happened is the duplicate values have become empty strings – but it works for the desired look in the final table.
= select_countries_3y_pop.copy()
grouped_continents = True, drop=True) # Reset the index
grouped_continents.reset_index(inplace = grouped_continents["continent"].duplicated() # Returns "False" for first item, "True" for subsequent
duplicate_continents "continent"] = "" # Replaces "True" values with blanks
grouped_continents.loc[duplicate_continents,7) # Check it out! Gives the impression of a multilevel index grouped_continents.head(
continent | country | 1997 | 2002 | 2007 | |
---|---|---|---|---|---|
0 | Africa | Algeria | 29072015.0 | 31287142.0 | 33333216.0 |
1 | Angola | 9875024.0 | 10866106.0 | 12420476.0 | |
2 | Benin | 6066080.0 | 7026113.0 | 8078314.0 | |
3 | Botswana | 1536536.0 | 1630347.0 | 1639131.0 | |
4 | Burkina Faso | 10352843.0 | 12251209.0 | 14326203.0 | |
5 | Americas | Argentina | 36203463.0 | 38331121.0 | 40301927.0 |
6 | Bolivia | 7693188.0 | 8445134.0 | 9119152.0 |
Let’s check out the effect when we apply it to our previous table:
# Create the Canvas
= toyplot.Canvas(width=700, height=500)
canvas
# Add the Data
= canvas.table(data = grouped_continents, trows = 2)
table
# Set alignment for Continent and Country
0, 1]].align = "left" # [[0,1]] only affects the first 2 columns.
table.cells.column[[
# Add the text in to the top row and format
= table.top.cell[0, 2:5].merge()
merged = "Year"
merged.data = "center"
merged.align
= table.top.cell[0, 0:2].merge()
merged2 = "Location"
merged2.data = "center"
merged2.align
# Set width for Country Column
1]].width = 150
table.cells.column[[
# Header Row Style
0].lstyle = {"font-size":"14px", "font-family":"sans-serif", "font-weight": "bold", "fill": "black"}
table.cells.row[
# Style table text
1:].lstyle = {"font-size":"12px", "font-family":"sans-serif", "fill": "black"}
table.cells.row[
# Set up the gridlines
1,2,3,4]]= "single" # ALL rows, columns 1 to 4
table.cells.grid.vlines[..., [1,...] = "single" # ROW 1 , ALL columns
table.cells.grid.hlines[= { "stroke-width": "1", "stroke": "grey"}
table.cells.grid.style
# Title
= 45, y= 20,
canvas.text(x = "Table 1: Population of select countries over three years",
text = {"font-size":"16px", "font-weight":"bold", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style# Subtitle
= 45, y= 35,
canvas.text(x = "Population for 1997, 2002 and 2007",
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style#Caption
= 510, y= 465,
canvas.text(x = ("<a target='_blank' href='https://www.gapminder.org/'>Source: Gapminder.org</a>"), # A link opens in a new window!
text = {"font-size":"14px", "font-family":"sans-serif", "text-anchor":"start", "fill": "black"})
style
# Colour even Rows
= [(each_row % 2 == 0) for each_row in range(len(grouped_continents))] # This uses list comprehension to highlight odd numbered rows.
rows_to_colour
= {"fill":"#F2F2F2"}; table.body.row[rows_to_colour].style
11 10. Saving Images
Toyplot has a few back ends to save our outputs to.
The most commonly used ones are PDF, SVG and HTML.
There is also the ability to save to a png; although I have been unable to get this to work.
There are methods of converting .svg, .html or .pdf files to .png within Python if needed. Or the open source software “InkScape” opens SVG files and can convert them to .png or .jpeg files.
# Save as HTML
import toyplot.html
"../outputs/figure1_html.html")
toyplot.html.render(canvas,
# Save as PDF
import toyplot.pdf
"../outputs/figure1_pdf.pdf")
toyplot.pdf.render(canvas,
# Save as SVG
import toyplot.svg
"../outputs/figure1_pdf.pdf") toyplot.svg.render(canvas,
12 End of Chapter
You have completed the main content of the Data Visualization Course.
You may wish to explore tables in Matplotlib - chapter 5b or continue to Chapter 6 - Case Studies.
Please ensure you complete the survey on the Learning Hub