diff --git a/bindings/pydeck-carto/Makefile b/bindings/pydeck-carto/Makefile index f640c312a2a..70bfdc1d89f 100644 --- a/bindings/pydeck-carto/Makefile +++ b/bindings/pydeck-carto/Makefile @@ -16,6 +16,9 @@ lint: test: $(BIN)/pytest tests --cov=pydeck_carto +test-scripts: + for file in examples/scripts/*.py; do $(BIN)/python "$$file"; done + publish-pypi: rm -rf $(DIST) $(BUILD) *.egg-info $(BIN)/python setup.py sdist bdist_wheel diff --git a/bindings/pydeck-carto/README.md b/bindings/pydeck-carto/README.md index f9de7dc5249..1586d07439c 100644 --- a/bindings/pydeck-carto/README.md +++ b/bindings/pydeck-carto/README.md @@ -31,16 +31,19 @@ from carto_auth import CartoAuth # Authentication with CARTO carto_auth = CartoAuth.from_oauth() -# Register CartoLayer in pydeck -pdkc.register_carto_layer() - -# Render CartoLayer in pydeck +# Register new layer types in pydeck +pdkc.register_layers() + +# Render CARTO layer in pydeck +data = pdkc.sources.vector_query_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + sql_query="SELECT geom, name FROM carto-demo-data.demo_tables.world_airports", +) layer = pdk.Layer( - "CartoLayer", - data="SELECT geom, name FROM carto-demo-data.demo_tables.airports", - type_=pdkc.MapType.QUERY, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), + "VectorTileLayer", + data=data, get_fill_color=[238, 77, 90], point_radius_min_pixels=2.5, pickable=True, diff --git a/bindings/pydeck-carto/examples/scripts/carto_layer_geo_query.py b/bindings/pydeck-carto/examples/scripts/carto_layer_geo_query.py index feb90e8c8ae..0ca441b402a 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_layer_geo_query.py +++ b/bindings/pydeck-carto/examples/scripts/carto_layer_geo_query.py @@ -7,17 +7,22 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() + +data = pdkc.sources.vector_query_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + sql_query="SELECT geom, name FROM carto-demo-data.demo_tables.world_airports", +) layer = pdk.Layer( - "CartoLayer", - data="SELECT geom, name FROM carto-demo-data.demo_tables.airports", - type_=pdkc.MapType.QUERY, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), + "VectorTileLayer", + data=data, get_fill_color=[238, 77, 90], point_radius_min_pixels=2.5, pickable=True, @@ -26,4 +31,4 @@ view_state = pdk.ViewState(latitude=0, longitude=0, zoom=1) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_layer_geo_query.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_layer_geo_query.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_layer_geo_query_param.py b/bindings/pydeck-carto/examples/scripts/carto_layer_geo_query_param.py index 2db170e8f07..2639b431bbb 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_layer_geo_query_param.py +++ b/bindings/pydeck-carto/examples/scripts/carto_layer_geo_query_param.py @@ -7,19 +7,24 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() -layer = pdk.Layer( - "CartoLayer", - data="SELECT geom, event FROM carto-demo-data.demo_tables" +data = pdkc.sources.vector_query_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + sql_query="SELECT geom, event FROM carto-demo-data.demo_tables" ".spain_earthquakes where depth > ?", query_parameters=[2], - type_=pdkc.MapType.QUERY, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), +) + +layer = pdk.Layer( + "VectorTileLayer", + data=data, get_fill_color=[238, 77, 90], point_radius_min_pixels=2.5, pickable=True, @@ -28,4 +33,4 @@ view_state = pdk.ViewState(latitude=36, longitude=-7.44, zoom=5) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_layer_geo_query_param.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_layer_geo_query_param.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_layer_geo_table.py b/bindings/pydeck-carto/examples/scripts/carto_layer_geo_table.py index 911be8bdd81..dd8ed122bbe 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_layer_geo_table.py +++ b/bindings/pydeck-carto/examples/scripts/carto_layer_geo_table.py @@ -7,17 +7,22 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() + +data = pdkc.sources.vector_table_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + table_name="carto-demo-data.demo_tables.world_airports", +) layer = pdk.Layer( - "CartoLayer", - data="carto-demo-data.demo_tables.airports", - type_=pdkc.MapType.TABLE, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), + "VectorTileLayer", + data=data, get_fill_color=[200, 0, 80], point_radius_min_pixels=2, pickable=True, @@ -26,4 +31,4 @@ view_state = pdk.ViewState(latitude=0, longitude=0, zoom=1) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_layer_geo_table.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_layer_geo_table.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_layer_geo_tileset.py b/bindings/pydeck-carto/examples/scripts/carto_layer_geo_tileset.py index bf58b41e5d3..72043f8d18a 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_layer_geo_tileset.py +++ b/bindings/pydeck-carto/examples/scripts/carto_layer_geo_tileset.py @@ -7,17 +7,22 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() + +data = pdkc.sources.vector_tileset_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + table_name="carto-demo-data.demo_tilesets.pointsofinterest_esp", +) layer = pdk.Layer( - "CartoLayer", - data="carto-demo-data.demo_tilesets.pointsofinterest_esp", - type_=pdkc.MapType.TILESET, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), + "VectorTileLayer", + data=data, get_fill_color=[200, 0, 80], stroked=False, point_radius_min_pixels=2, @@ -27,4 +32,4 @@ view_state = pdk.ViewState(latitude=36, longitude=-7.44, zoom=5) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_layer_geo_tileset.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_layer_geo_tileset.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_layer_h3_query.py b/bindings/pydeck-carto/examples/scripts/carto_layer_h3_query.py index 2202fe95e04..aadd5a87b2f 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_layer_h3_query.py +++ b/bindings/pydeck-carto/examples/scripts/carto_layer_h3_query.py @@ -7,19 +7,24 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() -layer = pdk.Layer( - "CartoLayer", - data="select * from carto-demo-data.demo_tables" +data = pdkc.sources.h3_query_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + sql_query="select * from carto-demo-data.demo_tables" ".derived_spatialfeatures_usa_h3res8_v1_yearly_v2", - type_=pdkc.MapType.QUERY, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), - geo_column=pdkc.GeoColumnType.H3, + aggregation_exp="sum(population) as population_sum", +) + +layer = pdk.Layer( + "H3TileLayer", + data=data, get_fill_color=[200, 0, 80], pickable=True, ) @@ -27,4 +32,4 @@ view_state = pdk.ViewState(latitude=44, longitude=-122, zoom=3) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_layer_h3_query.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_layer_h3_query.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_layer_h3_table.py b/bindings/pydeck-carto/examples/scripts/carto_layer_h3_table.py index 4bf55d61ef4..29457aa4901 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_layer_h3_table.py +++ b/bindings/pydeck-carto/examples/scripts/carto_layer_h3_table.py @@ -7,18 +7,24 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() + +data = pdkc.sources.h3_table_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + table_name="carto-demo-data.demo_tables" + ".derived_spatialfeatures_esp_h3res8_v1_yearly_v2", + aggregation_exp="sum(population) as population_sum", +) layer = pdk.Layer( - "CartoLayer", - data="carto-demo-data.demo_tables.derived_spatialfeatures_esp_h3res8_v1_yearly_v2", - type_=pdkc.MapType.TABLE, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), - geo_column=pdkc.GeoColumnType.H3, + "H3TileLayer", + data=data, get_fill_color=[200, 0, 80], pickable=True, ) @@ -26,4 +32,4 @@ view_state = pdk.ViewState(latitude=36, longitude=-7.44, zoom=5) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_layer_h3_table.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_layer_h3_table.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_layer_h3_tileset.py b/bindings/pydeck-carto/examples/scripts/carto_layer_h3_tileset.py index fb6f2bf6404..4c08c9deb29 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_layer_h3_tileset.py +++ b/bindings/pydeck-carto/examples/scripts/carto_layer_h3_tileset.py @@ -7,18 +7,24 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() -layer = pdk.Layer( - "CartoLayer", - data="carto-demo-data.demo_tilesets" +data = pdkc.sources.h3_tileset_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + table_name="carto-demo-data.demo_tilesets" ".derived_spatialfeatures_usa_h3res8_v1_yearly_v2_tileset", - type_=pdkc.MapType.TILESET, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), + aggregation_exp="sum(population) as population_sum", +) + +layer = pdk.Layer( + "H3TileLayer", + data=data, get_fill_color=[200, 0, 80], pickable=True, ) @@ -26,4 +32,4 @@ view_state = pdk.ViewState(latitude=44, longitude=-122, zoom=3) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_layer_h3_tileset.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_layer_h3_tileset.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_query.py b/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_query.py index a255f97024f..74924419d7e 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_query.py +++ b/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_query.py @@ -7,19 +7,24 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() -layer = pdk.Layer( - "CartoLayer", - data="select * from carto-demo-data.demo_tables" +data = pdkc.sources.quadbin_query_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + sql_query="select * from carto-demo-data.demo_tables" ".derived_spatialfeatures_usa_quadbin15_v1_yearly_v2", - type_=pdkc.MapType.QUERY, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), - geo_column=pdkc.GeoColumnType.QUADBIN, + aggregation_exp="sum(population) as population_sum", +) + +layer = pdk.Layer( + "QuadbinTileLayer", + data=data, get_fill_color=[200, 0, 80], pickable=True, ) @@ -27,4 +32,4 @@ view_state = pdk.ViewState(latitude=44, longitude=-122, zoom=3) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_layer_quadbin_query.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_layer_quadbin_query.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_table.py b/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_table.py index fccf23da2e3..951431f35a1 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_table.py +++ b/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_table.py @@ -7,19 +7,24 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() -layer = pdk.Layer( - "CartoLayer", - data="carto-demo-data.demo_tables" +data = pdkc.sources.quadbin_table_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + table_name="carto-demo-data.demo_tables" ".derived_spatialfeatures_esp_quadbin15_v1_yearly_v2", - type_=pdkc.MapType.TABLE, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), - geo_column=pdkc.GeoColumnType.QUADBIN, + aggregation_exp="sum(population) as population_sum", +) + +layer = pdk.Layer( + "QuadbinTileLayer", + data=data, get_fill_color=[200, 0, 80], pickable=True, ) @@ -27,4 +32,4 @@ view_state = pdk.ViewState(latitude=36, longitude=-7.44, zoom=5) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_layer_quadbin_table.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_layer_quadbin_table.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_tileset.py b/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_tileset.py index 8c8126e6810..e2f29358a29 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_tileset.py +++ b/bindings/pydeck-carto/examples/scripts/carto_layer_quadbin_tileset.py @@ -7,18 +7,24 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() -layer = pdk.Layer( - "CartoLayer", - data="carto-demo-data.demo_tilesets" +data = pdkc.sources.quadbin_tileset_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + table_name="carto-demo-data.demo_tilesets" ".derived_spatialfeatures_usa_quadbin15_v1_yearly_v2_tileset", - type_=pdkc.MapType.TILESET, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), + aggregation_exp="sum(population) as population_sum", +) + +layer = pdk.Layer( + "QuadbinTileLayer", + data=data, get_fill_color=[200, 0, 80], pickable=True, ) @@ -26,4 +32,4 @@ view_state = pdk.ViewState(latitude=44, longitude=-122, zoom=3) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_layer_quadbin_tileset.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_layer_quadbin_tileset.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_styles_color_bins.py b/bindings/pydeck-carto/examples/scripts/carto_styles_color_bins.py index a1f9aca6293..68ed73a565c 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_styles_color_bins.py +++ b/bindings/pydeck-carto/examples/scripts/carto_styles_color_bins.py @@ -7,18 +7,23 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() -layer = pdk.Layer( - "CartoLayer", - data="SELECT geom, pct_higher_ed " +data = pdkc.sources.vector_query_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + sql_query="SELECT geom, pct_higher_ed " "FROM `cartobq.public_account.higher_edu_by_county`", - type_=pdkc.MapType.QUERY, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), +) + +layer = pdk.Layer( + "VectorTileLayer", + data=data, get_fill_color=pdkc.styles.color_bins( "pct_higher_ed", [0, 20, 30, 40, 50, 60, 70], "PinkYl" ), @@ -30,4 +35,4 @@ view_state = pdk.ViewState(latitude=38, longitude=-98, zoom=3) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_styles_color_bins.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_styles_color_bins.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_styles_color_categories.py b/bindings/pydeck-carto/examples/scripts/carto_styles_color_categories.py index 651fff1ee82..371be6a0ed0 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_styles_color_categories.py +++ b/bindings/pydeck-carto/examples/scripts/carto_styles_color_categories.py @@ -7,17 +7,22 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() + +data = pdkc.sources.vector_query_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + sql_query="SELECT geom, landuse_type FROM `cartobq.public_account.wburg_parcels`", +) layer = pdk.Layer( - "CartoLayer", - data="SELECT geom, landuse_type FROM `cartobq.public_account.wburg_parcels`", - type_=pdkc.MapType.QUERY, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), + "VectorTileLayer", + data=data, get_fill_color=pdkc.styles.color_categories( "landuse_type", [ @@ -43,4 +48,4 @@ view_state = pdk.ViewState(latitude=40.715, longitude=-73.959, zoom=14) r = pdk.Deck(layer, map_style=pdk.map_styles.LIGHT, initial_view_state=view_state) -r.to_html("carto_styles_color_categories.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_styles_color_categories.html")) diff --git a/bindings/pydeck-carto/examples/scripts/carto_styles_color_continuous.py b/bindings/pydeck-carto/examples/scripts/carto_styles_color_continuous.py index 95020244681..2788f2d10fa 100644 --- a/bindings/pydeck-carto/examples/scripts/carto_styles_color_continuous.py +++ b/bindings/pydeck-carto/examples/scripts/carto_styles_color_continuous.py @@ -7,17 +7,23 @@ import pydeck as pdk import pydeck_carto as pdkc from carto_auth import CartoAuth +from os.path import join, dirname carto_auth = CartoAuth.from_oauth() -pdkc.register_carto_layer() +pdkc.register_layers() + +data = pdkc.sources.vector_query_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + sql_query="SELECT geom, value FROM cartobq.public_account.temps", +) + layer = pdk.Layer( - "CartoLayer", - data="SELECT geom, value FROM cartobq.public_account.temps", - type_=pdkc.MapType.QUERY, - connection=pdkc.CartoConnection.CARTO_DW, - credentials=pdkc.get_layer_credentials(carto_auth), + "VectorTileLayer", + data=data, get_fill_color=pdkc.styles.color_continuous( "value", [70, 75, 80, 85, 90, 95, 100], "Peach" ), @@ -27,4 +33,4 @@ view_state = pdk.ViewState(latitude=34, longitude=-98, zoom=3) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("carto_styles_color_continuous.html", open_browser=True) +r.to_html(join(dirname(__file__), "carto_styles_color_continuous.html")) diff --git a/bindings/pydeck-carto/examples/scripts/hello_world.py b/bindings/pydeck-carto/examples/scripts/hello_world.py index e2f6704ad4b..7b4d6d419fd 100644 --- a/bindings/pydeck-carto/examples/scripts/hello_world.py +++ b/bindings/pydeck-carto/examples/scripts/hello_world.py @@ -7,20 +7,23 @@ import pydeck as pdk import pydeck_carto as pdkc +from carto_auth import CartoAuth +from os.path import join, dirname -pdkc.register_carto_layer() +carto_auth = CartoAuth.from_oauth() + +pdkc.register_layers() + +data = pdkc.sources.vector_query_source( + access_token=carto_auth.get_access_token(), + api_base_url=carto_auth.get_api_base_url(), + connection_name="carto_dw", + sql_query="SELECT geom, name FROM cartobq.public_account.populated_places", +) layer = pdk.Layer( - "CartoLayer", - data="SELECT geom, name FROM cartobq.public_account.populated_places", - type_=pdkc.MapType.QUERY, - connection=pdk.types.String("bqconnection"), - credentials={ - "apiBaseUrl": "https://gcp-us-east1.api.carto.com", - "accessToken": "eyJhbGciOiJIUzI1NiJ9" - ".eyJhIjoiYWNfN3hoZnd5bWwiLCJqdGkiOiIwMGQ1NmFiMyJ9" - ".zqsprFkxiafKXQ91PDB8845nVeWGVnuLg22v49J3Wiw", - }, + "VectorTileLayer", + data=data, get_fill_color=[238, 77, 90], point_radius_min_pixels=2.5, ) @@ -28,4 +31,4 @@ view_state = pdk.ViewState(latitude=0, longitude=0, zoom=1) r = pdk.Deck(layer, map_style=pdk.map_styles.ROAD, initial_view_state=view_state) -r.to_html("hello_world.html", open_browser=True) +r.to_html(join(dirname(__file__), "hello_world.html")) diff --git a/bindings/pydeck-carto/pydeck_carto/__init__.py b/bindings/pydeck-carto/pydeck_carto/__init__.py index 187787eda64..755eb4eff27 100644 --- a/bindings/pydeck-carto/pydeck_carto/__init__.py +++ b/bindings/pydeck-carto/pydeck_carto/__init__.py @@ -1,19 +1,11 @@ from ._version import __version__ -from .layer import ( - MapType, - CartoConnection, - GeoColumnType, - register_carto_layer, - get_layer_credentials, -) +from .layer import register_layers +from . import sources from . import styles __all__ = [ "__version__", - "MapType", - "CartoConnection", - "GeoColumnType", - "register_carto_layer", - "get_layer_credentials", + "register_layers", + "sources", "styles", ] diff --git a/bindings/pydeck-carto/pydeck_carto/_version.py b/bindings/pydeck-carto/pydeck_carto/_version.py index 3dc1f76bc69..9aafb2b8b12 100644 --- a/bindings/pydeck-carto/pydeck_carto/_version.py +++ b/bindings/pydeck-carto/pydeck_carto/_version.py @@ -1 +1 @@ -__version__ = "0.1.0" +__version__ = "0.2.0b0" diff --git a/bindings/pydeck-carto/pydeck_carto/layer.py b/bindings/pydeck-carto/pydeck_carto/layer.py index ae541cbba82..c123fb13cda 100644 --- a/bindings/pydeck-carto/pydeck_carto/layer.py +++ b/bindings/pydeck-carto/pydeck_carto/layer.py @@ -1,7 +1,7 @@ import pydeck as pdk H3_VERSION = "~4.1.*" -DECKGL_VERSION = "~8.8.*" +DECKGL_VERSION = "~9.0.*" LIBRARIES_TO_INCLUDE = [ f"npm/h3-js@{H3_VERSION}/dist/h3-js.umd.js", @@ -12,33 +12,18 @@ CARTO_LAYER_BUNDLE_URL = f"https://cdn.jsdelivr.net/combine/{SELECTED_LIBRARIES}" -class MapType: - QUERY = pdk.types.String("query") - TABLE = pdk.types.String("table") - TILESET = pdk.types.String("tileset") - - -class CartoConnection: - CARTO_DW = pdk.types.String("carto_dw") - - -class GeoColumnType: - H3 = pdk.types.String("h3") - QUADBIN = pdk.types.String("quadbin") - - -def register_carto_layer(): - """Add CartoLayer JS bundle to pydeck's custom libraries.""" - library_name = "CartoLayerLibrary" +def register_layers(): + """Add carto layers JS bundle to pydeck's custom libraries.""" + library_name = "CartoLibrary" custom_library = { "libraryName": library_name, "resourceUri": CARTO_LAYER_BUNDLE_URL, } default_layer_attributes = { - "CartoLayer": { - "client_id": pdk.types.String("pydeck-carto"), - "on_data_error": pdk.types.Function("notifyError"), - } + "VectorTileLayer": {"on_data_error": pdk.types.Function("notifyError")}, + "H3TileLayer": {"on_data_error": pdk.types.Function("notifyError")}, + "QuadbinTileLayer": {"on_data_error": pdk.types.Function("notifyError")}, + "RasterTileLayer": {"on_data_error": pdk.types.Function("notifyError")}, } configuration = """{ functions: { @@ -73,19 +58,3 @@ def register_carto_layer(): ) if not exists: pdk.settings.custom_libraries.append(custom_library) - - -def get_layer_credentials(carto_auth) -> dict: - """Get the layer credentials object to gather information - from carto warehouses. - - The return object has the following structure: - ``{"apiVersion": "v3", "apiBaseUrl": "...", "accessToken": "...",}`` - """ - api_base_url = carto_auth.get_api_base_url() - access_token = carto_auth.get_access_token() - return { - "apiVersion": "v3", - "apiBaseUrl": api_base_url, - "accessToken": access_token, - } diff --git a/bindings/pydeck-carto/pydeck_carto/sources.py b/bindings/pydeck-carto/pydeck_carto/sources.py new file mode 100644 index 00000000000..b8c8e445e75 --- /dev/null +++ b/bindings/pydeck-carto/pydeck_carto/sources.py @@ -0,0 +1,278 @@ +import pydeck as pdk +from typing import TypedDict, List, Union +from typing_extensions import NotRequired, Unpack, assert_type + +# TYPES + + +class Options(TypedDict): + pass + + +class BaseSourceOptions(Options): + connection_name: str + access_token: str + api_base_url: str + + +class TableSourceOptions(BaseSourceOptions): + table_name: str + spatial_data_column: NotRequired[str] + + +QueryParameterValue = Union[str, int, float, bool] + + +class QuerySourceOptions(BaseSourceOptions): + sql_query: str + spatial_data_column: NotRequired[str] + query_parameters: NotRequired[ + List[Union[QueryParameterValue, List[QueryParameterValue]]] + ] + + +class TilesetSourceOptions(BaseSourceOptions): + table_name: str + + +class ColumnOptions(Options): + columns: NotRequired[List[str]] + + +class AggregationOptions(Options): + aggregation_exp: str + aggregation_res_level: NotRequired[int] + + +# VALIDATORS + + +def validate_str(args: Options, arg: str, required: bool = True): + """Validates given key on an options object is a string.""" + if arg not in args and required: + raise AssertionError('Missing argument "{}".'.format(arg)) + elif arg in args: + assert type(args[arg]) is str, "Argument {} must be of type str".format(arg) + + +def validate_int(args: Options, arg: str, required: bool = True): + """Validates given key on an options object is an int.""" + if arg not in args and required: + raise AssertionError('Missing argument "{}".'.format(arg)) + elif arg in args: + assert type(args[arg]) is int, "Argument {} must be of type int".format(arg) + + +# BASE SOURCES + + +def base_options(**kwargs: Unpack[BaseSourceOptions]): + assert_type(kwargs, BaseSourceOptions) + validate_str(kwargs, "connection_name") + validate_str(kwargs, "access_token") + validate_str(kwargs, "api_base_url") + return { + "connectionName": kwargs["connection_name"], + "accessToken": kwargs["access_token"], + "apiBaseUrl": kwargs["api_base_url"], + "clientId": "pydeck-carto", + } + + +def table_options(**kwargs: Unpack[TableSourceOptions]): + assert_type(kwargs, TableSourceOptions) + validate_str(kwargs, "table_name") + validate_str(kwargs, "spatial_data_column", False) + return { + "tableName": kwargs.get("table_name"), + **( + {"spatialDataColumn": kwargs["spatial_data_column"]} + if "spatial_data_column" in kwargs + else {} + ), + **base_options(**kwargs), + } + + +def query_options(**kwargs: Unpack[QuerySourceOptions]): + assert_type(kwargs, QuerySourceOptions) + validate_str(kwargs, "sql_query") + validate_str(kwargs, "spatial_data_column", False) + return { + "sqlQuery": kwargs.get("sql_query"), + **( + {"spatialDataColumn": kwargs["spatial_data_column"]} + if "spatial_data_column" in kwargs + else {} + ), + **( + {"queryParameters": kwargs["query_parameters"]} + if "query_parameters" in kwargs + else {} + ), + **base_options(**kwargs), + } + + +def tileset_options(**kwargs: Unpack[TilesetSourceOptions]): + assert_type(kwargs, TilesetSourceOptions) + validate_str(kwargs, "table_name") + return { + "tableName": kwargs["table_name"], + **base_options(**kwargs), + } + + +def column_options(**kwargs: Unpack[ColumnOptions]): + assert_type(kwargs, ColumnOptions) + return {"columns": kwargs["columns"]} if "columns" in kwargs else {} + + +def aggregation_options(**kwargs: Unpack[AggregationOptions]): + assert_type(kwargs, AggregationOptions) + validate_str(kwargs, "aggregation_exp") + validate_int(kwargs, "aggregation_res_level", False) + return { + "aggregationExp": kwargs["aggregation_exp"], + **( + {"aggregationResLevel": kwargs["aggregation_res_level"]} + if "aggregation_res_level" in kwargs + else {} + ), + } + + +# VECTOR SOURCES + + +class VectorTableSourceOptions(TableSourceOptions, ColumnOptions): + """Options for vector_table_source.""" + + pass + + +class VectorQuerySourceOptions(QuerySourceOptions, ColumnOptions): + """Options for vector_query_source.""" + + pass + + +class VectorTilesetSourceOptions(TilesetSourceOptions): + """Options for vector_tileset_source.""" + + pass + + +def vector_table_source(**kwargs: Unpack[VectorTableSourceOptions]): + """Defines a table as a data source for one or more vector layers.""" + return pdk.types.Function( + "vectorTableSource", **{**column_options(**kwargs), **table_options(**kwargs)} + ).serialize() + + +def vector_query_source(**kwargs: Unpack[VectorQuerySourceOptions]): + """Defines a query as a data source for one or more vector layers.""" + return pdk.types.Function( + "vectorQuerySource", **{**column_options(**kwargs), **query_options(**kwargs)} + ).serialize() + + +def vector_tileset_source(**kwargs: Unpack[VectorTilesetSourceOptions]): + """Defines a tileset as a data source for one or more vector layers.""" + return pdk.types.Function( + "vectorTilesetSource", **tileset_options(**kwargs) + ).serialize() + + +# H3 SOURCES + + +class H3TableSourceOptions(TableSourceOptions, AggregationOptions): + """Options for h3_table_source.""" + + pass + + +class H3QuerySourceOptions(QuerySourceOptions, AggregationOptions): + """Options for h3_query_source.""" + + pass + + +class H3TilesetSourceOptions(TilesetSourceOptions, AggregationOptions): + """Options for h3_tileset_source.""" + + pass + + +def h3_table_source(**kwargs: Unpack[H3TableSourceOptions]): + """Defines a table as a data source for one or more H3 layers.""" + return pdk.types.Function( + "h3TableSource", **{**aggregation_options(**kwargs), **table_options(**kwargs)} + ).serialize() + + +def h3_query_source(**kwargs: Unpack[H3QuerySourceOptions]): + """Defines a query as a data source for one or more H3 layers.""" + return pdk.types.Function( + "h3QuerySource", **{**aggregation_options(**kwargs), **query_options(**kwargs)} + ).serialize() + + +def h3_tileset_source(**kwargs: Unpack[H3TilesetSourceOptions]): + """Defines a tileset as a data source for one or more H3 layers.""" + return pdk.types.Function( + "h3TilesetSource", **tileset_options(**kwargs) + ).serialize() + + +# QUADBIN SOURCES + + +class QuadbinTableSourceOptions(TableSourceOptions, AggregationOptions): + """Options for quadbin_table_source.""" + + pass + + +class QuadbinQuerySourceOptions(QuerySourceOptions, AggregationOptions): + """Options for quadbin_query_source.""" + + pass + + +class QuadbinTilesetSourceOptions(TilesetSourceOptions, AggregationOptions): + """Options for quadbin_tileset_source.""" + + pass + + +def quadbin_table_source(**kwargs: Unpack[QuadbinTableSourceOptions]): + """Defines a table as a data source for one or more quadbin layers.""" + return pdk.types.Function( + "quadbinTableSource", + **{**aggregation_options(**kwargs), **table_options(**kwargs)} + ).serialize() + + +def quadbin_query_source(**kwargs: Unpack[QuadbinQuerySourceOptions]): + """Defines a query as a data source for one or more quadbin layers.""" + return pdk.types.Function( + "quadbinQuerySource", + **{**aggregation_options(**kwargs), **query_options(**kwargs)} + ).serialize() + + +def quadbin_tileset_source(**kwargs: Unpack[QuadbinTilesetSourceOptions]): + """Defines a tileset as a data source for one or more quadbin layers.""" + return pdk.types.Function( + "quadbinTilesetSource", **tileset_options(**kwargs) + ).serialize() + + +# RASTER SOURCES (EXPERIMENTAL) + + +def raster_tileset_source(**kwargs): + """EXPERIMENTAL.""" + raise RuntimeError("not implemented") diff --git a/bindings/pydeck-carto/requirements/requirements-dev.txt b/bindings/pydeck-carto/requirements/requirements-dev.txt index 8b101fe80cd..c2ee28c2446 100644 --- a/bindings/pydeck-carto/requirements/requirements-dev.txt +++ b/bindings/pydeck-carto/requirements/requirements-dev.txt @@ -1,10 +1,12 @@ -wheel==0.37.1 -flake8==4.0.1 black==22.3.0 +carto-auth>=0.2.0 +flake8==4.0.1 ipython>=7.8.0 -tokenize-rt>=3.2.0 -twine==4.0.0 +pytest-cov==3.0.0 +pytest-mock==3.8.2 pytest==7.1.2 requests-mock==1.9.3 -pytest-mock==3.8.2 -pytest-cov==3.0.0 +tokenize-rt>=3.2.0 +twine==4.0.0 +typing-extensions>=4.0.0 +wheel==0.37.1 diff --git a/bindings/pydeck-carto/setup.py b/bindings/pydeck-carto/setup.py index a6cbd8a7034..aa29b3ddebf 100644 --- a/bindings/pydeck-carto/setup.py +++ b/bindings/pydeck-carto/setup.py @@ -20,7 +20,8 @@ python_requires=">=3.8", install_requires=[ "pydeck>=0.8.0", - "carto-auth>=0.1.0", + "carto-auth>=0.2.0", + "typing-extensions>=4.0.0", ], classifiers=[ "Development Status :: 5 - Production/Stable", diff --git a/bindings/pydeck-carto/tests/test_layer.py b/bindings/pydeck-carto/tests/test_layer.py index 4da61ffcfbb..61796147daa 100644 --- a/bindings/pydeck-carto/tests/test_layer.py +++ b/bindings/pydeck-carto/tests/test_layer.py @@ -1,50 +1,16 @@ -import json import pydeck as pdk -from carto_auth import CartoAuth -from pydeck_carto import register_carto_layer, get_layer_credentials -from pydeck_carto.layer import MapType, CartoConnection +from pydeck_carto import register_layers -def test_register_carto_layer(): +def test_register_layers(): pdk.settings.configuration = None pdk.settings.default_layer_attributes = None pdk.settings.custom_libraries == [] - register_carto_layer() + register_layers() assert "notifyError" in pdk.settings.configuration - assert "CartoLayer" in pdk.settings.default_layer_attributes - assert pdk.settings.custom_libraries[0]["libraryName"] == "CartoLayerLibrary" - - -def test_get_layer_credentials(): - carto_auth = CartoAuth( - mode="oauth", - api_base_url="https://api.carto.com", - access_token="1234567890", - expiration=10000000000, - ) - assert get_layer_credentials(carto_auth) == { - "apiVersion": "v3", - "apiBaseUrl": "https://api.carto.com", - "accessToken": "1234567890", - } - - -def test_carto_layer_json(): - layer = pdk.Layer( - "CartoLayer", - data="carto-demo-data.demo_tables.wrong_table", - type_=MapType.TABLE, - connection=CartoConnection.CARTO_DW, - credentials={}, - ) - json_input = json.loads(layer.to_json()) - - assert json_input["@@type"] == "CartoLayer" - assert json_input["data"] == "carto-demo-data.demo_tables.wrong_table" - assert json_input["type"] == "table" - assert json_input["connection"] == "carto_dw" - assert json_input["credentials"] == {} - # Default attributes - assert json_input["clientId"] == "pydeck-carto" - assert json_input["onDataError"] == {"@@function": "notifyError"} + assert "VectorTileLayer" in pdk.settings.default_layer_attributes + assert "H3TileLayer" in pdk.settings.default_layer_attributes + assert "QuadbinTileLayer" in pdk.settings.default_layer_attributes + assert "RasterTileLayer" in pdk.settings.default_layer_attributes + assert pdk.settings.custom_libraries[0]["libraryName"] == "CartoLibrary" diff --git a/bindings/pydeck-carto/tests/test_sources.py b/bindings/pydeck-carto/tests/test_sources.py new file mode 100644 index 00000000000..db7cf2d0a0c --- /dev/null +++ b/bindings/pydeck-carto/tests/test_sources.py @@ -0,0 +1,164 @@ +from pydeck_carto.sources import ( + vector_table_source, + vector_query_source, + vector_tileset_source, + h3_table_source, + h3_query_source, + h3_tileset_source, + quadbin_table_source, + quadbin_query_source, + quadbin_tileset_source, +) +from typing import Any + +base_options: Any = { + "connection_name": "carto_dw", + "access_token": "1234", + "api_base_url": "https://carto.com", +} + +base_options_serialized: Any = { + "connectionName": "carto_dw", + "accessToken": "1234", + "apiBaseUrl": "https://carto.com", + "clientId": "pydeck-carto", +} + +# VECTOR + + +def test_vector_table_source(): + assert vector_table_source( + table_name="project.database.table", + spatial_data_column="geom", + **base_options, + ) == { + "@@function": "vectorTableSource", + "tableName": "project.database.table", + "spatialDataColumn": "geom", + **base_options_serialized, + } + + +def test_vector_query_source(): + assert vector_query_source( + sql_query="select * from project.database.table", + spatial_data_column="geom", + **base_options, + ) == { + "@@function": "vectorQuerySource", + "sqlQuery": "select * from project.database.table", + "spatialDataColumn": "geom", + **base_options_serialized, + } + + +def test_vector_tileset_source(): + assert vector_tileset_source( + table_name="project.database.table", + **base_options, + ) == { + "@@function": "vectorTilesetSource", + "tableName": "project.database.table", + **base_options_serialized, + } + + +# H3 + + +def test_h3_table_source(): + assert h3_table_source( + table_name="project.database.table", + spatial_data_column="geom", + aggregation_exp="SUM(pop) AS total_population", + aggregation_res_level=6, + **base_options, + ) == { + "@@function": "h3TableSource", + "tableName": "project.database.table", + "spatialDataColumn": "geom", + "aggregationExp": "SUM(pop) AS total_population", + "aggregationResLevel": 6, + **base_options_serialized, + } + + +def test_h3_query_source(): + assert h3_query_source( + sql_query="select * from project.database.table", + spatial_data_column="geom", + aggregation_exp="SUM(pop) AS total_population", + aggregation_res_level=6, + **base_options, + ) == { + "@@function": "h3QuerySource", + "sqlQuery": "select * from project.database.table", + "spatialDataColumn": "geom", + "aggregationExp": "SUM(pop) AS total_population", + "aggregationResLevel": 6, + **base_options_serialized, + } + + +def test_h3_tileset_source(): + assert h3_tileset_source(table_name="project.database.table", **base_options,) == { + "@@function": "h3TilesetSource", + "tableName": "project.database.table", + **base_options_serialized, + } + + +# QUADBIN + + +def test_quadbin_table_source(): + assert quadbin_table_source( + table_name="project.database.table", + spatial_data_column="geom", + aggregation_exp="SUM(pop) AS total_population", + aggregation_res_level=6, + **base_options, + ) == { + "@@function": "quadbinTableSource", + "tableName": "project.database.table", + "spatialDataColumn": "geom", + "aggregationExp": "SUM(pop) AS total_population", + "aggregationResLevel": 6, + **base_options_serialized, + } + + +def test_quadbin_query_source(): + assert quadbin_query_source( + sql_query="select * from project.database.table", + spatial_data_column="geom", + aggregation_exp="SUM(pop) AS total_population", + aggregation_res_level=6, + **base_options, + ) == { + "@@function": "quadbinQuerySource", + "sqlQuery": "select * from project.database.table", + "spatialDataColumn": "geom", + "aggregationExp": "SUM(pop) AS total_population", + "aggregationResLevel": 6, + **base_options_serialized, + } + + +def test_quadbin_tileset_source(): + assert quadbin_tileset_source( + table_name="project.database.table", + **base_options, + ) == { + "@@function": "quadbinTilesetSource", + "tableName": "project.database.table", + **base_options_serialized, + } + + +# RASTER + + +def test_raster_tileset_source(): + assert True # TODO diff --git a/bindings/pydeck/pydeck/_version.py b/bindings/pydeck/pydeck/_version.py index 10ba1c44737..7cca270a47b 100644 --- a/bindings/pydeck/pydeck/_version.py +++ b/bindings/pydeck/pydeck/_version.py @@ -1 +1 @@ -__version__ = "0.8.0b4" +__version__ = "0.9.0b1" diff --git a/bindings/pydeck/pydeck/frontend_semver.py b/bindings/pydeck/pydeck/frontend_semver.py index 8d9c8cc7f49..d3046c7b5fc 100644 --- a/bindings/pydeck/pydeck/frontend_semver.py +++ b/bindings/pydeck/pydeck/frontend_semver.py @@ -1 +1 @@ -DECKGL_SEMVER = "~8.8.*" +DECKGL_SEMVER = "~9.0.*" diff --git a/modules/carto/bundle.ts b/modules/carto/bundle.ts index fc001fb71e2..6cc8066a21f 100644 --- a/modules/carto/bundle.ts +++ b/modules/carto/bundle.ts @@ -7,3 +7,7 @@ import * as CartoUtils from '@deck.gl/carto'; export * from '../layers/bundle/peer-dependency'; export const carto = CartoUtils; + +// Export CARTO library for pydeck integration. +// More info: https://github.com/ajduberstein/pydeck_custom_layer +globalThis.CartoLibrary = CartoUtils;