2013-01-04 14 views
6

मैंने वायुमंडलीय मॉडल आउटपुट से ऊर्ध्वाधर क्रॉस सेक्शन बनाने के लिए एक दिनचर्या लिखी है। एक उदाहरण नीचे दिया गया है। मैं क्या करना चाहता हूं, दो लंबवत अक्ष दिखाने के लिए है: बाईं तरफ मैं लॉग मान पर प्रेशर वैल्यू प्रदर्शित करता हूं, और दाईं ओर मैं किमी में ऊंचाई दिखाता हूं। मैंने सोचा कि मॉडल स्तरों के स्थानों पर ऊंचाई दिखाना अच्छा होगा - यही कारण है कि वे अनियमित रूप से दूरी पर हैं। सभी अच्छी तरह से काम करते हैं, सिवाय इसके कि दाएं कोने के नीचे दाएं ओवरलैप पर लेबल। मुझे पता चला कि मैं ax2.get_yticklabels()[index].set_visible(False) का उपयोग करके विशिष्ट लेबल छुपा सकता हूं। मेरी समस्या यह है कि मैं कैसे निर्धारित करूं कि कौन से लेबल (इंडेस) मैं छिपाना चाहता हूं? मेरा मानना ​​है कि यह पता लगाना संभव होना चाहिए कि टिक लेबल कहां स्थित हैं (धुरी या आकृति निर्देशांक में)। तब मैंMatplotlib धुरी लेबल: यह पता लगाने के लिए कि वे कहां स्थित होंगे?

yp = -1 
for t in ax2.get_yticklabels(): 
    y = t.get_position().y0 # this doesn't yield any useful bbox! 
    if y-yp < threshold: 
     t.set_visible(False) 
    else: 
     yp = y 

दुर्भाग्य के रूप में एक सीमा से दूरी इस्तेमाल कर सकते हैं, मैं लेबल निर्देशांक पाने के लिए एक तरह से नहीं मिली है। कोई संकेत? यहाँ Vertical cross section plot

और पूरा कोड है कि अंकन करता है (डेटा 2-डी सरणी है, एक्स अक्षांश कर रहे हैं, और y दबाव मान रहे हैं):

यहाँ उदाहरण आंकड़ा है

def plotZM(data, x, y, plotOpt=None): 
    """Create a zonal mean contour plot of one variable 
    plotOpt is a dictionary with plotting options: 
    'scale_factor': multiply values with this factor before plotting 
    'units': a units label for the colorbar 
    'levels': use list of values as contour intervals 
    'title': a title for the plot 
    """ 
    if plotOpt is None: plotOpt = {} 
    # create figure and axes 
    fig = plt.figure() 
    ax1 = fig.add_subplot(111) 
    # scale data if requested 
    scale_factor = plotOpt.get('scale_factor', 1.0) 
    pdata = data * scale_factor 
    # determine contour levels to be used; default: linear spacing, 20 levels 
    clevs = plotOpt.get('levels', np.linspace(data.min(), data.max(), 20)) 
    # map contour values to colors 
    norm=matplotlib.colors.BoundaryNorm(clevs, ncolors=256, clip=False) 
    # draw the (filled) contours 
    contour = ax1.contourf(x, y, pdata, levels=clevs, norm=norm) 
    # add a title 
    title = plotOpt.get('title', 'Vertical cross section') 
    ax1.set_title(title) # optional keyword: fontsize="small" 
    # add colorbar 
    # Note: use of the ticks keyword forces colorbar to draw all labels 
    fmt = matplotlib.ticker.FormatStrFormatter("%g") 
    cbar = fig.colorbar(contour, ax=ax1, orientation='horizontal', shrink=0.8, 
         ticks=clevs, format=fmt) 
    cbar.set_label(plotOpt.get('units', '')) 
    for t in cbar.ax.get_xticklabels(): 
     t.set_fontsize("x-small") 
    # change font size of x labels 
    xlabels = ax1.get_xticklabels() 
    for t in xlabels: 
     t.set_fontsize("x-small") 
    # set up y axes: log pressure labels on the left y axis, altitude labels 
    # according to model levels on the right y axis 
    ax1.set_ylabel("Pressure [hPa]") 
    ax1.set_yscale('log') 
    ax1.set_ylim(y.max(), y.min()) 
    subs = [1,2,5] 
    print "y_max/y_min = ", y.max()/y.min() 
    if y.max()/y.min() < 30.: 
     subs = [1,2,3,4,5,6,7,8,9] 
    loc = matplotlib.ticker.LogLocator(base=10., subs=subs) 
    ax1.yaxis.set_major_locator(loc) 
    fmt = matplotlib.ticker.FormatStrFormatter("%g") 
    ax1.yaxis.set_major_formatter(fmt) 
    ylabels = ax1.get_yticklabels() 
    for t in ylabels: 
     t.set_fontsize("x-small") 
    # calculate altitudes from pressure values (use fixed scale height) 
    z0 = 8.400 # scale height for pressure_to_altitude conversion [km] 
    altitude = z0 * np.log(1015.23/y) 
    # add second y axis for altitude scale 
    ax2 = ax1.twinx() 
    ax2.set_ylabel("Altitude [km]") 
    ax2.set_ylim(altitude.min(), altitude.max()) 
    ax2.set_yticks(altitude) 
    fmt = matplotlib.ticker.FormatStrFormatter("%6.1f") 
    ax2.yaxis.set_major_formatter(fmt) 
    # tweak altitude labels 
    ylabels = ax2.get_yticklabels() 
    for i,t in enumerate(ylabels): 
     t.set_fontsize("x-small") 
    # show plot 
    plt.show() 

उत्तर

2

मैं ऐसी चीजें नहीं करना चाहूंगा। इससे समस्याएं हो सकती हैं, उदाहरण के लिए, साजिश विंडो का आकार बदलते समय या आउटपुट छवियों के डीपीआई को बदलते समय। और यह निश्चित रूप से अजीब लग जाएगा।

आप या तो AX2 पर

  1. सेट कम टिक (और, मेरी राय में, वे सीधे पैमाने पर ऊंचाई के लिए
  2. matplotlib से एक पूर्वनिर्धारित (या कस्टम) लोकेटर उपयोग किया जाना चाहिए। मैं ऐसा करना चाहिए AutoLocator और MaxNLocator की तरह, बस आप इस के साथ मदद की जरूरत है, बस पूछने की कोशिश सकें कि आप सबसे अच्छा परिणाम देता है।

2

यहाँ एक अद्यतन संस्करण च है o plotZM रूटीन जो मॉडल स्तर को दाईं ओर एक अलग पैनल में प्लॉट करेगा और ऊंचाई धुरी के लिए रैखिक समकक्ष मार्करों का उपयोग करेगा। सतह के दबाव के नीचे क्षेत्रों को मुखौटा करने के लिए एक और विकल्प जोड़ा गया है।

यह कोड "ज़ूम-सुरक्षित" है (यानी जब आप साजिश में ज़ूम करते हैं या पैन करते हैं तो ऊंचाई और दबाव लेबल अच्छी तरह से बदलते हैं, और मॉडल स्तर लगातार बदलते हैं)। इसमें धुरी और लेबल ट्विकिंग का एक गुच्छा भी शामिल है और इसलिए उम्मीद है कि आप दूसरों के लिए उपयोगी हो सकते हैं क्योंकि मैटलप्लिब के साथ आप क्या कर सकते हैं। एक उदाहरण आंकड़ा नीचे दिखाया गया है।

def plotZM(data, x, y, plotOpt=None, modelLevels=None, surfacePressure=None): 
    """Create a zonal mean contour plot of one variable 
    plotOpt is a dictionary with plotting options: 
     'scale_factor': multiply values with this factor before plotting 
     'units': a units label for the colorbar 
     'levels': use list of values as contour intervals 
     'title': a title for the plot 
    modelLevels: a list of pressure values indicating the model vertical resolution. If present, 
     a small side panel will be drawn with lines for each model level 
    surfacePressure: a list (dimension len(x)) of surface pressure values. If present, these will 
     be used to mask out regions below the surface 
    """ 
    # explanation of axes: 
    # ax1: primary coordinate system latitude vs. pressure (left ticks on y axis) 
    # ax2: twinned axes for altitude coordinates on right y axis 
    # axm: small side panel with shared y axis from ax2 for display of model levels 
    # right y ticks and y label will be drawn on axr if modelLevels are given, else on ax2 
    # axr: pointer to "right axis", either ax2 or axm 

    if plotOpt is None: plotOpt = {} 
    labelFontSize = "small" 
    # create figure and axes 
    fig = plt.figure() 
    ax1 = fig.add_subplot(111) 
    # scale data if requested 
    scale_factor = plotOpt.get('scale_factor', 1.0) 
    pdata = data * scale_factor 
    # determine contour levels to be used; default: linear spacing, 20 levels 
    clevs = plotOpt.get('levels', np.linspace(data.min(), data.max(), 20)) 
    # map contour values to colors 
    norm=matplotlib.colors.BoundaryNorm(clevs, ncolors=256, clip=False) 
    # draw the (filled) contours 
    contour = ax1.contourf(x, y, pdata, levels=clevs, norm=norm) 
    # mask out surface pressure if given 
    if not surfacePressure is None: 
     ax1.fill_between(x, surfacePressure, surfacePressure.max(), color="white")  
    # add a title 
    title = plotOpt.get('title', 'Vertical cross section') 
    ax1.set_title(title) 
    # add colorbar 
    # Note: use of the ticks keyword forces colorbar to draw all labels 
    fmt = matplotlib.ticker.FormatStrFormatter("%g") 
    cbar = fig.colorbar(contour, ax=ax1, orientation='horizontal', shrink=0.8, 
         ticks=clevs, format=fmt) 
    cbar.set_label(plotOpt.get('units', '')) 
    for t in cbar.ax.get_xticklabels(): 
     t.set_fontsize(labelFontSize) 
    # set up y axes: log pressure labels on the left y axis, altitude labels 
    # according to model levels on the right y axis 
    ax1.set_ylabel("Pressure [hPa]") 
    ax1.set_yscale('log') 
    ax1.set_ylim(10.*np.ceil(y.max()/10.), y.min()) # avoid truncation of 1000 hPa 
    subs = [1,2,5] 
    if y.max()/y.min() < 30.: 
     subs = [1,2,3,4,5,6,7,8,9] 
    y1loc = matplotlib.ticker.LogLocator(base=10., subs=subs) 
    ax1.yaxis.set_major_locator(y1loc) 
    fmt = matplotlib.ticker.FormatStrFormatter("%g") 
    ax1.yaxis.set_major_formatter(fmt) 
    for t in ax1.get_yticklabels(): 
     t.set_fontsize(labelFontSize) 
    # calculate altitudes from pressure values (use fixed scale height) 
    z0 = 8.400 # scale height for pressure_to_altitude conversion [km] 
    altitude = z0 * np.log(1015.23/y) 
    # add second y axis for altitude scale 
    ax2 = ax1.twinx() 
    # change values and font size of x labels 
    ax1.set_xlabel('Latitude [degrees]') 
    xloc = matplotlib.ticker.FixedLocator(np.arange(-90.,91.,30.)) 
    ax1.xaxis.set_major_locator(xloc) 
    for t in ax1.get_xticklabels(): 
     t.set_fontsize(labelFontSize) 
    # draw horizontal lines to the right to indicate model levels 
    if not modelLevels is None: 
     pos = ax1.get_position() 
     axm = fig.add_axes([pos.x1,pos.y0,0.02,pos.height], sharey=ax2) 
     axm.set_xlim(0., 1.) 
     axm.xaxis.set_visible(False) 
     modelLev = axm.hlines(altitude, 0., 1., color='0.5') 
     axr = axm  # specify y axis for right tick marks and labels 
     # turn off tick labels of ax2 
     for t in ax2.get_yticklabels(): 
      t.set_visible(False) 
     label_xcoor = 3.7 
    else: 
     axr = ax2 
     label_xcoor = 1.05 
    axr.set_ylabel("Altitude [km]") 
    axr.yaxis.set_label_coords(label_xcoor, 0.5) 
    axr.set_ylim(altitude.min(), altitude.max()) 
    yrloc = matplotlib.ticker.MaxNLocator(steps=[1,2,5,10]) 
    axr.yaxis.set_major_locator(yrloc) 
    axr.yaxis.tick_right() 
    for t in axr.yaxis.get_majorticklines(): 
     t.set_visible(False) 
    for t in axr.get_yticklabels(): 
     t.set_fontsize(labelFontSize) 
    # show plot 
    plt.show() 

vertical cross section plot with modified code