सबप्लॉट्स के लिए pyplot axes लेबल


187

मेरे पास निम्नलिखित कथानक हैं:

import matplotlib.pyplot as plt

fig2 = plt.figure()
ax3 = fig2.add_subplot(2,1,1)
ax4 = fig2.add_subplot(2,1,2)
ax4.loglog(x1, y1)
ax3.loglog(x2, y2)
ax3.set_ylabel('hello')

मैं कुल्हाड़ियों के लेबल और शीर्षक बनाने में सक्षम होना चाहता हूं, न कि प्रत्येक दो सबप्लॉट्स के लिए, बल्कि सामान्य लेबल भी हैं जो दोनों उपपट्टियों को फैलाते हैं। उदाहरण के लिए, चूंकि दोनों भूखंडों में समान अक्ष हैं, इसलिए मुझे केवल एक सेट x और y- अक्ष अक्षों की आवश्यकता है। मैं हालांकि प्रत्येक उपप्लॉट के लिए अलग-अलग शीर्षक चाहता हूं।

मैंने कुछ चीजों की कोशिश की लेकिन उनमें से किसी ने भी सही काम नहीं किया

जवाबों:


260

आप एक बड़ा सबप्लॉट बना सकते हैं जो दो सबप्लॉट को कवर करता है और फिर सामान्य लेबल सेट करता है।

import random
import matplotlib.pyplot as plt

x = range(1, 101)
y1 = [random.randint(1, 100) for _ in xrange(len(x))]
y2 = [random.randint(1, 100) for _ in xrange(len(x))]

fig = plt.figure()
ax = fig.add_subplot(111)    # The big subplot
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

# Turn off axis lines and ticks of the big subplot
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_color('none')
ax.spines['left'].set_color('none')
ax.spines['right'].set_color('none')
ax.tick_params(labelcolor='w', top=False, bottom=False, left=False, right=False)

ax1.loglog(x, y1)
ax2.loglog(x, y2)

# Set common labels
ax.set_xlabel('common xlabel')
ax.set_ylabel('common ylabel')

ax1.set_title('ax1 title')
ax2.set_title('ax2 title')

plt.savefig('common_labels.png', dpi=300)

common_labels.png

एक अन्य तरीका है अंजीर का उपयोग। () आम लेबल के स्थानों को सीधे सेट करने के लिए।

import random
import matplotlib.pyplot as plt

x = range(1, 101)
y1 = [random.randint(1, 100) for _ in xrange(len(x))]
y2 = [random.randint(1, 100) for _ in xrange(len(x))]

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

ax1.loglog(x, y1)
ax2.loglog(x, y2)

# Set common labels
fig.text(0.5, 0.04, 'common xlabel', ha='center', va='center')
fig.text(0.06, 0.5, 'common ylabel', ha='center', va='center', rotation='vertical')

ax1.set_title('ax1 title')
ax2.set_title('ax2 title')

plt.savefig('common_labels_text.png', dpi=300)

common_labels_text.png


1
Suptitle फ़ंक्शन fig.text () संस्करण का उपयोग करता है। तो यह ऐसा करने का "आधिकारिक" तरीका हो सकता है?
PhML

4
यह इस बात पर जोर देने के लायक है कि axपहले ax1और बाद में बनाया जाना चाहिए ax2, अन्यथा बड़े भूखंड छोटे भूखंडों को कवर करेंगे।
1 ''

यदि वैश्विक प्लॉटिंग मापदंडों में ए (दृश्यमान) ग्रिड शामिल है, तो ax.grid (गलत) या plt.grid (गलत) भी आवश्यक है।
नौरीन

3
ऐसा लगता है कि पहले दृष्टिकोण matplotplib के हाल के संस्करणों के साथ अब काम नहीं करता है (मैं 2.0.2 का उपयोग करता हूं): एन्क्लोजिंग कुल्हाड़ी में जोड़े गए लेबल दिखाई नहीं देते हैं।
एम। टोया

प्रत्येक व्यक्ति सबप्लॉट में y_labels कैसे जोड़ें?
फार्डिन

115

उपयोग करने का एक सरल तरीका subplots:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(3, 4, sharex=True, sharey=True)
# add a big axes, hide frame
fig.add_subplot(111, frameon=False)
# hide tick and tick label of the big axes
plt.tick_params(labelcolor='none', top='off', bottom='off', left='off', right='off')
plt.grid(False)
plt.xlabel("common X")
plt.ylabel("common Y")

1
यदि वैश्विक प्लॉटिंग मापदंडों में ए (दृश्यमान) ग्रिड शामिल है, तो ax.grid (गलत) या plt.grid (गलत) भी आवश्यक है।
नौरीन

1
मैं यह एक (5, 1) सबप्लॉट के लिए कर रहा हूं और मेरा यलैबेल सबप्लॉट्स के पास के बजाय खिड़की के बाएं किनारे पर बंद है।
इविड्लो

1
आपको एक उत्थान मिला है। लेकिन कृपया हमेशा समझाएं कि कोड क्या कर रहा है, एक छवि संलग्न करें या एक उदाहरण दिखाएं, क्योंकि निश्चित रूप से इसे प्राप्त करने में थोड़ा समय लगा।
करीम जिरौदी

4
बदले 'off'के लिए Falsematplotlib के नए संस्करण के साथ (मैं 2.2.2 है)
टेड

2
और फिर आप भूखंडों को कैसे जोड़ते हैं? for ax in axes: ax.plot(x, y)किसी भी अच्छा करने के लिए प्रतीत नहीं होता है।
usernumber

16

वेन-वी लिआओ का उत्तर अच्छा है यदि आप वेक्टर ग्राफिक्स निर्यात करने की कोशिश नहीं कर रहे हैं या आपने बेरंग कुल्हाड़ियों को अनदेखा करने के लिए अपने मेटप्लोटिब बैकेंड की स्थापना की है; अन्यथा छिपी हुई कुल्हाड़ी निर्यातित ग्राफ़िक में दिखाई देगी।

suplabelयहां मेरा जवाब समान है fig.suptitleजो fig.textफ़ंक्शन का उपयोग करता है । इसलिए वहाँ कोई कुल्हाड़ी कलाकार नहीं बनाया जा रहा है और बेरंग बना दिया है। हालाँकि, यदि आप इसे कई बार कॉल करने का प्रयास करते हैं, तो आपको एक-दूसरे के ऊपर पाठ जोड़ा जाएगा (जैसा fig.suptitleभी करता है)। वेन-वेई लियाओ का जवाब नहीं है, क्योंकि fig.add_subplot(111)यदि यह पहले से ही बनाया गया है तो वही एक्सिस ऑब्जेक्ट लौटाएगा।

प्लॉट बनने के बाद मेरा फंक्शन भी बुलाया जा सकता है।

def suplabel(axis,label,label_prop=None,
             labelpad=5,
             ha='center',va='center'):
    ''' Add super ylabel or xlabel to the figure
    Similar to matplotlib.suptitle
    axis       - string: "x" or "y"
    label      - string
    label_prop - keyword dictionary for Text
    labelpad   - padding from the axis (default: 5)
    ha         - horizontal alignment (default: "center")
    va         - vertical alignment (default: "center")
    '''
    fig = pylab.gcf()
    xmin = []
    ymin = []
    for ax in fig.axes:
        xmin.append(ax.get_position().xmin)
        ymin.append(ax.get_position().ymin)
    xmin,ymin = min(xmin),min(ymin)
    dpi = fig.dpi
    if axis.lower() == "y":
        rotation=90.
        x = xmin-float(labelpad)/dpi
        y = 0.5
    elif axis.lower() == 'x':
        rotation = 0.
        x = 0.5
        y = ymin - float(labelpad)/dpi
    else:
        raise Exception("Unexpected axis: x or y")
    if label_prop is None: 
        label_prop = dict()
    pylab.text(x,y,label,rotation=rotation,
               transform=fig.transFigure,
               ha=ha,va=va,
               **label_prop)

यह सबसे अच्छा उत्तर imo है। इसे लागू करना आसान है और लेबलपैड विकल्प के कारण लेबल ओवरलैप नहीं होते हैं।
आर्थर डेंट

8

यहाँ एक समाधान है जहाँ आप एक प्लॉट के यलैबेल को सेट करते हैं और उसकी स्थिति को समायोजित करते हैं ताकि यह लंबवत रूप से केंद्रित हो। इस तरह आप केवाईसी द्वारा बताई गई समस्याओं से बच जाते हैं।

import numpy as np
import matplotlib.pyplot as plt

def set_shared_ylabel(a, ylabel, labelpad = 0.01):
    """Set a y label shared by multiple axes
    Parameters
    ----------
    a: list of axes
    ylabel: string
    labelpad: float
        Sets the padding between ticklabels and axis label"""

    f = a[0].get_figure()
    f.canvas.draw() #sets f.canvas.renderer needed below

    # get the center position for all plots
    top = a[0].get_position().y1
    bottom = a[-1].get_position().y0

    # get the coordinates of the left side of the tick labels 
    x0 = 1
    for at in a:
        at.set_ylabel('') # just to make sure we don't and up with multiple labels
        bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer)
        bboxes = bboxes.inverse_transformed(f.transFigure)
        xt = bboxes.x0
        if xt < x0:
            x0 = xt
    tick_label_left = x0

    # set position of label
    a[-1].set_ylabel(ylabel)
    a[-1].yaxis.set_label_coords(tick_label_left - labelpad,(bottom + top)/2, transform=f.transFigure)

length = 100
x = np.linspace(0,100, length)
y1 = np.random.random(length) * 1000
y2 = np.random.random(length)

f,a = plt.subplots(2, sharex=True, gridspec_kw={'hspace':0})
a[0].plot(x, y1)
a[1].plot(x, y2)
set_shared_ylabel(a, 'shared y label (a. u.)')

यहां छवि विवरण दर्ज करें


7

plt.setp() काम करेंगे:

# plot something
fig, axs = plt.subplots(3,3, figsize=(15, 8), sharex=True, sharey=True)
for i, ax in enumerate(axs.flat):
    ax.scatter(*np.random.normal(size=(2,200)))
    ax.set_title(f'Title {i}')

# set labels
plt.setp(axs[-1, :], xlabel='x axis label')
plt.setp(axs[:, 0], ylabel='y axis label')

यहां छवि विवरण दर्ज करें


3
# list loss and acc are your data
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

ax1.plot(iteration1, loss)
ax2.plot(iteration2, acc)

ax1.set_title('Training Loss')
ax2.set_title('Training Accuracy')

ax1.set_xlabel('Iteration')
ax1.set_ylabel('Loss')

ax2.set_xlabel('Iteration')
ax2.set_ylabel('Accuracy')

1

अन्य उत्तरों में विधियाँ ठीक से काम नहीं करेंगी जब yticks बड़े होंगे। यालेबेल या तो टिक्स के साथ ओवरलैप करेगा, आंकड़े के बाईं या पूरी तरह से अदृश्य / बाहर क्लिप किया जाएगा।

मैंने Hagne के उत्तर को संशोधित किया है, इसलिए यह xlabel और ylabel दोनों के लिए सबप्लॉट के 1 से अधिक कॉलम के साथ काम करता है, और यह चित्र में दिखाई दे रहे ylabel को रखने के लिए कथानक को बदलता है।

def set_shared_ylabel(a, xlabel, ylabel, labelpad = 0.01, figleftpad=0.05):
    """Set a y label shared by multiple axes
    Parameters
    ----------
    a: list of axes
    ylabel: string
    labelpad: float
        Sets the padding between ticklabels and axis label"""

    f = a[0,0].get_figure()
    f.canvas.draw() #sets f.canvas.renderer needed below

    # get the center position for all plots
    top = a[0,0].get_position().y1
    bottom = a[-1,-1].get_position().y0

    # get the coordinates of the left side of the tick labels
    x0 = 1
    x1 = 1
    for at_row in a:
        at = at_row[0]
        at.set_ylabel('') # just to make sure we don't and up with multiple labels
        bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer)
        bboxes = bboxes.inverse_transformed(f.transFigure)
        xt = bboxes.x0
        if xt < x0:
            x0 = xt
            x1 = bboxes.x1
    tick_label_left = x0

    # shrink plot on left to prevent ylabel clipping
    # (x1 - tick_label_left) is the x coordinate of right end of tick label,
    # basically how much padding is needed to fit tick labels in the figure
    # figleftpad is additional padding to fit the ylabel
    plt.subplots_adjust(left=(x1 - tick_label_left) + figleftpad)

    # set position of label, 
    # note that (figleftpad-labelpad) refers to the middle of the ylabel
    a[-1,-1].set_ylabel(ylabel)
    a[-1,-1].yaxis.set_label_coords(figleftpad-labelpad,(bottom + top)/2, transform=f.transFigure)

    # set xlabel
    y0 = 1
    for at in axes[-1]:
        at.set_xlabel('')  # just to make sure we don't and up with multiple labels
        bboxes, _ = at.xaxis.get_ticklabel_extents(fig.canvas.renderer)
        bboxes = bboxes.inverse_transformed(fig.transFigure)
        yt = bboxes.y0
        if yt < y0:
            y0 = yt
    tick_label_bottom = y0

    axes[-1, -1].set_xlabel(xlabel)
    axes[-1, -1].xaxis.set_label_coords((left + right) / 2, tick_label_bottom - labelpad, transform=fig.transFigure)

यह निम्नलिखित उदाहरण के लिए काम करता है, जबकि हगेन का उत्तर यलैबेल (क्योंकि यह कैनवास के बाहर है) और केवाईसी के यलैबेल टिक लेबल के साथ ओवरलैप नहीं करेगा:

import matplotlib.pyplot as plt
import itertools

fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
for i, a in enumerate(itertools.chain(*axes)):
    a.plot([0,4**i], [0,4**i])
    a.set_title(i)
set_shared_ylabel(axes, 'common X', 'common Y')
plt.show()

वैकल्पिक रूप से, यदि आप बेरंग अक्ष के साथ ठीक हैं, तो मैंने जूलियन चेन के समाधान को संशोधित किया है ताकि ylabel टिक लेबल के साथ ओवरलैप न हो।

असल में, हमें बस बेरंग के यिलर्स को सेट करना है, इसलिए यह सबप्लाट्स के सबसे बड़े यिलर्स से मेल खाता है इसलिए बेरंग टिक लेबल यलबेल के लिए सही स्थान सेट करता है।

फिर से, हमें कतरन को रोकने के लिए साजिश को सिकोड़ना होगा। यहां मैंने हार्ड को सिकोड़ने के लिए राशि कोडित की है, लेकिन आप एक संख्या खोजने के लिए चारों ओर खेल सकते हैं जो आपके लिए काम करता है या ऊपर की विधि की तरह गणना करता है।

import matplotlib.pyplot as plt
import itertools

fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
miny = maxy = 0
for i, a in enumerate(itertools.chain(*axes)):
    a.plot([0,4**i], [0,4**i])
    a.set_title(i)
    miny = min(miny, a.get_ylim()[0])
    maxy = max(maxy, a.get_ylim()[1])

# add a big axes, hide frame
# set ylim to match the largest range of any subplot
ax_invis = fig.add_subplot(111, frameon=False)
ax_invis.set_ylim([miny, maxy])

# hide tick and tick label of the big axis
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.xlabel("common X")
plt.ylabel("common Y")

# shrink plot to prevent clipping
plt.subplots_adjust(left=0.15)
plt.show()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.