【问题标题】:Place ticks in the middle of each color in descrete colorbar将刻度放在离散颜色条中每种颜色的中间
【发布时间】:2018-07-04 16:26:41
【问题描述】:

我需要更改颜色条刻度的位置,并且需要帮助。到目前为止,我已经尝试了一些事情,但没有一件事情以令人满意的方式工作。

我有以下类型的数据框:

import pandas as pd
import random
country_iso = ['RU', 'FR', 'HU', 'AT', 'US', 'ES', 'DE', 'CH', 'LV', 'LU']
my_randoms=[random.uniform(0.0, 0.3) for _ in range (len(country_iso))]
df = pd.DataFrame({'iso':country_iso, 'values':my_randoms})
df.loc[df.iso.str.contains('US')]= ['US', 0]
df['binned']=pd.cut(df['values'], bins=[-0.01, 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3], labels=[0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3])
df.binned = pd.to_numeric(df.binned, errors='coerce')
df = df[['iso', 'binned']]

如您所见,这是一个数据框,其中等国家/地区值作为一列,一些作为第二列,分箱值介于 0 和 0.3 之间。美国的值为 0,我希望它具有独特的颜色。然后,我继续使用来自natural earth 的 shapefile 创建底图。

from matplotlib import pyplot as plt, colors as clr, cm
from mpl_toolkits.basemap import Basemap
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
from matplotlib.ticker import FuncFormatter    
import numpy as np

shapefile_path = #path to your shapefile

fig, ax = plt.subplots(figsize=(10,20))
m = Basemap(resolution='c', # c, l, i, h, f or None
            projection='mill',
            llcrnrlat=-62, urcrnrlat=85,
            llcrnrlon=-180, urcrnrlon=180)
m.readshapefile(shapefile_path+r'\ne_110m_admin_0_countries', 'areas')
df_poly = pd.DataFrame({
    'shapes': [Polygon(np.array(shape), True) for shape in m.areas],
    'iso': [gs['ISO_A2'] for gs in m.areas_info]
})
df_poly = df_poly.merge(df, on='iso', how='inner', indicator=True)

cmap = clr.LinearSegmentedColormap.from_list('custom blue', ['#d0dfef', '#24466b'], N=7)
cmap._init()
cmap._lut[0,: ] = np.array([200,5,5,200])/255
pc = PatchCollection(df_poly[df_poly[df.columns[1]].notnull()].shapes, zorder=2)
norm = clr.Normalize()
pc.set_facecolor(cmap(norm(df_poly[df_poly[df.columns[1]].notnull()][df.columns[1]].values)))
ax.add_collection(pc)

mapper = cm.ScalarMappable(norm=norm, cmap=cmap)
mapper.set_array(df_poly[df_poly[df.columns[1]].notnull()][df.columns[1]])
clb = plt.colorbar(mapper, shrink=0.19)

我创建了一个蓝色的 cmap,但将第一个颜色更改为红色。这是因为我希望值为 0 的国家/地区具有不同的颜色。一切都很好,但如果你看一下颜色条,刻度线就会偏离中心。

有人知道如何更正我的代码吗?非常感谢!

【问题讨论】:

  • 你正在做LinearSegmentedColormap.from_list(..., N=7) 但 7 并没有“很好地”进入 0.3。试试N=6
  • 我不确定“零”在这里的作用。如果将 0 放在颜色图红色部分的中间,则表示例如-0.025 和 +0.025 之间的值被着色为红色,而不仅仅是 0 本身。这是你要求的吗?
  • 您可以使用最简单的示例轻松提出您的问题。请这样做,您将有更多机会获得一个好的答案,并且对其他人更有用。
  • 我已经减少了很多代码,并在阅读了您的评论@Tom 后进一步减少了代码。我对 python 有点陌生,对绘图更是如此,并且不确定如何进一步减少它。似乎不需要底图来回答这个问题,但我不知道。至于颜色段,不幸的是 n=6 并不能解决问题,尽管它看起来更好。至于 0 值,围绕 0 的区间非常小,只能捕获值为 0 的国家/地区。
  • 我认为你的问题是可以的。每个人都可以看到您是 SO 的新手。将来,只要有可能,请尝试发布可以“开箱即用”运行的示例代码,以解决“此代码无法正常工作”类型的问题。有关这方面的更多信息,请参阅https://stackoverflow.com/help/mcve。另请注意,您的代码中有一些缩进问题——我猜这是因为将您的原始代码减少到显示的版本。

标签: python matplotlib matplotlib-basemap


【解决方案1】:

将您的示例归结为基本要素,您可以通过扩展传递给映射器的范围来实现您想要的。我猜想将颜色图扩展到负值是否有意义取决于具体的用例。无论如何,这是一个没有Basemapshapefiles 的完整示例,此问题不需要它们。

from matplotlib import pyplot as plt, colors as clr, cm
import numpy as np

fig= plt.figure()
ax = plt.subplot2grid((1,20),(0,0), colspan=19)
cax = plt.subplot2grid((1,20),(0,19))

upper = 0.3
lower = 0.0
N = 7

cmap = clr.LinearSegmentedColormap.from_list(
    'custom blue', ['#d0dfef', '#24466b'], N=N
)
cmap._init()
cmap._lut[0,: ] = np.array([200,5,5,200])/255.0
norm = clr.Normalize()

mapper = cm.ScalarMappable(norm=norm, cmap=cmap)

deltac = (upper-lower)/(2*(N-1))

mapper.set_array(np.linspace(lower-deltac,upper+deltac,10)) #<-- the 10 here is pretty arbitrary
clb = fig.colorbar(mapper, shrink=0.19, cax=cax)

plt.show()

我在颜色条的垂直延伸方面遇到了一些问题,这就是我选择使用cax 关键字的原因。另请注意,在 Python 2 中,整数除法存在一个小问题。因此,我将部门从/255 更改为/255.0。最终结果如下所示:

希望这会有所帮助。

编辑

显然对norm() 的调用改变了Normalize 对象的状态。通过向ScalarMappable 构造函数提供一个新的Normalize 对象,代码开始按预期工作。我仍然很困惑为什么会发生这种情况。无论如何,在生成绘图和颜色条的完整代码下方(请注意,我更改了图形大小和颜色条缩放比例):

from matplotlib import pyplot as plt, colors as clr, cm
from mpl_toolkits.basemap import Basemap
from matplotlib.patches import Polygon
import pandas as pd
import random
country_iso = ['RU', 'FR', 'HU', 'AT', 'US', 'ES', 'DE', 'CH', 'LV', 'LU']
my_randoms=[random.uniform(0.0, 0.3) for _ in range (len(country_iso))]
df = pd.DataFrame({'iso':country_iso, 'values':my_randoms})
df.loc[df.iso.str.contains('US')]= ['US', 0]
df['binned']=pd.cut(df['values'], bins=[-0.01, 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3], labels=[0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3])
df.binned = pd.to_numeric(df.binned, errors='coerce')
df = df[['iso', 'binned']]

import numpy as np
from matplotlib.collections import PatchCollection
from matplotlib.ticker import FuncFormatter

shapefile_path = 'shapefiles/'

fig, ax = plt.subplots()#figsize=(10,20))

upper = 0.3
lower = 0.0
N = 7

deltac = (upper-lower)/(2*(N-1))

m = Basemap(resolution='c', # c, l, i, h, f or None
            projection='mill',
            llcrnrlat=-62, urcrnrlat=85,
            llcrnrlon=-180, urcrnrlon=180,
            ax = ax,
            )
m.readshapefile(shapefile_path+r'ne_110m_admin_0_countries', 'areas')
df_poly = pd.DataFrame({
    'shapes': [Polygon(np.array(shape), True) for shape in m.areas],
    'iso': [gs['ISO_A2'] for gs in m.areas_info]
})

df_poly = df_poly.merge(df, on='iso', how='inner', indicator=True)

cmap = clr.LinearSegmentedColormap.from_list('custom blue', ['#d0dfef', '#24466b'], N=N)
cmap._init()
cmap._lut[0,: ] = np.array([200,5,5,200])/255.0

pc = PatchCollection(df_poly[df_poly[df.columns[1]].notnull()].shapes, zorder=2)
norm = clr.Normalize()

pc.set_facecolor(cmap(norm(df_poly[df_poly[df.columns[1]].notnull()][df.columns[1]].values)))
ax.add_collection(pc)

mapper = cm.ScalarMappable(norm=clr.Normalize(), cmap=cmap)
mapper.set_array([lower-deltac,upper+deltac])
clb = plt.colorbar(mapper, shrink=0.55)

plt.show()

生成的图如下所示:

【讨论】:

  • 嗨,Thomas,感谢您抽出宝贵时间将代码简化为基本要素并找到答案。不幸的是,到目前为止,我无法调整您的答案以使其适用于我的情况,但我相信我会到达那里。
  • @Wald 基本上您需要更改的只是代码中的mapper.set_array 行。您可以将绘制的数据与用于调整颜色条的数据完全分离。这就是为什么我选择了一个简单的numpy 数组来进行调整。
  • @Wald 实际上你甚至可以跳过numpy.linspace,直接写mapper.set_array([lower-deltac,upper+deltac])
  • 我觉得自己很蠢,但是我到底需要改变什么?更改 mapper.set_array 是我在阅读您的答案后做的第一件事,但由于某种原因,这并不能解决它。我想可能是我可能必须从您的示例中调整上/下和 deltac(我只是复制了它们),但这些是我使用的值。感谢您的耐心等待。
  • 哇,非常感谢。我非常感谢您为帮助我所花费的时间和精力。效果很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-20
  • 1970-01-01
  • 2021-06-04
  • 2021-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多