import polars as pl
from pylifemap import Lifemap
iucn = pl.read_parquet(
"https://raw.githubusercontent.com/Lifemap-ToL/pylifemap/main/data/iucn.parquet"
)Usage
See the Getting started page for a more gentle introduction.
In the following we will use the example IUCN dataset. It is a parquet file with the Red List category (in 2022) of more than 84000 species.
Installation
Install locally
You can add the package to a project with uv or to a virtual environment with pip:
# Install pylifemap, preferably in a virtual environment
pip install pylifemap# Add pylifemap to a python project
uv add pylifemapRun directly with uv
You can run pylifemap directly with uv run using a --with argument:
# Run a Jupyter session
uv run --with pylifemap --with jupyter jupyter-lab
# Run a marimo session
uv run --with pylifemap --with marimo marimo edit
# Run a custom script
uv run --with pylifemap my_script.pyRun with juv
juv is a toolkit for reproducible Jupyter notebooks, powered by uv.
You can easily create and run a notebook with pylifemap with:
juv init notebook.ipynb
juv add notebook.ipynb pylifemap
juv run notebook.ipynbRun with Docker
Another way to use the package without having to install it is to use our Docker image.
Run in Jupyter
To use pylifemap in a Jupyter environment, open a terminal in the directory containing your data and notebook files, and run:
docker run -it -p 127.0.0.1:8899:8899 -v $PWD:/local/ ghcr.io/lifemap-tol/pylifemap:latestOpen the following URL in your browser: http://127.0.0.1:8899/lab, and you will have access to a Jupyter notebook environment with pylifemap and its dependencies preinstalled.
Run a script
If you just want to run a Python script generating a pylifemap visualization, you can open a terminal in the script directory and run the following command:
docker run -v $PWD:/local/ ghcr.io/lifemap-tol/pylifemap:latest myscript.pyIn this case, if you use show() in your script the result will not be opened in your browser but will instead be saved in a lifemap.html file in your working directory.
Base map customization
Several arguments can be passed to Lifemap() when initializing the visualization.
For a complete list of Lifemap arguments, see its documentation.
Widget size
The width and height arguments allow to modify the widget size. They can be given in any CSS unit.
For example, the following initialization would make the visualization take the full available width, and an height of 800 pixels.
Lifemap(iucn, taxid_col="taxid", width="100%", height=800)Map theme
By default Lifemap displays its base map in a dark theme with a black background, but you can switch to another theme by adding a theme argument:
Lifemap(iucn, theme="light").layer_points().show()Warning: 779 taxids have not been found in Lifemap database.
Warning: 152 duplicated taxids have been found in the data.
Available themes are currently dark, light, lightgrey, lightblue and lightgreen.
Map controls
By default, the Lifemap widget displays several controls allowing to interact with the map. It is possible to customize which controls are shown by passing a controls argument to Lifemap:
Lifemap(iucn, taxid_col="taxid", controls=("zoom", "full_screen"))The following values are available:
"zoom": zoom in and zoom out buttons"reset_zoom": zoom reset button"png_export": button to export the current view to a PNG file"search": taxa search button"full_screen": full screen toggle button
Default view (center and zoom)
The center and zoom arguments allow to specify the initial map view at widget creation.
There are three different possible values for center:
"default": show the entire tree of life (default value)"auto": center the view on the displayed data- taxid (integer value): center the view on this taxid coordinates
If you set zoom to an integer value between 4 and 42, the initial zoom will be set to this level. If you leave zoom at its default None value, the zoom level will be computed according to the center value.
For technical reason, the center="auto" argument doesn’t take into account data passed to layer_screengrid or layer_heatmap_deck.
Visualization layers
Here are the currently available layers:
| Layer | Description |
|---|---|
| layer_points | Displays each observation with a point. Radius and color can be dependent of an attribute in the DataFrame. |
| layer_lines | Using aggregated data, highlights branches of the tree with lines of varying width and color. |
| layer_donuts | Displays aggregated categorical data as donut charts. |
| layer_heatmap | Displays a heatmap of the observations distribution in the tree. |
| layer_heatmap_deck | Displays a deck.gl heatmap of the observations distribution in the tree. |
| layer_screengrid | Displays the observations distribution with a colored grid with fixed-size cells.. |
| layer_text | Displays text labels by taxid |
| layer_icons | Displays icons associated to taxids |
Several layers can be added to the same map by chaining several methods:
Lifemap(iucn, taxid_col="taxid").layer_heatmap().layer_points().show()Layers customization
Each layer accepts a certain number of arguments to customize its appearance. For example we can change the radius, color and opacity of our points:
(
Lifemap(iucn)
.layer_points(fill="#EFB118", radius=5, opacity=0.5)
.show()
)Instead of providing fixed values to fill or radius, we can also pass data column names to make size or color depending on the column values. For example, we can make the color of the points depending on their status:
(
Lifemap(iucn)
.layer_points(fill="status", radius=4, opacity=0.9)
.show()
)See each layer documentation page for a complete list of its arguments.
Layers data
By default, layers use the data provided when calling Lifemap, but it is possible to give a specific dataset to a layer. To do this, just pass a data and optionally a taxid_col argument to the layer function.
icons_data = pl.DataFrame({
'taxid': ['1005039','9544','41956','35128','74311'],
'imageurl': ['https://images.phylopic.org/images/6767b093-d375-48c2-b4f2-9215b76ea08d/thumbnail/64x64.png',
'https://images.phylopic.org/images/4e9c5666-79cc-4766-a7d3-d547514b0d77/thumbnail/64x64.png',
'https://images.phylopic.org/images/f722ba34-03d4-4b90-8409-e02829a3c5d4/thumbnail/64x64.png',
'https://images.phylopic.org/images/ebff2e9f-3091-4ad6-a7b2-f39a77d3a960/thumbnail/64x64.png',
'https://images.phylopic.org/images/8fbb3dd3-24ff-4e96-b41c-92b334ff4560/thumbnail/64x64.png']
})
(
Lifemap(iucn, theme="lightgrey")
.layer_points(radius=4, opacity=0.9)
.layer_icons(data=icons_data, icon="imageurl", popup=True)
.show()
)Popups customization
For layers like layer_points, layer_lines or layer_icons that support popups, it is possible to customize the popup content by adding a popup_col argument. This argument must be the name of a data column containing the popup content for each data point.
icons_data = icons_data.with_columns(popup="The taxid of this node is <strong>" + pl.col("taxid") + "</strong>")
(
Lifemap(icons_data, theme="light")
.layer_icons(icon="imageurl", popup=True, popup_col="popup")
.show()
)Lazy loading
By default the entire user data points are loaded and displayed on the map. This can be slow when the dataset is big.
Lazy loading means that data isn’t loaded entirely when the widget is created, but incrementally depending on the current map view: only the visible points are loaded and displayed.
Lazy loading is available for the points, lines, text, donuts and icons layers. It is enabled by default for the donuts layer.
To manually enable or disable lazy loading, you can set the lazy argument to True or False when using one these layers creation function.
Another useful argument you can give is lazy_zoom, which is the maximum zoom depth to display. In other words, if the map view is currently at zoom level z, then only data points above zoom level z + lazy_zoom. You can set lazy_zoom to -1 to display all zoom levels.
In certain cases, lazy loading can make certain map area appear empty when zoomed out, whereas some data points become visible when zooming in.
Widget display and export
Lifemap and layer methods create a widget object but don’t display it. For it to appear, we have to call the show() method:
Lifemap(iucn, taxid_col="taxid").layer_points().show()When in a notebook environment, calling show() will display the visualisation as a widget. When called from a Python script or a Python REPL, the visualization will be saved to a temporary file and, if possible, displayed in the user’s browser. When called from a Python script running inside our Docker container, it will be saved to a file in the working directory.
The widget can also be saved to an HTML file by using the save() method:
Lifemap(iucn, taxid_col="taxid").layer_points().save("lifemap.html")You can also use Jupyter HTML export or Quarto document conversion to create HTML documents embedding interactive pylifemap widgets.
Lifemap is updated weekly from the latest NCBI data. During these updates, the precise coordinates of each taxon can change slightly.
If you export your widget to HTML and your data includes less than 100 000 data points, the up to date coordinates are retrieved from our API each time the widget is displayed, so the coordinates of the base map and of your dataset should still match. But if you have more than 100 000 data points, they may not correspond anymore if the base map has been updated since the widget creation.
You can also use the Export to PNG button on the widget to export the currently displayed view to an image file in PNG format.
Data aggregation
pylifemap provides several functions that allow to aggregate data along the branches of the tree:
| Function | Description |
|---|---|
aggregate_count |
Aggregates the number of children of each tree node. |
aggregate_num |
Aggregates a numerical variable along the tree branches with a given function (sum , mean, max…). |
aggregate_freq |
Aggregates the frequencies of the levels of a categorical variable. |
For example, if we filter our dataset to only keep the species with an “extinct” status:
iucn_extinct = iucn.filter(pl.col("status") == "Extinct")iucn_extinct = iucn[iucn["status"] == "Extinct"]We can then aggregate their count along the branches with aggregate_count:
from pylifemap import aggregate_count
iucn_extinct_agg = aggregate_count(iucn_extinct)
iucn_extinct_agg| taxid | n |
|---|---|
| i32 | u32 |
| null | 2 |
| 0 | 196 |
| 2759 | 196 |
| 3193 | 21 |
| 3268 | 1 |
| … | … |
| 3076244 | 1 |
| 3078114 | 76 |
| 3136023 | 1 |
| 3410119 | 1 |
| 3410121 | 1 |
Finally, we can represent this new dataset with a lines layer, making the lines width and color depending on the aggregated count values.
(
Lifemap(iucn_extinct_agg)
.layer_lines(color="n", width="n", label="Extinct species")
.show()
)Warning: 3 taxids have not been found in Lifemap database: [None, 1914395, 3041918].