Holoviews.save() fails to export the full the holoviews.Tiles set

I have been using holoviews.Tiles to generate an interactive map and it works wonderfully.

However, I also want to be able to generate a .png image of the map to create icons that represent the path of a parsed sonar log.

When I use holoviews.save() with the holoviews.Tiles and the bokeh backend, the png is occasionally missing tiles from the exported png file as you can see the blank white square in the example below.

This doesnt seem to happen in the interactive usage, so my guess is that the save is happening before the tile has been successfully downloaded. Is there a way to force the save() to wait for the tiles to have been fully downloaded before running?

Also is this a bug I should report?


Good question, as far as I can tell bokeh’s export_png functionality takes the screenshot as soon as the plot is loaded and there’s no option to make it wait. I think we might have to make a feature request for that in bokeh and then expose that option in holoviews and panel.

Thanks for the quick response.

I am happy to report these as a bug report in holoviews at: https://github.com/holoviz/holoviews/issues and a new feature request in bokeh at: https://github.com/bokeh/bokeh/issues

Is the the best way to go about this or would you prefer to do it (with likely more useful information particularly for the bokeh changes required knowing the internal details of holoviews)?

I think creating a minimal example of exporting a tile source in bokeh using export_png and filing that as an issue would be sufficient. Maybe also suggest your idea about adding a configurable timeout.

Sorry I have been a bit slow responding to this as I haven’t used bokeh directly before and realized would need to do some research to create the cut-down example. Anyhow was much simpler than I expected. It turns out, I think bokeh does indeed wait for the tiles before rendering on export_png.

With some very simple code like below (I couldn’t find a way to use the wikimedia in bokeh, so maybe this is related to that also) I see that it basically always exports the full image except once where it displayed the following error:

WARNING:bokeh.io.export:The webdriver raised a TimeoutException while waiting for a ‘bokeh:idle’ event to signify that the layout has rendered. Something may have gone wrong.

So it looks like it does wait for export, but on timeout skips with an exception. I guess the feature to request is to retry tile on failure instead of skipping it.

from bokeh.plotting import figure
from bokeh.tile_providers import Vendors, get_provider
from bokeh.io import export_png

tile_provider = get_provider(Vendors.CARTODBPOSITRON_RETINA)
p = figure(x_range=(16793809.66, 16794508.82), y_range=(-4095373.46, -4093791.58), x_axis_type="mercator", y_axis_type="mercator")
export_png(p, filename="plot.png")

The cutdown version in holoviews is:

import numpy.random
import datashader.geo
import holoviews
import time

# Configure the default renderer
renderer = holoviews.renderer('bokeh').instance(mode='server')

# Using longitude/latitude in WGS84 format
lon_min, lat_min = (150.86135898475558, -34.49433199671786)
lon_max, lat_max = (150.8676395946077, -34.482619315846264)

# Convert to northings/eastings in meters required to match the Tiles for overlay
left, bottom = datashader.geo.lnglat_to_meters(lon_min, lat_min)
right, top = datashader.geo.lnglat_to_meters(lon_max, lat_max)

tiles = holoviews.Tiles('https://maps.wikimedia.org/osm-intl/{Z}/{X}/{Y}@2x.png', name="Wikipedia")
tiles = tiles.opts(width=600, height=550)

# Adjust the framing of the tile to show the frame and not the entire world
# From: https://examples.pyviz.org/nyc_taxi/nyc_taxi.html
x_dim = holoviews.Dimension(
		range=(left, right)
y_dim = holoviews.Dimension(
		range=(bottom, top)
tiles = tiles.redim(x=x_dim, y=y_dim)

holoviews.save(tiles, 'tiles.png')