Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable concatenation of charts with tiles #39

Merged
merged 6 commits into from
Feb 6, 2025
Merged

Conversation

geo-mathijs
Copy link
Contributor

I've applied two small fixes to enable concatenation of charts that include altair_tiles.

  1. 4123a98 The dataset name is now unique, fixing Javascript Error: Duplicate data set name: "tile_list"
  2. a56939a Allow manually overriding the width and height, which are used to compute the transform_filter that filters out tiles that are off screen. This is needed to fix a weird bug where width or height are set to 0 in vconcat and hconcat.

I also played around with a hacky fix just detecting if width or height were zero and defaulting to a big number (e.g. windowSize()), but I figured just allowing the width and height to be set to be much cleaner.

Thanks,
M

Add a unique suffix to the tile data layer name. This ensures that a
basemap can be used in a concatenated chart, whereas this used to fail
with: Duplicate data set name: "tile_list".
Concatenation of charts somehow sets the height or width signal to zero
in vega. In those cases, the childHeight and childWidth signals are
set instead, but we cannot use these because they don't always exists
and referencing an undefined signal throws an error.

Instead, just allow using a manually provided width or height to allow
overriding the erroneous height or width signals.
@geo-mathijs geo-mathijs mentioned this pull request Feb 1, 2025
@geo-mathijs
Copy link
Contributor Author

I wasn't sure how to add a test for this, given that it fixes a visual artifact

@geo-mathijs
Copy link
Contributor Author

Just running the example in #33 should give an easy way to confirm my PR fixes the root issue.

@geo-mathijs
Copy link
Contributor Author

^ Tests are failing on unrelated code (e.g. linting on doc folder). Please advise

@mattijn
Copy link
Contributor

mattijn commented Feb 4, 2025

Thank you for this PR! Let's wait a few days if @binste, original author of this repository, has time to respond. Otherwise I will try my best to take over to make sure we can get this PR merged while tests remain happy.
Again, thank you! This seems very promising and useful in concatenated charts!

@binste
Copy link
Collaborator

binste commented Feb 4, 2025

Thank you @geo-mathijs for the PR and @mattijn for the ping!

I can probably review later this week and cut a new release.

@binste binste linked an issue Feb 6, 2025 that may be closed by this pull request
@binste binste merged commit e36caa2 into vega:main Feb 6, 2025
@binste
Copy link
Collaborator

binste commented Feb 6, 2025

Thanks again! Tested and it works great :)

@mattijn
Copy link
Contributor

mattijn commented Feb 6, 2025

I installed the latest released version (0.0.4), but when I try, I get the following output:

import geopandas as gpd
import altair as alt
import altair_tiles as til

gdf_ne = gpd.read_file("https://naciscdn.org/naturalearth/110m/cultural/ne_110m_admin_0_countries.zip")  # zipped shapefile
extent_roi = gdf_ne.loc[gdf_ne["CONTINENT"] == "Africa", ["CONTINENT", "geometry"]]

geoshape_countries = alt.Chart(extent_roi).mark_geoshape().project(type="mercator").properties(width=300, height=300)
til.add_tiles(geoshape_countries) | til.add_tiles(geoshape_countries)
image

and for

import altair as alt
import altair_tiles as til
from vega_datasets import data
import geopandas as gpd

# load data
gdf_quakies = gpd.read_file(data.earthquakes.url)

# defintion for interactive brush
brush = alt.selection_interval(
    encodings=["longitude"],
    empty=False,
    value={"longitude": [-50, -110]}
)

# world disk
sphere = alt.Chart(alt.sphere()).mark_geoshape(
    fill="transparent", stroke="lightgray", strokeWidth=1
)

# earthquakes as dots on map
quakes = alt.Chart(gdf_quakies).transform_calculate(
    lon="datum.geometry.coordinates[0]",
    lat="datum.geometry.coordinates[1]",
).mark_circle(opacity=0.35, tooltip=True).encode(
    longitude="lon:Q",
    latitude="lat:Q",
    color=alt.condition(brush, alt.value("goldenrod"), alt.value("steelblue")),
    size=alt.Size("mag:Q").scale(type="pow", range=[1, 1000], domain=[0, 7], exponent=4),
).add_params(brush)

# combine layers for the map
left_map = alt.layer(til.create_tiles_chart(), sphere, quakes).project(type="mercator").properties(width=300, height=300)

# histogram of binned earthquakes
bars = alt.Chart(gdf_quakies).mark_bar().encode(
    x=alt.X("mag:Q").bin(extent=[0,7]),
    y="count(mag):Q",
    color=alt.value("steelblue")
)

# filtered earthquakes
bars_overlay = bars.encode(color=alt.value("goldenrod")).transform_filter(brush)

# combine layers for histogram
right_bars = alt.layer(bars, bars_overlay)

left_map | right_bars
image

Is this something wrong on my side? Caching or something?

@mattijn
Copy link
Contributor

mattijn commented Feb 6, 2025

Ah got it. I should add the width and height parameters within the altair_tiles objects:

import geopandas as gpd
import altair as alt
import altair_tiles as til

gdf_ne = gpd.read_file("https://naciscdn.org/naturalearth/110m/cultural/ne_110m_admin_0_countries.zip")  # zipped shapefile
extent_roi = gdf_ne.loc[gdf_ne["CONTINENT"] == "Africa", ["CONTINENT", "geometry"]]

geoshape_countries = alt.Chart(extent_roi).mark_geoshape().project(type="mercator").properties(width=300, height=300)
til.add_tiles(geoshape_countries, width=300, height=300) | til.add_tiles(geoshape_countries, width=300, height=300)
image

and:

import altair as alt
import altair_tiles as til
from vega_datasets import data
import geopandas as gpd

# load data
gdf_quakies = gpd.read_file(data.earthquakes.url)

# defintion for interactive brush
brush = alt.selection_interval(
    encodings=["longitude"],
    empty=False,
    value={"longitude": [-50, -110]}
)

# world disk
sphere = alt.Chart(alt.sphere()).mark_geoshape(
    fill="transparent", stroke="lightgray", strokeWidth=1
)

# earthquakes as dots on map
quakes = alt.Chart(gdf_quakies).transform_calculate(
    lon="datum.geometry.coordinates[0]",
    lat="datum.geometry.coordinates[1]",
).mark_circle(opacity=0.35, tooltip=True).encode(
    longitude="lon:Q",
    latitude="lat:Q",
    color=alt.condition(brush, alt.value("goldenrod"), alt.value("steelblue")),
    size=alt.Size("mag:Q").scale(type="pow", range=[1, 1000], domain=[0, 7], exponent=4),
).add_params(brush)

# combine layers for the map
left_map = alt.layer(til.create_tiles_chart(width=300, height=300), sphere, quakes).project(type="mercator").properties(width=300, height=300)

# histogram of binned earthquakes
bars = alt.Chart(gdf_quakies).mark_bar().encode(
    x=alt.X("mag:Q").bin(extent=[0,7]),
    y="count(mag):Q",
    color=alt.value("steelblue")
)

# filtered earthquakes
bars_overlay = bars.encode(color=alt.value("goldenrod")).transform_filter(brush)

# combine layers for histogram
right_bars = alt.layer(bars, bars_overlay)

left_map | right_bars
image

@geo-mathijs
Copy link
Contributor Author

Great to hear it all works! Thanks for the quick release as well 🎊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support concatenation
3 participants