Skip to content

Commit f48fff7

Browse files
authored
Merge pull request #2 from CSOgroup/feature/complete-selectsim-py
perf: lazy-load plotting functions, drop unused seaborn dependency
2 parents 51d652f + 31a6f51 commit f48fff7

6 files changed

Lines changed: 108 additions & 75 deletions

File tree

NEWS.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,18 @@ Initial feature-complete Python port of the [SelectSim R package](https://github
102102
* This round of work was developed with the assistance of Claude Code
103103
(Anthropic), directed and verified by Arvind Iyer throughout; see
104104
`git log` for detailed commit history.
105+
106+
# SelectSim (Python) 0.3.1
107+
108+
* **Performance**: `import selectsim` dropped from ~1.5s to ~0.6s. The
109+
top-level package eagerly imported `selectsim.plotting`, which pulls in
110+
`matplotlib` and `scipy` (used nowhere outside `plotting.py`), even for
111+
callers who only ever call `selectX()` and never plot anything.
112+
Plotting functions (`obs_exp_scatter`, `ridge_plot_ed`, `oncoprint`,
113+
etc.) are now resolved lazily on first access (PEP 562 module
114+
`__getattr__`) instead -- same `ss.<name>` usage, just deferred. On the
115+
bundled LUAD benchmark this cut whole-process wall time by ~23% and
116+
peak memory by ~21%.
117+
* **Removed**: the `seaborn` dependency. It was listed in
118+
`pyproject.toml` and mentioned in a couple of docstrings, but never
119+
actually imported or used anywhere in the codebase.

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
project = 'SelectSim'
1414
copyright = '2026, Arvind Iyer, Marco Mina, Miljan Petrovic, Giovanni Ciriello'
1515
author = 'Arvind Iyer, Marco Mina, Miljan Petrovic, Giovanni Ciriello'
16-
release = '0.3.0'
16+
release = '0.3.1'
1717

1818
# -- General configuration ---------------------------------------------------
1919
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

docs/source/tutorials/introduction.ipynb

Lines changed: 56 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@
4040
"id": "d465b22a",
4141
"metadata": {
4242
"execution": {
43-
"iopub.execute_input": "2026-07-14T19:10:47.821334Z",
44-
"iopub.status.busy": "2026-07-14T19:10:47.820804Z",
45-
"iopub.status.idle": "2026-07-14T19:10:49.335540Z",
46-
"shell.execute_reply": "2026-07-14T19:10:49.334213Z"
43+
"iopub.execute_input": "2026-07-14T21:19:47.586776Z",
44+
"iopub.status.busy": "2026-07-14T21:19:47.586296Z",
45+
"iopub.status.idle": "2026-07-14T21:19:48.517073Z",
46+
"shell.execute_reply": "2026-07-14T21:19:48.515872Z"
4747
}
4848
},
4949
"outputs": [],
@@ -88,10 +88,10 @@
8888
"id": "b116ad1e",
8989
"metadata": {
9090
"execution": {
91-
"iopub.execute_input": "2026-07-14T19:10:49.339285Z",
92-
"iopub.status.busy": "2026-07-14T19:10:49.338828Z",
93-
"iopub.status.idle": "2026-07-14T19:10:49.449444Z",
94-
"shell.execute_reply": "2026-07-14T19:10:49.448430Z"
91+
"iopub.execute_input": "2026-07-14T21:19:48.521338Z",
92+
"iopub.status.busy": "2026-07-14T21:19:48.520743Z",
93+
"iopub.status.idle": "2026-07-14T21:19:48.624345Z",
94+
"shell.execute_reply": "2026-07-14T21:19:48.623192Z"
9595
}
9696
},
9797
"outputs": [
@@ -158,10 +158,10 @@
158158
"id": "4e61ac58",
159159
"metadata": {
160160
"execution": {
161-
"iopub.execute_input": "2026-07-14T19:10:49.452228Z",
162-
"iopub.status.busy": "2026-07-14T19:10:49.451965Z",
163-
"iopub.status.idle": "2026-07-14T19:10:51.127557Z",
164-
"shell.execute_reply": "2026-07-14T19:10:51.126450Z"
161+
"iopub.execute_input": "2026-07-14T21:19:48.626932Z",
162+
"iopub.status.busy": "2026-07-14T21:19:48.626645Z",
163+
"iopub.status.idle": "2026-07-14T21:19:50.237430Z",
164+
"shell.execute_reply": "2026-07-14T21:19:50.236217Z"
165165
}
166166
},
167167
"outputs": [],
@@ -219,10 +219,10 @@
219219
"id": "0de9e002",
220220
"metadata": {
221221
"execution": {
222-
"iopub.execute_input": "2026-07-14T19:10:51.130731Z",
223-
"iopub.status.busy": "2026-07-14T19:10:51.130441Z",
224-
"iopub.status.idle": "2026-07-14T19:10:51.148445Z",
225-
"shell.execute_reply": "2026-07-14T19:10:51.147133Z"
222+
"iopub.execute_input": "2026-07-14T21:19:50.240462Z",
223+
"iopub.status.busy": "2026-07-14T21:19:50.240142Z",
224+
"iopub.status.idle": "2026-07-14T21:19:50.259191Z",
225+
"shell.execute_reply": "2026-07-14T21:19:50.257902Z"
226226
}
227227
},
228228
"outputs": [
@@ -368,10 +368,10 @@
368368
"id": "72275c7f",
369369
"metadata": {
370370
"execution": {
371-
"iopub.execute_input": "2026-07-14T19:10:51.151166Z",
372-
"iopub.status.busy": "2026-07-14T19:10:51.150892Z",
373-
"iopub.status.idle": "2026-07-14T19:10:51.174015Z",
374-
"shell.execute_reply": "2026-07-14T19:10:51.172684Z"
371+
"iopub.execute_input": "2026-07-14T21:19:50.262765Z",
372+
"iopub.status.busy": "2026-07-14T21:19:50.262453Z",
373+
"iopub.status.idle": "2026-07-14T21:19:50.331965Z",
374+
"shell.execute_reply": "2026-07-14T21:19:50.330701Z"
375375
}
376376
},
377377
"outputs": [
@@ -515,10 +515,10 @@
515515
"id": "054959bf",
516516
"metadata": {
517517
"execution": {
518-
"iopub.execute_input": "2026-07-14T19:10:51.176540Z",
519-
"iopub.status.busy": "2026-07-14T19:10:51.176217Z",
520-
"iopub.status.idle": "2026-07-14T19:10:51.183444Z",
521-
"shell.execute_reply": "2026-07-14T19:10:51.181999Z"
518+
"iopub.execute_input": "2026-07-14T21:19:50.334898Z",
519+
"iopub.status.busy": "2026-07-14T21:19:50.334601Z",
520+
"iopub.status.idle": "2026-07-14T21:19:50.341525Z",
521+
"shell.execute_reply": "2026-07-14T21:19:50.340259Z"
522522
}
523523
},
524524
"outputs": [
@@ -554,10 +554,10 @@
554554
"id": "591930bf",
555555
"metadata": {
556556
"execution": {
557-
"iopub.execute_input": "2026-07-14T19:10:51.186313Z",
558-
"iopub.status.busy": "2026-07-14T19:10:51.186040Z",
559-
"iopub.status.idle": "2026-07-14T19:10:51.593042Z",
560-
"shell.execute_reply": "2026-07-14T19:10:51.591820Z"
557+
"iopub.execute_input": "2026-07-14T21:19:50.344474Z",
558+
"iopub.status.busy": "2026-07-14T21:19:50.344084Z",
559+
"iopub.status.idle": "2026-07-14T21:19:51.186802Z",
560+
"shell.execute_reply": "2026-07-14T21:19:51.185538Z"
561561
}
562562
},
563563
"outputs": [
@@ -596,10 +596,10 @@
596596
"id": "a8fa7702",
597597
"metadata": {
598598
"execution": {
599-
"iopub.execute_input": "2026-07-14T19:10:51.596645Z",
600-
"iopub.status.busy": "2026-07-14T19:10:51.596329Z",
601-
"iopub.status.idle": "2026-07-14T19:10:52.049139Z",
602-
"shell.execute_reply": "2026-07-14T19:10:52.047728Z"
599+
"iopub.execute_input": "2026-07-14T21:19:51.189656Z",
600+
"iopub.status.busy": "2026-07-14T21:19:51.189220Z",
601+
"iopub.status.idle": "2026-07-14T21:19:51.643855Z",
602+
"shell.execute_reply": "2026-07-14T21:19:51.642662Z"
603603
}
604604
},
605605
"outputs": [
@@ -640,10 +640,10 @@
640640
"id": "fe136f2f",
641641
"metadata": {
642642
"execution": {
643-
"iopub.execute_input": "2026-07-14T19:10:52.052238Z",
644-
"iopub.status.busy": "2026-07-14T19:10:52.051940Z",
645-
"iopub.status.idle": "2026-07-14T19:10:52.725521Z",
646-
"shell.execute_reply": "2026-07-14T19:10:52.724140Z"
643+
"iopub.execute_input": "2026-07-14T21:19:51.646977Z",
644+
"iopub.status.busy": "2026-07-14T21:19:51.646688Z",
645+
"iopub.status.idle": "2026-07-14T21:19:52.330554Z",
646+
"shell.execute_reply": "2026-07-14T21:19:52.329454Z"
647647
}
648648
},
649649
"outputs": [
@@ -680,10 +680,10 @@
680680
"id": "6ab2203a",
681681
"metadata": {
682682
"execution": {
683-
"iopub.execute_input": "2026-07-14T19:10:52.729596Z",
684-
"iopub.status.busy": "2026-07-14T19:10:52.729111Z",
685-
"iopub.status.idle": "2026-07-14T19:10:53.260060Z",
686-
"shell.execute_reply": "2026-07-14T19:10:53.258780Z"
683+
"iopub.execute_input": "2026-07-14T21:19:52.334811Z",
684+
"iopub.status.busy": "2026-07-14T21:19:52.334353Z",
685+
"iopub.status.idle": "2026-07-14T21:19:52.834136Z",
686+
"shell.execute_reply": "2026-07-14T21:19:52.832893Z"
687687
}
688688
},
689689
"outputs": [
@@ -725,10 +725,10 @@
725725
"id": "facae961",
726726
"metadata": {
727727
"execution": {
728-
"iopub.execute_input": "2026-07-14T19:10:53.263937Z",
729-
"iopub.status.busy": "2026-07-14T19:10:53.263606Z",
730-
"iopub.status.idle": "2026-07-14T19:10:53.596257Z",
731-
"shell.execute_reply": "2026-07-14T19:10:53.595263Z"
728+
"iopub.execute_input": "2026-07-14T21:19:52.836950Z",
729+
"iopub.status.busy": "2026-07-14T21:19:52.836652Z",
730+
"iopub.status.idle": "2026-07-14T21:19:53.180973Z",
731+
"shell.execute_reply": "2026-07-14T21:19:53.179559Z"
732732
}
733733
},
734734
"outputs": [
@@ -767,10 +767,10 @@
767767
"id": "f710be3d",
768768
"metadata": {
769769
"execution": {
770-
"iopub.execute_input": "2026-07-14T19:10:53.600242Z",
771-
"iopub.status.busy": "2026-07-14T19:10:53.599959Z",
772-
"iopub.status.idle": "2026-07-14T19:10:55.886460Z",
773-
"shell.execute_reply": "2026-07-14T19:10:55.883097Z"
770+
"iopub.execute_input": "2026-07-14T21:19:53.184063Z",
771+
"iopub.status.busy": "2026-07-14T21:19:53.183740Z",
772+
"iopub.status.idle": "2026-07-14T21:19:55.358728Z",
773+
"shell.execute_reply": "2026-07-14T21:19:55.357457Z"
774774
}
775775
},
776776
"outputs": [
@@ -831,10 +831,10 @@
831831
"id": "122cfeea",
832832
"metadata": {
833833
"execution": {
834-
"iopub.execute_input": "2026-07-14T19:10:55.890574Z",
835-
"iopub.status.busy": "2026-07-14T19:10:55.890147Z",
836-
"iopub.status.idle": "2026-07-14T19:10:56.057809Z",
837-
"shell.execute_reply": "2026-07-14T19:10:56.056266Z"
834+
"iopub.execute_input": "2026-07-14T21:19:55.362288Z",
835+
"iopub.status.busy": "2026-07-14T21:19:55.361948Z",
836+
"iopub.status.idle": "2026-07-14T21:19:55.368105Z",
837+
"shell.execute_reply": "2026-07-14T21:19:55.366668Z"
838838
}
839839
},
840840
"outputs": [
@@ -843,27 +843,25 @@
843843
"output_type": "stream",
844844
"text": [
845845
"python: 3.12.13 | packaged by conda-forge | (main, Mar 5 2026, 16:50:00) [GCC 14.3.0]\n",
846-
"selectsim: 0.2.0\n",
846+
"selectsim: 0.3.0\n",
847847
"numpy: 2.1.3\n",
848848
"pandas: 2.2.3\n",
849849
"scipy: 1.14.1\n",
850-
"matplotlib: 3.11.0\n",
851-
"seaborn: 0.13.2\n"
850+
"matplotlib: 3.11.0\n"
852851
]
853852
}
854853
],
855854
"source": [
856855
"import sys\n",
857-
"import numpy, pandas, scipy, matplotlib, seaborn\n",
856+
"import numpy, pandas, scipy, matplotlib\n",
858857
"import selectsim\n",
859858
"\n",
860859
"print(\"python:\", sys.version)\n",
861860
"print(\"selectsim:\", selectsim.__version__)\n",
862861
"print(\"numpy:\", numpy.__version__)\n",
863862
"print(\"pandas:\", pandas.__version__)\n",
864863
"print(\"scipy:\", scipy.__version__)\n",
865-
"print(\"matplotlib:\", matplotlib.__version__)\n",
866-
"print(\"seaborn:\", seaborn.__version__)"
864+
"print(\"matplotlib:\", matplotlib.__version__)"
867865
]
868866
}
869867
],

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "selectsim"
3-
version = "0.3.0"
3+
version = "0.3.1"
44
description = "A python package that implements the SelectSim algorithm"
55
authors = [
66
{ name = "Arvind Iyer", email = "ayalurarvind@gmail.com" },
@@ -22,7 +22,6 @@ dependencies = [
2222
"tqdm>=4.66.0,<5",
2323
"pyarrow>=18.0.0,<19",
2424
"matplotlib>=3.9.0,<4",
25-
"seaborn>=0.13.0,<0.14",
2625
]
2726

2827
[project.urls]

selectsim/__init__.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,24 +49,14 @@
4949
stat_maf_gene,
5050
maf_to_gam
5151
)
52-
from selectsim.plotting import (
53-
theme_publication,
54-
obs_exp_scatter,
55-
significance_heatmap,
56-
overlap_pair_extract,
57-
ridge_plot_ed,
58-
ridge_plot_ed_compare,
59-
oncoprint_pair,
60-
oncoprint
61-
)
6252
from selectsim.io import (
6353
read_parquet,
6454
write_parquet,
6555
create_zarr_null_store,
6656
open_zarr_store
6757
)
6858

69-
__version__ = "0.3.0"
59+
__version__ = "0.3.1"
7060

7161
__all__ = [
7262
# Main function
@@ -133,3 +123,34 @@
133123
"create_zarr_null_store",
134124
"open_zarr_store",
135125
]
126+
127+
# Plotting functions are resolved lazily (PEP 562), rather than imported
128+
# eagerly above like everything else: selectsim.plotting pulls in
129+
# matplotlib and scipy (measured ~1s import overhead combined, mostly
130+
# matplotlib.pyplot) -- overhead every `import selectsim` would otherwise
131+
# pay even for pure-computation use (e.g. just calling selectX()) that
132+
# never touches a plotting function. scipy is in fact used nowhere
133+
# outside plotting.py either. Deferring the import to first access of one
134+
# of these names (only) keeps `selectsim.<plotting name>` working exactly
135+
# as before, without forcing the cost on callers who never ask for it.
136+
_LAZY_PLOTTING_ATTRS = frozenset({
137+
"theme_publication",
138+
"obs_exp_scatter",
139+
"significance_heatmap",
140+
"overlap_pair_extract",
141+
"ridge_plot_ed",
142+
"ridge_plot_ed_compare",
143+
"oncoprint_pair",
144+
"oncoprint",
145+
})
146+
147+
148+
def __getattr__(name):
149+
if name in _LAZY_PLOTTING_ATTRS:
150+
from selectsim import plotting
151+
return getattr(plotting, name)
152+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
153+
154+
155+
def __dir__():
156+
return sorted(set(globals()) | _LAZY_PLOTTING_ATTRS)

selectsim/plotting.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
44
Python port of ``R/selectX_plot.R``. The R implementation is built on
55
``ggplot2``/``ggpubr``/``ggridges``; this module reproduces the same visual
6-
intent using ``matplotlib`` + ``seaborn`` (the library choice made for the
7-
Python port), since no display is assumed to be available.
6+
intent using ``matplotlib`` (the library choice made for the Python port),
7+
since no display is assumed to be available.
88
99
Functions
1010
---------
@@ -503,7 +503,7 @@ def ridge_plot_ed(
503503
Implementation note: this is the standard "joyplot"/ridgeline technique
504504
-- per-row Gaussian KDEs evaluated on a shared x-grid and stacked with a
505505
constant y-offset -- rather than ``ggridges::geom_density_ridges``,
506-
since matplotlib/seaborn has no ridge-plot geom built in.
506+
since matplotlib has no ridge-plot geom built in.
507507
508508
Parameters
509509
----------

0 commit comments

Comments
 (0)