Skip to content

fix(skore): Do not start matplotlib GUI in non-main thread#2459

Draft
glemaitre wants to merge 1 commit intoprobabl-ai:mainfrom
glemaitre:is/2409
Draft

fix(skore): Do not start matplotlib GUI in non-main thread#2459
glemaitre wants to merge 1 commit intoprobabl-ai:mainfrom
glemaitre:is/2409

Conversation

@glemaitre
Copy link
Copy Markdown
Member

related #2409

When putting in parallel, we trigger Matplotlib GUI outside of the main thread which seems to be tricky.

Here, plt.tight_layout is triggering such behaviour.

However, it does not address all the problem detected in #2409. Indeed, because we are using seaborn that call plt.figure, then the Matplotlib GUI is called from outside skore. The solution, would be to switch to a non-interactive backend.

But we end-up in the same issue pointed out by @thomass-dev. I assume that putting object in parallel will have exactly the same problem. So while using plt.ioff to deactivate the interactive mode allowing to not break matplotlib in a notebook, this solution does not solve really the problem of the backend.

So we might finally need to find a way to switch the plotting backend even once matplotlib has been imported because we don't have the hand on what seaborn is doing.

@glemaitre glemaitre marked this pull request as draft February 13, 2026 19:43
@thomass-dev
Copy link
Copy Markdown
Collaborator

thomass-dev commented Feb 13, 2026

So we might finally need to find a way to switch the plotting backend even once matplotlib has been imported because we don't have the hand on what seaborn is doing.

You can do something like

image

But i gave up this method because it will drastically impact the user by forgetting all the settings he could have made manually with plt.blabla.

@github-actions
Copy link
Copy Markdown
Contributor

Documentation preview @ 8968107

@github-actions
Copy link
Copy Markdown
Contributor

Coverage

Coverage Report for skore/
FileStmtsMissCoverMissing
skore/src/skore
   __init__.py280100% 
   _config.py310100% 
   _login.py140100% 
   exceptions.py440%4, 15, 19, 23
skore/src/skore/_sklearn
   __init__.py60100% 
   _base.py73889%272–279
   feature_names.py260100% 
   find_ml_task.py610100% 
   types.py28196%30
skore/src/skore/_sklearn/_comparison
   __init__.py70100% 
   inspection_accessor.py27196%124
   metrics_accessor.py166298%179, 1138
   report.py111397%488, 491, 497
   utils.py570100% 
skore/src/skore/_sklearn/_cross_validation
   __init__.py90100% 
   data_accessor.py320100% 
   inspection_accessor.py20195%116
   metrics_accessor.py169597%1054, 1115, 1118, 1144–1145
   report.py126397%498, 501, 507
skore/src/skore/_sklearn/_estimator
   __init__.py90100% 
   data_accessor.py46197%169
   inspection_accessor.py70297%315, 329
   metrics_accessor.py367698%427, 431, 446, 476, 1661, 1744
   report.py158298%463, 466
skore/src/skore/_sklearn/_plot
   __init__.py30100% 
   base.py62493%60–61, 223–224
   utils.py121298%273–274
skore/src/skore/_sklearn/_plot/data
   __init__.py20100% 
   table_report.py175199%657
skore/src/skore/_sklearn/_plot/inspection
   __init__.py00100% 
   coefficients.py2050100% 
   impurity_decrease.py61198%186
   permutation_importance.py1500100% 
   utils.py90100% 
skore/src/skore/_sklearn/_plot/metrics
   __init__.py60100% 
   confusion_matrix.py1560100% 
   metrics_summary_display.py80100% 
   precision_recall_curve.py1080100% 
   prediction_error.py1670100% 
   roc_curve.py1120100% 
skore/src/skore/_sklearn/train_test_split
   __init__.py00100% 
   train_test_split.py580100% 
skore/src/skore/_sklearn/train_test_split/warning
   __init__.py80100% 
   high_class_imbalance_too_few_examples_warning.py19194%83
   high_class_imbalance_warning.py200100% 
   random_state_unset_warning.py100100% 
   shuffle_true_warning.py90100% 
   stratify_is_set_warning.py100100% 
   time_based_column_warning.py210100% 
   train_test_split_warning.py30100% 
skore/src/skore/_utils
   __init__.py6266%8, 13
   _accessor.py112397%38, 214, 268
   _cache.py370100% 
   _dataframe.py34197%43
   _environment.py32293%41, 44
   _fixes.py80100% 
   _index.py50100% 
   _logger.py22481%15–17, 19
   _measure_time.py100100% 
   _parallel.py38392%23, 33, 124
   _patch.py211242%30, 35–39, 42–43, 46–47, 58, 60
   _progress_bar.py41490%55–56, 66–67
   _show_versions.py380100% 
   _testing.py1031189%20, 29, 157, 166, 177–182, 184
skore/src/skore/_utils/repr
   __init__.py20100% 
   base.py540100% 
   data.py1630100% 
   html_repr.py380100% 
   rich_repr.py810100% 
skore/src/skore/project
   __init__.py20100% 
   _summary.py75198%119
   _widget.py1870100% 
   project.py550100% 
TOTAL43129197% 

Tests Skipped Failures Errors Time
1720 5 💤 0 ❌ 0 🔥 6m 42s ⏱️

@thomass-dev
Copy link
Copy Markdown
Collaborator

thomass-dev commented Feb 13, 2026

Note that in #2114 ba12bb8 (WIP) in a threading context (so similar to the asyncio issue), i ended up by spawning a dedicated matplotlib plotter process.

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.

2 participants