使用PyQGIS设置栅格图层样式:样式面板与TOC异常问题
问题:PyQGIS应用Matplotlib色带后,TOC值范围与样式面板未正确更新
我使用PyQGIS为单波段QgsRasterLayer应用Matplotlib自定义色带时,地图画布显示正常,但目录(TOC)中的值范围始终显示为0-255(而非图层实际极值),尽管色带本身显示正确;样式面板也一直保留上次使用的色带设置,即使重启QGIS也无法更新。如何让这些内容同步正确更新?
原测试代码:
from matplotlib import colormaps import numpy as np lyr = iface.activeLayer() if isinstance(lyr, QgsRasterLayer): if lyr.bandCount() == 1: # define color map by name map = colormaps['viridis'] # get min/max values stats = lyr.dataProvider().bandStatistics(1, QgsRasterBandStats.All) val_min = stats.minimumValue val_max = stats.maximumValue # limit number of color steps to 20 if map.N > 20: colors = map(np.linspace(1, map.N, 20, dtype=np.int16)) else: colors = map(range(1,map.N)) colorsN = len(colors) # raster values for the color steps valList = np.linspace(val_min, val_max, colorsN) # making a colorRamp-list with colorsList = [] for idx, col in enumerate(colors): qcol = QColor(int(col[0]*255), int(col[1]*255), int(col[2]*255)) val = valList[idx] #print(val, qcol) colorsList.append( QgsColorRampShader.ColorRampItem(val, qcol) ) # apply code fcn = QgsColorRampShader() fcn.setColorRampType(QgsColorRampShader.Interpolated) fcn.setColorRampItemList(colorsList) shader = QgsRasterShader() shader.setRasterShaderFunction(fcn) renderer = QgsSingleBandPseudoColorRenderer(lyr.dataProvider(), 1, shader) lyr.setRenderer(renderer) lyr.renderer().createLegendNodes(QgsLayerTreeLayer(lyr.id())) lyr.triggerRepaint() lyr.emitStyleChanged()
解决方案
问题根源在于未正确同步渲染器的极值设置、图层统计信息缓存,以及样式面板的刷新机制。以下是修改后的代码,补充了关键同步步骤:
from matplotlib import colormaps import numpy as np lyr = iface.activeLayer() if isinstance(lyr, QgsRasterLayer) and lyr.bandCount() == 1: # 加载Matplotlib色带 cmap = colormaps['viridis'] # 获取图层实际统计极值 stats = lyr.dataProvider().bandStatistics(1, QgsRasterBandStats.All) val_min = stats.minimumValue val_max = stats.maximumValue # 限制色阶数量最多20个 color_count = min(cmap.N, 20) # 直接用0-1范围采样色带,避免原代码索引错误 colors = cmap(np.linspace(0, 1, color_count)) # 生成对应值范围的色阶节点 val_list = np.linspace(val_min, val_max, color_count) color_ramp_items = [] for val, col in zip(val_list, colors): qcol = QColor(int(col[0]*255), int(col[1]*255), int(col[2]*255)) color_ramp_items.append(QgsColorRampShader.ColorRampItem(val, qcol)) # 配置颜色渐变Shader color_ramp_shader = QgsColorRampShader() color_ramp_shader.setColorRampType(QgsColorRampShader.Interpolated) color_ramp_shader.setColorRampItemList(color_ramp_items) # 关键:明确设置Shader的极值范围 color_ramp_shader.setMinimumValue(val_min) color_ramp_shader.setMaximumValue(val_max) raster_shader = QgsRasterShader() raster_shader.setRasterShaderFunction(color_ramp_shader) # 创建并配置渲染器 renderer = QgsSingleBandPseudoColorRenderer(lyr.dataProvider(), 1, raster_shader) # 关键:设置渲染器的分类极值 renderer.setClassificationMin(val_min) renderer.setClassificationMax(val_max) lyr.setRenderer(renderer) # 关键:更新数据提供者的统计缓存,让TOC读取正确极值 lyr.dataProvider().setUserMinimumValue(1, val_min) lyr.dataProvider().setUserMaximumValue(1, val_max) lyr.dataProvider().setStatistics(1, QgsRasterBandStats.All, stats, True) # 触发图层刷新与样式更新 lyr.triggerRepaint() lyr.emitStyleChanged() # 强制刷新图层树的符号显示,同步样式面板 iface.layerTreeView().refreshLayerSymbology(lyr.id())
关键修改说明
- 修正色带采样逻辑:原代码用
map.N索引采样易出错,改为直接用0-1范围采样Matplotlib色带,更稳定 - 同步Shader与渲染器极值:通过
setMinimumValue/MaximumValue和setClassificationMin/Max让渲染器明确值范围,避免默认使用0-255 - 更新统计缓存:调用
setUserMinimumValue等方法强制QGIS存储正确极值,解决TOC显示错误问题 - 强制刷新图层树:
refreshLayerSymbology确保样式面板和目录同步显示新色带
内容的提问来源于stack exchange,提问作者Leviathan
相关产品推荐
相关产品推荐

