Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion examples/buildings.jGIS
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"color": "#086600",
"opacity": 1.0,
"source": "7a7ee6fd-c1e2-4c5d-a4e2-a7974db138a4",
"sourceLayer": "bingmlbuildings",
"type": "fill"
},
"type": "VectorTileLayer",
Expand Down
86 changes: 1 addition & 85 deletions packages/base/src/formbuilder/objectform/vectorlayerform.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,16 @@
import { IDict, IVectorLayer, IVectorTileSource } from '@jupytergis/schema';

import { IDict, IVectorLayer } from '@jupytergis/schema';
import { IChangeEvent } from '@rjsf/core';
import { getSourceLayerNames } from '../../tools';
import { ILayerProps, LayerPropertiesForm } from './layerform';

/**
* The form to modify a vector layer.
*/
export class VectorLayerPropertiesForm extends LayerPropertiesForm {
protected currentFormData: IVectorLayer;
private sourceLayers: string[] = [];
private currentSourceId: string;

constructor(props: ILayerProps) {
super(props);

this.fetchSourceLayers(this.props.sourceData as IVectorLayer | undefined);

// If there is a source form attached, we listen to its changes
if (this.sourceFormChangedSignal) {
this.sourceFormChangedSignal.connect((sender, sourceData) => {
if (this.props.sourceType === 'VectorTileSource') {
this.fetchSourceLayers(
this.currentFormData,
sourceData as IVectorTileSource
);
}
});
}
props.model.clientStateChanged.connect(() => {
if (!props.model.localState?.selected?.value) {
return;
}
const l = this.props.model.getLayer(
Object.keys(props.model.localState.selected.value)[0]
);
const source = this.props.model.getSource(l?.parameters!.source);

if (!source || source.type !== 'VectorTileSource') {
return;
}

const sourceData = source.parameters as IVectorTileSource;

this.fetchSourceLayers(this.currentFormData, sourceData);
});
}

protected onFormChange(e: IChangeEvent): void {
Expand All @@ -59,11 +25,6 @@ export class VectorLayerPropertiesForm extends LayerPropertiesForm {
if (!source || source.type !== 'VectorTileSource') {
return;
}

this.fetchSourceLayers(
this.currentFormData,
source.parameters as IVectorTileSource
);
}

protected processSchema(
Expand All @@ -78,50 +39,5 @@ export class VectorLayerPropertiesForm extends LayerPropertiesForm {
if (!data) {
return;
}

// Show a dropdown for available sourceLayers if available
// And automatically select one
if (this.sourceLayers.length !== 0) {
if (!data.sourceLayer || !this.sourceLayers.includes(data.sourceLayer)) {
data.sourceLayer = this.sourceLayers[0];
}

schema.properties.sourceLayer.enum = this.sourceLayers;
}
}

private async fetchSourceLayers(
data: IVectorLayer | undefined,
sourceData?: IVectorTileSource
) {
if (data && data.source) {
this.currentSourceId = data.source;

if (!sourceData) {
const currentSource = this.props.model.getSource(data.source);

if (!currentSource || currentSource.type !== 'VectorTileSource') {
this.sourceLayers = [];
this.forceUpdate();
return;
}

sourceData = currentSource.parameters as IVectorTileSource;
}

try {
this.sourceLayers = await getSourceLayerNames(
sourceData.url,
sourceData.urlParameters
);
this.forceUpdate();
} catch (e) {
console.error(e);
}
} else {
this.currentSourceId = '';
this.sourceLayers = [];
this.forceUpdate();
}
}
}
22 changes: 1 addition & 21 deletions packages/base/src/panelview/components/filter-panel/Filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ import { Button, ReactWidget } from '@jupyterlab/ui-components';
import { Panel } from '@lumino/widgets';
import { cloneDeep } from 'lodash';
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
import { debounce, getLayerTileInfo } from '../../../tools';
import { debounce, loadFile } from '../../../tools';
import { IControlPanelModel } from '../../../types';
import FilterRow from './FilterRow';
import { loadFile } from '../../../tools';

/**
* The filters panel widget.
Expand Down Expand Up @@ -165,7 +164,6 @@ const FilterComponent = (props: IFilterComponentProps) => {
}
const layer = model.getLayer(currentLayer ?? selectedLayer);
const source = model.getSource(layer?.parameters?.source);
const { latitude, longitude, extent, zoom } = model.getOptions();

if (!source || !layer) {
return;
Expand All @@ -189,24 +187,6 @@ const FilterComponent = (props: IFilterComponentProps) => {
}

switch (source.type) {
case 'VectorTileSource': {
try {
const tile = await getLayerTileInfo(source?.parameters?.url, {
latitude,
longitude,
extent,
zoom
});
const layerValue = tile.layers[layer.parameters?.sourceLayer];
for (let i = 0; i < layerValue.length; i++) {
const feature = layerValue.feature(i);
addFeatureValue(feature.properties, aggregatedProperties);
}
} catch (error) {
console.warn(`Error fetching tile info: ${error}`);
}
break;
}
case 'GeoJSONSource': {
const data = await loadFile({
filepath: source.parameters?.path,
Expand Down
22 changes: 3 additions & 19 deletions packages/base/src/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ import Protobuf from 'pbf';

import { VectorTile } from '@mapbox/vector-tile';

import { URLExt } from '@jupyterlab/coreutils';
import { PathExt, URLExt } from '@jupyterlab/coreutils';
import { Contents, ServerConnection } from '@jupyterlab/services';
import * as d3Color from 'd3-color';
import { PathExt } from '@jupyterlab/coreutils';
import shp from 'shpjs';

import {
IDict,
IJGISLayerBrowserRegistry,
IJGISOptions,
IRasterLayerGalleryEntry,
IJGISSource,
IJupyterGISModel
IJupyterGISModel,
IRasterLayerGalleryEntry
} from '@jupytergis/schema';
import RASTER_LAYER_GALLERY from '../rasterlayer_gallery/raster_layer_gallery.json';
import { getGdal } from './gdal';
Expand Down Expand Up @@ -290,21 +289,6 @@ export async function getLayerTileInfo(
return tile;
}

export async function getSourceLayerNames(
tileUrl: string,
urlParameters?: IDict<string>
) {
const tile = await getLayerTileInfo(
tileUrl,
{ latitude: 0, longitude: 0, zoom: 0, extent: [] },
urlParameters
);

const layerNames = Object.keys(tile.layers);

return layerNames;
}

export interface IParsedStyle {
fillColor: string;
strokeColor: string;
Expand Down
4 changes: 0 additions & 4 deletions packages/schema/src/schema/vectorTileLayer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@
"default": "line",
"description": "The type of vector layer"
},
"sourceLayer": {
"type": "string",
"description": "The source layer to use"
},
"color": {
"type": "object",
"description": "The color of the the object"
Expand Down
4 changes: 0 additions & 4 deletions packages/schema/src/schema/vectorlayer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@
"default": "line",
"description": "The type of vector layer"
},
"sourceLayer": {
"type": "string",
"description": "The source layer to use"
},
"color": {
"type": "object",
"description": "The color of the the object"
Expand Down
10 changes: 1 addition & 9 deletions python/jupytergis_lab/jupytergis_lab/notebook/gis_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
LayerType,
SourceType,
)
from .utils import get_source_layer_names, normalize_path
from .utils import normalize_path

logger = logging.getLogger(__file__)

Expand Down Expand Up @@ -172,7 +172,6 @@ def add_vectortile_layer(
self,
url: str,
name: str = "Vector Tile Layer",
source_layer: str | None = None,
attribution: str = "",
min_zoom: int = 0,
max_zoom: int = 24,
Expand All @@ -189,15 +188,9 @@ def add_vectortile_layer(

:param name: The name that will be used for the object in the document.
:param url: The tiles url.
:param source_layer: The source layer to use.
:param attribution: The attribution.
:param opacity: The opacity, between 0 and 1.
"""
source_layers = get_source_layer_names(url)
if source_layer is None and len(source_layers) == 1:
source_layer = source_layers[0]
if source_layer not in source_layers:
raise ValueError(f"source_layer should be one of {source_layers}")

source = {
"type": SourceType.VectorTileSource,
Expand All @@ -224,7 +217,6 @@ def add_vectortile_layer(
"source": source_id,
"type": type,
"opacity": opacity,
"sourceLayer": source_layer,
"color": color_expr,
"opacity": opacity,
},
Expand Down
16 changes: 0 additions & 16 deletions python/jupytergis_lab/jupytergis_lab/notebook/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,6 @@ class VectorTileTests(unittest.TestCase):
def setUp(self):
self.doc = GISDocument()

def test_sourcelayer(self):
# If there are multiple source layers available and none specified we raise
with self.assertRaises(ValueError):
self.doc.add_vectortile_layer(
"https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/tile/{z}/{y}/{x}.pbf"
)

# If there is on source layer available and none specified we select it
vector_tile = self.doc.add_vectortile_layer(
"https://planetarycomputer.microsoft.com/api/data/v1/vector/collections/ms-buildings/tilesets/global-footprints/tiles/{z}/{x}/{y}"
)
assert (
self.doc.layers[vector_tile]["parameters"]["sourceLayer"]
== "bingmlbuildings"
)


class TiffLayerTests(unittest.TestCase):
def setUp(self):
Expand Down
18 changes: 0 additions & 18 deletions python/jupytergis_lab/jupytergis_lab/notebook/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from enum import Enum
from urllib.parse import urljoin
import requests
import mapbox_vector_tile


class MESSAGE_ACTION(str, Enum):
Expand All @@ -24,20 +23,3 @@ def normalize_path(path: str) -> str:
return path
else:
return os.path.abspath(os.path.join(os.getcwd(), path))


def get_source_layer_names(tile_url):
# Fetch a sample tile (e.g., z=0, x=0, y=0)
sample_tile_url = tile_url.format(z=0, x=0, y=0)
response = requests.get(sample_tile_url)
response.raise_for_status()

tile_data = response.content
tile = mapbox_vector_tile.decode(tile_data)

layer_names = list(tile.keys())

if len(layer_names) != 0:
return layer_names
else:
raise ValueError("No layer found in the tile")
1 change: 0 additions & 1 deletion python/jupytergis_lab/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ classifiers = [
"Programming Language :: Python :: 3.12",
]
dependencies = [
"mapbox-vector-tile",
"requests",
"jupyter-ydoc>=2,<4",
"ypywidgets>=0.9.0,<0.10.0",
Expand Down
8 changes: 0 additions & 8 deletions python/jupytergis_qgis/jupytergis_qgis/qgis_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from urllib.parse import unquote
from uuid import uuid4

from jupytergis_lab.notebook.utils import get_source_layer_names
from PyQt5.QtGui import QColor
from qgis.core import (
QgsApplication,
Expand Down Expand Up @@ -224,13 +223,6 @@ def qgis_layer_to_jgis(
if geometry_type == 2:
color["fill-color"] = symbol.color().name() + alpha

# TODO Load source-layer properly, from qgis symbology?
try:
source_layer = get_source_layer_names(url)[0]
layer_parameters["sourceLayer"] = source_layer
except ValueError:
pass

layer_parameters.update(type="fill")
layer_parameters.update(color=color)

Expand Down
1 change: 0 additions & 1 deletion python/jupytergis_qgis/jupytergis_qgis/tests/test_qgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ def test_qgis_saver():
"stroke-color": "#e5b636ff",
},
"source": source_ids[2],
"sourceLayer": "bingmlbuildings",
"type": "fill",
},
"type": "VectorTileLayer",
Expand Down
Loading