2025, Oct 22 09:16

LaTeX \textwidth के लिए Seaborn फ़िगर्स को सही तरह स्केल करें

Seaborn/Matplotlib ग्राफ़ को LaTeX \textwidth पर फिट करें: सही फ़ॉन्ट साइज, LaTeX टेक्स्ट रेंडरिंग, PDF (bbox_inches='tight') और stripplot मार्कर ट्यूनिंग के व्यावहारिक कदम.

जब आप seaborn आकृतियों का आकार LaTeX \textwidth के अनुरूप सेट करते हैं और फिर भी प्लॉट भरे-भरे दिखते हैं, तो यह खीझ पैदा करता है। एक सामान्य लक्षण यह है कि चित्र अपेक्षा से छोटा नजर आता है—मार्कर और लेबल सघन लगते हैं—और वह तभी “ठीक” लगता है जब आप फ़िगर की चौड़ाई दोगुनी कर दें। उद्देश्य, हालांकि, लक्षित चौड़ाई को बरकरार रखते हुए फ़ॉन्ट का आकार पांडुलिपि के मुख्य पाठ के अनुरूप रखना है।

समस्या को पुनरुत्पादित करना

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

import matplotlib.pyplot as plt
import seaborn as sns
page_width = 7.00925
metrics = ['test_1', 'test_2', 'test_3']
panel_titles = ['Test 1', 'Test 2', 'Test 3']
canvas, axarr = plt.subplots(1, 3, figsize=(page_width, 3), sharey=True)
for idx, (target_col, ttl) in enumerate(zip(metrics, panel_titles)):
    pane = axarr[idx]
    # स्ट्रिपप्लॉट
    sns.stripplot(
        x='diagnosis_grouped', y=target_col, data=plot_frame, ax=pane,
        palette='viridis', alpha=0.7, jitter=True
    )
    # बॉक्सप्लॉट
    sns.boxplot(
        x='group', y=target_col, data=plot_frame, ax=pane, showfliers=False,
        width=0.3,
        boxprops=dict(facecolor='none', edgecolor='black'),
        medianprops=dict(color='black'),
        whiskerprops=dict(color='black'),
        capprops=dict(color='black')
    )
    pane.set_title(ttl, fontsize=label_size)
    pane.set_xlabel('Group', fontsize=label_size)
    if idx == 0:
        pane.set_ylabel('Score', fontsize=label_size)
    else:
        pane.set_ylabel('')
    pane.tick_params(axis='x', rotation=20, labelsize=label_size)
    pane.tick_params(axis='y', labelsize=label_size)
plt.tight_layout(rect=[0, 0, 1, 0.95])
plt.savefig('/path/figure_1.eps', dpi=800)

असल में हो क्या रहा है

दृश्य प्रभाव पर दो अलग-अलग कारक असर डालते हैं। पहला, figsize बढ़ाने पर वही डेटा अधिक क्षैतिज जगह घेरता है, इसलिए बिंदु और बॉक्स स्वाभाविक रूप से फैलते हैं और कम भीड़भाड़ लगती है। दूसरा, यदि फ़ॉन्ट आकार लक्ष्य दस्तावेज़ के अनुरूप स्पष्ट रूप से नहीं मिलाए गए, तो सही फ़िगर चौड़ाई होने पर भी अक्ष लेबल और टिक असंतुलित दिख सकते हैं। एक बार फ़ॉन्ट सोच-समझकर सेट कर दिए जाएँ, तो वही चौड़ाई पृष्ठ पर इच्छित रूप में पढ़ी जाती है। LaTeX के साथ टेक्स्ट रेंडरिंग करने से लेबल और गणितीय चिन्ह दस्तावेज़ की टाइपोग्राफ़ी से मेल खाते हैं।

समाधान

लक्षित चौड़ाई बनाए रखें। अपने दस्तावेज़ से मेल खाने वाला एक ठोस लेबल आकार निर्धारित करें (उदाहरण के लिए, 11)। टाइपोग्राफ़ी को सुसंगत रखने के लिए LaTeX-आधारित टेक्स्ट रेंडरिंग सक्षम करें। PDF जैसे वेक्टर फ़ॉर्मेट में, और tight bounding box के साथ सेव करने से तीक्ष्णता और व्हाइटस्पेस पर नियंत्रण बना रहता है। यदि बिंदु अब भी घने लगें, तो sns.stripplot में size पैरामीटर से मार्कर का आकार कम करें।

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib import rcParams
# सभी टेक्स्ट रेंडरिंग के लिए LaTeX का उपयोग करें
rcParams.update({"text.usetex": True})
# पांडुलिपि से मेल खाने के लिए फ़ॉन्ट आकार निर्धारित करें
rcParams.update({
    "font.size": 11,
    "axes.labelsize": 11,
    "axes.titlesize": 11,
    "xtick.labelsize": 11,
    "ytick.labelsize": 11,
    "legend.fontsize": 11,
})
label_size = 11
page_width_in = 7.00925
panel_height_in = 3
frame_metrics = ['test_1', 'test_2', 'test_3']
frame_titles = ['Test 1', 'Test 2', 'Test 3']
board, panels = plt.subplots(1, 3, figsize=(page_width_in, panel_height_in), sharey=True)
for j, (col_name, title_txt) in enumerate(zip(frame_metrics, frame_titles)):
    slot = panels[j]
    sns.stripplot(
        x='diagnosis_grouped', y=col_name, data=plot_frame, ax=slot,
        palette='viridis', alpha=0.7, jitter=True
        # size=4  # यदि घना लगे तो बिंदु का आकार वैकल्पिक रूप से घटाएँ
    )
    sns.boxplot(
        x='group', y=col_name, data=plot_frame, ax=slot, showfliers=False,
        width=0.3,
        boxprops=dict(facecolor='none', edgecolor='black'),
        medianprops=dict(color='black'),
        whiskerprops=dict(color='black'),
        capprops=dict(color='black')
    )
    slot.set_title(title_txt, fontsize=label_size)
    slot.set_xlabel('Group', fontsize=label_size)
    if j == 0:
        slot.set_ylabel('Score', fontsize=label_size)
    else:
        slot.set_ylabel('')
    slot.tick_params(axis='x', rotation=20, labelsize=label_size)
    slot.tick_params(axis='y', labelsize=label_size)
plt.tight_layout(rect=[0, 0, 1, 0.95])
plt.savefig('/path/figure_1.pdf', bbox_inches='tight')
plt.show()

प्रकाशन कार्यप्रवाह में यह क्यों मायने रखता है

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

मुख्य निष्कर्ष

कैनवास को लक्ष्य चौड़ाई पर सेट करें, फिर फ़ॉन्ट आकार स्पष्ट रूप से निर्धारित करें ताकि लेबल पांडुलिपि से मेल खाएँ। टाइपोग्राफ़ी को एकसमान रखने के लिए LaTeX टेक्स्ट रेंडरिंग का उपयोग करें और साफ़ आउटपुट के लिए tight bounding box के साथ PDF में सेव करें। यदि सही चौड़ाई पर भी दृश्य घनत्व ज़्यादा लगे, तो फ़िगर का आकार बढ़ाने के बजाय स्ट्रिपप्लॉट में मार्कर आकार घटाएँ। इस तरह आप \textwidth का पालन करते हुए पठनीयता और लेआउट से समझौता नहीं करते।

यह लेख StackOverflow के एक प्रश्न (लेखक: RBG) और Thomas Beck के उत्तर पर आधारित है।