为 geopandas.explore 图创建自定义颜色图

Creating custom colourmap for geopandas.explore plot

所有代码:

def rgb2hex(r,g,b):
    return '#{:02x}{:02x}{:02x}'.format(r,g,b)

def rg(num):
    num = int(np.round((num / 100) * 124))
    r = (124 - num)
    g = (124 + num)
    b = (0)
    x = rgb2hex(r,g,b)
    return x

def colourmap(value):
    if math.isnan(value) == False:
        y = rg(value)
    else:
        y = '#808080'
    return y

m = homes.explore(
     column="Percentage",
     cmap=lambda value: colourmap(value),#map to custom colour scheme
     marker_kwds=dict(radius=15, fill=True), # make marker radius 15px with fill
     tooltip=labels, # show labels in the tooltip
     legend=False, 
     name="Homes" # name of the layer in the map
)
m #plot

您好,我对 Whosebug 和使用 geopandas 比较陌生,因此欢迎任何意见。

我正在尝试创建处理 NaN 值的自定义配色方案。

绿色表示百分比高,黄色表示百分比低但灰色表示 NaN。

但是我得到这个错误:


ValueError                                Traceback (most recent call last)
_______________________________________.ipynb Cell 33' in <module>
      3 labels = ["Worker Type","Postcode","Name","Percentage"]
---> 16 m = homes.explore(
     17      column="Percentage",
     18      cmap=lambda value: colourmap(value)
     19      marker_kwds=dict(radius=15, fill=True)
     20      tooltip=labels
     22      legend=False, # do not show column label in the tooltip
     23      name="Homes" # name of the layer in the map

File ____________________\ref_env\lib\site-packages\geopandas\geodataframe.py:1858, in GeoDataFrame.explore(self, *args, **kwargs)
   1855 @doc(_explore)
   1856 def explore(self, *args, **kwargs):
   1857     """Interactive map based on folium/leaflet.js"""
-> 1858     return _explore(self, *args, **kwargs)

File ________________\ref_env\lib\site-packages\geopandas\explore.py:457, in _explore(df, column, cmap, color, m, tiles, attr, tooltip, popup, highlight, categorical, legend, scheme, k, vmin, vmax, width, height, categories, classification_kwds, control_scale, marker_type, marker_kwds, style_kwds, highlight_kwds, missing_kwds, tooltip_kwds, popup_kwds, legend_kwds, **kwargs)
    454     nan_color = missing_kwds.pop("color", None)
    456     gdf["__folium_color"] = nan_color
--> 457     gdf.loc[~nan_idx, "__folium_color"] = color
    458 else:
    459     gdf["__folium_color"] = color

File _______________\ref_env\lib\site-packages\pandas\core\indexing.py:723, in _LocationIndexer.__setitem__(self, key, value)
    720 self._has_valid_setitem_indexer(key)
    722 iloc = self if self.name == "iloc" else self.obj.iloc
--> 723 iloc._setitem_with_indexer(indexer, value, self.name)

File _________________\ref_env\lib\site-packages\pandas\core\indexing.py:1730, in _iLocIndexer._setitem_with_indexer(self, indexer, value, name)
   1727 # align and set the values
   1728 if take_split_path:
   1729     # We have to operate column-wise
-> 1730     self._setitem_with_indexer_split_path(indexer, value, name)
   1731 else:
   1732     self._setitem_single_block(indexer, value, name)

File ______________\ref_env\lib\site-packages\pandas\core\indexing.py:1785, in _iLocIndexer._setitem_with_indexer_split_path(self, indexer, value, name)
   1780     if len(value) == 1 and not is_integer(info_axis):
   1781         # This is a case like df.iloc[:3, [1]] = [0]
   1782         #  where we treat as df.iloc[:3, 1] = 0
   1783         return self._setitem_with_indexer((pi, info_axis[0]), value[0])
-> 1785     raise ValueError(
   1786         "Must have equal len keys and value "
   1787         "when setting with an iterable"
   1788     )
   1790 elif lplane_indexer == 0 and len(value) == len(self.obj.index):
   1791     # We get here in one case via .loc with a all-False mask
   1792     pass

ValueError: Must have equal len keys and value when setting with an iterable

有人可以向我描述这个错误并指导我下一步看哪里吗?

编辑:我应该包括我正在使用点几何

  • 已使用标准几何模拟此问题的数据
  • cmap 是可调用的并且它们是 中的 NaN 值时,我发现的似乎是一个错误列
  • 已经解决了
    1. fillna(-99)
    2. 调整你的 colormap() 函数来处理 -99 与 NaN
  • 根据围绕 JSON 序列化的评论扩展了答案。创建了一个功能列。测试列是 JSON 可序列化的,然后排除不可序列化的列 我在 geopandas 中对 explore() 做出了改进。我正在研究导致此问题/错误的参数排列。将针对 Geopandas 提出问题并可能提交 PR。与此同时,我建议使用上述解决方法。

更新 产生了一个问题 https://github.com/geopandas/geopandas/issues/2408

import geopandas as gpd
import numpy as np
import math
import json


def rgb2hex(r, g, b):
    return "#{:02x}{:02x}{:02x}".format(r, g, b)


def rg(num):
    num = int(np.round((num / 100) * 124))
    r = 124 - num
    g = 124 + num
    b = 0
    x = rgb2hex(r, g, b)
    return x


def colourmap(value):
    if value != -99 and math.isnan(value) == False:  # changed to treat -99 as NaN :-(
        y = rg(value)
    else:
        y = "#808080"

    return y


# some geometry to demonstrate
def foo():
    return True


homes = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
homes["Percentage"] = np.random.randint(1, 100, len(homes))
homes["func_col"] = foo
homes.loc[homes.sample(20).index, "Percentage"] = np.nan
# miss this line and error is generated...
homes["Percentage"] = homes["Percentage"].fillna(-99)

excl = {}
for c in homes.columns:
    try:
        json.dumps(homes[c].to_dict())
    except TypeError as e:
        if c != "geometry":
            excl[c] = str(e)

m = homes.loc[:, [c for c in homes.columns if c not in excl.keys()]].explore(
    column="Percentage",
    cmap=lambda value: colourmap(value),  # map to custom colour scheme
    marker_kwds=dict(radius=15, fill=True),  # make marker radius 15px with fill
    # tooltip=labels, # show labels in the tooltip
    legend=False,
    name="Homes",  # name of the layer in the map
)
m  # plot

结合 Rob 的回答和评论中的讨论,这是我最终使用的最终解决方案:

import geopandas as gpd
import numpy as np
import math
import json
import random
import pandas as pd
import random

def rgb2hex(r, g, b):
    return "#{:02x}{:02x}{:02x}".format(r, g, b)
    
def rg(p):
    d = [255,0,0]
    d[1] = int((510*p)/100)
    if d[1]>255:
        d[0] -= d[1]-255
        d[1] = 255
    x = rgb2hex(d[0],d[1],d[2])
    return x

def colourmap(value):
    if value != -99 and math.isnan(value) == False:  # changed to treat -99 as NaN :-(
        y = rg(value)
    else:
        y = "#808080"

    return y

def foo(df):
    x = np.random.randint(-180, 180, len(df))
    y = np.random.randint(-90, 90, len(df))
    s = gpd.GeoSeries.from_xy(x, y, crs="EPSG:4326")
    return s

homes = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
homes["Percentage"] = np.random.randint(1, 100, len(homes))
homes["func_col"] = foo(homes)
homes.loc[homes.sample(20).index, "Percentage"] = np.nan
# miss this line and error is generated...
homes["Percentage"] = homes["Percentage"].fillna(-99)

homes = homes.set_geometry('func_col')

excl = {}
for c in homes.columns:
    try:
        json.dumps(homes[c].to_dict())
    except TypeError as e:
        if c != "geometry":
            excl[c] = str(e)

m = homes.explore(
     column="Percentage",
     cmap=lambda value: colourmap(value),
     marker_kwds=dict(radius=15, fill=True), # make marker radius 15px with fill
     tooltip=["name"], # show "name" column in the tooltip
     legend_kwds=dict(caption="Percentage",colorbar=True), # do not use colorbar
     legend=False, # do not show column label in the tooltip
     name="homes" # name of the layer in the map
)

m