plotly / plotly/plotly.js

[BUG]: Violin plot width incorrectly calculated in grouped mode with multiple x-categories

未关闭
#7,611 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

bug
主要语言
JavaScript
星标
18.3k
派生
2k
平均合并
2 天 12 小时
30 天内合并 PR
28

描述

Description

When using violinmode: 'group' with violins at multiple x-axis categories, but without offsetgroup set, the width calculation uses the total number of traces across the entire plot instead of the number of traces at each x-position. This causes excessive empty space even when gap parameters are set to 0.

Screenshots/Video
Image
Steps to reproduce
<!DOCTYPE html>
<html>
<head>
	<!-- Load plotly.js into the DOM -->
	<script src='https://cdn.plot.ly/plotly-3.1.2.js'></script>
</head>
<body>
    <div id="myDiv"></div>
    <script>
        // Create data: 2 models × 3 evaluations = 6 traces total
        // But at each x-position, there are only 2 violins

        const models = ["Model A", "Model B"];
        const evals = ["Eval 1", "Eval 2", "Eval 3"];
        const colors = ["blue", "red"];

        const traces = [];

        models.forEach((model, modelIdx) => {
            evals.forEach((evalName, evalIdx) => {
                const yData = Array.from({length: 50}, () =>
                    Math.random() * 2 - 1 + modelIdx
                );

                traces.push({
                    type: 'violin',
                    x: Array(50).fill(evalName),
                    y: yData,
                    name: model,
                    legendgroup: model,
                    scalegroup: model,
                    // offsetgroup: model, // Uncomment to fix spacing
                    showlegend: evalIdx === 0,
                    line: { color: colors[modelIdx] }
                });
            });
        });

        const layout = {
            violinmode: 'group',
            violingap: 0,      // No gap between categories
            violingroupgap: 0, // No gap between groups
            title: 'Bug Demo: Excessive empty space despite gap=0'
        };

        Plotly.newPlot('myDiv', traces, layout);
    </script>
</body>
</html>
Notes
Root Cause

I think the issue is in src/traces/box/cross_trace_calc.js.

When traces are split across multiple x-categories (each trace appears at only one x-value) but offsetgroup is not set, the formula incorrectly uses the global trace count numTotal:

var num = nOffsetGroups || numTotal;
...
bdPos = dPos * groupFraction * groupGapFraction / num;

This should divide by the number of traces at each specific x-position, not the total number of traces in the plot.

Workaround

Uncommenting offsetgroup: model, below scalegroup: model, in the above code produces the expected behaviour with no space between violins. See the below image:
Image
However I don't believe this should be required - certainly it isn't mentioned in the docs.

Related

This probably also affects box plots since they share the width calculation logic in cross_trace_calc.js.

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

先阅读 src/traces/box/cross_trace_calc.js,并复现包含六条小提琴 trace、分组模式且不使用 offsetgroup 的示例。将每个 x 位置的宽度分配与当前的全局 trace 计算进行比较,然后验证分组小提琴 trace 的间距是否与零间隔设置一致,并考虑共享的 box-plot 逻辑是否受到影响。

由索引模型根据 Issue 内容生成。

评估

技术栈
javascript
领域
data-visualization
Issue 类型
缺陷
难度
3/5
预计耗时
1-2 天
活跃度
停滞
描述清晰度
描述清楚
新手友好度
58/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。