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

Remote widget calculation for spatial indexed sources #898

Merged

Conversation

zbigg
Copy link
Contributor

@zbigg zbigg commented Jul 31, 2024

Description

Shortcut: https://app.shortcut.com/cartoteam/story/425306

  1. Spatial index sources use remote widgets calculation.
  2. addSource: Support for spatialDataType, spatialIndexColumn instead of old geoColumn, at least for remote widgets
  3. remote widgets: support for new parameters spatialDataType, spatialIndexColumn, spatialFiltersResolution and spatialFiltersMode

Type of change

  • Feature

Acceptance

...

Basic checklist

  • Good PR name
  • Shortcut link
  • Changelog entry
  • Just one issue per PR
  • GitHub labels
  • Proper status & reviewers
  • Tests
  • Documentation

Copy link

github-actions bot commented Jul 31, 2024

Pull Request Test Coverage Report for Build 10722661073

Details

  • 21 of 38 (55.26%) changed or added relevant lines in 2 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-0.2%) to 70.957%

Changes Missing Coverage Covered Lines Changed/Added Lines %
packages/react-api/src/api/model.js 16 22 72.73%
packages/react-widgets/src/hooks/useWidgetFetch.js 5 16 31.25%
Totals Coverage Status
Change from base Build 10145530283: -0.2%
Covered Lines: 2835
Relevant Lines: 3678

💛 - Coveralls

Copy link

github-actions bot commented Jul 31, 2024

Visit the preview URL for this PR (updated for commit c5e9740):

https://cartodb-fb-storybook-react-dev--pr898-feature-sc-42530-68u0achy.web.app

(expires Thu, 12 Sep 2024 14:47:06 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 517cc4d31d7e09cf277774e034094b67c301cd4c

@zbigg zbigg force-pushed the feature/sc-425306/c4r-support-for-spatial-indexes-and-proper branch from 1049f70 to cdeb4cf Compare September 3, 2024 13:21
Copy link
Contributor

@jmgaya jmgaya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything seems correct and the enhancements seem correct for supporting spatial indexes, at least from my side/knowledge, great job!

queryParams.spatialFilters = JSON.stringify(spatialFilters);
queryParams.spatialDataType = spatialDataType;
if (spatialDataType !== 'geo') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see geo repeated a few times in this file, so what do you think about extracting it somewhere and naming it as something like const DEFAULT_SPATIAL_DATA_TYPE?

queryParams.spatialFilters = JSON.stringify(spatialFilters);
queryParams.spatialDataType = spatialDataType;
if (spatialDataType !== 'geo') {
if (source.spatialFiltersResolution !== undefined) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity: Could source.spatialFiltersResolution be null at some point? If so, maybe we can double negate this expression to prevent this case, or is there any edge case related to a 0 resolution?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this we can't protect user from themselves.

If he passed number, he's ok. If he didn't passed anything (undefined), he's ok - default is used. If he passed null or object or date, it's his own fault - i don't believe that we should check every possible failure mode if we already defined that spatialFiltersResolution is optional number.

This is just API wrapper, nothing will explode - just weird stuff will be sent to.

(and btw, this is internal code - validation if required should be placed somewhere on top of widget)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking more about something like !!source.spatialFiltersResolution, WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like !!source.spatialFiltersResolution for one reason: who said, 0 is bad value for this parameter (is it?). I only care if user provided it or not - and that's why we have undefined in JS.

packages/react-api/src/types.d.ts Outdated Show resolved Hide resolved
@@ -93,6 +107,36 @@ export default function useWidgetFetch(
[global, viewport, spatialFilter]
);

const source2 = useMemo(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably a more descriptive name for this parameter would help our future ourselves? What about enrichedSource?

Comment on lines 75 to 76
if (source.geoColumn) {
const parsedGeoColumn = source.geoColumn ? source.geoColumn.split(':') : [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking source.geoColumn redundantly here – probably one or the other isn't required?

Comment on lines +80 to +83
} else if (parsedGeoColumn.length === 1) {
spatialDataColumn = parsedGeoColumn[0] || DEFAULT_GEO_COLUMN;
spatialDataType = 'geo';
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could parsedGeoColumn really be []? If so do we need a third case for it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so (and i've checked as i wasn't sure):

> "".split(':')
['']
> "a".split(':')
['a']
> "a:b".split(':')
['a', 'b']

dataResoultion?: number;
spatialDataType?: string;
spatialDataColumn?: string;
spatialFiltersResolution?: number;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spatialFilter parameter is singular, not plural – assuming these are related, should this be spatialFilterResolution instead? Note that this may become a public-facing API once added to @carto/api-client, though I do see the note in the AD that we may not expose it.

Copy link
Contributor Author

@zbigg zbigg Sep 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spatialFiltersResolution is term already used in platform maps API. Didn't invent this name

I think, creating another slightly different symbol would be confusing, so i would leave it as it is.

@thedae @josemaria-vilaplana I leave this comment to You. Maybe we should broaden reviews of new platform API that is about to be visible in many places us for long time
(wrong, see below)

Copy link
Contributor Author

@zbigg zbigg Sep 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, platform APIs already spell this as spatialFilters so naming inconsitency is only visible in "carto4react" source API.

@donmccurdy I think we're free to fix it in new frontend packages/APIs. I would leave it as it is in c4r which - i believe - is in deprecated mode and we don't refactor things here anymore

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok — sounds good to me!

Comment on lines +60 to +72
// stolen from deck.gl/modules/carto/src/layers/h3-tileset-2d.ts
const BIAS = 2;
export function getHexagonResolution(viewport, tileSize) {
// Difference in given tile size compared to deck's internal 512px tile size,
// expressed as an offset to the viewport zoom.
const zoomOffset = Math.log2(tileSize / 512);
const hexagonScaleFactor = (2 / 3) * (viewport.zoom - zoomOffset);
const latitudeScaleFactor = Math.log(1 / Math.cos((Math.PI * viewport.latitude) / 180));

// Clip and bias
return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(no action required) @felixpalmer maybe this is something we'll want to pull into @carto/api-client to reuse in both places? Once the repository is public and can be made a dependency, that is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, wouldn't it be better to export it from deck? It's a key part of how H3Tileset works

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yes – that does sound better. :)

@@ -204,6 +204,8 @@ export const createCartoSlice = (initialState) => {
* @param {FiltersLogicalOperators=} data.filtersLogicalOperator - logical operator that defines how filters for different columns are joined together.
* @param {import('@deck.gl/carto').QueryParameters} data.queryParameters - SQL query parameters.
* @param {string=} data.geoColumn - (optional) name of column containing geometries or spatial index data.
* @param {number=} data.dataResolution - data resolution for spatial index data.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this connected to spatialDataType and spatialDataColumn, and would spatialDataResolution be a clearer name if so? For my own learning, is more information on what the parameters do available somewhere?

Copy link
Contributor Author

@zbigg zbigg Sep 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't understand connection "well" enough yet.

dataResolution is property of tileset - namely, maximum resolution of h3 or quadbin index encountered in table.

To apply filters, we need to apply some resolution that is not bigger than dataResolution

The idea is that we allow users to provide two:

  • dataResolution - so c4r is smart enough to determine some resolution from property received in map instantiation (dataResolution exists in tilejson response)
  • spatialFiltersResolution - if user (like builder) wants to control this value directly.

That's why we have this getHexagonResolution - it's only used when spatialFiltersResolution is needed (h3/quadbin) and user didn't provided it, so we derive it from dataResolution.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks! I guess it's a request for the API team more, but a glossary in docs would be really helpful. 😓

queryParams.spatialFilters = JSON.stringify(spatialFilters);
queryParams.spatialDataType = spatialDataType;
if (spatialDataType !== 'geo') {
if (source.spatialFiltersResolution !== undefined) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking more about something like !!source.spatialFiltersResolution, WDYT?

@zbigg zbigg merged commit fcfed20 into master Sep 5, 2024
2 checks passed
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.

4 participants