You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Plotly箱线图填充类别间空隙?Django+Plotly实现

解决Plotly箱线图类别内宽度挤压问题

核心思路

Plotly默认布局会为所有类别预留统一的箱线空间,哪怕单个类别只有一组箱线,导致视觉上被过度挤压。要让每个类别下的箱线占满所属类别宽度,核心是通过布局参数调整间距,或自定义x轴刻度位置来分配空间。


方案一:调整Plotly布局参数(推荐)

通过boxgap和boxgroupgap参数精准控制类别间、类别内的间距,让单组箱线直接占满类别宽度。

后端Python(Django生成Trace与布局)

假设你的数据结构如下:

# 数据示例
categories = ["A", "B", "C"]
data = {
    "A": [10, 12, 15, 18, 20],
    "B": [8, 9, 11, 13],
    "C": [14, 16, 17, 19, 21, 23]
}

生成图表数据时添加关键布局配置:

import plotly.graph_objects as go

traces = []
for cat, values in data.items():
    traces.append(go.Box(
        y=values,
        x=[cat]*len(values),  # 绑定数据到对应类别
        name=cat
    ))

# 核心布局设置
layout = go.Layout(
    boxmode='group',  # 按类别分组箱线
    boxgap=0.1,  # 类别之间的间距(取值0-1,0为无间距)
    boxgroupgap=0.0,  # 同一类别内箱线的间距(设为0让单箱线占满宽度)
    xaxis=dict(
        title="类别",
        tickmode="array",
        tickvals=categories,
        ticktext=categories
    )
)

# 转为JSON传给前端
fig = go.Figure(data=traces, layout=layout)
chart_json = fig.to_json()

前端JS渲染

直接用Plotly渲染即可,无需额外修改:

// 后端传递的JSON通过Django模板变量传入
const chartData = JSON.parse('{{ chart_json|safe }}');
Plotly.newPlot('box-chart', chartData.data, chartData.layout);

方案二:自定义x轴刻度位置(适配多箱线类别)

如果部分类别下有多组箱线,需要让它们平分类别宽度,可以通过自定义数值型x轴刻度,再映射为类别名称实现。

后端Python调整

import plotly.graph_objects as go

# 数据示例:类别A有2组箱线,B有1组,C有3组
category_config = {
    "A": {"count": 2, "values": [[10,12,15], [18,20,22]]},
    "B": {"count": 1, "values": [[8,9,11,13]]},
    "C": {"count": 3, "values": [[14,16], [17,19], [21,23]]}
}

traces = []
x_tickvals = []
x_ticktext = []
current_x = 0

for cat, config in category_config.items():
    box_count = config["count"]
    step = 1 / box_count  # 每组箱线占据的宽度比例
    center_x = current_x + 0.5  # 类别中心位置,用于刻度显示
    x_tickvals.append(center_x)
    x_ticktext.append(cat)
    
    for i, values in enumerate(config["values"]):
        # 计算每组箱线的x轴位置
        x_pos = current_x + (i + 0.5) * step
        traces.append(go.Box(
            y=values,
            x=[x_pos]*len(values),
            name=f"{cat}-{i+1}"
        ))
    current_x += 1

layout = go.Layout(
    xaxis=dict(
        title="类别",
        tickmode="array",
        tickvals=x_tickvals,
        ticktext=x_ticktext,
        range=[-0.5, current_x - 0.5]  # 让类别边缘对齐图表边界
    ),
    boxmode='overlay',  # 按自定义位置覆盖排列箱线
    boxgap=0,
    boxgroupgap=0
)

fig = go.Figure(data=traces, layout=layout)
chart_json = fig.to_json()

前端JS渲染

直接渲染即可:

const chartData = JSON.parse('{{ chart_json|safe }}');
Plotly.newPlot('box-chart', chartData.data, chartData.layout);

效果验证

两种方案均可实现:

  • 单箱线类别:箱线完全填充所属类别宽度,无多余留白
  • 多箱线类别:各组箱线平分类别宽度,布局紧凑清晰

内容的提问来源于stack exchange,提问作者Yujin Kim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 06:06:22