Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ceecc2a
Linting/formatting
camdecoster Jul 1, 2026
8e33f3f
fix: Dynamically compute default zoom/center for map traces
camdecoster Jul 1, 2026
a888c2f
Add tests
camdecoster Jul 1, 2026
fd7650b
Handle view reset with 'Reset view' button
camdecoster Jul 1, 2026
be253fa
Add mocks and baseline images
camdecoster Jul 1, 2026
6999db8
Update mocks to use v3 defaults
camdecoster Jul 1, 2026
c124086
Update tests to use skip auto-fit
camdecoster Jul 1, 2026
906b1db
Remove unnecessary mock and baseline image
camdecoster Jul 1, 2026
2737396
Add draftlog
camdecoster Jul 1, 2026
7e48373
Merge remote-tracking branch 'origin/v4.0' into cam/7674/compute-map-…
camdecoster Jul 7, 2026
1b3b284
Improve efficiency of getMapFitBounds
camdecoster Jul 7, 2026
e260f36
Use fitBounds in updateMap; consolidate updates to viewInitial
camdecoster Jul 7, 2026
3ff7fc4
Merge remote-tracking branch 'origin/v4.0' into cam/7674/compute-map-…
camdecoster Jul 14, 2026
2758fab
Linting/formatting
camdecoster Jul 14, 2026
53f5470
Switch to computeBbox for getMapFitBounds
camdecoster Jul 14, 2026
b72c849
Add test
camdecoster Jul 14, 2026
b35def4
Add fitbounds attribute to map traces
camdecoster Jul 14, 2026
a91d89d
Re-fit map view on data changes; fix broken zoom button behavior
camdecoster Jul 14, 2026
e2b2024
Add map fitbounds tests
camdecoster Jul 14, 2026
db1ea2f
Update schema and types
camdecoster Jul 14, 2026
098ccff
Clarify some comments
camdecoster Jul 15, 2026
20adf25
Don't track bearing/pitch for view comparison
camdecoster Jul 15, 2026
b2c9dd4
Update language regarding supplyDefaults
camdecoster Jul 15, 2026
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
6 changes: 4 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,10 @@ All traces modules set:
This object is used to generate the plot-schema JSON.
- `_module.supplyDefaults`: Takes in input trace settings and coerces them into "full" settings
under `gd._fullData`. This one is called during the figure-wide `Plots.supplyDefaults` routine.
Note that the `supplyDefaults` method performance should scale with the number of attributes (**not** the
number of data points - so it should not loop over any data arrays).
As a rule, `supplyDefaults` performance should scale with the number of attributes rather than
the number of data points, so avoid looping over data arrays in this function. That being said,
there are a few exceptions to this rule due to technical requirements (`fitbounds` on map subplots).
The same guidance applies to `_module.supplyLayoutDefaults`.
- `_module.calc`: Converts inputs data into "calculated" (or sanitized) data. This one is called during
the figure-wide `Plots.doCalcdata` routine. The `calc` method is allowed to
scale with the number of data points and is in general more costly than `supplyDefaults`.
Expand Down
1 change: 1 addition & 0 deletions draftlogs/7884_fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Fix `scattermap`, `densitymap` traces not showing all points by dynamically computing `center`, `zoom` values [[#7884](https://github.com/plotly/plotly.js/pull/7884)], with thanks to @palmerusaf and @DhruvGarg111 for the contributions!
10 changes: 4 additions & 6 deletions src/plots/map/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,15 @@ var styleValuesMap = sortObjectKeys(stylesMap);

module.exports = {
styleValueDflt: 'basic',
stylesMap: stylesMap,
styleValuesMap: styleValuesMap,

stylesMap,
styleValuesMap,
traceLayerPrefix: 'plotly-trace-layer-',
layoutLayerPrefix: 'plotly-layout-layer-',

missingStyleErrorMsg: [
'No valid maplibre style found, please set `map.style` to one of:',
styleValuesMap.join(', '),
'or use a tile service.'
].join('\n'),

mapOnErrorMsg: 'Map error.'
mapOnErrorMsg: 'Map error.',
fitBoundsPadding: 20
};
55 changes: 55 additions & 0 deletions src/plots/map/get_map_fit_bounds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { computeBbox } from '../../lib/geo_location_utils';
import type { MapLayout, ScattermapData } from '../../types/generated/schema';

// Same shape as the user-facing `map.bounds` attribute, but with all fields required
type LonLatBox = Required<NonNullable<MapLayout['bounds']>>;

// Minimal shape of the fullData entries this helper reads
interface FitBoundsTrace extends Pick<ScattermapData, 'subplot' | 'visible'> {
// Tighten lat/lon to be more specific than default
lat?: ArrayLike<number>;
lon?: ArrayLike<number>;
// Broaden type since this could run against multiple trace types
type?: string;
}

/**
* Compute a lon/lat bounding box from lonlat-bearing traces (`scattermap`,
* `densitymap`) on the given map subplot.
*
* Returns null when:
* - no fittable data exists on the subplot;
* - a location-based trace (`choroplethmap`) is present — those carry
* `locations`/`geojson`, not raw lon/lat, and need geojson bbox handling
* that isn't implemented here.
*
* @param fullData - The full data array (post supply-defaults)
* @param subplotId - e.g. `'map'`, `'map2'`
*/
export function getMapFitBounds(fullData: FitBoundsTrace[], subplotId: string): LonLatBox | null {
const coordinates: [number, number][] = [];

for (const trace of fullData) {
if (trace.subplot !== subplotId || trace.visible !== true) continue;

// choroplethmap traces carry locations/geojson, not raw lon/lat; bail
// out rather than frame around a subset of the subplot's data.
if (trace.type === 'choroplethmap') return null;

const { lat, lon } = trace;
if (!lon || !lat) continue;

const len = Math.min(lon.length, lat.length);
for (let j = 0; j < len; j++) {
const lo = lon[j];
const la = lat[j];
if (Number.isFinite(lo) && Number.isFinite(la)) coordinates.push([lo, la]);
}
}

const bbox = computeBbox({ type: 'MultiPoint', coordinates });
if (!bbox) return null;

const [west, south, east, north] = bbox;
return { west, east, south, north };
}
9 changes: 0 additions & 9 deletions src/plots/map/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,6 @@ exports.plot = function plot(gd) {
fullLayout[id]._subplot = map;
}

if(!map.viewInitial) {
map.viewInitial = {
center: Lib.extendFlat({}, opts.center),
zoom: opts.zoom,
bearing: opts.bearing,
pitch: opts.pitch
};
}

map.plot(subplotCalcData, fullLayout, gd._promises);
}
};
Expand Down
Loading
Loading