Efficiently create a density plot for high-density regions, points for sparse regions

后端 未结 4 1287
栀梦
栀梦 2020-12-13 22:01

I need to make a plot that functions like a density plot for high-density regions on the plot, but below some threshold uses individual points. I couldn\'t find any existing

4条回答
  •  失恋的感觉
    2020-12-13 22:37

    After a night to sleep on it and reading through Oz123's suggestions, I figured it out. The trick is to compute which bin each x,y point falls into (xi,yi), then test if H[xi,yi] (actually, in my case H[yi,xi]) is beneath the threshold. The code is below, and runs very fast for large numbers of points and is much cleaner:

    import numpy as np
    import math
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    import pylab
    import numpy.random
    
    #Create the colormap:
    halfpurples = {'blue': [(0.0,1.0,1.0),(0.000001, 0.78431373834609985, 0.78431373834609985),
    0.25, 0.729411780834198, 0.729411780834198), (0.5,
    0.63921570777893066, 0.63921570777893066), (0.75,
    0.56078433990478516, 0.56078433990478516), (1.0, 0.49019607901573181,
    0.49019607901573181)],
    
        'green': [(0.0,1.0,1.0),(0.000001,
        0.60392159223556519, 0.60392159223556519), (0.25,
        0.49019607901573181, 0.49019607901573181), (0.5,
        0.31764706969261169, 0.31764706969261169), (0.75,
        0.15294118225574493, 0.15294118225574493), (1.0, 0.0, 0.0)],
    
        'red': [(0.0,1.0,1.0),(0.000001,
        0.61960786581039429, 0.61960786581039429), (0.25,
        0.50196081399917603, 0.50196081399917603), (0.5,
        0.41568627953529358, 0.41568627953529358), (0.75,
        0.32941177487373352, 0.32941177487373352), (1.0,
        0.24705882370471954, 0.24705882370471954)]} 
    
    halfpurplecmap = mpl.colors.LinearSegmentedColormap('halfpurples',halfpurples,256)
    
    #Create x,y arrays of normally distributed points
    npts = 100000
    x = numpy.random.standard_normal(npts)
    y = numpy.random.standard_normal(npts)
    
    #Set bin numbers in both axes
    nxbins = 100
    nybins = 100
    
    #Set the cutoff for resolving the individual points
    minperbin = 1
    
    #Make the density histrogram
    H, yedges, xedges = np.histogram2d(y,x,bins=(nybins,nxbins))
    #Reorient the axes
    H =  H[::-1]
    
    extent = [xedges[0],xedges[-1],yedges[0],yedges[-1]]
    
    #Figure out which bin each x,y point is in
    xbinsize = xedges[1]-xedges[0]
    ybinsize = yedges[1]-yedges[0]
    xi = ((x-xedges[0])/xbinsize).astype(np.integer)
    yi = nybins-1-((y-yedges[0])/ybinsize).astype(np.integer)
    
    #Subtract one from any points exactly on the right and upper edges of the region
    xim1 = xi-1
    yim1 = yi-1
    xi = np.where(xi < nxbins,xi,xim1)
    yi = np.where(yi < nybins,yi,yim1)
    
    #Get all points with density below the threshold
    lowdensityx = x[H[yi,xi] <= minperbin]
    lowdensityy = y[H[yi,xi] <= minperbin]
    
    #Plot
    fig1 = plt.figure()
    ax1 = fig1.add_subplot(111)
    ax1.plot(lowdensityx,lowdensityy,linestyle='.',marker='o',mfc='k',mec='k',ms=3)
    cp1 = ax1.imshow(H,interpolation='nearest',extent=extent,cmap=halfpurplecmap,vmin=minperbin)
    fig1.colorbar(cp1)
    
    fig1.savefig('contourtest.eps')
    

提交回复
热议问题