Changing the longitude of NetCDF from 0-360 to -180-180?

I want to use the Tmax data from https://psl.noaa.gov/data/gridded/data.cpc.globaltemp.html. Tmax is in the format of netcdf and longitude range is from 0 to 360. I want to make the longitude range from -180 to 180 and exported the changed data so that next time when I use it, I can have the proper longitude.
The latitude starts from the north so the image is flipped. How can I also change the latitude so that I can have the latitude in the data attribute starting from south.
Does anyone know how to solve the problem?
Thanks.

Answers (1)

I am attaching a .mat file with some CPC Global Temperature data as an example.
EDIT: Corrections thanks to @Walter Roberson
load cpc.mat
% Convert latitude and longitude data into type 'double' (by default CPC
% lat/lon data are of type 'single' which is not valid for plotting on map axes)
lat = double(lat);
lon = double(lon);
% Convert lon from [0 360] to [-180 180]
mask = lon > 180;
lon(mask) = lon(mask) - 360;
% Flip lat from [90 -90] to [-90 90]
lat = flip(lat);
% Rotate tmax and flip so that the dimensions are 360x720 (instead of
% 720x360)
tmax = flipud(tmax');
% Plot
figure(1)
ax=axesm('braun'); % Use whatever map projection you prefer
pcolorm(lat, lon, tmax)
mlabel('on') % Longitude tick labels
plabel('on') % Latitude tick labels
colorbar
tightmap
framem
gridm
To save the data for later:
save('mydata.mat','lat','lon','tmax')

9 Comments

% Convert lon from [0 360] to [-180 180]
lon = lon - 180;
No, should be
mask = lon > 180;
lon(mask) = lon(mask) - 360;
Thanks, @Walter Roberson! I see why my original longitude conversion was problematic. I have edited the answer accordingly.
Thank you so much. It is really helpful. Is it possible to export netCDF file since the original data is netCDF? Thanks.
You can create new NetCDF files with netcdf.create (link to documentation). Here is a basic example:
% Generate netcdf file
file_name = 'new.nc';
ncid = netcdf.create(file_name, 'NETCDF4');
% Define the dimensions of the netcdf data
lat_len = length(lat);
lon_len = length(lon);
lat_dim = netcdf.defDim(ncid, 'lat', lat_len);
lon_dim = netcdf.defDim(ncid, 'lon', lon_len);
% Define the variables of the netcdf data
lat_var = netcdf.defVar(ncid, 'lat', 'double', lat_dim);
lon_var = netcdf.defVar(ncid, 'lon', 'double', lon_dim);
tmax_var = netcdf.defVar(ncid, 'tmax', 'double', [lat_dim, lon_dim]);
netcdf.endDef(ncid);
% Put the data into the variables
netcdf.putVar(ncid, lat_var, lat);
netcdf.putVar(ncid, lon_var, lon);
netcdf.putVar(ncid, tmax_var, tmax);
% Stop generating netcdf file
netcdf.close(ncid);
This should save a new netcdf file called new.nc to your current folder, including the new variables lat, lon, and tmax.
Hi Austin, thank you so much for the code. I still got some issue using the exported netcdf file. I used the following code to show the data. There seems something wrong with the converted NetCDF file. Do you know why and how to fix this? Thank you so much.
ncdisp('new.nc');
mync = ncread('new.nc','tmax');
lat = ncread('new.nc','lat');
lon = ncread('new.nc','lon');
pcolor(lon, lat, mync)
colorbar
shading interp
That is curious. I am not sure why the data is plotting like that, but I think it might be an issue with pcolor, which is plotting the data in Cartesian coordinates. When the data is visualized using pcolorm, which plots the data using map axes, everything looks fine:
% Repeating the first part
load cpc.mat
lat = double(lat);
lon = double(lon);
mask = lon > 180;
lon(mask) = lon(mask) - 360;
lat = flip(lat);
tmax = flipud(tmax');
% Repeating making a new netcdf file
file_name = 'new.nc';
ncid = netcdf.create(file_name, 'NETCDF4');
lat_len = length(lat);
lon_len = length(lon);
lat_dim = netcdf.defDim(ncid, 'lat', lat_len);
lon_dim = netcdf.defDim(ncid, 'lon', lon_len);
lat_var = netcdf.defVar(ncid, 'lat', 'double', lat_dim);
lon_var = netcdf.defVar(ncid, 'lon', 'double', lon_dim);
tmax_var = netcdf.defVar(ncid, 'tmax', 'double', [lat_dim, lon_dim]);
netcdf.endDef(ncid);
netcdf.putVar(ncid, lat_var, lat);
netcdf.putVar(ncid, lon_var, lon);
netcdf.putVar(ncid, tmax_var, tmax);
netcdf.close(ncid);
% Visualize
mync = ncread('new.nc','tmax');
lat = ncread('new.nc','lat');
lon = ncread('new.nc','lon');
figure(1)
subplot(2,1,1)
pcolor(lon, lat, mync)
title('Cartesian Axes with pcolor()')
colorbar
shading interp
axis equal tight
grid on
subplot(2,1,2)
axesm('eqdcylin')
pcolorm(lat, lon, mync)
title('Map Axes with pcolorm()')
colorbar
shading interp
tightmap
gridm
mlabel('south') % Longitude tick labels
plabel('on') % Latitude tick labels
However, I am not sure why this is happening. It might be worth submitting this as a separate question on MATLAB Answers.
Thanks you so much for your answer and the comparison between pcolor() and pcolorm(). I will submit this as a seperate question. Thanks a lot. Did you notice that there is a line without data after converting the longitude as shown in the figure below.
Yes, the "line" at 0° longitude is actually not a line but rather missing data. This is an artifact of the original CDC data, which has longitude values ranging from 0.25° to 359.75°. The Earth is a sphere, so that means the original dataset did not include the longitude values that wrap back from 359.75° to 0.25°. Therefore, 1° of longitude is missing from the original data.
When we rescaled the longitudes from -180° to 180°, this missing 1° of longitude became centered at the prime meridian. The dataset simply doesn't contain longitude coordinates for that location, but this gap is covered up if you add a grid to the map.
Thanks so much for your explaination. I think I fixed the problem by changeing the longitude lareger than 180 minus 359.75 and smaller than 180 minus 0.25.
load cpc.mat
% Convert latitude and longitude data into type 'double' (by default CPC
% lat/lon data are of type 'single' which is not valid for plotting on map axes)
lat = double(lat);
lon = double(lon);
% Convert lon from [0 360] to [-180 180] Revised based on the range [0.25,359.75]
mask = lon > 180;
lon(mask) = lon(mask) - 359.75;
lon(~mask) = lon(~mask)-0.25;
% Flip lat from [90 -90] to [-90 90]
lat = flip(lat);
% Rotate tmax and flip so that the dimensions are 360x720 (instead of
% 720x360)
tmax = flipud(tmax');
% Plot
figure(1)
ax=axesm('braun'); % Use whatever map projection you prefer
pcolorm(lat, lon, tmax)
mlabel('on') % Longitude tick labels
plabel('on') % Latitude tick labels
colorbar
tightmap
framem
% gridm

Sign in to comment.

Asked:

on 10 Mar 2024

Commented:

on 17 Mar 2024

Community Treasure Hunt

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

Start Hunting!