Ukuran hex dalam hexagon matplotlib berdasarkan kepadatan poin terdekat

9

Saya punya kode berikut yang menghasilkan gambar berikut

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'])

menyebarkan

Saya membuat grafik data menggunakan hexbins, seperti yang tercantum di bawah ini

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()

hexbins

Saya ingin mengubah ukuran segi enam berdasarkan kepadatan titik yang diplot di area yang dicakup segi enam. Misalnya, segi enam di kiri bawah (di mana titik-titiknya kompak) akan lebih besar dari segi enam di tempat lain (di mana titik-titiknya jarang). Apakah ada cara untuk melakukan ini?

Sunting: Saya mencoba solusi ini , tetapi saya tidak tahu bagaimana cara mewarnai heksa berdasarkan df ['Bin'], atau bagaimana mengatur ukuran hex min dan max.

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()

solusi yang diusulkan

Ethan
sumber
1
Apakah Anda melihat stackoverflow.com/questions/48844600/… ?
plasmon360
@ plasmon360 Saya memperbarui posting dengan pekerjaan saya dari solusi yang diusulkan
Ethan
1
Saat Anda menggunakannya C=df['Bin'],tidak akan menunjukkan kepadatan, melainkan kuantitas yang ada di Binkolom. Jadi plotnya benar. Anda dapat meninggalkan Cargumen, dan mendapatkan ukuran berdasarkan kepadatan.
ImportanceOfBeingErnest
@ImportanceOfBeingErnest oke, mengerti. Bagaimana saya bisa mewarnai heks dengan df ['Bin']? Saya juga ingin dapat mengubah ukuran min dari segi enam menjadi sedikit lebih besar, apakah ini mungkin?
Ethan
1
Ukurannya ditentukan oleh rasio val/madalam kode. Anda dapat menggantinya dengan apa pun yang menurut Anda cocok. Warna-warna diatur melalui pc.set_array(values); Anda dapat menggunakan sesuatu selain valuestentu saja.
ImportanceOfBeingErnest

Jawaban:

3

Anda mungkin ingin menghabiskan waktu dalam memahami pemetaan warna.

    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()

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

hilang di
sumber
Bagaimana saya bisa mengubah warna berdasarkan df['Bin']kolom?
Ethan
Jadi Anda tidak ingin melihat frekuensi dalam hexbin tetapi jumlah dari nilai df ['Bin']?
Lostin
Ya, saya ingin warna heksagon didasarkan pada df['Bin']kolom, sehingga heksa kiri bawah berwarna biru dan lainnya berwarna merah
Ethan
Saya menambahkan plot berdasarkan jumlah df ['Bins']. Anda dapat mengedit cmap untuk mengelola warna. Tidak yakin apakah Anda ingin melakukan sesuatu yang lain.
Lostin
Saya tidak ingin mewarnainya berdasarkan jumlah nilai dalam nampan, bukan nilai nampan itu sendiri. Apakah ada cara untuk melakukan itu? Warna akan cocok dengan warna pada plot kedua dari contoh saya
Ethan