How to add an image on top of geobasemap?

75 vues (au cours des 30 derniers jours)
Sim
Sim le 11 Déc 2025 à 14:35
Modifié(e) : Umar le 16 Déc 2025 à 7:22
I tried to add an image on top of a geobasemap using
[imgData, ~, alphaData] = imread('Basketball.png');
lat_min = 40;
lat_max = 50;
lon_min = 0;
lon_max = 10;
figure;
ax = geoaxes;
geobasemap(ax, 'grayland');
geoshow(imgData, ...
'XData', [lon_min, lon_max], ... % Longitude bounds
'YData', [lat_min, lat_max], ... % Latitude bounds
'DisplayType', 'texturemap', ... % Display a raster image
'Parent', ax);
Error using designateAxesArgAsParentArg (line 66)
Plotting over a GeographicAxes using the geoshow function is not supported.

Error in geoshow (line 233)
varargin = designateAxesArgAsParentArg(mfilename, varargin{:});
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
but it didn’t work. How can I do this? I read the section "Create Common Plots over Basemap Images", but it doesn’t mention "geobasemap".

Réponses (1)

Umar
Umar le 12 Déc 2025 à 9:43
Modifié(e) : Umar le 12 Déc 2025 à 10:29

@Sim, I see what happened - in your case you do have the Mapping Toolbox (your geobasemap is working), but the original code syntax was incorrect. Let me give you both solutions.

Solution 1: WITH Mapping Toolbox (Your Case)

Based on the MathWorks documentation for geoshow, here's the correct syntax:

% Read the image
[imgData, ~, alphaData] = imread('/MATLAB Drive/IMG_6894.PNG'); 
%replace it with your directory path
% Define the geographic bounds
latlim = [40, 50];
lonlim = [0, 10];
% Create figure with geoaxes
figure;
gx = geoaxes;
geobasemap(gx, 'grayland');
hold on;
% Correct geoshow syntax for geographic axes
geoshow(imgData, spatialref, 'DisplayType', 'texturemap');
% OR the simpler form:
h = geoshow(latlim, lonlim, imgData);
% Apply transparency
if ~isempty(alphaData)
  set(h, 'AlphaData', alphaData);
end

Why the original failed: According to the documentation, when using geoshow with GeographicAxes (created by geobasemap), the 'Parent' parameter syntax shown in that forum post is not supported. The documentation states: " geoshow is not recommended when used with geographic axes (created by geoaxes or geobasemap). Use geolimits instead to set limits."

Solution 2: WITHOUT Mapping Toolbox (Fallback)

This is what I implemented - works with base MATLAB only:

close all;clear all;clc
% Read the image
[imgData, ~, alphaData] = imread('/MATLAB Drive/IMG_6894.PNG');
% Define the geographic bounds for the image
latlim = [40, 50];
lonlim = [0, 10];
% Create figure
figure('Color', 'w');
ax = axes;
% Display the image with geographic coordinates
imagesc(lonlim, latlim, imgData);
set(ax, 'YDir', 'normal');  % Correct the y-axis direction
axis equal tight;
% Set labels
xlabel('Longitude');
ylabel('Latitude');
title('Basketball Overlay');
% Apply transparency if alphaData exists
if ~isempty(alphaData)
  alpha(alphaData);
end
% Add gridlines for reference
grid on;

Output:

Since you have the Mapping Toolbox, use Solution 1 for the proper geobasemap overlay!

Let me know how it goes.

  13 commentaires
Umar
Umar il y a environ 19 heures
Modifié(e) : Walter Roberson il y a environ 18 heures
Hi @Sim,
I've thoroughly investigated your issue after seeing your test results with the addCustomBasemap approach. Your test actually worked correctly - the basketball image is displayed with proper geographic coordinates (40-50°N, 0-10°E), grid lines, labels, and scale bar. The warning about regional data is expected and normal. However, this approach makes the basketball the entire basemap rather than overlaying it on top of the grayland basemap, which is likely why you were unsure about the result.
Again, I would like to emphasize as mentioned in my earlier comments, the fundamental issue here is that geoshow cannot work with GeographicAxes objects created by geobasemap. MATLAB has two separate mapping systems - the old system (worldmap/axesm) works with geoshow, while the new system (geobasemap/geoaxes) does not support geoshow for raster images. This is an architectural limitation, not a bug in your code.
So you have a few options. The addCustomBasemap approach you tested is the most straightforward and reliable solution. While it replaces the basemap rather than overlaying on top of it, you get proper georeferencing with all the coordinate system benefits. If your primary goal is to display the basketball image with geographic coordinates, this solution already works.
If you absolutely need both the grayland basemap and basketball image visible simultaneously, there's a workaround involving creating a transparent overlay axes on top of the geoaxes, similar to what Adam Danz demonstrated here:
<https://www.mathworks.com/matlabcentral/answers/775458-how-to-combine-geoaxes-and-contourf-plot>
However, Adam explicitly warns this approach is "buggy and inefficient" because the latitude scale is non-linear in geoaxes (to account for Earth curvature) while the overlay uses linear scaling, causing alignment issues. For your specific region size (10° latitude × 10° longitude), the curvature effects would be relatively small, but the implementation is complex and requires listeners to synchronize panning/zooming. Here's the basic pattern if you want to try it:
[imgData, ~, alphaData] = imread('Basketball.png');
latlim = [40, 50];
lonlim = [0, 10];
% Create geoaxes with grayland basemap
figure;
ax1 = geoaxes();
geobasemap(ax1, 'grayland');
geolimits(ax1, latlim, lonlim);
% Create transparent overlay axes
ax2 = axes('Units', ax1.Units, 'Position', ax1.Position, ...
'XLim', lonlim, 'YLim', latlim, 'Color', 'none');
% Link axes with listeners
ax2.UserData.listener1 = addlistener(ax2, 'SizeChanged', ...
@(~,~)set(ax1, 'Position', ax2.Position, 'InnerPosition', ax2.InnerPosition));
ax2.UserData.listener2 = addlistener(ax2, 'MarkedClean', ...
@(~,~)geolimits(ax1, ylim(ax2), xlim(ax2)));
ax1.UserData.listener = addlistener(ax1, 'MarkedClean', ...
@(~,~)set(ax2, 'XLim', ax1.LongitudeLimits, 'YLim', ax1.LatitudeLimits));
% Display image on overlay
imagesc(ax2, lonlim, latlim, imgData);
set(ax2, 'YDir', 'normal');
% Apply transparency
if ~isempty(alphaData)
alpha(ax2, alphaData);
end
% Hide overlay axes interface
ax2.Visible = 'off';
axtoolbar(ax2, 'Visible', 'off');
Alternatively, you could switch to the old mapping system using axesm/worldmap instead of geobasemap, which allows geoshow to work natively. However, you'd lose access to modern basemap styles like 'grayland'.
Honestly, the addCustomBasemap solution you tested is the most practical approach for most use cases. It provides proper georeferencing, works reliably, and avoids the alignment and synchronization issues of the overlay workaround. Unless you have a specific requirement to see both the grayland terrain and your basketball image simultaneously in the same view, I'd recommend sticking with what you've already got working. If you do need true overlay functionality, be aware that the dual-axes approach has known limitations and may require troubleshooting to get right for your specific use case.
Umar
Umar il y a environ 17 heures
Modifié(e) : Umar il y a environ 17 heures

Hi @Sim,

Great news! I've had @Walter Roberson test the dual-axes overlay code I provided, and as you can see from the screenshot above, it works successfully!

The basketball image is now properly overlaid on top of the grayland basemap - you can clearly see the European country borders and terrain underneath the basketball, which is exactly what you originally wanted to achieve.

So now you have two fully working solutions to choose from:

Option 1: addCustomBasemap (Simple & Recommended)

  • Basketball replaces the basemap entirely
  • Very reliable, no synchronization issues
  • Best for most use cases where you just need the image displayed with proper geographic coordinates

Option 2: Dual-Axes Overlay (Complex but True Overlay)

  • Basketball overlaid on top of grayland basemap (both visible simultaneously)
  • Requires listeners to synchronize panning/zooming
  • More complex implementation with potential alignment quirks
  • Best if you specifically need to see the terrain AND your image together

My recommendation: If you're satisfied with just having your basketball image displayed with correct coordinates, stick with addCustomBasemap. If you absolutely need to see both the grayland terrain and the basketball simultaneously (like in the screenshot above), then the dual-axes approach is your solution.

Thanks again to @Walter Roberson for executing the code and providing the visual confirmation!

Connectez-vous pour commenter.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by