Yakındaki noktaların yoğunluğuna bağlı olarak matplotlib altıgenlerde onaltılık boyut


9

Aşağıdaki kodu üreten aşağıdaki kodu var

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

saçmak

Verileri aşağıda belirtildiği gibi altıgenler kullanarak grafikledim

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

Altıgenlerin boyutunu, altıgenin kapladığı alanda çizilen noktaların yoğunluğuna göre değiştirmek istiyorum. Örneğin, sol alt kısımdaki (noktaların kompakt olduğu) altıgenler, başka her yerde (noktaların seyrek olduğu) altıgenlerden daha büyük olacaktır. Bunu yapmanın bir yolu var mı?

Düzenleme: Ben bu çözümü denedim , ama nasıl df ['Bin'] dayalı hexes renklendirmek veya min ve max hex boyutu ayarlamak için nasıl anlayamıyorum.

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

Önerilen çözüm



@ plasmon360 Önerilen çözümden çalışmalarımla gönderiyi güncelledim
Ethan

1
Kullandığınızda C=df['Bin'],yoğunluğu değil, Binsütundaki miktarı gösterecektir . Yani çizim doğru. CArgümanı dışarıda bırakabilir ve yoğunluğa göre boyutları elde edebilirsiniz.
ImportanceOfBeingErnest

@ImportanceOfBeingErnest tamam, anladım. Hex'leri df ['Bin'] ile nasıl renklendirebilirim? Ayrıca altıgenlerin minik boyutunu biraz daha büyük olacak şekilde değiştirmek istiyorum, bu mümkün mü?
Ethan

1
Boyut, val/makoddaki oranla belirlenir . Uygun bulduklarınızla değiştirebilirsiniz. Renkler pc.set_array(values); valueselbette başka bir şey kullanabilirsiniz .
ImportanceOfBeingErnest

Yanıtlar:


3

Bir zamanlar renk eşlemesini anlamak için harcamak isteyebilirsiniz.

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

resim açıklamasını buraya girin

resim açıklamasını buraya girin

resim açıklamasını buraya girin


Kolona göre rengi nasıl değiştirebilirim df['Bin']?
Ethan

Yani, hexbin'de frekansı görmek istemiyorsunuz ama df ['Bin'] değerlerinin toplamını mı görmek istiyorsunuz?
lostin

Evet, altıgenlerin renginin df['Bin']sütuna dayanmasını istiyorum , bu yüzden sol alt altıgenler mavi ve diğerleri kırmızı
Ethan

Df ['Bins'] toplamına göre çizim ekledim. Rengi yönetmek için cmap'i düzenleyebilirsiniz. Başka bir şey yapmak isteyip istemediğinizden emin değilim.
lostin

Bunun yerine, bin içindeki değerlerin toplamını temel alarak renklendirmek istemiyorum. Bunu yapmanın bir yolu var mı? Renkler, örneğimin ikinci grafiğindeki renklerle eşleşecek
Ethan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.