Kích thước hex trong hexbins matplotlib dựa trên mật độ của các điểm lân cận


9

Tôi đã nhận được mã sau đây tạo ra hình sau

import numpy as np
np.random.seed(3)
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame()
df['X'] = list(np.random.randint(100, size=100)) + list(np.random.randint(30, size=100))
df['Y'] = list(np.random.randint(100, size=100)) + list(np.random.randint(30, size=100))

df['Bin'] = df.apply(lambda row: .1 if row['X'] < 30 and row['Y'] < 30 else .9, axis=1)

fig, ax = plt.subplots(figsize=(10,10))
plt.scatter(df['X'], df['Y'])

tiêu tan

Tôi đã vẽ đồ thị dữ liệu bằng cách sử dụng hexbins, như được lưu ý dưới đây

from matplotlib import cm

fig, ax = plt.subplots(figsize=(10,10))
hexbin = ax.hexbin(df['X'], df['Y'], C=df['Bin'], gridsize=20, cmap= cm.get_cmap('RdYlBu_r'),edgecolors='black')
plt.show()

lục giác

Tôi muốn thay đổi kích thước của các hình lục giác dựa trên mật độ của các điểm được vẽ trong khu vực mà hình lục giác bao phủ. Ví dụ, các hình lục giác ở phía dưới bên trái (nơi các điểm nhỏ gọn) sẽ lớn hơn các hình lục giác ở mọi nơi khác (nơi các điểm thưa thớt). Có cách nào để làm việc này không?

Chỉnh sửa: Tôi đã thử giải pháp này , nhưng tôi không thể tìm ra cách tô màu các hình lục giác dựa trên df ['Bin'] hoặc cách đặt kích thước hex tối thiểu và tối đa.

from matplotlib.collections import PatchCollection
from matplotlib.path import Path
from matplotlib.patches import PathPatch
fig, ax = plt.subplots(figsize=(10,10))
hexbin = ax.hexbin(df['X'], df['Y'], C=df['Bins'], gridsize=20, cmap= cm.get_cmap('RdYlBu_r'),edgecolors='black')
def sized_hexbin(ax,hc):
    offsets = hc.get_offsets()
    orgpath = hc.get_paths()[0]
    verts = orgpath.vertices
    values = hc.get_array()
    ma = values.max()
    patches = []
    for offset,val in zip(offsets,values):
        v1 = verts*val/ma+offset
        path = Path(v1, orgpath.codes)
        patch = PathPatch(path)
        patches.append(patch)

    pc = PatchCollection(patches, cmap=cm.get_cmap('RdYlBu_r'), edgecolors='black')
    pc.set_array(values)
    ax.add_collection(pc)
    hc.remove()

sized_hexbin(ax,hexbin)
plt.show()

đề xuất giải pháp



@ plasmon360 Tôi đã cập nhật bài đăng với công việc của mình từ giải pháp được đề xuất
Ethan

1
Khi bạn sử dụng C=df['Bin'],nó sẽ không hiển thị mật độ, mà là số lượng trong Bincột. Vì vậy, cốt truyện là chính xác. Bạn có thể bỏ qua Cđối số và lấy kích thước dựa trên mật độ.
ImportanceOfByingErnest

@ImportanceOfByingErnest được rồi, gotcha. Làm cách nào tôi có thể tô màu các hình lục giác bằng df ['Bin']? Tôi cũng muốn có thể thay đổi kích thước tối thiểu của các hình lục giác để lớn hơn một chút, điều này có thể không?
Ethan

1
Kích thước được xác định bởi tỷ lệ val/matrong mã. Bạn có thể thay thế nó bằng bất cứ điều gì bạn thấy phù hợp. Các màu được thiết lập thông qua pc.set_array(values); bạn có thể sử dụng một cái gì đó khác hơn valueslà tất nhiên.
ImportanceOfByingErnest

Câu trả lời:


3

Bạn có thể muốn dành đôi khi để hiểu bản đồ màu.

    import numpy as np
    np.random.seed(3)
    import pandas as pd
    import matplotlib.pyplot as plt
    from matplotlib.collections import PatchCollection
    from matplotlib.path import Path
    from matplotlib.patches import PathPatch
    df = pd.DataFrame()
    df['X'] = list(np.random.randint(100, size=100)) + list(np.random.randint(30, size=100))
    df['Y'] = list(np.random.randint(100, size=100)) + list(np.random.randint(30, size=100))

    df['Bin'] = df.apply(lambda row: .1 if row['X'] < 30 and row['Y'] < 30 else .9, axis=1)

    #fig, ((ax1, ax2)) = plt.subplots(1, 2, sharex=True, sharey=True)
    ax1 = plt.scatter(df['X'], df['Y'])

    fig,ax2 = plt.subplots(figsize=(10,10))
    hexbin = ax2.hexbin(df['X'], df['Y'], C=df['Bin'], gridsize=20,edgecolors='black',cmap= 'RdBu', reduce_C_function=np.bincount) #**

    def sized_hexbin(ax,hc):
        offsets = hc.get_offsets()
        orgpath = hc.get_paths()[0]
        verts = orgpath.vertices
        values = hc.get_array()
        ma = values.max()
        patches = []
        for offset,val in zip(offsets,values):
            v1 = verts*val/ma + offset
            path = Path(v1, orgpath.codes)
            patch = PathPatch(path)
            patches.append(patch)

        pc = PatchCollection(patches, cmap= 'RdBu', edgecolors='black')
        pc.set_array(values)

        ax.add_collection(pc)

        hc.remove()

    sized_hexbin(ax2,hexbin)
    cb = plt.colorbar(hexbin, ax=ax2)

    plt.show()

To plot the chart based on df['bins'] values - 

Need to change the reduce_C_function in #** marked line -

    hexbin = ax2.hexbin(df['X'], df['Y'], C=df['Bin'], gridsize=20,edgecolors='black',cmap= 'RdBu', reduce_C_function=np.sum)

[![enter image description here][2]][2]


  [1]: https://i.stack.imgur.com/kv0U4.png
  [2]: https://i.stack.imgur.com/mb0gD.png

# Another variation of the chart :

# Where size is based on count of points in the bins and color is based on values of the df['bin']./ Also added if condition to control minimum hexbin size.


import numpy as np
np.random.seed(3)
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
from matplotlib.path import Path
from matplotlib.patches import PathPatch
from functools import partial

mycmp = 'coolwarm'

df = pd.DataFrame()
df['X'] = list(np.random.randint(100, size=100)) + list(np.random.randint(30, size=100))
df['Y'] = list(np.random.randint(100, size=100)) + list(np.random.randint(30, size=100))

df['Bin'] = df.apply(lambda row: .1 if row['X'] < 30 and row['Y'] < 30 else .9, axis=1)

#fig, ((ax1, ax2)) = plt.subplots(1, 2, sharex=True, sharey=True)
ax1 = plt.scatter(df['X'], df['Y'])


fig,ax2 = plt.subplots(figsize=(10,10))
hexbin = ax2.hexbin(df['X'], df['Y'], C=df['Bin'], gridsize=15,edgecolors='black',cmap= newcmp , reduce_C_function=np.bincount)
hexbin2 = ax2.hexbin(df['X'], df['Y'], C=df['Bin'], gridsize=15,edgecolors='black',cmap= newcmp , reduce_C_function=np.mean)

def sized_hexbin(ax,hc,hc2):
    offsets = hc.get_offsets()
    orgpath = hc.get_paths()[0]
    verts = orgpath.vertices
    values1 = hc.get_array()
    values2 = hc2.get_array()
    ma = values1.max()
    patches = []

    for offset,val in zip(offsets,values1):
        # Adding condition for minimum size 
        if (val/ma) < 0.2:
            val_t = 0.2
        else:
            val_t = val/ma
        v1 =  verts*val_t + offset
        path = Path(v1, orgpath.codes)
        print(path)
        patch = PathPatch(path)
        patches.append(patch)

    pc = PatchCollection(patches, cmap=  newcmp)  #edgecolors='black'
    pc.set_array(values2)

    ax.add_collection(pc)
    hc.remove()
    hc2.remove()


sized_hexbin(ax2,hexbin,hexbin2)
cb = plt.colorbar(hexbin2, ax=ax2)

plt.xlim((-5, 100))
plt.ylim((-5, 100))

plt.show()

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


Làm cách nào để thay đổi màu dựa trên df['Bin']cột?
Ethan

Vì vậy, bạn không muốn thấy tần số trong hexbin mà là tổng các giá trị df ['Bin']?
lostin

Có, tôi muốn màu của các hình lục giác dựa trên df['Bin']cột, vì vậy các hình lục giác phía dưới bên trái có màu xanh và các hình khác có màu đỏ
Ethan

Tôi đã thêm cốt truyện dựa trên tổng của df ['Bins']. Bạn có thể chỉnh sửa cmap để quản lý màu. Không chắc chắn nếu bạn đang tìm kiếm để làm một cái gì đó khác.
lostin

Tôi không muốn tô màu nó dựa trên tổng các giá trị trong thùng, thay vào đó là giá trị của chính thùng đó. Có cách nào làm được việc này không? Các màu sẽ khớp với các màu trong ô thứ hai trong ví dụ của tôi
Ethan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.