Skip to content

Add options to omit empty or default columns from v2 tables - #543

Merged
dweindl merged 2 commits into
PEtab-dev:mainfrom
dweindl:column_modes
Oct 15, 2026
Merged

dweindl merged 2 commits into
PEtab-dev:mainfrom
dweindl:column_modes

Conversation

@dweindl

@dweindl dweindl commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Converting PEtab v2 tables to DataFrames or TSV files currently always includes all standard columns, even if they are empty in every row (#523). This adds three column modes via petab.v2.TableColumns:

  • all: all columns (default, unchanged behavior)
  • non_empty: omit columns that are empty in every row
  • non_default: additionally omit columns that have their default value in every row (e.g., noiseDistribution=normal)

Required columns are always included. The mode can be passed explicitly, or set globally or temporarily, which also applies to the Problem.*_df properties:

problem.parameter_tables[0].to_df(columns="non_default")
problem.to_files("out/", columns="non_empty")

petab.v2.set_options(table_columns="non_empty")
with petab.v2.option_context(table_columns="non_default"):
    problem.parameter_df

Further changes:

  • parameterName is now a field of Parameter (Parameter.name) instead of an extra attribute.
  • Required columns are taken from C.*_DF_REQUIRED_COLS. nominalValue was added to C.PARAMETER_DF_REQUIRED_COLS, as the spec requires the column to be present.
  • to_df now works for empty parameter, observable, and measurement tables.

Closes #523.

🤖 Generated with Claude Code

@codecov-commenter

codecov-commenter commented Oct 14, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.99%. Comparing base (6278958) to head (6611e0e).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #543      +/-   ##
==========================================
+ Coverage   77.77%   77.99%   +0.22%     
==========================================
  Files          67       68       +1     
  Lines        7708     7786      +78     
  Branches     1380     1389       +9     
==========================================
+ Hits         5995     6073      +78     
  Misses       1226     1226              
  Partials      487      487              

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dweindl
dweindl force-pushed the column_modes branch 2 times, most recently from 11c6e96 to f6635e6 Compare October 15, 2026 07:47
@dweindl
dweindl marked this pull request as ready for review October 15, 2026 08:01
@dweindl
dweindl requested a review from a team as a code owner October 15, 2026 08:01
Comment thread petab/v2/core.py Outdated
continue
default = field.get_default(call_default_factory=True)
if all(getattr(row, name) == default for row in self.elements):
result.append(field.alias or name)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should field.alias or name default to the other? Since field.alias or name appears twice.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved it to a helper

Comment thread petab/v2/core.py
Comment on lines +1026 to +1029
#: Parameter name.
name: Annotated[str | None, BeforeValidator(_convert_nan_to_none)] = Field(
alias=C.PARAMETER_NAME, default=None
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it useful to do this? We should always keep columns that are not covered by the standard -- why treat parameterName specially?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameterName is covered by the standard. Not great, but it's there. And it's unclear how any conflict with annotations through the mapping table would be resolved.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh true, somehow I thought we dropped it.

Comment thread petab/v2/options.py Outdated
Comment thread petab/v2/C.py
PARAMETER_ID,
LOWER_BOUND,
UPPER_BOUND,
NOMINAL_VALUE,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nominalValue was added to C.PARAMETER_DF_REQUIRED_COLS, as the spec requires the column to be present.

It is optional if estimate is true. Might be problematic to expect it always.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not marked [nominalValue] in the specs, so my understanding is that the column is mandatory, but the respective field may be empty. Other columns, such as observableParameters, explicitly state the if all-empty, the column can be omitted. For nominalValue this isn't the case. While I'd say your interpretation is desirable, I don't think this what the specs say.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, I see your point. Also applies to upper and lower bound.

Do you know whether your description is the intended interpretation while writing the spec, or just a grey area we forgot to clarify? If the latter then I think it's fine to update the spec now, just like we updated the v1 spec when we realized some things were unclear.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add that to PEtab-dev/PEtab#681, so it can be discussed. Generally, I am in favor of dropping it if all-empty. For the bounds it's unlikely that they would ever be all-empty, because that would mean there is no parameter to estimate at all. Allowed, I guess. Useful? Not sure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since multiple parameter tables are supported, one could keep their fixed parameters in a separate table to their estimated ones. Then it's slightly nicer to not have columns related to estimation, in the fixed parameters table.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, I didn't consider this use case.

Converting PEtab v2 tables to DataFrames or TSV files currently always
includes all standard columns, even if they are empty in every row.

Add `TableColumns` modes `all` (default, current behavior), `non_empty`,
and `non_default` to select the columns to include. Required columns
(`C.*_DF_REQUIRED_COLS`) are always included. The mode can be passed to
`to_df`, `to_tsv`, and `Problem.to_files`, or set via
`petab.v2.set_options` or temporarily via `petab.v2.option_context`,
which also applies to `Problem.*_df`.

Also add the `parameterName` column as `Parameter.name`, add
`nominalValue` to the required parameter table columns as in the spec,
and make `to_df` work for empty parameter, observable, and measurement
tables.

Closes PEtab-dev#523.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dilan Pathirana <59329744+dilpath@users.noreply.github.com>
@dweindl
dweindl merged commit 498ee18 into PEtab-dev:main Oct 15, 2026
7 checks passed
@dweindl
dweindl deleted the column_modes branch October 15, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tables to dataframes includes useless columns

3 participants