聆風祈 发表于 2023-4-17 09:28:30

matlab代码

读取气温nc文件,并整理成逐年逐站点平均气温或者出气温分布图

歌者文明清理员 发表于 2023-4-17 09:31:33

本帖最后由 歌者文明清理员 于 2023-4-17 09:34 编辑

以下是 MATLAB 读取气温 nc 文件并生成逐年逐站点平均气温的代码示例:

% 指定 nc 文件路径
filename = 'path/to/temperature_file.nc';

% 读取 nc 文件中某一个变量(这里假设为气温变量)
temp = ncread(filename, 'temperature');

% 获取参考时间的起始日期
ref_date = ncreadatt(filename, '/', 'units');
ref_date_str = extractAfter(ref_date, 'since ');
ref_date_val = datetime(ref_date_str);

% 读取站点的经纬度信息和站名
lat = ncread(filename, 'latitude');
lon = ncread(filename, 'longitude');
station_names = ncread(filename, 'station_name');

% 计算每个站点每年的平均气温
= size(temp);
annual_mean_temp = zeros(n_stations, n_years);
for i = 1:n_stations
    for j = 1:n_years
      year_temp = temp(i, (12*(j-1)+1):(12*j)); % 提取一年中的气温数据
      annual_mean_temp(i,j) = mean(year_temp(year_temp > -999)); % 计算有效气温的平均值
    end
end

% 生成逐年逐站点平均气温的热力图(需要安装 Mapping Toolbox)
figure
worldmap('World')
load('coastlines')
plotm(coastlat, coastlon)
cmap = jet(256);
colormap(cmap)
title('Annual Mean Temperature')
for i = 1:n_stations
    lat_idx = find(abs(lat(i)-coastlat) == min(abs(lat(i)-coastlat)));
    lon_idx = find(abs(lon(i)-coastlon) == min(abs(lon(i)-coastlon)));
    if ~isempty(lat_idx) && ~isempty(lon_idx)
      color_idx = round((annual_mean_temp(i,1)-min(annual_mean_temp(:)))/(max(annual_mean_temp(:))-min(annual_mean_temp(:)))*255)+1; % 计算颜色索引
      scatterm(lat(i), lon(i), 10, cmap(color_idx,:), 'filled', 'MarkerEdgeColor', 'k')
      textm(lat(i), lon(i), station_names(i,:), 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle')
    end
end

如果你需要绘制每个站点的逐年气温分布图,可以使用 boxplot 函数:

% 绘制逐年逐站点气温分布箱线图
figure
for i = 1:n_stations
    subplot(ceil(sqrt(n_stations)),ceil(sqrt(n_stations)),i);
    boxplot(squeeze(temp(i,:,:)), 'Labels', (ref_date_val.Year+1):(ref_date_val.Year+n_years), 'Whisker', 2.3);
    title(station_names(i, :))
end
suptitle('Station Temperature Distribution')
如果你需要绘制整个区域内所有站点的气温分布图,可以使用 histogram2 函数:

% 绘制整个区域内所有站点的气温分布图(需要安装 Statistics and Machine Learning Toolbox)
figure
histogram2(lon(:), lat(:), 'BinMethod', 'fd', 'FaceColor', 'flat')
colormap(jet)
colorbar
xlabel('Longitude')
ylabel('Latitude')
zlabel('Temperature')
title('Temperature Distribution')
这是生成站点温度分布可以使用 scatterm 函数:

% 绘制整个区域内所有站点的气温散点图(需要安装 Mapping Toolbox)
figure
worldmap('World')
load('coastlines')
plotm(coastlat, coastlon)
cmap = jet(256);
colormap(cmap)
title('Temperature Distribution')
for i = 1:n_stations
    lat_idx = find(abs(lat(i)-coastlat) == min(abs(lat(i)-coastlat)));
    lon_idx = find(abs(lon(i)-coastlon) == min(abs(lon(i)-coastlon)));
    if ~isempty(lat_idx) && ~isempty(lon_idx)
      color_idx = round((annual_mean_temp(i,1)-min(annual_mean_temp(:)))/(max(annual_mean_temp(:))-min(annual_mean_temp(:)))*255)+1; % 计算颜色索引
      scatterm(lat(i), lon(i), 10, cmap(color_idx,:), 'filled', 'MarkerEdgeColor', 'k')
      textm(lat(i), lon(i), station_names(i,:), 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle')
    end
end
请注意,这些示例代码可能需要根据你的实际数据情况进行一定的修改。

聆風祈 发表于 2023-4-17 09:34:54

歌者文明清理员 发表于 2023-4-17 09:31
以下是 MATLAB 读取气温 nc 文件并生成逐年逐站点平均气温的代码示例:




大佬,啥意思,那个nc好像是二进制的,打开乱码

聆風祈 发表于 2023-4-17 09:35:40

歌者文明清理员 发表于 2023-4-17 09:31
以下是 MATLAB 读取气温 nc 文件并生成逐年逐站点平均气温的代码示例:




嗷嗷,好的,谢谢大佬,我试试去

isdkz 发表于 2023-4-17 09:35:41

根据您的要求,下面是一个MATLAB代码示例,用于读取气温数据的NetCDF文件,并按年和站点计算平均气温以及生成气温分布图。

% 加载nc文件
filename = 'temperature_data.nc';
temp_var = 'temperature'; % 根据您的nc文件中的变量名进行替换

% 获取时间、站点和气温信息
time = ncread(filename, 'time');
station = ncread(filename, 'station');
temperature = ncread(filename, temp_var);

% 计算逐年逐站点平均气温
years = unique(floor(time/365)); % 假设时间单位为天数
num_years = length(years);
num_stations = length(station);
annual_avg_temp = zeros(num_years, num_stations);

for i = 1:num_years
    year = years(i);
    start_day = year * 365 + 1;
    end_day = start_day + 364;
    annual_avg_temp(i, :) = mean(temperature(start_day:end_day, :), 1);
end

% 输出结果
disp('逐年逐站点平均气温:');
disp(annual_avg_temp);

% 生成气温分布图
= meshgrid(1:num_stations, years);
figure;
contourf(X, Y, annual_avg_temp);
colorbar;
xlabel('Station ID');
ylabel('Year');
title('Annual Average Temperature by Station');


请将filename变量更改为您的NetCDF文件名,并根据您的数据集确保temp_var变量名称正确。这个代码示例假设时间单位是天数,如果您的数据集时间单位不同,请相应地调整时间计算。

如果您需要进一步的帮助,请随时提问。

歌者文明清理员 发表于 2023-4-17 09:36:56

聆風祈 发表于 2023-4-17 09:34
大佬,啥意思,那个nc好像是二进制的,打开乱码

NC 文件(netCDF 文件)是一种二进制文件格式,不能直接使用文本编辑器打开查看。你需要使用专门的工具或编程语言进行读取和处理。

在 MATLAB 中,你可以使用 ncread 函数读取 nc 文件中的变量,并使用其他函数操作它们。如果你仍然只是想查看 NC 文件内容,请考虑使用如下工具:


[*]Panoply 可以用来快速查看和分析 nc 文件。
[*]ncdump 命令行工具可以将 nc 文件转换成 ASCII 格式,方便你阅读。

还有其他很多处理和可视化 NC 文件的方式和工具,具体取决于你的需求和技术水平。

聆風祈 发表于 2023-4-17 18:54:39

isdkz 发表于 2023-4-17 09:35
根据您的要求,下面是一个MATLAB代码示例,用于读取气温数据的NetCDF文件,并按年和站点计算平均气温以及生 ...

nc文件中变量名和数据集时间单位如何查看啊

isdkz 发表于 2023-4-17 18:56:54

聆風祈 发表于 2023-4-17 18:54
nc文件中变量名和数据集时间单位如何查看啊

您可以使用MATLAB中的ncdisp函数查看NetCDF文件中的变量名和数据集时间单位。下面是如何使用ncdisp函数的示例。

% 加载nc文件
filename = 'temperature_data.nc';

% 显示nc文件信息
ncdisp(filename);


在运行此代码后,MATLAB命令窗口将显示文件中的变量和属性。找到对应的气温变量(例如,temperature或air_temperature),并检查时间变量(通常为time)的单位。

时间单位可能类似于days since 1900-01-01,表示从1900年1月1日开始的天数。您还可能会看到诸如hours since 1900-01-01(从1900年1月1日开始的小时数)这样的时间单位。

根据您的数据集,您可能需要相应地调整上述计算平均气温的MATLAB代码示例中的时间计算。

聆風祈 发表于 2023-4-17 19:14:56

本帖最后由 聆風祈 于 2023-4-17 19:19 编辑

isdkz 发表于 2023-4-17 18:56
您可以使用MATLAB中的ncdisp函数查看NetCDF文件中的变量名和数据集时间单位。下面是如何使用ncdisp函数的 ...

查看之后发现是网格数据
Variables:
lat
         Size:       73x1
         Dimensions: lat
         Datatype:   single
         Attributes:
                     units         = 'degrees_north'
                     actual_range=
                     long_name   = 'Latitude'
                     standard_name = 'latitude'
                     axis          = 'Y'
    lon
         Size:       144x1
         Dimensions: lon
         Datatype:   single
         Attributes:
                     units         = 'degrees_east'
                     long_name   = 'Longitude'
                     actual_range=
                     standard_name = 'longitude'
                     axis          = 'X'
    time
         Size:       901x1
         Dimensions: time
         Datatype:   double
         Attributes:
                     long_name       = 'Time'
                     delta_t         = '0000-01-00 00:00:00'
                     avg_period      = '0000-01-00 00:00:00'
                     prev_avg_period = '0000-00-01 00:00:00'
                     standard_name   = 'time'
                     axis            = 'T'
                     units         = 'hours since 1800-01-01 00:00:0.0'
                     actual_range    =
    air
         Size:       144x73x901
         Dimensions: lon,lat,time
         Datatype:   single
         Attributes:
                     long_name               = 'Monthly Mean Air Temperature at sigma level 0.995'
                     valid_range             = [-20002000]
                     units                   = 'degC'
                     add_offset            = 0
                     scale_factor            = 1
                     missing_value         = -9.969209968386869e+36
                     precision               = 1
                     least_significant_digit = 0
                     var_desc                = 'Air Temperature'
                     statistic               = 'Mean'
                     parent_stat             = 'Individual Obs'
                     dataset               = 'NCEP Reanalysis Derived Products'
                     level_desc            = '0.995 sigma'
                     actual_range            = [-73.78       42.146]
可以将其处理成一个工作簿一年,年平均气温按经纬度分布的excel文件么

isdkz 发表于 2023-4-17 19:34:42

聆風祈 发表于 2023-4-17 19:14
查看之后发现是网格数据
Variables:
lat


根据您提供的变量信息,下面是一个MATLAB代码示例,用于读取网格化气温数据的NetCDF文件,并按年计算平均气温,然后将结果保存到Excel文件中,其中每个工作表代表一年。

% 加载nc文件
filename = 'temperature_data.nc';

% 获取经度、纬度、时间和气温信息
lon = ncread(filename, 'lon');
lat = ncread(filename, 'lat');
time = ncread(filename, 'time');
air = ncread(filename, 'air');

% 计算每个时间单位的小时数
time_units = ncreadatt(filename, 'time', 'units');
time_hours = sscanf(time_units, 'hours since %*s') / 24;

% 计算逐年平均气温
years = unique(floor(time / (365 * time_hours)));
num_years = length(years);
annual_avg_temp = zeros(length(lat), length(lon), num_years);

for i = 1:num_years
    year = years(i);
    start_time = year * 365 * time_hours + 1;
    end_time = start_time + 364 * time_hours;
    annual_avg_temp(:, :, i) = mean(air(:, :, start_time:end_time), 3);
end

% 输出结果到Excel文件
excel_filename = 'Annual_Avg_Temperature.xlsx';

for i = 1:num_years
    year = years(i);
    sheet_name = sprintf('Year %d', year);
    T = array2table(annual_avg_temp(:, :, i), 'VariableNames', cellstr(num2str(lon')), 'RowNames', cellstr(num2str(lat)));
    writetable(T, excel_filename, 'Sheet', sheet_name, 'WriteRowNames', true);
end

disp('已将年平均气温按经纬度分布保存到Excel文件。');

请将filename变量更改为您的NetCDF文件名。此代码示例会将结果保存到名为Annual_Avg_Temperature.xlsx的Excel文件中。每个工作表代表一年,行名表示纬度,列名表示经度,单元格中的值表示该年该位置的平均气温。

注意:在运行此代码之前,请确保已安装了支持Excel文件读写的MATLAB插件。如果尚未安装,请在MATLAB命令窗口中输入以下命令:

addpath(fullfile(matlabroot, 'toolbox', 'matlab', 'xlswrite'));


如果您需要进一步的帮助,请随时提问。

聆風祈 发表于 2023-4-17 19:59:42

isdkz 发表于 2023-4-17 19:34
根据您提供的变量信息,下面是一个MATLAB代码示例,用于读取网格化气温数据的NetCDF文件,并按年计算平均 ...

错误使用/
矩阵维度必须一致。

出错 untitled (第 15 行)
years = unique(floor(time / (365 * time_hours)));

运行后提示这个

isdkz 发表于 2023-4-17 20:02:22

聆風祈 发表于 2023-4-17 19:59
错误使用/
矩阵维度必须一致。



对不起,我犯了一个错误。time_hours应该是一个标量值,而不是数组。我们只需要提取小时数。这里是修复后的代码:

% 计算每个时间单位的小时数
time_units = ncreadatt(filename, 'time', 'units');
hour_str = regexp(time_units, '\d+', 'match');
time_hours = str2double(hour_str{1}) / 24;

% 其他代码保持不变...
这将解决矩阵维度不一致的问题。请使用这个修复后的代码片段替换之前的time_hours计算部分。如果您还有其他问题,请随时提问。

聆風祈 发表于 2023-4-17 20:10:36

isdkz 发表于 2023-4-17 20:02
对不起,我犯了一个错误。time_hours应该是一个标量值,而不是数组。我们只需要提取小时数。这里是修复后 ...

修改之后提示这个

位置 3 处的索引超出数组边界。索引不能超过 901。

出错 untitled (第 254行)
    annual_avg_temp(:, :, i) = mean(air(:, :, start_time:end_time), 3);

isdkz 发表于 2023-4-17 20:12:49

聆風祈 发表于 2023-4-17 20:10
修改之后提示这个

位置 3 处的索引超出数组边界。索引不能超过 901。


这个错误是因为在计算start_time和end_time时,没有将time数组中的起始时间考虑进去。以下是修复后的代码:

% 计算逐年平均气温
start_year = str2double(regexp(time_units, '\d{4}', 'match'));
years = start_year + unique(floor((time - time(1)) / (365 * time_hours)));
num_years = length(years);
annual_avg_temp = zeros(length(lat), length(lon), num_years);

for i = 1:num_years
    year = years(i);
    start_time = (year - start_year) * 365 * time_hours + 1;
    end_time = start_time + 364 * time_hours;
    if end_time > length(time) % 防止超出时间范围
      end_time = length(time);
    end
    annual_avg_temp(:, :, i) = mean(air(:, :, start_time:end_time), 3);
end

% 其他代码保持不变...


这将解决数组索引越界的问题。请使用这个修复后的代码片段替换之前的逐年平均气温计算部分。如果您还有其他问题,请随时提问。

聆風祈 发表于 2023-4-17 20:28:58

isdkz 发表于 2023-4-17 20:12
这个错误是因为在计算start_time和end_time时,没有将time数组中的起始时间考虑进去。以下是修复后的代码 ...

修改之后提示这样

无法执行赋值,因为左侧的大小为 73×144,右侧的大小为 144×73。

出错 untitled (第 28 行)
    annual_avg_temp(:, :, i) = mean(air(:, :, start_time:end_time), 3);

isdkz 发表于 2023-4-17 20:45:41

聆風祈 发表于 2023-4-17 20:28
修改之后提示这样

无法执行赋值,因为左侧的大小为 73×144,右侧的大小为 144×73。


这个问题是由于在为annual_avg_temp数组分配值时,维度不匹配所致。我们需要将air数组的第一个和第二个维度转置。以下是修复后的代码:

% 计算逐年平均气温
start_year = str2double(regexp(time_units, '\d{4}', 'match'));
years = start_year + unique(floor((time - time(1)) / (365 * time_hours)));
num_years = length(years);
annual_avg_temp = zeros(length(lat), length(lon), num_years);

for i = 1:num_years
    year = years(i);
    start_time = (year - start_year) * 365 * time_hours + 1;
    end_time = start_time + 364 * time_hours;
    if end_time > length(time) % 防止超出时间范围
      end_time = length(time);
    end
    annual_avg_temp(:, :, i) = mean(permute(air(:, :, start_time:end_time), ), 3);
end

% 其他代码保持不变...


这将解决维度不匹配的问题。请使用这个修复后的代码片段替换之前的逐年平均气温计算部分。如果您还有其他问题,请随时提问。

聆風祈 发表于 2023-4-17 22:06:35

isdkz 发表于 2023-4-17 20:45
这个问题是由于在为annual_avg_temp数组分配值时,维度不匹配所致。我们需要将air数组的第一个和第二个维 ...

错误使用 array2table
'0         2.5             5         7.5            10          12.5            15
17.5            20          22.5            25          27.5            30          32.5
35          37.5            40          42.5            45          47.5            50
52.5            55          57.5            60          62.5            65          67.5
70          72.5            75          77.5            80          82.5            85
87.5            90          92.5            95          97.5         100         102.5
105         107.5         110         112.5         115         117.5         120
122.5         125         127.5         130         132.5         135         137.5
140         142.5         145         147.5         150         152.5         155
157.5         160         162.5         165         167.5         170         172.5
175         177.5         180         182.5         185         187.5         190
192.5         195         197.5         200         202.5         205         207.5
210         212.5         215         217.5         220         222.5         225
227.5         230         232.5         235         237.5         240         242.5
245         247.5         250         252.5         255         257.5         260
262.5         265         267.5         270         272.5         275         277.5
280         282.5         285         287.5         290         292.5         295
297.5         300         302.5         305         307.5         310         312.5
315         317.5         320         322.5         325         327.5         330
332.5         335         337.5         340         342.5         345         347.5
350         352.5         355         357.5' 超过了表变量名称允许的最大长度。

出错 untitled (第 37 行)
    T = array2table(annual_avg_temp(:, :, i), 'VariableNames', cellstr(num2str(lon')), 'RowNames', cellstr(num2str(lat)));

修改之后这样

聆風祈 发表于 2023-4-18 14:40:56

isdkz 发表于 2023-4-17 20:45
这个问题是由于在为annual_avg_temp数组分配值时,维度不匹配所致。我们需要将air数组的第一个和第二个维 ...

大佬在嘛{:10_254:}

聆風祈 发表于 2023-4-18 22:18:07

isdkz 发表于 2023-4-17 20:45
这个问题是由于在为annual_avg_temp数组分配值时,维度不匹配所致。我们需要将air数组的第一个和第二个维 ...

大佬,修改完之后这里跑不通
错误使用 array2table
'0         2.5             5         7.5            10          12.5            15
17.5            20          22.5            25          27.5            30          32.5
35          37.5            40          42.5            45          47.5            50
52.5            55          57.5            60          62.5            65          67.5
70          72.5            75          77.5            80          82.5            85
87.5            90          92.5            95          97.5         100         102.5
105         107.5         110         112.5         115         117.5         120
122.5         125         127.5         130         132.5         135         137.5
140         142.5         145         147.5         150         152.5         155
157.5         160         162.5         165         167.5         170         172.5
175         177.5         180         182.5         185         187.5         190
192.5         195         197.5         200         202.5         205         207.5
210         212.5         215         217.5         220         222.5         225
227.5         230         232.5         235         237.5         240         242.5
245         247.5         250         252.5         255         257.5         260
262.5         265         267.5         270         272.5         275         277.5
280         282.5         285         287.5         290         292.5         295
297.5         300         302.5         305         307.5         310         312.5
315         317.5         320         322.5         325         327.5         330
332.5         335         337.5         340         342.5         345         347.5
350         352.5         355         357.5' 超过了表变量名称允许的最大长度。

出错 untitled (第 37 行)
    T = array2table(annual_avg_temp(:, :, i), 'VariableNames', cellstr(num2str(lon')), 'RowNames', cellstr(num2str(lat)));

isdkz 发表于 2023-4-18 22:23:49

聆風祈 发表于 2023-4-18 22:18
大佬,修改完之后这里跑不通
错误使用 array2table
'0         2.5             5         7.5   ...

问题是由于变量名和行名超出了Excel表格允许的最大长度。为解决这个问题,我们需要将经度和纬度的值转换为更短的字符串。以下是修复后的代码:

% 输出结果到Excel文件
excel_filename = 'Annual_Avg_Temperature.xlsx';

for i = 1:num_years
    year = years(i);
    sheet_name = sprintf('Year %d', year);
    % 创建更短的经度和纬度字符串
    lon_str = cellstr(sprintfc('Lon%.1f', lon));
    lat_str = cellstr(sprintfc('Lat%.1f', lat));
    T = array2table(annual_avg_temp(:, :, i), 'VariableNames', lon_str, 'RowNames', lat_str);
    writetable(T, excel_filename, 'Sheet', sheet_name, 'WriteRowNames', true);
end

disp('已将年平均气温按经纬度分布保存到Excel文件。');

这将创建更短的经度和纬度字符串(例如,Lon0.0,Lat90.0),用作Excel表格的变量名和行名。

请使用这个修复后的代码片段替换之前的Excel输出部分。如果您还有其他问题,请随时提问。
页: [1] 2
查看完整版本: matlab代码