Skip to content

Add Sankey diagram visualization functions - #989

Merged
sueoglu merged 33 commits into
mainfrom
enhancement/issue-232-clean
Dec 19, 2025
Merged

Add Sankey diagram visualization functions #989
sueoglu merged 33 commits into
mainfrom
enhancement/issue-232-clean

Conversation

@sueoglu

@sueoglu sueoglu commented Nov 26, 2025

Copy link
Copy Markdown
Collaborator

fixes #232
two new visualization functions sankey_diagram and sankey_diagram_time for creating Sankey diagrams to analyze patient flows and state transitions in EHR data, added comprehensive tests

sankey_diagram : relationships across observation columns
sankey_diagram_time: observation state transitions over time

Examples

  • ep.pl.sankey_diagram()
import ehrapy as ep
import ehrdata as ed

edata = diabetes_130_fairlearn_sample_100()
ep.pl.sankey_diagram(edata, columns=["gender", "race"])

Output:

image
  • ep.pl.sankey_diagram_time()
import ehrapy as ep
import ehrdata as ed

edata = ed.dt.ehrdata_blobs(base_timepoints=5, n_variables=1, n_observations=5, random_state=59)
edata.layers["tem_data] = edata.layers["tem_data].astype(int)
sankey_time = ep.pl.sankey_diagram_time(edata, var_name="feature_0", layer="tem_data", state_labels={-2: "no", -3: "mild", -4: "moderate", -5: "severe", -6: "critical"})

Output:
image

@review-notebook-app

Copy link
Copy Markdown

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@sueoglu
sueoglu marked this pull request as ready for review December 12, 2025 08:52
@sueoglu
sueoglu requested review from Zethson and eroell December 12, 2025 10:11

@Zethson Zethson left a comment

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.

Thank you very much!

  1. Don't forget add the function to our docs, please.
  2. Could you please add previews to the PR description?
  3. We should have a consistent plotting user interface where all have the same parameters and style like height, width etc. We should avoid kwargs where possible.
  4. Great tests! We might need to use try -> finally because you're changing the plotting backend. If the test fails and the plotting backend is not reset, it could cause other tests to fail.

Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread tests/plot/test_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py
@github-actions github-actions Bot added the chore label Dec 17, 2025
@Zethson

Zethson commented Dec 17, 2025

Copy link
Copy Markdown
Member

@sueoglu FYI you have to ensure that you're not updating the submodule of the tutorials in this PR, please. Unless you're adding your new plotting functions somewhere of course but I don't think that we're there yet.

@eroell eroell left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  • Make self-contained examples in the first comment of this PR (currently, they don't run

I'm not sure how 2 columns are used in ep.pl.sankey_diagram_time:

import ehrdata as ed
import ehrapy as ep
edata = ed.dt.ehrdata_blobs(base_timepoints=5, n_variables=2, n_observations=5, random_state=59)
edata.layers["tem_data"] = edata.layers["tem_data"].astype(int)
state_labels = {-2: "no", -3: "mild", -4: "moderate", -5: "severe", -6: "critical"}
ep.pl.sankey_diagram_time(
    edata,
    columns=["feature_0", "feature_1"],
    layer="tem_data",
    state_labels=state_labels,
)

and

import ehrdata as ed
import ehrapy as ep
edata = ed.dt.ehrdata_blobs(base_timepoints=5, n_variables=2, n_observations=5, random_state=59)
edata.layers["tem_data"] = edata.layers["tem_data"].astype(int)
state_labels = {-2: "no", -3: "mild", -4: "moderate", -5: "severe", -6: "critical"}
ep.pl.sankey_diagram_time(
    edata,
    columns=["feature_0"],
    layer="tem_data",
    state_labels=state_labels,
)

Yield the same plots if I see this correctly, and I think only 1 variable being allowed makes sense, or do I misunderstand that? :)

Comment thread ehrapy/plot/_sankey.py
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated

@Zethson Zethson left a comment

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.

I'm very confident that we're very close to merging this now.

Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/_compat.py Outdated
@Zethson

Zethson commented Dec 18, 2025

Copy link
Copy Markdown
Member
edata.layers["tem_data] = edata.layers["tem_data].astype(int)

is there a way to circumvent this requirement? Like handling it internally or it working with any type here?

@sueoglu

sueoglu commented Dec 18, 2025

Copy link
Copy Markdown
Collaborator Author
edata.layers["tem_data] = edata.layers["tem_data].astype(int)

is there a way to circumvent this requirement? Like handling it internally or it working with any type here?

For the time being, I did it with type casting so that we can have a working example and tests as ehrdata_blobs currently doesnt produce discrete states. But if the state labels in a given input could also be of other types I should also handle the conversion internally

@Zethson

Zethson commented Dec 18, 2025

Copy link
Copy Markdown
Member

This is related to theislab/ehrdata#196 right? I'm fine with temporarily having this until we have a new ehrdata release but I feel like the plotting function might need to be more robust? Like sure - blobs looks like this but our users can do whatever they like.

WDYT?

@eroell

eroell commented Dec 18, 2025

Copy link
Copy Markdown
Collaborator

This is related to theislab/ehrdata#196 right?

yes it is

I'm fine with temporarily having this until we have a new ehrdata release but I feel like the plotting function might need to be more robust?

If you have continuous values in a feature, then the sankey diagram is not the right way to plot it, no? If you'd want a sankey diagram of a continuous value, you need to bin your data, and I'd suggest users need to think about that and do the binning before calling this plotting function

@Zethson

Zethson commented Dec 18, 2025

Copy link
Copy Markdown
Member

Yeah so I think we need to

  1. Fail early and suggest a solution
  2. Automatically bin

But I think that atm we do neither.

@eroell

eroell commented Dec 18, 2025

Copy link
Copy Markdown
Collaborator

Yep - I'm in favor of 1

@sueoglu
sueoglu requested review from Zethson and eroell December 19, 2025 09:34
@Zethson Zethson added enhancement New feature or request and removed chore labels Dec 19, 2025

@eroell eroell left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

3 small points - when they are addressed, this looks good from my side!

Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread tests/plot/test_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread ehrapy/plot/_sankey.py Outdated
Comment thread tests/plot/test_sankey.py Outdated
@github-actions github-actions Bot added the chore label Dec 19, 2025
@sueoglu sueoglu removed the chore label Dec 19, 2025
@github-actions github-actions Bot added the chore label Dec 19, 2025
@sueoglu sueoglu removed the chore label Dec 19, 2025
@sueoglu
sueoglu merged commit 4f64d43 into main Dec 19, 2025
18 checks passed
@sueoglu
sueoglu deleted the enhancement/issue-232-clean branch December 19, 2025 12:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request skip-gpu-ci

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add time based sankey diagrams

3 participants