How to cut out part of x axis in scatter plot ?

Hi,
I have have used scatter plots to plot Lattitude on x axis, Longitude on y axis and Absolute VTEC on Z axis.Typically my data is on both side of 180 deg. The longitudinal values are form -130 to -180 deg in West side while 180 to 130 deg in East side. When I plot the graph the longitudal values are displayed form -180 to 180 and my the graphs are seperated by showing large gaps in the x axis.
First I want to remove the part of this axis which dosent have graphs.
Secondly I wish bring the graph together at 180 deg and the x axis to be labled as
+130, .....+150 +160, +170, 180, -170 , -160, -150..........-130
Any suggestions will be highly appriciated.
Im attaching the codes that I used to obtain the graph.
mask = isfinite(Latitude) & isfinite(Longitude);
Latitude = Latitude(mask); Longitude = Longitude(mask);
N = 80;
[latbins, latedges] = discretize(Latitude, N);
[lonbins, lonedges] = discretize(Longitude, N+1);
denmat = accumarray([latbins(:), lonbins(:)], Absolute_VTEC(mask), [], @mean, NaN);
latmid = (latedges(1:end-1) + latedges(2:end))/2;
lonmid = (lonedges(1:end-1) + lonedges(2:end))/2;
h = pcolor(lonmid, latmid, denmat);
h.EdgeColor = 'none';
colorbar ()
colormap jet
ax = gca;
ax.LineWidth = 2;
ylim([-30 30]);
h = colorbar;
set(get(h,'label'),'string','VTEC');
ylabel('Latitude [Deg]','fontweight','bold','FontSize',12)
xlabel('Longitude [Deg]','fontweight','bold','FontSize',12)
title('$October$ $2016$','Interpreter','LaTex','FontSize',16)

4 Comments

"Im attaching the codes that I used to obtain the graph. "
mask = isfinite(Latitude) & isfinite(Longitude);
Unrecognized function or variable 'Latitude'.
Latitude = Latitude(mask); Longitude = Longitude(mask);
N = 80;
[latbins, latedges] = discretize(Latitude, N);
[lonbins, lonedges] = discretize(Longitude, N+1);
denmat = accumarray([latbins(:), lonbins(:)], Absolute_VTEC(mask), [], @mean, NaN);
latmid = (latedges(1:end-1) + latedges(2:end))/2;
Apparently not so, or at least not enough for us to run the code snippet that you supplied. Please give working code and data.
If you have any more questions, then attach your data and code to read it in with the paperclip icon after you read this:
Hi
I have attached the sample data.
hi may be due to the slow network it might have happened. I have re -attached the data.

Sign in to comment.

 Accepted Answer

Unfortunately, MATLAB doesn't have the facility to create either split axes to show such a gap or to condense a section of an axes that doesn't contain data, nor to draw on an axes anything other than against the input x,y locations.
Those facilities would be nice to have, indeed, but for now you've got to work around it in one way or another.
There are two choices I see, first rescale the longitudinal data to be continuous--that's the following illustrative code:
FIRST METHOD
To create a representation such as you're looking for here on a single axes would require creating the x data to be continuous from [-130 +130] across +/-180.
Do this by linear mapping and joining the two subsections from [-180 -130] and [180 130]
xW=[-130 -180]; % west coordinate range
xE=[ 180 130]; % east coordinate range
bW=polyfit(xW,[xW(1) 0],1) % linear scaling coefficients for W coordinates
bW = 1×2
-2.6000 -468.0000
bE=polyfit(xE,[0 xE(2)],1) % and for E
bE = 1×2
-2.6000 468.0000
NOTA BENE: the slope is same, just opposite sign of intercept so can set one from the other if desired rather than recompute.
So, now if given an input set of coordinates, to patch them together would be
x=[polyval(bW,[-130:-10:-180]) polyval(bE,[180:-10:130])]
x = 1×12
-130.0000 -104.0000 -78.0000 -52.0000 -26.0000 0 0.0000 26.0000 52.0000 78.0000 104.0000 130.0000
which gives a continuous vector across the discontinuity.
You then use xticklabels to write the desired actual coordinates in place of the tick values.
SECOND METHOD
The alternate way to create the plot would be to use two independent axes drawn side by side -- this is doable, but tends to get complicated. Well, let's see what we can do here quickly...
hAx=axes; % make a default axes
posn=hAx.Position; % get the default position
hold on % don't destroy/change it
posn(3)=posn(3)/2; % set new width to one-half the default width
hAx(2)=axes('Position',posn+[posn(1)+posn(3)*2/3 0 0 0]); % make new offset by 2/3rds width
yticks(hAx(2),[]) % wipe out the second axes yticks so can see axis location
hAx(1).Position=posn; % now set the first width to half, too...
One sees you now do have to axes that look like they are one with the exception of the xlim both go from the default [0 1] range. Now you can plot the W and E portions of the data into the respective axes; (I've not tried, you may be able to ignore and clipping will take care of the other data at the RH limits of the two axes.)
When ready to plot set
hAx(2).YAxis.Visible='off'; % to hide the vertical line
so the extra y axis isn't visible. The 'box' property cannot be used here; if desired, will have to be drawn as xline, yline objects on the two axes or the opposite axis tick marks will show up again.
Then, for the tick labels, the last trick is
x=[-130:-25:-180; 180:-25:130]; % get the range of long's match the tick number
xstr=cellstr(num2str(x(1,:).')); xstr(end)={''}; % tick label str for LH axes
hAx(1).XTickLabel=xstr;
xstr=cellstr(num2str(x(2,:).')); % tick label str for RH axes
hAx(2).XTickLabel=xstr;

15 Comments

Hi, Thank you for your help however I'm not able to get the required graph. when run all the codes the whole graph moves to one side. I have attached my data sample
dpb
dpb on 22 Feb 2023
Edited: dpb on 22 Feb 2023
Show your work...either can be made to work as shown, but use either one or the other of the above ways to approach it, NOT both.
While I didn't write it explicitly, with the second way you must plot the two pieces independently into the proper axes/half of overall figure.
Hi my codesand the graphs and attached
mask = isfinite(Latitude) & isfinite(Longitude);
Latitude = Latitude(mask); Longitude = Longitude(mask);
N = 80;
[latbins, latedges] = discretize(Latitude, N);
[lonbins, lonedges] = discretize(Longitude, N+1);
denmat = accumarray([latbins(:), lonbins(:)], Absolute_VTEC(mask), [], @mean, NaN);
latmid = (latedges(1:end-1) + latedges(2:end))/2;
lonmid = (lonedges(1:end-1) + lonedges(2:end))/2;
h = pcolor(lonmid, latmid, denmat);
h.EdgeColor = 'none';
colorbar ()
colormap jet
ax = gca;
ax.LineWidth = 2;
ylim([-30 30]);
xticks([]);
h = colorbar;
set(get(h,'label'),'string','VTEC');
ylabel('Latitude [Deg]','fontweight','bold','FontSize',12)
title('$October$ $2016$','Interpreter','LaTex','FontSize',16)
hAx=axes; % make a default axes
posn=hAx.Position; % get the default position
hold on % don't destroy/change it
posn(3)=posn(3)/2; % set new width to one-half the default width
hAx(2)=axes('Position',posn+[posn(1)+posn(3)*2/3 0 0 0]); % make new offset by 2/3rds width
yticks(hAx(2),[]) % wipe out the second axes yticks so can see axis location
hAx(1).Position=posn;
hAx(2).YAxis.Visible='off';
x=[-130:-10:-180; 180:-10:130]; % get the range of long's match the tick number
xstr=cellstr(num2str(x(1,:).')); xstr(end)={''}; % tick label str for LH axes
hAx(1).XTickLabel=xstr;
yticks([]);
xstr=cellstr(num2str(x(2,:).')); % tick label str for RH axes
hAx(2).XTickLabel=xstr;
dpb
dpb on 22 Feb 2023
Edited: dpb on 23 Feb 2023
You did the call to pcolor before you ever created the two axes to plot into...
The point is to create the two axes that are each set to hold their respective pieces of the whole--the E and W have to be separated and plotted separately, one into each of the two new axes.
I showed you how to create axes that would let you do that; no data with which to try to go any further...
Rearrange the code entirely -- split the data first (either actually into separate variables or with indexing expressions) so you have the two pieces ready to go when get the axes created to receive their parts.
Then create the two axes and then, using the handle to the axes of one at a time as the first parameter in the call to pcolor, pass it and the appropriate subsection of the data alone.
Then, the two pieces will fill the axes as they will initially auto-scale to the range of the coordinates passed into them.
hAx=axes; % make a default axes
posn=hAx.Position; % get the default position
hold on % don't destroy/change it
posn(3)=posn(3)/2; % set new width to one-half the default width
hAx(2)=axes('Position',posn+[posn(1)+posn(3)*2/3 0 0 0]); % make new offset by 2/3rds width
yticks(hAx(2),[]) % wipe out the second axes yticks so can see axis location
hAx(1).Position=posn; % now set the first width to half, too...
Above is the section of the code that creates the two axes before the steps that turn off the second axes y axis and redo the tick labelsl....you see you have two totally independent canvases upon which to draw; each needs to hold only its half of the total; you cannot pass the whole array to either.
Maybe that will help you visualize what you're trying to accomplish here before the details are hidden by the later cosmetics...
Hi actually Im very new to matlab programming and Im confused to orginsed these. I will try out plottting the axis first and follow your suggestion. However have attached my data as "data sample 2" kindly requesting if you could help me out with this issues.
You're problem is that with the data as you have it originally, when you used discretize over the whole data set, it created the 80 bins over the entire range of all the data from -180 - +180. But, since there are no data between the two +/-130 locations around the 0 side, it filled all the intermediary locations with NaNs.
So, in your final output of your denmat array, only
>> ixlon=find(~all(isnan(denmat)))
ixlon =
1 2 3 4 5 6 7 8 9 10
71 72 73 74 75 76 77 78 79 80 81
columns are those that contain any data -- you have only 21 out of the total 80 bins that are real.
I'm sure that's not what you intended; I'd be pretty certain you were intending those to be all containing data. To do that, you would need to do as I suggested earlier; discriminate between W and E halves initially but then apply the aggregation function over those sections independently at whatever resolution you want each to be -- if you really did want 80 bins total, specifically, then use 40 for each half.
I've yet to figure out how to get to a link as you've posted to the data to get the online engine inside Answers to load that data but the simplest way to put your two pieces that you have now together would be simply paste the two sections together and then write the ticklabels as desired.
hPC=pcolor(denmat(:,ixLon)); % just put finite data on axis
hPC.EdgeColor='none';
colormap(jet)
xlm=xlim; % will be 1:number columns nnz
xticks(linspace(xlm(1),xlm(2),11)) % space out the ticks to be centered
xticklabels([linspace(130,180,6) linspace(170,130,5)]) % and the desired coordinates
ylm=ylim; % same exercise, y axis
yticks(linspace(ylm(1),ylm(2),7))
yticklabels(linspace(-30,30,7))
Locally, the above created:
This then shows up the much reduced actual density of the remaining data owing to the binning across the entire range as was done.
Plotting this way also misrepresents the actual location of the data; they need to be reversed left-to-right to patch them together continuously; the present representation puts the two +/-130 locations together instead.
I've other things I have to go do at the moment so don't have any further time to commit to this, but my recommendation is to revert to the first alternative I gave before rather than the second and-
  1. Separate the E and W datasets individually
  2. Do the averaging/binning over those regions so don't introduce the NaN elements
  3. Convert the coordinates from longitude relative to 180 location to linear from [-130:-180] --> [-130:-0] for W and then [180 130[ --> [0 50] so the overall range is univariate/unwrapped around the change in direction sense
  4. Plot against the above single vector of longitude so don't rewrap the data again, and then finally
  5. Use tick labels to relabel with the [130 ... 180 ... 130] display coordinates as shown above.
Good luck, it really isn't as difficult as it seems; draw a picture of a circle looking down and arrows each way to the coordinates and you'll see how to unwrap...
Noted. Thank you for your suggestions.
Do you have mapping toolbox by any chance? I don't so I'm not sure, but if you do it probably has routines builtin that would handle the coordinates vector...
I don't have mapping toolbox.
Well, I don't know that it has the specifics or not, anyway; just a thought that if you did would be worth looking for a function that did the angle unwrapping around the -180 location for you.
Use the linear expression as shown earlier over the two halves and piece them together to be the one continuous set of coordinate angles against which to plot in increasing magnitude to the signs of the actual coordinates don't cause the reversal of the data left-to-right because the increasing magnitude is in the reverse direction of the projection of the data from left to right on the viewing plane.
That is, what you want to appear on the plot is the data from the longitudes
-130 -140 -150 -160 -170 -180 170 160 150 140 130
in that order from LtoR but if you use those coordinates as input to plot, the data will be swapped because -180<-130 and 130<180 which pastes the two +/-130 locations together instead.
Another approach that's a little simpler but gets to the same spot...
% First make up a set of imaginary data that can see what is east/west and right/wrong
% Straight symmmetric line about +/-180 longitude
xW=[-130:-10:-180]; yW=linspace(1,numel(xW),numel(xW));
xE=fliplr(-xW); yE=fliplr(yW);
Now different ways to put on figure
Two axes -- this simulates the first approach w/o positioning the second axes -- works but is two axes to work with and the complications of placement and hiding unwanted parts still there
NOTA BENE: Reversing x-axis direction puts data in right orientation and patches the two matching locations together correctly
subplot(1,2,1), plot(xW,yW), set(gca,'XDir','reverse')
xlabel('West Longitude')
subplot(1,2,2), plot(xE,yE), set(gca,'XDir','reverse')
xlabel('East Longitude')
sgtitle('Longitude Coordinates Separate Reverse Axes')
Now use one axes using actual coordinates gives correct orienatation but the reverse axis flips East and West positions visually on the axes and they are separated by the gap. This illustrates what was talking about earlier about the pcolor plots being reversed and pasted together wrong edge to.
subplot(3,1,1), plot([xW xE],[yW yE]), set(gca,'XDir','reverse')
title('Longitude Coordinates Independent One Reverse Axes')
Next use the one axes but "unwrap" the East longitude cooordinates by subtracting 360 degrees -- turns +180 --> -180, etc., ...Now West/East abut and patched together correctly but axis tick values aren't the desired coordinates to use for interpretation
subplot(3,1,2), plot([xW xE-360],[yW yE]), set(gca,'XDir','reverse')
title('Longitude Coordinates Unwrapped One Reverse Axes')
Same as above except write the corrected ticklabels for display
Voila! Just what we wanted for Christmas!
subplot(3,1,3), plot([xW xE-360],[yW yE]), set(gca,'XDir','reverse')
xticklabels([linspace(130,180,6) linspace(170,130,5)])
title('Longitude Coordinates Unwrapped One Reverse Axes With Tick Labels')
BTW, the Signal Processing TB has the <unwrap> function to do this, but it's in radians and, inexplicably doesn't have an option for degrees so one has to convert to/from to use it...
>> rad2deg(unwrap(deg2rad([xW xE])))
ans =
-130 -140 -150 -160 -170 -180 -180 -190 -200 -210 -220 -230
>> ([xW xE-360])
ans =
-130 -140 -150 -160 -170 -180 -180 -190 -200 -210 -220 -230
>>
Thanks alot. I have managed to plot the required graph using your suggestion.
Glad to have helped...if this has solved the original problem, why not go ahead and Accept the original Answer to let community know, if nothing else...

Sign in to comment.

More Answers (0)

Asked:

on 21 Feb 2023

Commented:

dpb
on 28 Feb 2023

Community Treasure Hunt

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

Start Hunting!