ipyleaflet icon indicating copy to clipboard operation
ipyleaflet copied to clipboard

Add style callbacks for VectorTileLayer

Open deeplook opened this issue 5 years ago • 11 comments

Styling for vector tiles can be pretty complex and the current implementation of VectorTileLayer only allows for one static style per "tile layer" e.g. "roads". This is a severe limitation as one cannot exploit the rich feature properties stored in vector tiles, e.g. to render different types of roads individually. The Leaflet VectorGrid plugin does support function callbacks for more dynamic styling as described here: https://leaflet.github.io/Leaflet.VectorGrid/vectorgrid-api-docs.html#styling-vectorgrids. So I think it should be possible to wrap this functionality and expose it in ipyleaflet, too, in a way similar to the style_callback parameter for GeoJSON layer.

deeplook avatar Nov 04 '20 17:11 deeplook

I don't think this is technically doable without transpiling the Python code into JS.

In GeoJSON we can modify the data with a style_callback because they are available in the Python process. In the VectorTileLayer we don't have access to the tiles data in the Python process, something like a style_callback would need to be performed in JS.

Also, we provide access to styling the VectorTileLayer already IIRC.

martinRenou avatar Nov 05 '20 07:11 martinRenou

In the VectorTileLayer we don't have access to the tiles data in the Python process

But the VectorGrid plugin has access to it or it couldn't apply the styling functions mentions on the page above. Maybe it's possible to have deeper access to this plugin?

Also, we provide access to styling the VectorTileLayer already IIRC.

To some degree at least. Maybe @omanges can help.

deeplook avatar Nov 05 '20 10:11 deeplook

But the VectorGrid plugin has access to it or it couldn't apply the styling functions mentions on the page above

Only JavaScript side.

A style_callback feature you are requesting would need to be provided in Python I guess. Unless we ask people to write JavaScript, but I personally don't wish anyone to have to write JavaScript.

martinRenou avatar Nov 05 '20 10:11 martinRenou

but I personally don't wish anyone to have to write JavaScript.

I surely share that feeling. ;) How about a JupyterLab extension, then? ;)

deeplook avatar Nov 05 '20 10:11 deeplook

How about a JupyterLab extension, then? ;)

What do you mean? ipyleaflet already contains a JupyterLab extension

martinRenou avatar Nov 05 '20 11:11 martinRenou

Sure, but maybe the extension could cover the more intricate JS code...

deeplook avatar Nov 05 '20 14:11 deeplook

What kind of API do you have in mind?

martinRenou avatar Nov 05 '20 14:11 martinRenou

But the VectorGrid plugin has access to it or it couldn't apply the styling functions mentions on the page above

Only JavaScript side.

A style_callback feature you are requesting would need to be provided in Python I guess. Unless we ask people to write JavaScript, but I personally don't wish anyone to have to write JavaScript.

Are there any plans for this? I wouldn't mind providing a small callback function in Javascript if it means I can do conditional styling.

For example, I would like to be able to do something like this:

image

var vectorTileOptions = {
  minZoom: 0,
  maxNativeZoom: 13,
  interactive: true,
  vectorTileLayerStyles: {
    // Define your custom styles for the vector tile layer
    "2015ETm3": function (properties, zoom) {
      // Function to style the fields in different colors
      // based on one attribute (e.g. fieldUse).
      var fieldColor = "#ffffcc"; // default color
      if (properties.fieldUse >= 0.25) {
        fieldColor = "#c2e699";
      }
      if (properties.fieldUse >= 0.5) {
        fieldColor = "#78c679";
      }
      if (properties.fieldUse >= 0.75) {
        fieldColor = "#31a354";
      }
      if (properties.fieldUse >= 1) {
        fieldColor = "#006837";
      }
      return {
        fillOpacity: 1,
        fillColor: fieldColor,
        fill: true,
        weight: 1,
        color: "white",
        opacity: 1,
      };
    },
  },
};

is this currently possible in ipyleaflet? what other options are there for achieving this?

lopezvoliver avatar Mar 13 '24 07:03 lopezvoliver

This is currently possible using folium with the vectorGrid plugin:

image

where options is a string including the JS function:

options='''{ "vectorTileLayerStyles": { "2015ETm3": function(f) { var fieldColor = "#ffffcc"; if (f.fieldUse >= 0.25) { fieldColor = "#c2e699"; } if (f.fieldUse >= 0.5) { fieldColor = "#78c679"; } if (f.fieldUse >= 0.75) { fieldColor = "#31a354"; } if (f.fieldUse >= 1) { fieldColor = "#006837"; } return { fillOpacity: 1, fillColor: fieldColor, fill: true, weight: 1, color: "white", opacity: 1, }; } }
}'''

lopezvoliver avatar Mar 13 '24 08:03 lopezvoliver

@martinRenou

Would it be possible to add some small typescript code (potentially just one line?) in LeafletVectorTileLayerModel that sets vectorTileLayerStyles either as a dictionary (as it currently is) OR a string that gets converted to a dictionary?

e.g., similar as what the folium vectorgrid plugin does here

This way the user has the option to define the vector_tile_layer_styles as a string and optionally include logic for styling features (in javascript).

lopezvoliver avatar Jun 11 '24 08:06 lopezvoliver

Definitely, would you like to try a PR to ipyleaflet?

martinRenou avatar Jun 11 '24 12:06 martinRenou