2012-10-18 2 views
9

Io uso il metodo di matplotlib hexbin per calcolare istogrammi 2d sui miei dati. Ma mi piacerebbe ottenere le coordinate dei centri degli esagoni al fine di elaborare ulteriormente i risultati.ottiene coordinate bin con hexbin in matplotlib

Ho ottenuto i valori utilizzando il metodo get_array() sul risultato, ma non riesco a capire come ottenere le coordinate dei raccoglitori.

Ho provato a calcolarli dato il numero di contenitori e l'estensione dei miei dati ma non conosco il numero esatto di contenitori in ogni direzione. gridsize=(10,2) dovrebbe fare il trucco ma non sembra funzionare.

Qualche idea?

+0

Potrei sbagliarmi ma non sembra essere un modo per ottenere le coordinate. Fortunatamente è tutto open source (cerca 'hexbin' in questo file: https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes.py) così puoi controllare come viene calcolata la griglia e replicalo nel tuo codice. In bocca al lupo! – Tobold

+0

Ciao, grazie, Tobold, controllerò il codice sorgente che hai menzionato. – user1151446

risposta

16

Penso che funzioni.

from __future__ import division 
import numpy as np 
import math 
import matplotlib.pyplot as plt 

def generate_data(n): 
    """Make random, correlated x & y arrays""" 
    points = np.random.multivariate_normal(mean=(0,0), 
     cov=[[0.4,9],[9,10]],size=int(n)) 
    return points 

if __name__ =='__main__': 

    color_map = plt.cm.Spectral_r 
    n = 1e4 
    points = generate_data(n) 

    xbnds = np.array([-20.0,20.0]) 
    ybnds = np.array([-20.0,20.0]) 
    extent = [xbnds[0],xbnds[1],ybnds[0],ybnds[1]] 

    fig=plt.figure(figsize=(10,9)) 
    ax = fig.add_subplot(111) 
    x, y = points.T 
    # Set gridsize just to make them visually large 
    image = plt.hexbin(x,y,cmap=color_map,gridsize=20,extent=extent,mincnt=1,bins='log') 
    # Note that mincnt=1 adds 1 to each count 
    counts = image.get_array() 
    ncnts = np.count_nonzero(np.power(10,counts)) 
    verts = image.get_offsets() 
    for offc in xrange(verts.shape[0]): 
     binx,biny = verts[offc][0],verts[offc][1] 
     if counts[offc]: 
      plt.plot(binx,biny,'k.',zorder=100) 
    ax.set_xlim(xbnds) 
    ax.set_ylim(ybnds) 
    plt.grid(True) 
    cb = plt.colorbar(image,spacing='uniform',extend='max') 
    plt.show() 

enter image description here

+1

Potete fornire un numero di versione per i moduli eseguiti con questo codice? Non capisco i dati dal get_offsets(): In [1]: verts = image.get_offsets() In [2]: verts Out [2]: array ([], DTYPE = float64) Questo è in esecuzione matplotlib 1.0.1, numpy 1.5.1 – Dave

+1

Mi sono permesso di modificare la domanda per includere l'immagine che genera. Bella risposta! – Hooked

2

mi piacerebbe confermare che il codice da Hooked utilizzando get_offsets() funziona, ma ho provato diverse iterazioni del codice di cui sopra per recuperare posizioni centrali e, come detto Dave, get_offsets () rimane vuoto. La soluzione che ho trovato è quella di utilizzare l'opzione 'image.get_paths()' non vuota. Il mio codice è il mezzo per trovare i centri ma il che significa che è solo un smidge più lungo, ma funziona.

L'opzione get_paths() restituisce un insieme di coordinate x, y incorporato che può essere ripetuto su un loop e quindi mediato per restituire la posizione centrale per ciascun esagramma.

Il codice che ho è il seguente:

counts=image.get_array() #counts in each hexagon, works great 
verts=image.get_offsets() #empty, don't use this 
b=image.get_paths() #this does work, gives Path([[]][]) which can be plotted 

for x in xrange(len(b)): 
    xav=np.mean(b[x].vertices[0:6,0]) #center in x (RA) 
    yav=np.mean(b[x].vertices[0:6,1]) #center in y (DEC) 
    plt.plot(xav,yav,'k.',zorder=100) 
0

Ho avuto questo stesso problema. Penso che ciò che deve essere sviluppato sia un framework per avere un oggetto HexagonalGrid che può quindi essere applicato a molti set di dati diversi (e sarebbe fantastico farlo per N dimensioni). Questo è possibile e mi sorprende che né Scipy né Numpy abbiano qualcosa per questo (inoltre non sembra esserci nient'altro eccetto forse binify)

Detto questo, presumo che tu voglia usare hexbinning per confrontare più insiemi di dati con binnati . Ciò richiede una base comune. Ho ottenuto questo lavoro utilizzando hexbin di matplotlib nel seguente modo:

import numpy as np 
import matplotlib.pyplot as plt 

def get_data (mean,cov,n=1e3): 
    """ 
    Quick fake data builder 
    """ 
    np.random.seed(101) 
    points = np.random.multivariate_normal(mean=mean,cov=cov,size=int(n)) 
    x, y = points.T 
    return x,y 

def get_centers (hexbin_output): 
    """ 
    about 40% faster than previous post only cause you're not calculating the 
    min/max every time 
    """ 
    paths = hexbin_output.get_paths() 
    v = paths[0].vertices[:-1] # adds a value [0,0] to the end 
    vx,vy = v.T 

    idx = [3,0,5,2] # index for [xmin,xmax,ymin,ymax]  
    xmin,xmax,ymin,ymax = vx[idx[0]],vx[idx[1]],vy[idx[2]],vy[idx[3]] 

    half_width_x = abs(xmax-xmin)/2.0 
    half_width_y = abs(ymax-ymin)/2.0 

    centers = [] 
    for i in xrange(len(paths)): 
     cx = paths[i].vertices[idx[0],0]+half_width_x 
     cy = paths[i].vertices[idx[2],1]+half_width_y 
     centers.append((cx,cy)) 

    return np.asarray(centers) 


# important parts ==> 

class Hexagonal2DGrid (object): 
    """ 
    Used to fix the gridsize, extent, and bins 
    """ 
    def __init__ (self,gridsize,extent,bins=None): 
     self.gridsize = gridsize 
     self.extent = extent 
     self.bins = bins 

def hexbin (x,y,hexgrid): 
    """ 
    To hexagonally bin the data in 2 dimensions 
    """ 
    fig = plt.figure() 
    ax = fig.add_subplot(111) 

    # Note mincnt=0 so that it will return a value for every point in the 
    # hexgrid, not just those with count>mincnt 

    # Basically you fix the gridsize, extent, and bins to keep them the same 
    # then the resulting count array is the same 
    hexbin = plt.hexbin(x,y, mincnt=0, 
         gridsize=hexgrid.gridsize, 
         extent=hexgrid.extent, 
         bins=hexgrid.bins) 
    # you could close the figure if you don't want it 
    # plt.close(fig.number) 

    counts = hexbin.get_array().copy() 
    return counts, hexbin 

# Example ===> 
if __name__ == "__main__": 
    hexgrid = Hexagonal2DGrid((21,5),[-70,70,-20,20]) 
    x_data,y_data = get_data((0,0),[[-40,95],[90,10]]) 
    x_model,y_model = get_data((0,10),[[100,30],[3,30]]) 

    counts_data, hexbin_data = hexbin(x_data,y_data,hexgrid) 
    counts_model, hexbin_model = hexbin(x_model,y_model,hexgrid) 

    # if you want the centers, they will be the same for both 
    centers = get_centers(hexbin_data) 

    # if you want to ignore the cells with zeros then use the following mask. 
    # But if want zeros for some bins and not others I'm not sure an elegant way 
    # to do this without using the centers 
    nonzero = counts_data != 0 

    # now you can compare the two data sets 
    variance_data = counts_data[nonzero] 
    square_diffs = (counts_data[nonzero]-counts_model[nonzero])**2 
    chi2 = np.sum(square_diffs/variance_data) 
    print(" chi2={}".format(chi2))