मैटलपोटलिब सबप्लॉट्स के लिए सामान्य xlabel / ylabel


143

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

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

और अब मैं इस भूखंड को सामान्य एक्स-अक्ष लेबल और वाई-अक्ष लेबल देना चाहूंगा। "सामान्य" के साथ, मेरा मतलब है कि सबप्लॉट्स के पूरे ग्रिड के नीचे एक बड़ा एक्स-अक्ष लेबल होना चाहिए, और दाईं ओर एक बड़ा वाई-अक्ष लेबल होना चाहिए। मैं इसके बारे में दस्तावेज में कुछ भी नहीं पा सकता हूं plt.subplots, और मेरे गुगलों ने सुझाव दिया है कि मुझे plt.subplot(111)शुरू करने के लिए एक बड़ा बनाने की आवश्यकता है - लेकिन मैं फिर कैसे अपने 5 * 2 सबप्लॉट को उस उपयोग में डालूं plt.subplots?


2
प्रश्न के अपडेट के साथ, और नीचे दिए गए उत्तरों में छोड़ी गई टिप्पणियाँ stackoverflow.com/questions/6963035/…
हुक किए गए

वास्तव में नहीं, चूंकि मेरा प्रश्न plt.subplots () के लिए है, और आप जो प्रश्न add_subplot का उपयोग करने के लिए लिंक करते हैं - मैं उस पद्धति का उपयोग नहीं कर सकता जब तक कि मैं add_subplot पर स्विच नहीं करता, जिससे मैं बचना चाहूंगा। मैं plt.text समाधान का उपयोग कर सकता हूं जो आपके लिंक में वैकल्पिक समाधान के रूप में दिया गया है, लेकिन यह सबसे सुरुचिपूर्ण समाधान नहीं है।
jolindbe

विस्तृत करने के लिए, जहां तक ​​मैं समझता हूं, plt.subplots मौजूदा अक्ष वातावरण के भीतर सबप्लॉट का एक सेट उत्पन्न नहीं कर सकता है, लेकिन हमेशा एक नया आंकड़ा बनाता है। सही?
jolindbe

एक सबसे सुंदर समाधान यहां पाया जा सकता है: stackoverflow.com/questions/6963035/…
श्री एचएच

आपका लिंक 4 वर्ष से अधिक समय पहले उपयोगकर्ता द्वारा प्रदान किया गया था (आपके ऊपर कुछ टिप्पणियाँ)। जैसा कि मैंने पहले कहा, वह समाधान add_subplot से संबंधित है, न कि plt.subplots () से।
jolindbe

जवाबों:


206

ऐसा लगता है कि आप वास्तव में क्या चाहते हैं। यह आपके विशिष्ट मामले में इस उत्तर के समान दृष्टिकोण को लागू करता है:

import matplotlib.pyplot as plt

fig, ax = plt.subplots(nrows=3, ncols=3, sharex=True, sharey=True, figsize=(6, 6))

fig.text(0.5, 0.04, 'common X', ha='center')
fig.text(0.04, 0.5, 'common Y', va='center', rotation='vertical')

आम कुल्हाड़ी लेबल के साथ कई भूखंड


4
ध्यान दें कि एक्स-लेबल के एक्स-समन्वय के लिए 0.5 केंद्र सबप्लॉट के केंद्र में लेबल नहीं डालता है। आपको उस yticklabels के लिए खाते की तुलना में थोड़ा बड़ा जाना होगा।
23

2
इस उत्तर के लिए एक विधि है कि उपयोग नहीं करता है पर एक नज़र है plt.text। आप अपने सबप्लॉट बनाते हैं, लेकिन फिर एक बिट प्लॉट जोड़ते हैं, इसे अदृश्य बनाते हैं, और इसके x और y को लेबल करते हैं।
जेम्स ओनर्स

धन्यवाद, सामान्य रूप से काम किया। उपयोग करते समय टूट-फूट का कोई उपाय tight_layout?
सर्व-इंक

3
@ सर्व-इन के साथ tight_layoutबदलने के 0.04साथ 0काम करने लगता है।
दिवालिएपन

3
का उपयोग करना fig.textएक अच्छा विचार नहीं है। यह चीज़ों को गड़बड़ कर देता है जैसेplt.tight_layout()
शांतिपूर्ण

55

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

import matplotlib.pyplot as plt
fig, axes = plt.subplots(5, 2, sharex=True, sharey=True, figsize=(6,15))
# add a big axis, hide frame
fig.add_subplot(111, frameon=False)
# 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")

इसका परिणाम निम्नलिखित है (matplotlib संस्करण 2.2.0 के साथ):

5 पंक्तियाँ और 2 कॉलम सामान्य x और y अक्ष लेबल के साथ उप-बिंदु हैं


4
सादगी के कारण यह स्वीकृत उत्तर होना चाहिए। बहुत सीधा है। अभी भी matplotlib v3.x के लिए प्रासंगिक है
काइल स्वानसन

मैं यह जानना चाहूंगा कि इसे कई फिगर ऑब्जेक्ट्स के साथ कैसे इस्तेमाल किया जा सकता है? fig.xlabel ("foo") काम नहीं करता है।
हॉरर वेकई

FYI करें: अब जब लोग StackOverflow में डार्क थीम का उपयोग करते हैं, तो लेबल को मुश्किल से पढ़ा जा सकता है इसलिए अपने png को सफेद पृष्ठभूमि के साथ निर्यात करना बेहतर होगा
xyzzyqed

@xyzzyqed मुझे नहीं पता था कि स्टैकओवरफ्लो में "थीम" जैसी कोई चीज थी, और मुझे यह भी याद नहीं है कि मैंने आंकड़ा कैसे निर्यात किया। निर्यात करते समय मैं पृष्ठभूमि को कैसे नियंत्रित कर सकता हूं?
ब्लि

2
इस समाधान की एकमात्र समस्या यह है कि यह उपयोग करते समय काम नहीं करता है constrained_layout=Trueक्योंकि यह अतिव्यापी लेबल बनाता है। इस मामले में आपको मैन्युअल रूप से सबप्लॉट की सीमाओं को समायोजित करना होगा।
बैकुंठ

35

आपके बिना sharex=True, sharey=True:

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

इसके साथ आपको यह मिलना चाहिए:

fig, axes2d = plt.subplots(nrows=3, ncols=3,
                           sharex=True, sharey=True,
                           figsize=(6,6))

for i, row in enumerate(axes2d):
    for j, cell in enumerate(row):
        cell.imshow(np.random.rand(32,32))

plt.tight_layout()

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

लेकिन अगर आप अतिरिक्त लेबल जोड़ना चाहते हैं, तो आपको उन्हें केवल किनारे के भूखंडों में जोड़ना चाहिए:

fig, axes2d = plt.subplots(nrows=3, ncols=3,
                           sharex=True, sharey=True,
                           figsize=(6,6))

for i, row in enumerate(axes2d):
    for j, cell in enumerate(row):
        cell.imshow(np.random.rand(32,32))
        if i == len(axes2d) - 1:
            cell.set_xlabel("noise column: {0:d}".format(j + 1))
        if j == 0:
            cell.set_ylabel("noise row: {0:d}".format(i + 1))

plt.tight_layout()

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

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


यह बहुत कठिन है यदि, उदाहरण के लिए, भूखंडों की संख्या अज्ञात है (उदाहरण के लिए आपको एक सामान्यीकृत प्लॉट फ़ंक्शन मिला है जो किसी भी संख्या में सबप्लॉट के लिए काम करता है)।
naught101

15

कमांड के बाद से:

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

आपने उपयोग किया हुआ एक टपल दिया जिसमें आकृति और अक्षों के उदाहरणों की एक सूची है, यह पहले से ही कुछ ऐसा करने के लिए पर्याप्त है (मन जिसे मैंने बदल दिया fig,axहै fig,axes):

fig,axes = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

for ax in axes:
    ax.set_xlabel('Common x-label')
    ax.set_ylabel('Common y-label')

आप एक विशिष्ट subplot में कुछ विवरण में परिवर्तन करना चाहते हैं तो आप इसे माध्यम से उपयोग कर सकते हैं axes[i]जहां iअपने subplots से अधिक दोहराता।

यह भी शामिल करने के लिए बहुत उपयोगी हो सकता है

fig.tight_layout()

plt.show()ओवरलैपिंग लेबल से बचने के लिए , फ़ाइल के अंत में, से पहले ।


5
मुझे खेद है कि मैं थोड़ा अस्पष्ट था। "सामान्य" के साथ मेरा मतलब था कि सभी भूखंडों के नीचे एक एकल एक्स लेबल, और भूखंडों के बाईं ओर एक एकल वाई लेबल, मैंने इसे प्रतिबिंबित करने के लिए सवाल अपडेट किया है।
जोलिंडबे

2
@JohanLindberg: यहां और ऊपर अपनी टिप्पणियों के बारे में: वास्तव में plt.subplots()एक नया आंकड़ा उदाहरण तैयार करेगा। यदि आप इस आदेश के साथ रहना चाहते हैं, तो आप आसानी से एक जोड़ सकते हैं big_ax = fig.add_subplot(111), क्योंकि आपके पास पहले से ही एक आंकड़ा है और एक और अक्ष जोड़ सकते हैं। उसके बाद, आप big_axहुक के लिंक में दिखाए गए तरीके से हेरफेर कर सकते हैं ।
मारीस

आपके सुझावों के लिए धन्यवाद, लेकिन अगर मैं ऐसा करता हूं, तो मुझे plt.subplots () के बाद big_ax को जोड़ना होगा, और मुझे उस सबप्लॉट को बाकी सब चीजों के ऊपर मिलेगा - क्या मैं इसे पारदर्शी बना सकता हूं या इसे किसी भी तरह वापस भेज सकता हूं? भले ही मैंने हुकड के लिंक में सभी रंगों को सेट नहीं किया है, फिर भी यह एक सफेद बॉक्स है जो मेरे सभी सबप्लॉट को कवर करता है।
jolindbe

2
@JohanLindberg, आप सही हैं, मैंने वह जाँच नहीं की थी। लेकिन आप बड़ी धुरी की पृष्ठभूमि का रंग आसानी से कर सकते हैं none: big_ax.set_axis_bgcolor('none')आपको लेबलकोलर भी बनाना चाहिए none(जैसे हुक से जुड़े उदाहरण के विपरीत):big_ax.tick_params(labelcolor='none', top='off', bottom='off', left='off', right='off')
Marius

2
मुझे एक त्रुटि मिलती है: AttributeError: 'numpy.ndarray' object has no attribute 'set_xlabel'कथन में ax.set_xlabel('Common x-label')। क्या आप इसका पता लगा सकते हैं?
hengxin

5

नीचे के कोने में स्थित सबप्लॉट के लिए अदृश्य लेबल बनाकर सामान्य लेबल के लिए स्थान आरक्षित करने पर यह बेहतर लगेगा। RcParams से फॉण्टाइज़ में पास करना भी अच्छा है। इस तरह, सामान्य लेबल आपके आरसी सेटअप के साथ आकार बदल जाएगा, और कुल्हाड़ियों को भी आम लेबल के लिए जगह छोड़ने के लिए समायोजित किया जाएगा।

fig_size = [8, 6]
fig, ax = plt.subplots(5, 2, sharex=True, sharey=True, figsize=fig_size)
# Reserve space for axis labels
ax[-1, 0].set_xlabel('.', color=(0, 0, 0, 0))
ax[-1, 0].set_ylabel('.', color=(0, 0, 0, 0))
# Make common axis labels
fig.text(0.5, 0.04, 'common X', va='center', ha='center', fontsize=rcParams['axes.labelsize'])
fig.text(0.04, 0.5, 'common Y', va='center', ha='center', rotation='vertical', fontsize=rcParams['axes.labelsize'])

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


1
अदृश्य लेबल का अच्छा उपयोग! धन्यवाद
colelemonz

3

मैं ग्राफ की एक ग्रिड की साजिश रचते समय एक समान समस्या में भाग गया। ग्राफ़ में दो भाग (ऊपर और नीचे) शामिल थे। वाई-लेबल को दोनों भागों पर केंद्रित होना चाहिए था।

मैं एक ऐसे समाधान का उपयोग नहीं करना चाहता था जो बाहरी आकृति (जैसे कि अंजीर) () में स्थिति जानने पर निर्भर करता है, इसलिए मैंने set_ylabel () फ़ंक्शन की y-स्थिति में हेरफेर किया। यह आमतौर पर 0.5 है, जिस प्लॉट के बीच में इसे जोड़ा जाता है। जैसा कि मेरे कोड में भागों (हेस) के बीच पैडिंग शून्य था, मैं ऊपरी हिस्से के सापेक्ष दो भागों के मध्य की गणना कर सकता था।

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

# Create outer and inner grid
outerGrid = gridspec.GridSpec(2, 3, width_ratios=[1,1,1], height_ratios=[1,1])
somePlot = gridspec.GridSpecFromSubplotSpec(2, 1,
               subplot_spec=outerGrid[3], height_ratios=[1,3], hspace = 0)

# Add two partial plots
partA = plt.subplot(somePlot[0])
partB = plt.subplot(somePlot[1])

# No x-ticks for the upper plot
plt.setp(partA.get_xticklabels(), visible=False)

# The center is (height(top)-height(bottom))/(2*height(top))
# Simplified to 0.5 - height(bottom)/(2*height(top))
mid = 0.5-somePlot.get_height_ratios()[1]/(2.*somePlot.get_height_ratios()[0])
# Place the y-label
partA.set_ylabel('shared label', y = mid)

plt.show()

चित्र

downsides:

  • प्लॉट की क्षैतिज दूरी शीर्ष भाग पर आधारित है, नीचे की टिकें लेबल में विस्तारित हो सकती हैं।

  • सूत्र भागों के बीच स्थान को ध्यान में नहीं रखता है।

  • शीर्ष भाग की ऊंचाई 0 होने पर एक अपवाद फेंकता है।

संभवतः एक सामान्य समाधान है जो आंकड़ों के बीच पैडिंग को ध्यान में रखता है।


अरे, मैंने आपके उत्तर की नस में बहुत कुछ करने का एक तरीका निकाला है, लेकिन इनमें से कुछ मुद्दों को हल कर सकता हूं; देखें stackoverflow.com/a/44020303/4970632 (नीचे)
ल्यूक डेविस

2

अपडेट करें:

यह सुविधा अब proplot matplotlib पैकेज का हिस्सा है जिसे मैंने हाल ही में pypi पर जारी किया है। डिफ़ॉल्ट रूप से, जब आप आंकड़े बनाते हैं, तो कुल्हाड़ियों के बीच लेबल "साझा" होते हैं।


मूल उत्तर:

मैंने एक और अधिक मजबूत तरीका खोजा:

यदि आप को पता है bottomऔर topkwargs कि एक GridSpecप्रारंभ में चला गया , या आप अन्यथा Figureनिर्देशांक में अपने कुल्हाड़ियों के किनारों की स्थिति जानते हैं , तो आप Figureकुछ फैंसी "ट्रांसफ़ॉर्म" जादू के साथ निर्देशांक में यलैब की स्थिति भी निर्दिष्ट कर सकते हैं । उदाहरण के लिए:

import matplotlib.transforms as mtransforms
bottom, top = .1, .9
f, a = plt.subplots(nrows=2, ncols=1, bottom=bottom, top=top)
avepos = (bottom+top)/2
a[0].yaxis.label.set_transform(mtransforms.blended_transform_factory(
       mtransforms.IdentityTransform(), f.transFigure # specify x, y transform
       )) # changed from default blend (IdentityTransform(), a[0].transAxes)
a[0].yaxis.label.set_position((0, avepos))
a[0].set_ylabel('Hello, world!')

... और आपको यह देखना चाहिए कि लेबल अभी भी सामान्य रूप से, टिकबैबल्स के साथ ओवरलैपिंग से रखने के लिए बाएं-दाएं को उचित रूप से समायोजित करता है - लेकिन अब यह हमेशा वांछित सबप्लॉट के बीच समायोजित होगा ।

इसके अलावा, यदि आप भी उपयोग नहीं करते हैं set_position, तो यलैब डिफ़ॉल्ट रूप से आकृति के आधे हिस्से तक दिखाई देगा । मैं यह अनुमान लगा रहा हूं क्योंकि जब लेबल अंत में तैयार हो जाता है, तो matplotlib0.5 का उपयोग करता है y-कोर्डिनेट के लिए यह जांचे बिना कि क्या अंतर्निहित समन्वय परिवर्तन बदल गया है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.