2015-10-23 232 views
4

所以,我有2個問題:matplotlib和numpy的 - 直方圖條的顏色和正常化

1-我有一個2D直方圖瓦特沿x & y軸/ 1D直方圖。這些直方圖總計各自的x和y值,而主直方圖合計對數x-y bin中的值。代碼如下。我已經使用pcolormesh生成二維直方圖...並且我已經在vmin = 1,vmax = 14 ...的範圍內生成了一個顏色條。我使這些不變,因爲我生成了一組這些圖寬泛的數據範圍 - 我希望顏色在它們之間保持一致。

我也想根據相同的規範化顏色的一維直方圖酒吧。我已經設置了一個函數來完成映射,但它是固定的線性 - 即使我爲映射指定了LogNorm。

我附上了一些情節,顯示我認爲是一維直方圖的線性刻度。查看10^4(或10^6)左右的X軸直方圖值...它們在顏色欄中的1/2路點處着色,而不是在對數刻度點處着色。

我在做什麼錯?

2-我還希望通過箱寬(xrange或yrange)最終歸一化一維直方圖。但是,我不認爲我可以直接在matplotlib.hist中完成它。也許我應該使用np hist,但是我不知道如何做一個matplotlib.bar繪圖,使用對數刻度和彩色條(再次,映射我用於2D hist的顏色)。

下面的代碼:

# 
# 20 Oct 2015 
# Rick Sarmento 
# 
# Purpose: 
# Reads star particle data and creates phase plots 
# Place histograms of x and y axis along axes 
# Uses pcolormesh norm=LogNorm(vmin=1,vmax=8) 
# 
# Method: 
# Main plot uses np.hist2d then takes log of result 
# 
# Revision history 
# 

# ########################################################## 
# Generate colors for histogram bars based on height 
# This is not right! 
# ########################################################## 
def colorHistOnHeight(N, patches): 
    # we need to normalize the data to 0..1 for the full 
    # range of the colormap 
    print("N max: %.2lf"%N.max()) 
    fracs = np.log10(N.astype(float))/9.0 # normalize colors to the top of our scale 
    print("fracs max: %.2lf"%fracs.max()) 
    norm = mpl.colors.LogNorm(2.0, 9.0) 
    # NOTE this color mapping is different from the one below. 
    for thisfrac, thispatch in zip(fracs, patches): 
     color = mpl.cm.jet(thisfrac) 
     thispatch.set_facecolor(color) 

    return 

# ########################################################## 
# Generate a combo contour/density plot 
# ########################################################## 
def genDensityPlot(x, y, mass, pf, z, filename, xaxislabel): 
    """ 

    :rtype : none 
    """ 
    nullfmt = NullFormatter() 

    # Plot location and size 
    fig = plt.figure(figsize=(20, 20)) 
    ax2dhist = plt.axes(rect_2dhist) 
    axHistx = plt.axes(rect_histx) 
    axHisty = plt.axes(rect_histy) 

    # Fix any "log10(0)" points... 
    x[x == np.inf] = 0.0 
    y[y == np.inf] = 0.0 
    y[y > 1.0] = 1.0 # Fix any minor numerical errors that could result in y>1 

    # Bin data in log-space 
    xrange = np.logspace(minX,maxX,xbins) 
    yrange = np.logspace(minY,maxY,ybins) 
    # Note axis order: y then x 
    # H is the binned data... counts normalized by star particle mass 
    # TODO -- if we're looking at x = log Z, don't weight by mass * f_p... just mass! 
    H, xedges, yedges = np.histogram2d(y, x, weights=mass * (1.0 - pf), # We have log bins, so we take 
             bins=(yrange,xrange)) 

    # Use the bins to find the extent of our plot 
    extent = [yedges[0], yedges[-1], xedges[0], xedges[-1]] 

    # levels = (5, 4, 3) # Needed for contours only... 

    X,Y=np.meshgrid(xrange,yrange) # Create a mess over our range of bins 

    # Take log of the bin data 
    H = np.log10(H) 
    masked_array = np.ma.array(H, mask=np.isnan(H)) # mask out all nan, i.e. log10(0.0) 

    # Fix colors -- white for values of 1.0. 
    cmap = copy.copy(mpl.cm.jet) 
    cmap.set_bad('w', 1.) # w is color, for values of 1.0 

    # Create a plot of the binned 
    cax = (ax2dhist.pcolormesh(X,Y,masked_array, cmap=cmap, norm=LogNorm(vmin=1,vmax=8))) 
    print("Normalized H max %.2lf"%masked_array.max()) 

    # Setup the color bar 
    cbar = fig.colorbar(cax, ticks=[1, 2, 4, 6, 8]) 
    cbar.ax.set_yticklabels(['1', '2', '4', '6', '8'], size=24) 
    cbar.set_label('$log\, M_{sp, pol,\odot}$', size=30) 

    ax2dhist.tick_params(axis='x', labelsize=22) 
    ax2dhist.tick_params(axis='y', labelsize=22) 
    ax2dhist.set_xlabel(xaxislabel, size=30) 
    ax2dhist.set_ylabel('$log\, Z_{pri}/Z$', size=30) 

    ax2dhist.set_xlim([10**minX,10**maxX]) 
    ax2dhist.set_ylim([10**minY,10**maxY]) 
    ax2dhist.set_xscale('log') 
    ax2dhist.set_yscale('log') 
    ax2dhist.grid(color='0.75', linestyle=':', linewidth=2) 

    # Generate the xy axes histograms 
    ylims = ax2dhist.get_ylim() 
    xlims = ax2dhist.get_xlim() 

    ########################################################## 
    # Create the axes histograms 
    ########################################################## 
    # Note that even with log=True, the array N is NOT log of the weighted counts 
    # Eventually we want to normalize these value (in N) by binwidth and overall 
    # simulation volume... but I don't know how to do that. 
    N, bins, patches = axHistx.hist(x, bins=xrange, log=True, weights=mass * (1.0 - pf)) 
    axHistx.set_xscale("log") 
    colorHistOnHeight(N, patches) 
    N, bins, patches = axHisty.hist(y, bins=yrange, log=True, weights=mass * (1.0 - pf), 
            orientation='horizontal') 
    axHisty.set_yscale('log') 
    colorHistOnHeight(N, patches) 

    # Setup format of the histograms 
    axHistx.set_xlim(ax2dhist.get_xlim()) # Match the x range on the horiz hist 
    axHistx.set_ylim([100.0,10.0**9])  # Constant range for all histograms 
    axHistx.tick_params(labelsize=22) 
    axHistx.yaxis.set_ticks([1e2,1e4,1e6,1e8]) 
    axHistx.grid(color='0.75', linestyle=':', linewidth=2) 

    axHisty.set_xlim([100.0,10.0**9])  # We're rotated, so x axis is the value 
    axHisty.set_ylim([10**minY,10**maxY]) # Match the y range on the vert hist 
    axHisty.tick_params(labelsize=22) 
    axHisty.xaxis.set_ticks([1e2,1e4,1e6,1e8]) 
    axHisty.grid(color='0.75', linestyle=':', linewidth=2) 

    # no labels 
    axHistx.xaxis.set_major_formatter(nullfmt) 
    axHisty.yaxis.set_major_formatter(nullfmt) 

    if z[0] == '0': z = z[1:] 
    axHistx.set_title('z=' + z, size=40) 

    plt.savefig(filename + "-z_" + z + ".png", dpi=fig.dpi) 
    # plt.show() 
    plt.close(fig) # Release memory assoc'd with the plot 
    return 


# ########################################################## 
# ########################################################## 
## 
## Main program 
## 
# ########################################################## 
# ########################################################## 
import matplotlib as mpl 
import matplotlib.pyplot as plt 
#import matplotlib.colors as colors # For the colored 1d histogram routine 
from matplotlib.ticker import NullFormatter 
from matplotlib.colors import LogNorm 
from matplotlib.ticker import LogFormatterMathtext 
import numpy as np 
import copy as copy 

files = [ 
    "18.00", 
    "17.00", 
    "16.00", 
    "15.00", 
    "14.00", 
    "13.00", 
    "12.00", 
    "11.00", 
    "10.00", 
    "09.00", 
    "08.50", 
    "08.00", 
    "07.50", 
    "07.00", 
    "06.50", 
    "06.00", 
    "05.50", 
    "05.09" 
] 
# Plot parameters - global 
left, width = 0.1, 0.63 
bottom, height = 0.1, 0.63 
bottom_h = left_h = left + width + 0.01 

xbins = ybins = 100 

rect_2dhist = [left, bottom, width, height] 
rect_histx = [left, bottom_h, width, 0.15] 
rect_histy = [left_h, bottom, 0.2, height] 

prefix = "./" 
# prefix="20Sep-BIG/" 
for indx, z in enumerate(files): 
    spZ = np.loadtxt(prefix + "spZ_" + z + ".txt", skiprows=1) 
    spPZ = np.loadtxt(prefix + "spPZ_" + z + ".txt", skiprows=1) 
    spPF = np.loadtxt(prefix + "spPPF_" + z + ".txt", skiprows=1) 
    spMass = np.loadtxt(prefix + "spMass_" + z + ".txt", skiprows=1) 

    print ("Generating phase diagram for z=%s" % z) 
    minY = -4.0 
    maxY = 0.5 
    minX = -8.0 
    maxX = 0.5 
    genDensityPlot(spZ, spPZ/spZ, spMass, spPF, z, 
        "Z_PMassZ-MassHistLogNorm", "$log\, Z_{\odot}$") 
    minX = -5.0 
    genDensityPlot((spZ)/(1.0 - spPF), spPZ/spZ, spMass, spPF, z, 
        "Z_PMassZ1-PGF-MassHistLogNorm", "$log\, Z_{\odot}/f_{pol}$") 

以下是示出與圖1D軸的着色問題幾個重複直方圖

Plot 1

Plot 2

回答

3

0)您的代碼是非常好(有幫助!)記錄,但它將是非常有用的你修剪到一個最小工作示例。
1)colorHistOnHeight中的fracs數組不包含1e2的下界。
2)您的不同LogNorm色彩地圖的邊界在整個代碼中發生變化(例如[1,8]與[2,9])。將這些參數設置爲變量,並根據需要傳遞這些變量。
3)創建一個標量可映射對象matplotlib.cm.ScalarMappable對象,使用to_rgba方法將標量值直接轉換爲顏色。

希望這些幫助之一!

+0

是的。就像'(log10(N)-2.0)/ 9.0' – DilithiumMatrix

+0

啊謝謝......我只是意識到我創造了規範,但不要使用它! 1)哼哼...真的。我想我目前將我的範圍的底部映射到2-9的區間。 2)這是一個錯字 - 我確實設置了相同的範圍。 3)我會研究一下。謝謝!! – earnric

+0

我無法理解如何使用ScalarMappable ......如果你能指出我的例子,我會很感激。 – earnric

2

我想出瞭如何使用上面的建議:matplotlib.sm.ScalarMappable。這樣做!該映射符合我的顏色條比例。

# ########################################################## 
# Generate colors for histogram bars based on height 
# Method: 
# Take log of the histogram values (weighted counts).. 
# Create a LogNorm mapping between 1->9 
# Use the norm to map scalar values between 1 & 9 to rgb 
# ########################################################## 
def colorHistOnHeight(N, patches): 
    cleanN = np.ma.masked_where(N == 0.0, N) 
    fracs = np.log10(cleanN) # normalize colors to the top of our scale 
    norm = mpl.colors.LogNorm(vmin=1.0, vmax=9.0) 
    sm  = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.jet) 
    sm.set_clim([1.0,9.0]) 
    for thisfrac, thispatch in zip(fracs, patches): 
     color = sm.to_rgba(thisfrac) 
     thispatch.set_facecolor(color) 
    return 
0

這裏就是我如何能夠通過對數箱寬度(和我的模擬量 - 標值)正常化matplotlib歷史。有人請檢查我的解決方案。

yrange = np.logspace(minY,maxY,ybins) 
N, bins, patches = axHisty.hist(y, bins=yrange, log=True, weights=mass * (1.0 - pf)) 

widths = np.diff(bins) 
for item,dbx in zip(patches,widths): 
    item.set_height(item.get_height()/dbx/cmvol) 

我由箱寬度(DBX)和我的模擬(cmvol)的共動體積歸一化直方圖矩形高度。我認爲這是它!

Normalized plot