Skip to content

Dynamic map defaults - #7692

Closed
palmerusaf wants to merge 9 commits into
plotly:masterfrom
palmerusaf:dynamic-map-defaults
Closed

Dynamic map defaults#7692
palmerusaf wants to merge 9 commits into
plotly:masterfrom
palmerusaf:dynamic-map-defaults

Conversation

@palmerusaf

Copy link
Copy Markdown

This is for issue #7674. This uses a custom algo to get the bounds, then uses mapLibre to set the zoom/center via fitBounds. Turf.js doesn't handle the anti-meridian correctly. If you'd like I can add the helper functions to geo location utils to knock out a TODO there. I just need to refactor the signatures.

@palmerusaf

Copy link
Copy Markdown
Author

Also I wasn't sure how to handle if the user provides center or zoom. Right now it will simply not do box fitting if either of those params are provided.

@emilykl

Copy link
Copy Markdown
Contributor

Hi @palmerusaf ! Sincere apologies for my delay in getting back to you.

I think this approach makes sense at a high level. My only concern is the performance; could you do a basic benchmark of the time to compute getMinBoundLon(lon) for inputs of length, say, 10^2 up through 10^7?

If there's a noticeable performance impact, maybe we could still pursue this approach but provide a way to disable auto-fitting of bounds. Or maybe the fact that it can be skipped by manually setting center or zoom is enough.

I'll leave a few other small comments on the code. The implementation isn't expected to be working quite yet, correct?

Comment threadsrc/plots/map/layout_defaults.js Outdated
var { minLat, maxLat } = getMinBoundLat(lat);
// this param is called bounds in mapLibre ctor
// not to be confused with maxBounds aliased below
containerOut.fitBounds = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Prefix this property with an underscore since it's an internal property, not part of the plot schema.

Suggested change
containerOut.fitBounds={
containerOut._fitBounds={

Comment threadsrc/plots/map/layout_defaults.js Outdated
containerOut._input = containerIn;
}

function getMinBoundLon(lon) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
functiongetMinBoundLon(lon){
functiongetLonBounds(lon){

Comment threadsrc/plots/map/layout_defaults.js Outdated
}
}

function getMinBoundLat(lat) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
functiongetMinBoundLat(lat){
functiongetLatBounds(lat){

Comment threadsrc/plots/map/map.js Outdated
pitch: opts.pitch,
bounds: fitBounds,
fitBoundsOptions: {
padding: 20,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since this padding is used twice, define it as a constant in map/constants.js.

Will these fitBoundsOptions have any effect if bounds is null?

@camdecoster

Copy link
Copy Markdown
Contributor

@palmerusaf are you still interested in working on this PR?

@palmerusaf
palmerusafforce-pushed the dynamic-map-defaults branch from 5dc6b40 to 2ade804CompareApril 22, 2026 15:21
@palmerusaf
palmerusafforce-pushed the dynamic-map-defaults branch from 2ade804 to 7e08880CompareApril 22, 2026 16:02
@palmerusaf

Copy link
Copy Markdown
Author

@camdecoster@emilykl I apologize for the late reply. I've made all the changes suggested above. Also, I have rebased this branch on top of the current master branch.

I also performed the suggested performance tests in the browser console. The performance hit of the longitudinal sorting does become quite noticeable when points are in the 1e7 range. Below are the results of those tests.

I've went ahead and added a flag to disable dynamic centering. However, by default it is enabled. Would you prefer this to be reversed where dynamic centering is an opt-in option?

(function(){functionstatic(data){constgd=document.createElement("div");Plotly.newPlot(gd,[{type: "scattermap",mode: "markers",lat: data.lat,lon: data.lon,marker: {color: "#636efa",},},],{map: {disableDynamicCentering: true,},},);Plotly.purge(gd);gd.remove();}functiondynamic(data){constgd=document.createElement("div");Plotly.newPlot(gd,[{type: "scattermap",mode: "markers",lat: data.lat,lon: data.lon,marker: {color: "#636efa",},},]);Plotly.purge(gd);gd.remove();}// generate lat/lon datafunctiongenerateLatLon(n){return{lat: Array.from({length: n},()=>Math.random()*180-90),lon: Array.from({length: n},()=>Math.random()*360-180),};}consttestList=[1e2,1e3,1e4,1e5,1e6,1e7];for(leti=0;i<testList.length;i++){console.log(`Test with 1e${i+2} data.`);// if you run 1e7 more than once you run out of memoryconstnumOfRuns=i<testList.length-1 ? 10 : 1;constdata=generateLatLon(testList[i]);window.timeit(static,numOfRuns,1,data);window.timeit(dynamic,numOfRuns,1,data);}})();

VM23:55 Test with 1e2 data.
test_dashboard-bundle.js:24891 static timing (ms) - min: 11.7000 max: 29.5000 median: 13.2000 mean: 15.6100 first: 29.5000 last: 18.3000
test_dashboard-bundle.js:24891 dynamic timing (ms) - min: 11.9000 max: 19.7000 median: 13.0000 mean: 13.6300 first: 19.7000 last: 11.9000
VM23:55 Test with 1e3 data.
test_dashboard-bundle.js:24891 static timing (ms) - min: 10.8000 max: 22.2000 median: 13.6000 mean: 14.3900 first: 16.0000 last: 22.2000
test_dashboard-bundle.js:24891 dynamic timing (ms) - min: 12.0000 max: 17.3000 median: 13.1000 mean: 13.4800 first: 17.3000 last: 14.2000
VM23:55 Test with 1e4 data.
test_dashboard-bundle.js:24891 static timing (ms) - min: 12.3000 max: 14.7000 median: 13.6000 mean: 13.4000 first: 14.3000 last: 13.6000
test_dashboard-bundle.js:24891 dynamic timing (ms) - min: 17.4000 max: 29.0000 median: 20.4000 mean: 20.5300 first: 20.8000 last: 29.0000
VM23:55 Test with 1e5 data.
test_dashboard-bundle.js:24891 static timing (ms) - min: 17.1000 max: 38.8000 median: 18.5000 mean: 20.7700 first: 22.7000 last: 18.6000
test_dashboard-bundle.js:24891 dynamic timing (ms) - min: 77.2000 max: 116.6000 median: 90.6000 mean: 92.4300 first: 116.6000 last: 86.6000
VM23:55 Test with 1e6 data.
test_dashboard-bundle.js:24891 static timing (ms) - min: 56.8000 max: 183.3000 median: 151.7000 mean: 136.5000 first: 56.8000 last: 117.2000
test_dashboard-bundle.js:24891 dynamic timing (ms) - min: 389.8000 max: 962.2000 median: 415.6000 mean: 580.4600 first: 908.8000 last: 395.6000
VM23:55 Test with 1e7 data.
test_dashboard-bundle.js:24891 static timing (ms) - min: 784.9000 max: 784.9000 median: 784.9000 mean: 784.9000 first: 784.9000 last: 784.9000
test_dashboard-bundle.js:24891 dynamic timing (ms) - min: 6372.3000 max: 6372.3000 median: 6372.3000 mean: 6372.3000 first: 6372.3000 last: 6372.3000
undefined

@camdecoster

Copy link
Copy Markdown
Contributor

Hello @palmerusaf! Sorry for the late response. I've been reviewing this PR along with another closed one and one that got merged recently and I think there are pieces that can be used from each to fix this issue. If you're not opposed, I'd like to make push some changes that will help this move forward.

@palmerusaf

Copy link
Copy Markdown
Author

@camdecoster Sounds good.

@camdecoster

Copy link
Copy Markdown
Contributor

@palmerusaf my PR is up in #7884. Would you be willing to kick the tires?

@camdecoster

Copy link
Copy Markdown
Contributor

Since this work was folded into #7884, I'm closing this PR. Thanks @palmerusaf for your efforts on this!

Sign up for freeto 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.

3 participants

@palmerusaf@emilykl@camdecoster