Skip to content

Dynamic map defaults#7692

Draft
palmerusaf wants to merge 9 commits intoplotly:masterfrom
palmerusaf:dynamic-map-defaults
Draft

Dynamic map defaults#7692
palmerusaf wants to merge 9 commits intoplotly: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

emilykl commented Feb 18, 2026

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 thread src/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 thread src/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
function getMinBoundLon(lon) {
function getLonBounds(lon) {

Comment thread src/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
function getMinBoundLat(lat) {
function getLatBounds(lat) {

Comment thread src/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?

@camdecoster camdecoster assigned palmerusaf and unassigned emilykl Apr 15, 2026
@palmerusaf palmerusaf force-pushed the dynamic-map-defaults branch from 5dc6b40 to 2ade804 Compare April 22, 2026 15:21
@palmerusaf palmerusaf force-pushed the dynamic-map-defaults branch from 2ade804 to 7e08880 Compare April 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() {
  function static(data) {
    const gd = 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();
  }

  function dynamic(data) {
    const gd = 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 data
  function generateLatLon(n) {
    return {
      lat: Array.from({ length: n }, () => Math.random() * 180 - 90),
      lon: Array.from({ length: n }, () => Math.random() * 360 - 180),
    };
  }

  const testList = [1e2, 1e3, 1e4, 1e5, 1e6, 1e7];

  for (let i = 0; i < testList.length; i++) {
    console.log(`Test with 1e${i + 2} data.`);
    // if you run 1e7 more than once you run out of memory
    const numOfRuns = i < testList.length - 1 ? 10 : 1;
    const data = 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

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.

3 participants