Skip to content

feat(workflow-operator): volcano plot labels follow columns - #9040

Open
eugenegujing wants to merge 3 commits into
apache:mainfrom
eugenegujing:fix/volcano-plot-axis-labels
Open

eugenegujing wants to merge 3 commits into
apache:mainfrom
eugenegujing:fix/volcano-plot-axis-labels

Conversation

@eugenegujing

@eugenegujing eugenegujing commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

What changes were proposed in this PR?

Root cause: VolcanoPlotOpDesc.generatePythonCode hard-codes the y column as the literal "-log10(pvalue)" and plots it under that name, so the y axis always says -log10(pvalue) even when the selected column is padj. The title is the literal "Volcano Plot" and the x axis and color bar show the raw effect column name. None of this can be changed from the property panel.

Before:  P-Value Column = padj  ->  y column "-log10(pvalue)"  ->  y axis "-log10(pvalue)"
After:   P-Value Column = padj  ->  y column "-log10(padj)"    ->  y axis "-log10(padj)", or the Y Label the user typed

The y column is now named after the selected p-value column, so the axis and the hover text say which column was transformed. Four optional label properties are added, empty by default:

Property Empty Set
Title Volcano Plot the text typed
X Label effect column name the text typed
Y Label -log10(<p-value column>) the text typed
Color Bar Label effect column name the text typed

The labels go through fig.update_layout(xaxis_title, yaxis_title, coloraxis_colorbar_title_text), same as Line Chart's X Label / Y Label. Each label is an EncodableString, so quotes and non-ASCII text are fine. A whitespace-only field counts as empty. The hover box still shows raw column names (plotly behaviour, same as Line Chart).

Behavior change for saved workflows: a workflow with padj as the p-value column now renders -log10(padj) instead of -log10(pvalue). That is the fix.

Since #8504 merged, the operator also has an export path, generateStandaloneCode(), which writes the same figure as a standalone script. It carried the same hard-coded "-log10(pvalue)" and title="Volcano Plot", so this PR applies the same change there: the y column is named after the selected p-value column and the four labels go through fig.update_layout as escaped Python literals (the export has no decoder, so pyStringLiteral escapes quotes and backslashes). The engine template and the exported script now label the figure the same way, and a spec checks that across the label combinations.

Rebase note: coloraxis_colorbar_title_text is emitted unconditionally, in both templates. Once the significance-coloring PR (#9039) lands, the categorical mode has no coloraxis, so whichever branch rebases second needs to make that entry conditional.

Figures below are the operator's generated Python from main and from this branch, run on the 430-gene example workflow from the issue; the third one has all four labels filled in.

Before After (defaults) After (labels set)
before-main labels-after-default labels-after-custom

Any related issues, documentation, discussions?

Closes #9037

PR #8504 (merged) added the generateStandaloneCode() export path with the same hard-coded "-log10(pvalue)"; the mirroring described above is the follow-up it needed.

How was this PR tested?

New tests in VolcanoPlotOpDescSpec, written before the source change:

  • y column and axis are named after the selected p-value column; the old literal is gone
  • every label falls back to its default when empty or whitespace-only
  • a set label replaces its default and reaches the code only as a decode site (sentinels with quotes, backslash, non-ASCII)
  • one set label leaves the other three at their defaults
  • a workflow JSON saved before this change (only the two column keys) generates byte-for-byte the same code as a default-constructed operator
  • generateStandaloneCode: the y column and axis are named after the p-value column (including a name with a quote, p"adj), the labels fall back to the column-derived defaults, a set label is emitted as an escaped literal and the default title is gone, whitespace-only keeps the default, a saved workflow renders as a default-constructed operator, and a cross-path test checks that the engine template and the exported script carry the same title, axis and color bar labels
sbt -Dsbt.server.forcestart=true "WorkflowOperator/testOnly *VolcanoPlotOpDescSpec"
# Tests: succeeded 17, failed 0, canceled 0, ignored 0, pending 1   (the pending one is pre-existing)

sbt -Dsbt.server.forcestart=true "WorkflowOperator/scalafmtAll" "WorkflowOperator/Test/scalafmtAll"
sbt -Dsbt.server.forcestart=true "WorkflowOperator/scalafixAll --check"
# success

Smoke run: the generated code was executed outside Texera (pytexera stubbed, pandas + plotly 5.24.1) on the 430-gene mock table. Defaults give title Volcano Plot, x lfc_shrunk, y -log10(padj), color bar lfc_shrunk; with all four labels set the figure shows the typed text; whitespace-only title and y label fall back to the defaults. The exported script for the default and the all-labels configuration parses with ast.parse.

Was this PR authored or co-authored using generative AI tooling?

Yes. Generated-by: Claude Code (claude-fable-5-1). Co-authored with Claude; the author reviewed the change before submission.

Name the y column and its axis -log10(<p-value column>) instead of the fixed "-log10(pvalue)". Add optional Title, X Label, Y Label and Color Bar Label properties that override the column-derived text when set; an empty or blank field keeps the default.
@github-actions

Copy link
Copy Markdown
Contributor

Automated Reviewer Suggestions

Based on the git blame history of the changed files, we recommend the following reviewers:

  • Contributors with relevant context: @kz930, @Yicong-Huang
    You can notify them by mentioning @kz930, @Yicong-Huang in a comment.

@codecov-commenter

codecov-commenter commented Oct 24, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.87%. Comparing base (98c6337) to head (ba9e78d).

Additional details and impacted files
@@            Coverage Diff            @@
##               main    #9040   +/-   ##
=========================================
  Coverage     91.87%   91.87%           
  Complexity     5049     5049           
=========================================
  Files          1265     1265           
  Lines         54915    54913    -2     
  Branches       6940     6940           
=========================================
- Hits          50453    50452    -1     
+ Misses         2769     2768    -1     
  Partials       1693     1693           
Flag Coverage Δ *Carryforward flag
access-control-service 77.38% <ø> (ø)
agent-service 99.16% <ø> (ø) Carriedforward from 98c6337
amber 86.07% <ø> (+<0.01%) ⬆️ Carriedforward from 98c6337
computing-unit-managing-service 60.48% <ø> (ø)
config-service 87.37% <ø> (ø)
file-service 82.00% <ø> (ø)
frontend 96.50% <ø> (ø) Carriedforward from 98c6337
notebook-migration-service 83.73% <ø> (ø)
pyamber 98.54% <ø> (ø) Carriedforward from 98c6337
workflow-compiling-service 72.43% <ø> (ø)

*This pull request uses carry forward flags. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Benchmark changes need a look

🟢 2 better · 🔴 7 worse · ⚪ 6 noise (<±5%) · 0 without baseline

Compared against main 98c6337 benchmarked on this same runner, so the delta is largely free of cross-runner hardware noise. The "7d avg" column still reflects the gh-pages dashboard. Treat <±5% as noise unless repeated.

Dashboard · Run

config throughput MB/s latency max Δ latest / 7d
🔴 bs=10 sw=10 sl=64 526 0.321 18,053/28,515/28,515 us 🔴 +12.6% / 🔴 +100.3%
🟢 bs=100 sw=10 sl=64 1,233 0.752 80,266/90,358/90,358 us 🟢 -40.9% / 🟢 -12.1%
🔴 bs=1000 sw=10 sl=64 1,443 0.88 691,544/763,007/763,007 us 🔴 +6.7% / 🟢 +22.1%
Baseline details

Latest main 98c6337 from same runner

config metric PR latest main 7d avg Δ latest Δ 7d
bs=10 sw=10 sl=64 throughput 526 tuples/sec 592 tuples/sec 879.16 tuples/sec -11.1% -40.2%
bs=10 sw=10 sl=64 MB/s 0.321 MB/s 0.361 MB/s 0.537 MB/s -11.1% -40.2%
bs=10 sw=10 sl=64 p50 18,053 us 16,032 us 11,504 us +12.6% +56.9%
bs=10 sw=10 sl=64 p95 28,515 us 26,442 us 14,234 us +7.8% +100.3%
bs=10 sw=10 sl=64 p99 28,515 us 26,442 us 17,338 us +7.8% +64.5%
bs=100 sw=10 sl=64 throughput 1,233 tuples/sec 1,219 tuples/sec 1,147 tuples/sec +1.1% +7.5%
bs=100 sw=10 sl=64 MB/s 0.752 MB/s 0.744 MB/s 0.7 MB/s +1.1% +7.4%
bs=100 sw=10 sl=64 p50 80,266 us 77,479 us 88,987 us +3.6% -9.8%
bs=100 sw=10 sl=64 p95 90,358 us 152,989 us 96,473 us -40.9% -6.3%
bs=100 sw=10 sl=64 p99 90,358 us 152,989 us 102,791 us -40.9% -12.1%
bs=1000 sw=10 sl=64 throughput 1,443 tuples/sec 1,489 tuples/sec 1,182 tuples/sec -3.1% +22.1%
bs=1000 sw=10 sl=64 MB/s 0.88 MB/s 0.909 MB/s 0.721 MB/s -3.2% +22.0%
bs=1000 sw=10 sl=64 p50 691,544 us 673,998 us 872,751 us +2.6% -20.8%
bs=1000 sw=10 sl=64 p95 763,007 us 714,851 us 910,151 us +6.7% -16.2%
bs=1000 sw=10 sl=64 p99 763,007 us 714,851 us 941,479 us +6.7% -19.0%
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,380.06,200,128000,526,0.321,18053.36,28514.66,28514.66
1,100,10,64,20,1622.43,2000,1280000,1233,0.752,80265.87,90357.90,90357.90
2,1000,10,64,20,13863.99,20000,12800000,1443,0.880,691544.10,763007.41,763007.41

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Volcano Plot labels the y axis "-log10(pvalue)" regardless of the selected column, and offers no title / axis / color-bar labels

2 participants