如何正确缩放cmapcolor使条形颜色匹配色条?
解决cmap颜色与色条不匹配的问题
问题原因
你遇到的颜色不匹配问题,核心是未对Distance值做归一化处理。Matplotlib的颜色映射函数(如cmapz())要求输入参数必须是**[0, 1]区间的数值**,但你的Distance取值范围是0到4,当传入大于1的数值时,会被自动截断为1,导致所有Distance>1的片段都显示色条最右端的颜色(比如plasma的黄色),和色条标注的对应值完全不符。
解决方案
只需要将Distance值归一化到[0,1]区间后,再传入颜色映射函数即可,以下提供两种可行方式:
方式1:使用Normalize类(推荐,更规范)
导入Normalize类,基于Distance的实际取值范围创建归一化对象,统一处理数值映射:
from matplotlib.colors import Normalize # 基于Distance的最小/最大值创建归一化对象 norm = Normalize(vmin=min(Distanceslst), vmax=max(Distanceslst))
然后在循环生成条形颜色时,用归一化后的值获取颜色:
cmapcolor = cmapz(norm(Distanceslst[i]))
方式2:手动归一化(简单直接)
直接将每个Distance值除以最大值,缩放到[0,1]区间:
max_dist = max(Distanceslst) cmapcolor = cmapz(Distanceslst[i] / max_dist)
修正后的完整代码
另外注意原代码中templength未定义,这里替换为从数据中获取模板长度,避免报错:
#Create some fake example data and store it in a dataframe import pandas as pd import random as rd exampledf=pd.DataFrame() tempname='Template' queryname='Query' templatenamelst=[] querynamelst=[] startlst=[] endlst=[] querystartslst=[] queryendslst=[] distancelst=[] for i in range(20): start=i*5 end=(i*5)+25 distance=rd.uniform(0, 4) querystart=rd.randint(0, 95) queryend=querystart+25 templatenamelst.append(tempname) querynamelst.append(queryname) startlst.append(start) endlst.append(end) distancelst.append(distance) querystartslst.append(querystart) queryendslst.append(queryend) exampledf['TempName']=templatenamelst exampledf['QueryName']=querynamelst exampledf['TempStarts']=startlst exampledf['TempEnds']=endlst exampledf['QueryStarts']=querystartslst exampledf['QueryEnds']=queryendslst exampledf['Distances']=distancelst display(exampledf) #Build the plot from the example data import numpy as np import warnings import matplotlib.pyplot as plt from matplotlib import cm from matplotlib.colors import Normalize warnings.filterwarnings('ignore') TempName=exampledf.iloc[0]['TempName'] QueryName=exampledf.iloc[0]['QueryName'] NumSeqFrags=len(exampledf) # 从数据中获取模板长度,替换未定义的templength TempLength = max(exampledf['TempEnds']) Distanceslst=list(exampledf.Distances) XMax=max(list(exampledf.TempEnds)) cmapz = cm.get_cmap('plasma') # 创建归一化对象 norm = Normalize(vmin=min(Distanceslst), vmax=max(Distanceslst)) img = plt.imshow(np.array([[0,max(Distanceslst)]]), cmap="plasma") img.set_visible(False) barheight=6 plt.barh(width=TempLength, left=0, height=barheight, y=0,color='Black') ticklabels=[TempName] ticklocations=[0] #Add the fragments for i in range (len(exampledf)): # 使用归一化后的值获取颜色 cmapcolor=cmapz(norm(Distanceslst[i])) width=int(exampledf.iloc[i]['TempEnds'])-int(exampledf.iloc[i]['TempStarts']) start=int(exampledf.iloc[i]['TempStarts']) yloc=(barheight+4)*i+barheight plt.barh(width=width, left=start, height=barheight, y=yloc,color=cmapcolor) fullname=str(exampledf.iloc[i]['QueryName'])+'('+str(exampledf.iloc[i]['QueryStarts'])+':'+str(exampledf.iloc[i]['QueryEnds'])+')'+'(Distance='+str(round(Distanceslst[i],2))+')' ticklabels.append(fullname) ticklocations.append(yloc) plt.yticks(ticks=ticklocations, labels=ticklabels,fontsize=8) plt.colorbar(orientation="horizontal",fraction=0.05,label='Distance') plt.show()
效果说明
修改后,每个条形的颜色会根据Distance的实际值,对应色条上的位置显示正确颜色,比如Distance=1.75的片段会显示plasma色条上对应1.75的浅紫色,和色条标注完全匹配。
内容的提问来源于stack exchange,提问作者Jamie
相关产品推荐
相关产品推荐

