метка формата / круглой цифровой легенды в GeoPandas - PullRequest
0 голосов
/ 25 сентября 2018

Я ищу способ форматирования / округления числовых надписей на тех картах, которые были созданы функцией .plot() в GeoPandas.Например:

gdf.plot(column='pop2010', scheme='QUANTILES', k=4)

Это дает мне легенду с большим количеством десятичных знаков:

enter image description here

Я хочу, чтобы метка легенды былацелые числа.

Ответы [ 2 ]

0 голосов
/ 26 июня 2019

Метод 1:

GeoPandas использует классификатор PySal .Вот пример карты квантилей (k = 5).

import matplotlib.pyplot as plt
import numpy as np
import pysal.viz.mapclassify as mc
import geopandas as gpd

# load dataset
path = gpd.datasets.get_path('naturalearth_lowres')
gdf = gpd.read_file(path)
# generate a random column
gdf['random_col'] = np.random.normal(100, 10, len(gdf))

# plot quantiles map
fig, ax = plt.subplots(figsize=(10, 10))
gdf.plot(column='random_col', scheme='quantiles', k=5, cmap='Blues',
         legend=True, legend_kwds=dict(loc=6), ax=ax)

Это дает нам: enter image description here

Предположим, что мы хотим округлить числа влегенда.Мы можем получить классификацию с помощью функции .Quantiles() в pysal.viz.mapclassify.

mc.Quantiles(gdf.random_col, k=5)

Функция возвращает объект classifiers.Quantiles:

Quantiles                 

 Lower            Upper              Count
==========================================
          x[i] <=  93.122               36
 93.122 < x[i] <=  98.055               35
 98.055 < x[i] <= 103.076               35
103.076 < x[i] <= 109.610               35
109.610 < x[i] <= 127.971               36

Объект имеет атрибут bins, который возвращает массив, содержащий верхние границы во всех классах.

array([ 93.12248452,  98.05536454, 103.07553581, 109.60974753,
       127.97082465])

Таким образом, мы можем использовать эту функцию, чтобы получить все границы классов, так как верхняя граница в нижнем классе равна нижнемусвязаны в более высоком классе.Отсутствует только одна нижняя граница в низшем классе, которая равна минимальному значению столбца, который вы пытаетесь классифицировать в вашем DataFrame.

Вот пример округления всех чисел до целых:

# get all upper bounds
upper_bounds = mc.Quantiles(gdf.random_col, k=5).bins

# get and format all bounds
bounds = []
for index, upper_bound in enumerate(upper_bounds):
    if index == 0:
        lower_bound = gdf.random_col.min()
    else:
        lower_bound = upper_bounds[index-1]

    # format the numerical legend here
    bound = f'{lower_bound:.0f} - {upper_bound:.0f}'
    bounds.append(bound)

# get all the legend labels
legend_labels = ax.get_legend().get_texts()

# replace the legend labels
for bound, legend_label in zip(bounds, legend_labels):
    legend_label.set_text(bound)

В итоге мы получим: enter image description here


Метод 2:

В дополнение к GeoPandas '.plot()В качестве метода вы также можете рассмотреть функцию .choropleth(), предлагаемую геоплотом , в которой вы можете легко использовать различные типы схем и количество классов при передаче аргумента legend_labels для изменения меток легенды.Например,

import geopandas as gpd
import geoplot as gplt

path = gpd.datasets.get_path('naturalearth_lowres')
gdf = gpd.read_file(path)

legend_labels = ['< 2.4', '2.4 - 6', '6 - 15', '15 - 38', '38 - 140 M']
gplt.choropleth(gdf, hue='pop_est', cmap='Blues', scheme='quantiles',
                legend=True, legend_labels=legend_labels)

, что дает вам

enter image description here

0 голосов
/ 14 июня 2019

Поскольку недавно я столкнулся с той же проблемой, и решение, по-видимому, недоступно для переполнения стека или других сайтов, я подумал, что опубликую подход, который использовал, в случае его полезности.

Сначалабазовый сюжет с использованием карты мира geopandas:

# load world data set    
world_orig = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))
world = world_orig[(world_orig['pop_est'] > 0) & (world_orig['name'] != "Antarctica")].copy()
world['gdp_per_cap'] = world['gdp_md_est'] / world['pop_est']

# basic plot
fig = world.plot(column='pop_est', figsize=(12,8), scheme='fisher_jenks', 
                 cmap='YlGnBu', legend=True)
leg = fig.get_legend()
leg._loc = 3
plt.show()

world map v1

Метод, который я использовал, опирался на метод get_texts() для matplotlib.legend.Legend объекта, затем перебирая элементы в leg.get_texts(), разбивая текстовый элемент на нижнюю и верхнюю границы, а затем создавая новую строку с примененным форматированием и устанавливая ее с помощью метода set_text().

# formatted legend
fig = world.plot(column='pop_est', figsize=(12,8), scheme='fisher_jenks', 
                 cmap='YlGnBu', legend=True)
leg = fig.get_legend()
leg._loc = 3

for lbl in leg.get_texts():
    label_text = lbl.get_text()
    lower = label_text.split()[0]
    upper = label_text.split()[2]
    new_text = f'{float(lower):,.0f} - {float(upper):,.0f}'
    lbl.set_text(new_text)

plt.show()

Это очень подход «проб и ошибок», поэтому я не удивлюсь, если бы был лучший способ.Тем не менее, возможно, это будет полезно.

world map v2

...