How to create a bubble plot with Antarctic Mapping Tool

5 views (last 30 days)
I'm fairly new to Matlab but I had to learn it because there are some specific kind of plot I need to obtain and that should be easily plotted using Matlab add ons Antarctic Mapping Tools and BedMachine.
And to be honest. The code work, like I am able to obtain what I need with some simple lines of code
Lat = linspace(-76,-75,30)';
Long= linspace(120, 150, 30)';
Sodium=randi(50,30,1);
scatterps(Lat, Long, Sodium,'filled')
legend('Sodium (ppb)')
box on
mapzoomps('sw')
graticuleps(-88:2:-76,-150:30:180)
scalebarps
bedmachine('surface','contour', 0:100:5000)
give me the plot I need: some dots of my sample's concentration over the surface of antarctica where I am also highlighting the surface elevation. The size of the dot, is correlated to the concentration of the sample (Sodium).
But my question is... the current legend doesn't show any information on the size of the dots. I tried to follow Bubblechart's tutorial, but of course they refer to a different kind of plots. I'm asking because I tried to use a color scale, but it's
1) extremely hard to read
2) every time I add the elevation contour lines, they are also added to the color scale and of course this makes it impossible to read the actual concentration.
Am I missing something? I know I'm new to Matlab and programming in general but I can't find any solution on the Documentation

Accepted Answer

Chad Greene
Chad Greene on 19 Apr 2021
First off, excellent job on creating a minimal working example. That really helps me understand where you're at and what you're trying to do. I was able to create this plot using your code:
We'll tackle your Point #2 first: When you try to plot color-scaled circles in the same map as color-scaled contour lines, Matlab gets confused. That's not your fault. That's Matlab's fault. The ability to plot two colormaps on the same plot is something users have been requesting for decades, but for some reason Matlab is still refusing to allow it. There are a few workarounds, but they're sort of clunky and probably not worth getting into here.
For your case, I recommend that you either use color for surface elevation, or you use color for the scattered data. Here's how you could use color for the scattered data and make all of the contour lines gray:
Lat = linspace(-76,-75,30)';
Long= linspace(120, 150, 30)';
Sodium=randi(50,30,1);
scatterps(Lat, Long,50, Sodium,'filled')
legend('Sodium (ppb)')
box on
mapzoomps('sw')
graticuleps(-88:2:-76,-150:30:180)
scalebarps
h = bedmachine('surface','contour',0:100:5000,'k');
caxis([min(Sodium(:)) max(Sodium(:))])
h.Color = 0.6*[1 1 1]; % gray contour lines
If you want to label those contours, you'll have to take a manual approach. Instead of simply calling bedmachine to plot the data, you'll have to load the bedmachine data using the x and y limits of the map, then contour and label it, like this:
[sfz,x,y] = bedmachine_data('surface',xlim,ylim); % enough data to fill the map
[C,h] = contour(x,y,sfz,0:100:5000,'k');
caxis([min(Sodium(:)) max(Sodium(:))])
h.Color = 0.6*[1 1 1]; % gray contour lines
clabel(C,h,'labelspacing',1000,'fontsize',7,'color',0.6*[1 1 1])
You could use other data like a background image for better context:
modismoaps('contrast','low')
h.Color = 'r';
Or if you want to use the size of circles to represent data values, here's how you can do it (caveat below).
Lat = linspace(-76,-75,30)';
Long= linspace(120, 150, 30)';
Sodium=randi(50,30,1);
circleps(Lat, Long,Sodium,'facecolor',[.01 .26 .87],'facealpha',0.8)
box on
mapzoomps('sw')
graticuleps(-88:2:-76,-150:30:180)
scalebarps
bedmachine('surface','contour',0:100:5000);
% Get the current axis limits:
xl = xlim;
yl = ylim;
% Get the coordinates of five points near the top left corner:
[lat_legend,lon_legend] = ps2ll(xl(1) + diff(xl)/10,yl(2)-diff(yl)/15-(1:5)*diff(yl)/15);
% Plot circles of radii 5 to 45 km:
circleps(lat_legend,lon_legend,5:10:45,'facecolor',[.01 .26 .87],'facealpha',0.8)
% Label the circles:
textps(lat_legend,lon_legend,{'5';'15';'25';'35';'45 ppb'},'horiz','center','vert','middle','color','w')
In the map above, the circles are sized based on 1 km radius per 1 ppb Sodium. And you could easily multiply the circle radii by some factor to make them visible on your map.
A word of caution about this approach though: On the face of it, it makes sense to scale the size of circles with the numeric value of your Sodium data, and this type of bubble chart is very common in geospatial data visualization, especially in popular media. However, Edward Tufte opened my eyes to the fact that size-scaled bubble charts are intrinsically inaccurate.
In the example above, I've scaled the circle raddi linearly with the Sodium data, but of course the area of a circle scales as the square of the radius. In this sense, the linear scaling of the radius exaggerates the size of the large data and minimizes the small data.
It might be better to scale the circle radii with the square root of the Sodium data, because then the amount of ink on the page devoted to each circle will scale linearly with the underlying data. However, the human brain does not perceive the size of circles as a linear function of radius or area. In truth, we tend to perceive circle sizes somewhere in between.
There's a feature in ArcGIS that acknowledges the fact that neither radius nor area is a good way to scale numeric data, and so in ArcGIS you can select an option to plot circle sizes based on some approximate human perception, but that introduces yet another problem, because then it becomes impossible to measure any part of the visualization and tie it directly to the underlying data.
Anywho, I try to stick with color scaling for numeric data, and single-color labeled contours and/or hillshade when plotting surface elevation or context. But do whatever makes most sense for your data.
  5 Comments
Chad Greene
Chad Greene on 20 Apr 2021
Ah, I just used xlim and ylim in the example above, like this:
[sfz,x,y] = bedmachine_data('surface',xlim,ylim);
And the reason I'm using xlim and ylim is because they simply return the x and y limits of the current plot. Make sure you already have your map open and zoomed to the area of interest if you do it this way. Otherwise, xlim and ylim will won't be of much use.
Alternatively, you could do
[sfz,x,y] = bedmachine_data('surface',Lat,Lon,'buffer',100);
or something like that, which would load enough bedmachine data to cover all your Sulfur data, plus 100 km on all sides for context.
Raffaello Nardin
Raffaello Nardin on 21 Apr 2021
Oh ok, nevermid, I'm used to R where I'd have to specify the actual limits and I thought that was the case, not that xlim and ylim were already built in functions that "extract" these values from the current plot.
Once again, thank you so much

Sign in to comment.

More Answers (0)

Categories

Find more on Geographic Plots in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!