2025, Oct 31 20:01
pandas और matplotlib में स्टैक्ड क्षैतिज बार का एलाइनमेंट कैसे ठीक करें
pandas और matplotlib में स्टैक्ड क्षैतिज बार चार्ट का एलाइनमेंट ठीक करें: ट्विन/सेकेंडरी अक्ष के साथ लेबल, लेजेंड, z-order और y-अक्ष सिंक करने की सरल, चरणबद्ध विधि
pandas और matplotlib के साथ क्षैतिज बार चार्ट सीधे-सादे लगते हैं, जब तक कि स्टैक्ड बार और सेकेंडरी अक्ष बीच में न आ जाएँ। एक आम समस्या यह है कि जब कोई लेयर ट्विन एक्सिस पर खींची जाती है, तो बार एक लाइन में नहीं बैठते। यह दृश्य असंगति हल्की लग सकती है, फिर भी चार्ट की बात बिगाड़ देती है। यहाँ बताया गया है कि कैटेगरी लेबल बचाए रखते हुए, बैकग्राउंड बैंड को पीछे और लेजेंड को सलीके से रखते हुए एलाइनमेंट कैसे ठीक करें।
समस्या को दोहराना
नीचे दिया गया स्निपेट एक सरल DataFrame बनाता है और दो क्षैतिज बार लेयर अलग-अलग एक्सिस पर ड्रॉ करता है। स्टैक्ड बार सेकेंडरी y-अक्ष पर जाते हैं, जबकि अर्ध-पारदर्शी बैकग्राउंड बैंड प्राइमरी y-अक्ष पर रहता है। नतीजा: बार असमान हो जाते हैं और लेआउट में कुछ अटपटी चीजें दिखती हैं।
import pandas as pd
import matplotlib.pyplot as plt
records = {'Name': ["A", "B", "C", "D", 'E'],
'Todo': [4, 5, 6, 7, 3],
'Done': [6, 2, 6, 8, 6],
'TimeRemaining': [4, 4, 4, 4, 4]}
frame = pd.DataFrame(records)
canvas, left_ax = plt.subplots(figsize=(10, 8))
right_ax = left_ax.twinx()
pick_cols = frame.columns[0:2].to_list()
bar_ax = frame.plot(kind='barh', y=pick_cols, stacked=True, ax=right_ax)
for box in bar_ax.containers:
labels = [r.get_width() if r.get_width() > 0 else '' for r in box]
bar_ax.bar_label(box, fmt=lambda val: f'{val:.0f}' if val > 0 else '', label_type='center')
frame.set_index('Name').plot(kind='barh', y=["TimeRemaining"], color='whitesmoke',
alpha=0.3, ax=left_ax, align='center', width=0.8,
edgecolor='blue')
right_ax.tick_params(axis='y', labelright=False, right=False)
right_ax.set_yticklabels([])
left_ax.get_legend().remove()
plt.title('Status Chart')
plt.tight_layout()
plt.show()
असल में हो क्या रहा है
यहाँ दो अलग-अलग एक्सिस इस्तेमाल हो रहे हैं: एक स्टैक्ड बार के लिए और दूसरा अर्ध-पारदर्शी बैंड के लिए। हर एक्सिस अपने y-अक्ष की पोजिशन खुद मैनेज करता है। चूँकि बार अलग-अलग एक्सिस पर हैं, उनकी कैटेगरी के केंद्र मेल नहीं खाते और लेयरें एक-दूसरे पर ठीक से नहीं बैठतीं। अगर सब कुछ एक ही एक्सिस पर ले आएँ, तो बार तो लाइन में आ जाते हैं, लेकिन बाएँ तरफ के कैटेगरी लेबल खो जाते हैं, एक अनचाही लेजेंड प्रविष्टि जुड़ जाती है, और पारदर्शी बैंड ऊपर खिंच जाता है।
समाधान
दोनों प्लॉट एक ही एक्सिस पर रखें ताकि बार के केंद्र मेल खाएँ, और ट्विन एक्सिस का उपयोग केवल बाएँ तरफ के लेबल दिखाने के लिए करें। बाएँ y-अक्ष को दाएँ y-अक्ष की पोजिशन के साथ सिंक करें, दाएँ तरफ के टिक लेबल छिपाएँ, लेजेंड में सिर्फ ज़रूरी आइटम रखें, और zorder के साथ बैकग्राउंड बैंड को पीछे भेजें। अगर दाएँ तरफ कोई ylabel दिखे, तो उसे स्पष्ट रूप से खाली कर दें।
import pandas as pd
import matplotlib.pyplot as plt
records = {'Name': ["A", "B", "C", "D", 'E'],
'Todo': [4, 5, 6, 7, 3],
'Done': [6, 2, 6, 8, 6],
'TimeRemaining': [4, 4, 4, 4, 4]}
frame = pd.DataFrame(records)
canvas, left_ax = plt.subplots(figsize=(10, 8))
right_ax = left_ax.twinx()
stack_cols = frame.columns[1:3].to_list()
bars_ax = frame.set_index('Name').plot(kind='barh', y=stack_cols, stacked=True, ax=right_ax)
for grp in bars_ax.containers:
labels = [seg.get_width() if seg.get_width() > 0 else '' for seg in grp]
bars_ax.bar_label(grp, fmt=lambda v: f'{v:.0f}' if v > 0 else '', label_type='center')
frame.set_index('Name').plot(kind='barh', y=["TimeRemaining"], color='whitesmoke',
alpha=0.3, ax=right_ax, align='center', width=0.8,
edgecolor='blue', zorder=0)
right_ax.tick_params(axis='y', labelright=False, right=False)
left_ax.tick_params(axis='y', labelleft=True, left=True)
left_ax.set_ylim(right_ax.get_ylim())
left_ax.set_yticks(right_ax.get_yticks())
left_ax.set_yticklabels(frame['Name'])
handles, labels = right_ax.get_legend_handles_labels()
right_ax.legend([handles[0]], [labels[0]], loc='upper right')
right_ax.set_ylabel('')
plt.title('Status Chart')
plt.tight_layout()
plt.show()
क्यों मायने रखता है
क्षैतिज बार चार्ट में कैटेगरी एलाइनमेंट नज़रअंदाज करना आसान है, पर एक बार दिख जाए तो अनदेखा करना मुश्किल। जब लेयरें अलग-अलग माप दर्शाती हैं, तो असमानता गलत संबंध का आभास करा सकती है। दोनों लेयरों को एक ही एक्सिस पर रखना सटीकता बनाए रखता है और चार्ट पढ़ने में आसान रहता है—खासकर जब आपको स्टैक्ड मान, अर्ध-पारदर्शी बेसलाइन बैंड, केंद्र-संरेखित लेबल और साफ-सुथरा लेजेंड चाहिए।
समापन
एलाइनमेंट सुनिश्चित करने के लिए सभी बार लेयर एक ही प्लॉटिंग एक्सिस पर रखें। ट्विन एक्सिस को केवल बाईं ओर के लेबल के लिए इस्तेमाल करें, y-अक्ष की सीमाएँ और टिक को मिरर करें, और z-order से बैकग्राउंड बैंड पीछे रखें। लेजेंड को सुसंगत करें और दाईं ओर का कोई भी अनचाहा ylabel हटा दें। परिणाम: एक सुसंगत, पठनीय क्षैतिज बार चार्ट, जो बिना लेआउट की अप्रत्याशित समस्याओं के सही बात स्पष्ट करता है।