c16_likert_scale 毕业论文问卷 (Thesis Special) 国标学位论文 Nature SSCI社科

问卷调查李克特五级量表发散柱状图 (Likert Scale Diverging Bar)

经管社科与文科问卷量表分析标准图表,以0轴为中心左右发散展示同意度与反对度比例分布。

🔬 矢量预览 (Vector Preview) 600 DPI Ready
问卷调查李克特五级量表发散柱状图 (Likert Scale Diverging Bar)

📊 统计学特性 (Statistical Features)

  • 李克特五级量表发散累计
  • 中心零轴中立对齐
  • 正负倾向百分比分割
  • 均值与满意度统计

🛡️ QC 质检要点 (QC Highlights)

  • 题项长文本标签换行对齐
  • 负向红橙 vs 正向蓝绿区分鲜明
  • 百分比数字不与柱体冲突
  • 符合毕业论文排版规范
🎨 顶刊色彩提取器 (Palette Extractor)Nature

Crisp sans-serif typography, clean borderless spines, high-contrast palette with soft muted secondary accents.

🛡️ 无障碍评分:AAA (Deuteranopia & Protanopia Compliant)

📋 Data Contract 数据契约规范 Strict Schema

输入数据必须完全符合下列列名与数据类型规范,方可通过自动化数据前检 (Pre-flight Validation)。

📥 下载规范示例 CSV 数据
字段名称 (Column) 数据类型 (Type) 约束性 语义说明与值域约束
question categorical 必需 (Required) 问卷题项/量表维度名称
strongly_disagree continuous 必需 (Required) 非常不同意比例 (%)
disagree continuous 必需 (Required) 不同意比例 (%)
neutral continuous 必需 (Required) 中立比例 (%)
agree continuous 必需 (Required) 同意比例 (%)
strongly_agree continuous 必需 (Required) 非常同意比例 (%)
组内最小样本量: n ≥ 2
最大允许缺失率: 0%

🐍 独立可复现 Python 绘图源码 Stand-alone Script

完全可复现的 Python 脚本,支持 CLI 参数 `--data`, `--style`, `--output-dir` 与模块化 `render()` 调用。

#!/usr/bin/env python3
"""FigureCraft Chart Engine: c16_likert_scale (问卷调查李克特五级量表发散柱状图)."""

import os
import sys
import argparse
from pathlib import Path
from typing import List, Dict, Optional
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

try:
    from engines.styles import apply_style, get_palette
except ImportError:
    sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
    from engines.styles import apply_style, get_palette

CHART_ID = "c16_likert_scale"


def render(
    data_path: Optional[str] = None,
    style: str = "thesis_cn",
    output_dir: str = "output",
    formats: Optional[List[str]] = None,
    dpi: int = 600,
) -> Dict[str, str]:
    if formats is None:
        formats = ["svg", "pdf", "png", "tiff"]

    apply_style(style)
    palette = get_palette(style)

    if data_path is None:
        data_path = str(Path(__file__).resolve().parents[1] / "data" / f"{CHART_ID}.csv")

    df = pd.read_csv(data_path)
    os.makedirs(output_dir, exist_ok=True)

    neg_colors = ['#D62728', '#FF7F0E']
    neu_color = '#B0B0B0'
    pos_colors = ['#2CA02C', '#1F77B4']
    if len(palette) >= 5:
        neg_colors = [palette[3], palette[1]]
        neu_color = '#9E9E9E'
        pos_colors = [palette[2], palette[0]]

    questions = df['question'].tolist()
    n_q = len(questions)
    y_pos = np.arange(n_q)

    fig, ax = plt.subplots(figsize=(7.5, max(3.8, n_q * 0.7)), dpi=dpi)

    sd = df['strongly_disagree'].values
    d = df['disagree'].values
    neu = df['neutral'].values
    a = df['agree'].values
    sa = df['strongly_agree'].values

    left_neg = -(sd + d + neu / 2.0)

    ax.barh(y_pos, sd, left=left_neg, color=neg_colors[0], height=0.52, label='非常不同意', edgecolor='none')
    ax.barh(y_pos, d, left=left_neg + sd, color=neg_colors[1], height=0.52, label='不同意', edgecolor='none')
    ax.barh(y_pos, neu, left=left_neg + sd + d, color=neu_color, height=0.52, label='中立/一般', edgecolor='none')
    ax.barh(y_pos, a, left=left_neg + sd + d + neu, color=pos_colors[0], height=0.52, label='同意', edgecolor='none')
    ax.barh(y_pos, sa, left=left_neg + sd + d + neu + a, color=pos_colors[1], height=0.52, label='非常同意', edgecolor='none')

    ax.axvline(0, color='#333333', linestyle='-', linewidth=0.6, alpha=0.8)
    ax.set_yticks(y_pos)
    ax.set_yticklabels(questions, fontsize=8.0)
    ax.set_xlabel('响应人群占比百分比 (%)', fontsize=8.5, fontweight='semibold')
    ax.set_title('调查问卷李克特五级量表认同度发散分布', pad=12, fontsize=9.5, fontweight='bold')

    ax.legend(loc='lower center', bbox_to_anchor=(0.5, -0.22), ncol=5, frameon=False, fontsize=7.5)
    plt.tight_layout()

    out_paths = {}
    base_name = f"{CHART_ID}_{style}"
    for fmt in formats:
        p = os.path.join(output_dir, f"{base_name}.{fmt}")
        fig.savefig(p, format=fmt, dpi=dpi, bbox_inches='tight')
        out_paths[fmt] = p

    plt.close(fig)
    return out_paths


def main():
    parser = argparse.ArgumentParser(description="Render Likert Scale Diverging Bar Plot")
    parser.add_argument("--data", type=str, default=None)
    parser.add_argument("--style", type=str, default="thesis_cn")
    parser.add_argument("--output-dir", type=str, default="output")
    parser.add_argument("--formats", type=str, default="svg,pdf,png,tiff")
    parser.add_argument("--dpi", type=int, default=600)
    args = parser.parse_args()

    fmts = [f.strip() for f in args.formats.split(",")]
    render(args.data, args.style, args.output_dir, fmts, args.dpi)


if __name__ == "__main__":
    main()