第一次接触地理信息系统(GIS)数据时,我被.shp文件搞得一头雾水。直到用Matlab打开第一个道路网络数据,才明白这种矢量数据格式的强大之处。Shapefile其实是由多个文件组成的集合,主文件.shp存储几何数据,.shx是索引文件,.dbf存放属性数据。Matlab的Mapping Toolbox让处理这些文件变得异常简单。
我在处理城市交通数据时发现,Matlab读取shp文件的速度比许多专业GIS软件还要快。这得益于其优化的二进制读取算法。举个例子,读取一个包含10万条道路记录的北京路网数据,在我的i7笔记本上仅需2.3秒。对于非专业GIS人员来说,用Matlab处理地理数据有个明显优势——不需要学习复杂的GIS软件操作,用熟悉的Matlab环境就能完成从数据读取到可视化的全流程。
shaperead是Matlab读取shp文件的核心函数。最基本的用法就是指定文件路径:
matlab复制road_network = shaperead('beijing_roads.shp');
这个简单的命令会返回一个结构体数组,每个元素代表shp文件中的一个地理要素。我常用来检查数据是否读取成功的技巧是查看第一个元素的字段:
matlab复制disp(road_network(1))
你会看到类似这样的输出:
code复制Geometry: 'Line'
BoundingBox: [2x2 double]
X: [1x100 double]
Y: [1x100 double]
ID: 1
RoadType: '主干道'
Length: 1250.3
实际项目中,我们经常不需要读取全部数据。shaperead提供了几个实用的筛选参数:
matlab复制% 只读取前100条记录
partial_data = shaperead('data.shp', 'RecordNumbers', 1:100);
% 只读取特定区域的数据([minX minY; maxX maxY])
bbox = [116.3 39.8; 116.5 40.0];
area_data = shaperead('beijing.shp', 'BoundingBox', bbox);
% 只选择特定属性的字段
selected_fields = shaperead('data.shp', 'Selector',...
{@(attr) strcmp(attr.RoadType,'主干道'), 'RoadType'});
我处理城市POI数据时,曾经因为忘记使用BoundingBox参数,不小心读取了整个城市的数据,导致内存溢出。这个教训让我明白,处理大型地理数据集时,一定要先了解数据规模,必要时分批读取。
读取数据后,第一步应该是了解数据的整体情况。shapeinfo函数就是为此而生:
matlab复制info = shapeinfo('landuse.shp');
disp(info)
这个命令会返回包含以下关键信息的结构体:
我在分析某城市土地利用变化时,曾因忽略CRS信息导致面积计算全部错误。后来发现数据使用的是UTM投影坐标,而我把它们当成了经纬度处理。现在我会习惯性地首先检查:
matlab复制crs = info.CoordinateReferenceSystem;
disp(crs.Name) % 显示坐标系统名称
Matlab能够自动识别大多数常见坐标系统,但有时需要手动处理:
matlab复制% 转换坐标系统示例
[lat, lon] = projinv(crs, x, y); % 投影坐标转经纬度
[x_new, y_new] = projfwd(new_crs, lat, lon); % 经纬度转新投影坐标
对于没有CRS信息的旧数据,我通常会这样处理:
mapshow是最简单的地图可视化函数:
matlab复制roads = shaperead('city_roads.shp');
figure
mapshow(roads)
title('城市道路网络')
但实际项目中,这样的基础地图往往不够用。我常用的增强技巧包括:
matlab复制% 设置不同颜色显示不同道路等级
colors = containers.Map({'高速路','主干道','次干道','支路'},...
{'red','orange','blue','green'});
for i = 1:length(roads)
mapshow(roads(i), 'Color', colors(roads(i).RoadClass))
end
% 添加图例
legend({'高速路','主干道','次干道','支路'},...
'Location','bestoutside')
对于面状数据(如行政区划),我喜欢用半透明填充:
matlab复制districts = shaperead('districts.shp');
mapshow(districts, 'FaceColor', [0.5 0.5 1], 'FaceAlpha', 0.5,...
'EdgeColor', 'b', 'LineWidth', 1.5);
处理大量点时,直接绘制会导致性能问题。我的解决方案是:
matlab复制% 随机抽样显示
points = shaperead('poi.shp');
sample_idx = randperm(length(points), 1000);
mapshow(points(sample_idx), 'Marker', '.', 'MarkerSize', 6)
分析城市绿地分布时,我开发了一套完整的可视化流程:
matlab复制% 1. 读取数据
greenspace = shaperead('greenspace.shp');
% 2. 按面积分类
area = arrayfun(@(x) x.Area, greenspace);
class = discretize(area, [0 5000 20000 inf]);
% 3. 设置样式
colors = [0.8 1 0.8; 0.5 0.9 0.5; 0.2 0.7 0.2];
labels = {'小型绿地(<5k㎡)','中型绿地(5-20k㎡)','大型绿地(>20k㎡)'};
% 4. 绘制
figure
hold on
for i = 1:3
idx = (class == i);
if any(idx)
mapshow(greenspace(idx), 'FaceColor', colors(i,:),...
'EdgeColor', 'none')
end
end
legend(labels)
title('城市绿地分布专题图')
Matlab提供了一系列空间分析函数。我最常用的是polyxpoly计算线要素交点:
matlab复制% 计算两条道路的交点
[x_int, y_int] = polyxpoly(road1.X, road1.Y, road2.X, road2.Y);
处理行政区划数据时,inpolygon非常实用:
matlab复制% 判断点是否在多边形内
in = inpolygon(point_x, point_y, poly_x, poly_y);
创建缓冲区是常见的空间分析操作:
matlab复制% 为河流创建500米缓冲区
river = shaperead('river.shp');
buffer = bufferm(river.X, river.Y, 500); % 距离单位与CRS一致
mapshow(buffer, 'FaceColor', 'cyan', 'FaceAlpha', 0.3)
分析结果经常需要导出供他人使用:
matlab复制% 导出为shp文件
shapewrite(processed_data, 'result.shp')
% 导出为GeoTIFF
R = maprasterref('RasterSize', size(data),...
'XLimWorld', xlim, 'YLimWorld', ylim);
geotiffwrite('output.tif', data, R)
在处理一个城市规划项目时,我开发了完整的处理流程:从原始shp数据读取、坐标转换、空间分析到最终的可视化输出。这个过程中,Matlab表现出色的一点是,所有步骤都可以在一个环境中完成,不需要在不同软件间来回切换数据。