plotly / plotly/plotly.js

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

オープン
#7,611 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

bug
主要言語
JavaScript
スター
18.3k
フォーク
2k
平均マージ
2日 12時間
マージ済み PR(30日)
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. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず src/traces/box/cross_trace_calc.js を読み、6つのバイオリン・トレース、grouped モード、offsetgroup なしの例を再現してください。各 x 位置での幅の割り当てを現在のグローバル・トレース計算と比較し、次に、grouped のバイオリン・トレースの間隔がゼロ間隔の設定と一致することを確認し、共有されている box-plot ロジックに影響があるか検討してください。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
javascript
領域
data-visualization
issue の種類
バグ
難易度
3/5
見積もり時間
1〜2日
活発さ
停滞
明瞭さ
明確に書かれている
初心者へのやさしさ
58/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。