Rendering images in Great Tables is straightforward with GT.fmt_image() and vals.fmt_image().
In this post, we’ll explore three key topics:
- Four examples demonstrating how to render images within the body using
GT.fmt_image(). - How to render images anywhere using
vals.fmt_image()andhtml(). - How to manually render images anywhere using
html().
Rendering Images in the Body#
GT.fmt_image() is the go-to tool for rendering images within the body of a table. Below, we’ll present four examples corresponding to the cases outlined in the documentation:
- Case 1: Local file paths.
- Case 2: Full HTTP/HTTPS URLs.
- Case 3: Image names with the
path=argument. - Case 4: Image names using both the
path=andfile_pattern=arguments.
Finding the Right Case for Your Needs
- Case 1 and Case 2 work best for data sourced directly from a database.
- Case 3 is ideal for users dealing with image names relative to a base directory or URL (e.g.,
/path/to/images).- Case 4 is tailored for users working with patterned image names (e.g.,
metro_{}.svg).
Preparations#
For this demonstration, we’ll use the first five rows of the built-in metro
dataset, specifically the name and lines columns.
To ensure a smooth walkthrough, we’ll manipulate the data (a Python dictionary) directly. However,
in real-world applications, such operations are more likely performed at the DataFrame level to leverage
the benefits of vectorized operations.
Code
|
|
data = {
"name": [
"Argentine",
"Bastille",
"Bérault",
"Champs-Élysées—Clemenceau",
"Charles de Gaulle—Étoile",
],
"lines": ["1", "1, 5, 8", "1", "1, 13", "1, 2, 6"],
}
Attentive readers may have noticed that the values for the key lines are lists of strings, each
containing one or more numbers separated by commas. GT.fmt_image() is specifically designed to
handle such cases, allowing users to render multiple images in a single row.
Case 1: Local File Paths#
Case 1 demonstrates how to simulate a column containing strings representing local file paths. We’ll
use images stored in the data/metro_images directory of Great Tables:
|
|
- Line 1
- These image files follow a patterned naming convention, such as
metro_1.svg,metro_2.svg, and so on.
Below is a Pandas DataFrame called metro_mini1, where the case1 column contains local file
paths that we want to render as images.
Code
|
|
| name | lines | case1 | |
|---|---|---|---|
| 0 | Argentine | 1 | /Users/charlottewickham/Documents/posit/open-source-website/content/blog/great-tables/.venv/lib/python3.13/site-packages/great_tables/data/metro_i... |
| 1 | Bastille | 1, 5, 8 | /Users/charlottewickham/Documents/posit/open-source-website/content/blog/great-tables/.venv/lib/python3.13/site-packages/great_tables/data/metro_i... |
| 2 | Bérault | 1 | /Users/charlottewickham/Documents/posit/open-source-website/content/blog/great-tables/.venv/lib/python3.13/site-packages/great_tables/data/metro_i... |
| 3 | Champs-Élysées—Clemenceau | 1, 13 | /Users/charlottewickham/Documents/posit/open-source-website/content/blog/great-tables/.venv/lib/python3.13/site-packages/great_tables/data/metro_i... |
| 4 | Charles de Gaulle—Étoile | 1, 2, 6 | /Users/charlottewickham/Documents/posit/open-source-website/content/blog/great-tables/.venv/lib/python3.13/site-packages/great_tables/data/metro_i... |
Use the
pathlibModule to Construct PathsLocal file paths can vary depending on the operating system, which makes it easy to accidentally construct invalid paths. A good practice to mitigate this is to use Python’s built-in pathlib module to construct paths first and then convert them to strings. In this example,
img_local_pathsis actually an instance ofpathlib.Path.
1 2 3from pathlib import Path isinstance(img_local_paths, Path) # True
The case1 column is quite lengthy due to the inclusion of img_local_paths. In Case 3, we’ll
share a useful trick to avoid repeating the directory name each time—stay tuned!
For now, let’s use GT.fmt_image() to render images by passing "case1" as the first argument:
|
|
| name | lines | case1 |
|---|---|---|
| Argentine | 1 | |
| Bastille | 1, 5, 8 | |
| Bérault | 1 | |
| Champs-Élysées—Clemenceau | 1, 13 | |
| Charles de Gaulle—Étoile | 1, 2, 6 |
Case 2: Full HTTP/HTTPS URLs#
Case 2 demonstrates how to simulate a column containing strings representing HTTP/HTTPS URLs. We’ll use the same images as in Case 1, but this time, retrieve them from the Great Tables GitHub repository:
|
|
Below is a Pandas DataFrame called metro_mini2, where the case2 column contains
full HTTP/HTTPS URLs that we aim to render as images.
Code
|
|
The lengthy case2 column issue can also be addressed using the trick shared in Case 3.
Similarly, we can use GT.fmt_image() to render images by passing "case2" as the first argument:
|
|
| name | lines | case2 |
|---|---|---|
| Argentine | 1 | |
| Bastille | 1, 5, 8 | |
| Bérault | 1 | |
| Champs-Élysées—Clemenceau | 1, 13 | |
| Charles de Gaulle—Étoile | 1, 2, 6 |
Case 3: Image Names with the path= Argument#
Case 3 demonstrates how to use the path= argument to specify images relative to a base directory
or URL. This approach eliminates much of the repetition in file names, offering a solution to the
issues in Case 1 and Case 2.
Below is a Pandas DataFrame called metro_mini3, where the case3 column contains file names that
we aim to render as images.
Code
|
|
| name | lines | case3 | |
|---|---|---|---|
| 0 | Argentine | 1 | metro_1.svg |
| 1 | Bastille | 1, 5, 8 | metro_1.svg, metro_5.svg, metro_8.svg |
| 2 | Bérault | 1 | metro_1.svg |
| 3 | Champs-Élysées—Clemenceau | 1, 13 | metro_1.svg, metro_13.svg |
| 4 | Charles de Gaulle—Étoile | 1, 2, 6 | metro_1.svg, metro_2.svg, metro_6.svg |
Now we can use GT.fmt_image() to render the images by passing "case3" as the first argument and
specifying either img_local_paths or img_url_paths as the path= argument:
|
|
| name | lines | case3 |
|---|---|---|
| Argentine | 1 | |
| Bastille | 1, 5, 8 | |
| Bérault | 1 | |
| Champs-Élysées—Clemenceau | 1, 13 | |
| Charles de Gaulle—Étoile | 1, 2, 6 |
After exploring Case 1 and Case 2, you’ll likely appreciate the functionality of the path=
argument. However, manually constructing file names can still be a bit tedious. If your file names
follow a consistent pattern, the file_pattern= argument can simplify the process. Let’s see how
this works in Case 4 below.
Case 4: Image Names Using Both the path= and file_pattern= Arguments#
Case 4 demonstrates how to use path= and file_pattern= to specify images with names following
a common pattern. For example, you could use file_pattern="metro_{}.svg" to reference images like
metro_1.svg, metro_2.svg, and so on.
Below is a Pandas DataFrame called metro_mini4, where the case4 column contains a copy of
data["lines"], which we aim to render as images.
Code
|
|
| name | lines | case4 | |
|---|---|---|---|
| 0 | Argentine | 1 | 1 |
| 1 | Bastille | 1, 5, 8 | 1, 5, 8 |
| 2 | Bérault | 1 | 1 |
| 3 | Champs-Élysées—Clemenceau | 1, 13 | 1, 13 |
| 4 | Charles de Gaulle—Étoile | 1, 2, 6 | 1, 2, 6 |
First, define a string pattern to illustrate the file naming convention, using {} to indicate the
variable portion:
|
|
Next, pass "case4" as the first argument, along with img_local_paths or img_url_paths as the
path= argument, and file_pattern as the file_pattern= argument. This allows GT.fmt_image()
to render the images:
|
|
| name | lines | case4 |
|---|---|---|
| Argentine | 1 | |
| Bastille | 1, 5, 8 | |
| Bérault | 1 | |
| Champs-Élysées—Clemenceau | 1, 13 | |
| Charles de Gaulle—Étoile | 1, 2, 6 |
Using
file_pattern=IndependentlyThe
file_pattern=argument is typically used in conjunction with thepath=argument, but this is not a strict rule. If your local file paths or HTTP/HTTPS URLs follow a pattern, you can usefile_pattern=alone withoutpath=. This allows you to include the shared portion of the file paths or URLs directly infile_pattern, as shown below:
1 2 3 4 5 6file_pattern = str(img_local_paths / "metro_{}.svg") ( GT(metro_mini4) .fmt_image("case4", file_pattern=file_pattern) .cols_align(align="right", columns="case4") )
name lines case4 Argentine 1 Bastille 1, 5, 8 ![]()
![]()
Bérault 1 Champs-Élysées—Clemenceau 1, 13 ![]()
Charles de Gaulle—Étoile 1, 2, 6 ![]()
![]()
Case 4 is undoubtedly one of the most powerful features of Great Tables. While mastering it may take some practice, we hope this example helps you render images effortlessly and effectively.
Rendering Images Anywhere#
While GT.fmt_image() is primarily designed for rendering images in the table body, what if you
need to display images in other locations, such as the header? In such cases, you can turn to the versatile
vals.fmt_image()
.
vals.fmt_image() is a hidden gem in Great Tables. Its usage is similar to GT.fmt_image(), but
instead of working directly with DataFrame columns, it lets you pass a string or a list of strings
as the first argument, returning a list of strings, each representing an image. You can then wrap
these strings with html()
,
allowing Great Tables to render the images anywhere in the table.
Preparations#
We will create a Pandas DataFrame named metro_mini using the data dictionary. This will be used
for demonstration in the following examples:
Code
|
|
| name | lines | |
|---|---|---|
| 0 | Argentine | 1 |
| 1 | Bastille | 1, 5, 8 |
| 2 | Bérault | 1 |
| 3 | Champs-Élysées—Clemenceau | 1, 13 |
| 4 | Charles de Gaulle—Étoile | 1, 2, 6 |
Single Image#
This example shows how to render a valid URL as an image in the title of the table header:
|
|
- Line 3
vals.fmt_image()returns a list of strings. Here, we use tuple unpacking to extract the first item from the list.
| name | lines |
|---|---|
| Argentine | |
| Bastille | |
| Bérault | |
| Champs-Élysées—Clemenceau | |
| Charles de Gaulle—Étoile | |
Multiple Images#
This example demonstrates how to render two valid URLs as images in the title and subtitle of the table header:
|
|
- Line 4
- Note that if you need to render images with different
heightorwidth, you might need to make two separate calls tovals.fmt_image().
| name | lines |
|---|---|
| Argentine | |
| Bastille | |
| Bérault | |
| Champs-Élysées—Clemenceau | |
| Charles de Gaulle—Étoile | |
Manually Rendering Images Anywhere#
Remember, you can always use html() to manually construct your desired output. For example, the
previous table can be created without relying on vals.fmt_image() like this:
|
|
Alternatively, you can manually encode the image using Python’s built-in
base64
module, specify the appropriate MIME type
and HTML attributes, and then wrap it in html() to display the table.
Final Words#
In this post, we focused on the most common use cases for rendering images in Great Tables, deliberately avoiding excessive DataFrame operations. Including such details could have overwhelmed the post with examples of string manipulations and the complexities of working with various DataFrame libraries.
We hope you found this guide helpful and enjoyed the structured approach. Until next time, happy table creation with Great Tables!
Appendix: Related PRs
If you’re interested in the recent enhancements we’ve made to image rendering, be sure to check out #444 , #451 and #520 for all the details.
