2010-10-12 21 views
22

Şu anda x ekseninde 2 veya 3 diğer ölçüme (bazen kategorik) karşı bir ölçüm çizmek için matplotlib kullanıyorum. Şu anda, x ekseni üzerindeki verileri tuples halinde gruplandırıyorum ve çizim yapmadan önce onları sıralıyorum ... sonuç, aşağıdaki soldaki görüntü gibi görünüyor. Yapmak istediğim şey, doğru görüntüde gördüğünüz gibi verileri çoklu x eksenleriyle çizmek. "Tedavi" x ekseni etiketlerinin gruplandırılması kek üzerine krema yapacaktır.Matplotlib'de nasıl birden fazla X veya Y ekseni çizebilirim?

alt text

cevap

19

Öncelikle, serin soru! Matplotlib> = 1.0.0 ile kesinlikle mümkündür.

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib as mpl 

def main(): 
    #-- Generate some data ---------------------------------------------------- 
    nx = 10 
    x = np.linspace(0, 2*np.pi, 10) 
    y = 2 * np.sin(x) 

    groups = [('GroupA', (x[0], x[nx//3])), 
       ('GroupB', (x[-2*nx//3], x[2*nx//3])), 
       ('GroupC', (x[-nx//3], x[-1]))] 

    #-- Plot the results ------------------------------------------------------ 
    fig = plt.figure() 
    ax = fig.add_subplot(111) 

    # Give ourselves a bit more room at the bottom 
    plt.subplots_adjust(bottom=0.2) 

    ax.plot(x,y, 'k^') 

    # Drop the bottom spine by 40 pts 
    ax.spines['bottom'].set_position(('outward', 40)) 

    # Make a second bottom spine in the position of the original bottom spine 
    make_second_bottom_spine(label='Treatment') 

    # Annotate the groups 
    for name, xspan in groups: 
     annotate_group(name, xspan) 

    plt.xlabel('Dose') 
    plt.ylabel('Response') 
    plt.title('Experimental Data') 

    plt.show() 


def annotate_group(name, xspan, ax=None): 
    """Annotates a span of the x-axis""" 
    def annotate(ax, name, left, right, y, pad): 
     arrow = ax.annotate(name, 
       xy=(left, y), xycoords='data', 
       xytext=(right, y-pad), textcoords='data', 
       annotation_clip=False, verticalalignment='top', 
       horizontalalignment='center', linespacing=2.0, 
       arrowprops=dict(arrowstyle='-', shrinkA=0, shrinkB=0, 
         connectionstyle='angle,angleB=90,angleA=0,rad=5') 
       ) 
     return arrow 
    if ax is None: 
     ax = plt.gca() 
    ymin = ax.get_ylim()[0] 
    ypad = 0.01 * np.ptp(ax.get_ylim()) 
    xcenter = np.mean(xspan) 
    left_arrow = annotate(ax, name, xspan[0], xcenter, ymin, ypad) 
    right_arrow = annotate(ax, name, xspan[1], xcenter, ymin, ypad) 
    return left_arrow, right_arrow 

def make_second_bottom_spine(ax=None, label=None, offset=0, labeloffset=20): 
    """Makes a second bottom spine""" 
    if ax is None: 
     ax = plt.gca() 
    second_bottom = mpl.spines.Spine(ax, 'bottom', ax.spines['bottom']._path) 
    second_bottom.set_position(('outward', offset)) 
    ax.spines['second_bottom'] = second_bottom 

    if label is not None: 
     # Make a new xlabel 
     ax.annotate(label, 
       xy=(0.5, 0), xycoords='axes fraction', 
       xytext=(0, -labeloffset), textcoords='offset points', 
       verticalalignment='top', horizontalalignment='center') 

if __name__ == '__main__': 
    main() 

Two bottom spines in a matplotlib plot

+0

Bu voodoo aşina olduğum - bakım daha kategorik eksenler için bu genelleme nasıl göstermek için? Üçüncü bir omurga yaratmanın bazı ofsetleri görünür kılacağını düşündüm, ama bu benim için çalışmıyor - hala ikinci sırada. (Yeni bir soru açabilirmiyiz) – Thomas

+0

nm Şimdi anladım - yine de (temiz) uygulamanızı görmeyi çok isterim. – Thomas

9

: Bu ... Benim örnek mükemmel olmaktan uzak, ama umarım bazı mantıklı olsa da, voodoo adil biraz gerektirir

(yeni dikenler işlevselliği izin veriyorsa) Joe'nun örneği iyi. Bende benimkini de atacağım. Birkaç saat önce üzerinde çalışıyordum, ama sonra bir toplantıya gitmek zorunda kaldı. here'dan çalıyor.

import matplotlib.pyplot as plt 
import matplotlib.ticker as ticker 

## the following two functions override the default behavior or twiny() 
def make_patch_spines_invisible(ax): 
    ax.set_frame_on(True) 
    ax.patch.set_visible(False) 
    for sp in ax.spines.itervalues(): 
     sp.set_visible(False) 

def make_spine_invisible(ax, direction): 
    if direction in ["right", "left"]: 
     ax.yaxis.set_ticks_position(direction) 
     ax.yaxis.set_label_position(direction) 
    elif direction in ["top", "bottom"]: 
     ax.xaxis.set_ticks_position(direction) 
     ax.xaxis.set_label_position(direction) 
    else: 
     raise ValueError("Unknown Direction : %s" % (direction,)) 

    ax.spines[direction].set_visible(True) 

data = (('A',0.01),('A',0.02),('B',0.10),('B',0.20)) # fake data 

fig = plt.figure(1) 
sb = fig.add_subplot(111) 
sb.xaxis.set_major_locator(ticker.FixedLocator([0,1,2,3])) 

sb.plot([i[1] for i in data],"*",markersize=10) 
sb.set_xlabel("dose") 

plt.subplots_adjust(bottom=0.17) # make room on bottom 

par2 = sb.twiny() # create a second axes 
par2.spines["bottom"].set_position(("axes", -.1)) # move it down 

## override the default behavior for a twiny axis 
make_patch_spines_invisible(par2) 
make_spine_invisible(par2, "bottom") 
par2.set_xlabel("treatment") 

par2.plot([i[1] for i in data],"*",markersize=10) #redraw to put twiny on same scale 
par2.xaxis.set_major_locator(ticker.FixedLocator([0,1,2,3])) 
par2.xaxis.set_ticklabels([i[0] for i in data]) 

plt.show() 

üretir:

alt text

İlgili konular