├── .prettierignore ├── .gitattributes ├── .vercelignore ├── .vscode └── extensions.json ├── public ├── favicon.ico ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── mstile-150x150.png ├── images │ └── thumbnails │ │ ├── ax.webp │ │ ├── b2.webp │ │ ├── brax.webp │ │ ├── dash.webp │ │ ├── eli5.webp │ │ ├── gilp.webp │ │ ├── igv.webp │ │ ├── ivpy.webp │ │ ├── lux.webp │ │ ├── mage.webp │ │ ├── pi2.webp │ │ ├── pyzx.webp │ │ ├── shap.webp │ │ ├── ulca.webp │ │ ├── vaex.webp │ │ ├── wrex.webp │ │ ├── altair.webp │ │ ├── atria.webp │ │ ├── autoviz.webp │ │ ├── bacata.webp │ │ ├── bertviz.webp │ │ ├── bokeh.webp │ │ ├── bqplot.webp │ │ ├── cactus.webp │ │ ├── chartpy.webp │ │ ├── czml3.webp │ │ ├── docml.webp │ │ ├── emblaze.webp │ │ ├── escher.webp │ │ ├── farsight.jpg │ │ ├── firefly.webp │ │ ├── flexx.webp │ │ ├── folium.webp │ │ ├── gatenlp.webp │ │ ├── gravis.webp │ │ ├── gwaihir.webp │ │ ├── hciplot.webp │ │ ├── hiplot.webp │ │ ├── inksight.jpg │ │ ├── intake.webp │ │ ├── ipytree.webp │ │ ├── itables.webp │ │ ├── jgraph.webp │ │ ├── jigsaw.webp │ │ ├── keras.webp │ │ ├── mayavi.webp │ │ ├── meganno.webp │ │ ├── naavre.webp │ │ ├── nbtutor.webp │ │ ├── nengo.webp │ │ ├── nglview.webp │ │ ├── nilearn.webp │ │ ├── nl4dv.webp │ │ ├── nolies.webp │ │ ├── nomad.webp │ │ ├── notable.webp │ │ ├── open3d.webp │ │ ├── panel.webp │ │ ├── pathpy.webp │ │ ├── pigeon.webp │ │ ├── plotly.webp │ │ ├── pragma.webp │ │ ├── py3dmol.webp │ │ ├── pycaret.webp │ │ ├── pydeck.webp │ │ ├── pydgrid.webp │ │ ├── pymove.webp │ │ ├── pytket.webp │ │ ├── pyvis.webp │ │ ├── qgrid.webp │ │ ├── quickda.webp │ │ ├── slide4n.webp │ │ ├── smoothy.webp │ │ ├── solas.webp │ │ ├── taggle.webp │ │ ├── toyplot.webp │ │ ├── trimesh.webp │ │ ├── vaine.webp │ │ ├── vizic.webp │ │ ├── vizprog.webp │ │ ├── vizseq.webp │ │ ├── wandb.webp │ │ ├── weedle.webp │ │ ├── aequitas.webp │ │ ├── anteater.webp │ │ ├── argo-lite.webp │ │ ├── bamboolib.webp │ │ ├── bertopic.webp │ │ ├── calibrate.webp │ │ ├── catboost.webp │ │ ├── causalvis.webp │ │ ├── cyberhubs.webp │ │ ├── d3fdgraph.webp │ │ ├── datapane.webp │ │ ├── dataprep.webp │ │ ├── dea-tools.webp │ │ ├── dea_tools.webp │ │ ├── errudite.webp │ │ ├── evidently.webp │ │ ├── fiftyone.webp │ │ ├── geopandas.webp │ │ ├── geoviews.webp │ │ ├── imolecule.webp │ │ ├── ipysheet.webp │ │ ├── ipyvizzu.webp │ │ ├── keplergl.webp │ │ ├── lightgbm.webp │ │ ├── lit-tool.webp │ │ ├── mlprovlab.webp │ │ ├── mols2grid.webp │ │ ├── networkit.webp │ │ ├── pandasgui.webp │ │ ├── pixiedust.webp │ │ ├── pyldavis.webp │ │ ├── pypathway.webp │ │ ├── pypotree.webp │ │ ├── quick-eda.webp │ │ ├── sweetviz.webp │ │ ├── symphony.webp │ │ ├── vizsmith.webp │ │ ├── whatlies.webp │ │ ├── witwidget.webp │ │ ├── apache-beam.webp │ │ ├── apache_beam.webp │ │ ├── autoprofiler.webp │ │ ├── cytoscapejs.webp │ │ ├── data+shift.webp │ │ ├── datapurifier.webp │ │ ├── edassistant.webp │ │ ├── gam-changer.webp │ │ ├── graphistry.webp │ │ ├── interpretml.webp │ │ ├── ipyannotate.webp │ │ ├── ipydatagrid.webp │ │ ├── ipython-vega.webp │ │ ├── itkwidgets.webp │ │ ├── jupyter-dash.webp │ │ ├── jupyterpidaq.webp │ │ ├── kaleidoscope.webp │ │ ├── lightkurve.webp │ │ ├── matplotlib.webp │ │ ├── nbinteract.webp │ │ ├── neo4jupyter.webp │ │ ├── nvdashboard.webp │ │ ├── pandas-bokeh.webp │ │ ├── perspective.webp │ │ ├── py2cytoscape.webp │ │ ├── pygeohydro.webp │ │ ├── quantstats.webp │ │ ├── rai-widgets.webp │ │ ├── raiwidgets.webp │ │ ├── spatialtis.webp │ │ ├── st-visions.webp │ │ ├── tensorboard.webp │ │ ├── timbertrek.webp │ │ ├── tissuumaps.webp │ │ ├── what-if-tool.webp │ │ ├── autovizwidget.webp │ │ ├── clustergrammar.webp │ │ ├── create_report.webp │ │ ├── data-purifier.webp │ │ ├── jyquickhelper.webp │ │ ├── moving-pandas.webp │ │ ├── plotting-agent.webp │ │ ├── visjs2jupyter.webp │ │ ├── visual-auditor.webp │ │ ├── visual_auditor.webp │ │ ├── digautoprofiler.webp │ │ ├── modelsketchbook.webp │ │ ├── pandas_profiling.webp │ │ ├── pipelineprofiler.webp │ │ ├── plotly-resampler.webp │ │ ├── tf-model-analysis.webp │ │ ├── ydata-profiling.webp │ │ ├── interpret-community.webp │ │ ├── statcast-dashboard.webp │ │ ├── calling-context-tree.webp │ │ └── tensorflow_model_analysis.webp ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── browserconfig.xml ├── site.webmanifest └── safari-pinned-tab.svg ├── src ├── vite-env.d.ts ├── main.ts ├── imgs │ ├── icon-caret-down.svg │ ├── icon-link-2.svg │ ├── icon-minus.svg │ ├── icon-github.svg │ ├── icon-point.svg │ ├── icon-play-solid.svg │ ├── icon-plus.svg │ ├── icon-search.svg │ ├── icon-play.svg │ ├── icon-check.svg │ ├── icon-time.svg │ ├── icon-github-2.svg │ ├── icon-folder.svg │ ├── icon-pause-solid.svg │ ├── icon-top.svg │ ├── icon-grid.svg │ ├── icon-file.svg │ ├── icon-link.svg │ ├── icon-cancel.svg │ ├── icon-home.svg │ ├── icon-pin.svg │ ├── icon-contour.svg │ ├── icon-label.svg │ ├── icon-gear-fill.svg │ ├── icon-gear.svg │ └── supernova-logo.svg ├── stores.ts ├── components │ ├── search-panel │ │ ├── SearchPanel.ts │ │ ├── SearchPanel.scss │ │ └── SearchPanel.svelte │ ├── header │ │ ├── Header.svelte │ │ └── Header.scss │ ├── supernova │ │ ├── SuperNOVA.svelte │ │ └── SuperNOVA.scss │ └── grid-panel │ │ ├── GridPanel.ts │ │ └── GridPanel.scss ├── scripts │ └── convert-img-format.py ├── utils │ ├── text-width.ts │ ├── d3-import.ts │ ├── font-width-data │ │ └── lato.json │ └── utils.ts └── types │ └── common-types.ts ├── tsconfig.node.json ├── .prettierrc ├── svelte.config.js ├── .gitignore ├── App.svelte ├── .github ├── workflows │ ├── build.yml │ └── gh-pages.yml └── pull_request_template.md ├── tsconfig.json ├── LICENSE ├── vite.config.ts ├── .eslintrc.cjs ├── index.html ├── metadata ├── parse-issues.ipynb ├── github-issues.py ├── paper-count.ipynb ├── github-stars.ipynb └── notebook-script.py ├── package.json └── README.md /.prettierignore: -------------------------------------------------------------------------------- 1 | # *.svelte -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.ipynb linguist-vendored -------------------------------------------------------------------------------- /.vercelignore: -------------------------------------------------------------------------------- 1 | umap-1m.json 2 | umap-1m.ndjson 3 | umap-image-150k.ndjson -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["svelte.svelte-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/mstile-150x150.png -------------------------------------------------------------------------------- /public/images/thumbnails/ax.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/ax.webp -------------------------------------------------------------------------------- /public/images/thumbnails/b2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/b2.webp -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/images/thumbnails/brax.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/brax.webp -------------------------------------------------------------------------------- /public/images/thumbnails/dash.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/dash.webp -------------------------------------------------------------------------------- /public/images/thumbnails/eli5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/eli5.webp -------------------------------------------------------------------------------- /public/images/thumbnails/gilp.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/gilp.webp -------------------------------------------------------------------------------- /public/images/thumbnails/igv.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/igv.webp -------------------------------------------------------------------------------- /public/images/thumbnails/ivpy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/ivpy.webp -------------------------------------------------------------------------------- /public/images/thumbnails/lux.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/lux.webp -------------------------------------------------------------------------------- /public/images/thumbnails/mage.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/mage.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pi2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pi2.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pyzx.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pyzx.webp -------------------------------------------------------------------------------- /public/images/thumbnails/shap.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/shap.webp -------------------------------------------------------------------------------- /public/images/thumbnails/ulca.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/ulca.webp -------------------------------------------------------------------------------- /public/images/thumbnails/vaex.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/vaex.webp -------------------------------------------------------------------------------- /public/images/thumbnails/wrex.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/wrex.webp -------------------------------------------------------------------------------- /public/images/thumbnails/altair.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/altair.webp -------------------------------------------------------------------------------- /public/images/thumbnails/atria.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/atria.webp -------------------------------------------------------------------------------- /public/images/thumbnails/autoviz.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/autoviz.webp -------------------------------------------------------------------------------- /public/images/thumbnails/bacata.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/bacata.webp -------------------------------------------------------------------------------- /public/images/thumbnails/bertviz.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/bertviz.webp -------------------------------------------------------------------------------- /public/images/thumbnails/bokeh.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/bokeh.webp -------------------------------------------------------------------------------- /public/images/thumbnails/bqplot.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/bqplot.webp -------------------------------------------------------------------------------- /public/images/thumbnails/cactus.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/cactus.webp -------------------------------------------------------------------------------- /public/images/thumbnails/chartpy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/chartpy.webp -------------------------------------------------------------------------------- /public/images/thumbnails/czml3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/czml3.webp -------------------------------------------------------------------------------- /public/images/thumbnails/docml.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/docml.webp -------------------------------------------------------------------------------- /public/images/thumbnails/emblaze.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/emblaze.webp -------------------------------------------------------------------------------- /public/images/thumbnails/escher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/escher.webp -------------------------------------------------------------------------------- /public/images/thumbnails/farsight.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/farsight.jpg -------------------------------------------------------------------------------- /public/images/thumbnails/firefly.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/firefly.webp -------------------------------------------------------------------------------- /public/images/thumbnails/flexx.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/flexx.webp -------------------------------------------------------------------------------- /public/images/thumbnails/folium.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/folium.webp -------------------------------------------------------------------------------- /public/images/thumbnails/gatenlp.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/gatenlp.webp -------------------------------------------------------------------------------- /public/images/thumbnails/gravis.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/gravis.webp -------------------------------------------------------------------------------- /public/images/thumbnails/gwaihir.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/gwaihir.webp -------------------------------------------------------------------------------- /public/images/thumbnails/hciplot.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/hciplot.webp -------------------------------------------------------------------------------- /public/images/thumbnails/hiplot.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/hiplot.webp -------------------------------------------------------------------------------- /public/images/thumbnails/inksight.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/inksight.jpg -------------------------------------------------------------------------------- /public/images/thumbnails/intake.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/intake.webp -------------------------------------------------------------------------------- /public/images/thumbnails/ipytree.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/ipytree.webp -------------------------------------------------------------------------------- /public/images/thumbnails/itables.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/itables.webp -------------------------------------------------------------------------------- /public/images/thumbnails/jgraph.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/jgraph.webp -------------------------------------------------------------------------------- /public/images/thumbnails/jigsaw.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/jigsaw.webp -------------------------------------------------------------------------------- /public/images/thumbnails/keras.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/keras.webp -------------------------------------------------------------------------------- /public/images/thumbnails/mayavi.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/mayavi.webp -------------------------------------------------------------------------------- /public/images/thumbnails/meganno.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/meganno.webp -------------------------------------------------------------------------------- /public/images/thumbnails/naavre.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/naavre.webp -------------------------------------------------------------------------------- /public/images/thumbnails/nbtutor.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/nbtutor.webp -------------------------------------------------------------------------------- /public/images/thumbnails/nengo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/nengo.webp -------------------------------------------------------------------------------- /public/images/thumbnails/nglview.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/nglview.webp -------------------------------------------------------------------------------- /public/images/thumbnails/nilearn.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/nilearn.webp -------------------------------------------------------------------------------- /public/images/thumbnails/nl4dv.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/nl4dv.webp -------------------------------------------------------------------------------- /public/images/thumbnails/nolies.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/nolies.webp -------------------------------------------------------------------------------- /public/images/thumbnails/nomad.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/nomad.webp -------------------------------------------------------------------------------- /public/images/thumbnails/notable.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/notable.webp -------------------------------------------------------------------------------- /public/images/thumbnails/open3d.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/open3d.webp -------------------------------------------------------------------------------- /public/images/thumbnails/panel.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/panel.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pathpy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pathpy.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pigeon.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pigeon.webp -------------------------------------------------------------------------------- /public/images/thumbnails/plotly.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/plotly.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pragma.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pragma.webp -------------------------------------------------------------------------------- /public/images/thumbnails/py3dmol.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/py3dmol.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pycaret.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pycaret.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pydeck.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pydeck.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pydgrid.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pydgrid.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pymove.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pymove.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pytket.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pytket.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pyvis.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pyvis.webp -------------------------------------------------------------------------------- /public/images/thumbnails/qgrid.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/qgrid.webp -------------------------------------------------------------------------------- /public/images/thumbnails/quickda.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/quickda.webp -------------------------------------------------------------------------------- /public/images/thumbnails/slide4n.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/slide4n.webp -------------------------------------------------------------------------------- /public/images/thumbnails/smoothy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/smoothy.webp -------------------------------------------------------------------------------- /public/images/thumbnails/solas.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/solas.webp -------------------------------------------------------------------------------- /public/images/thumbnails/taggle.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/taggle.webp -------------------------------------------------------------------------------- /public/images/thumbnails/toyplot.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/toyplot.webp -------------------------------------------------------------------------------- /public/images/thumbnails/trimesh.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/trimesh.webp -------------------------------------------------------------------------------- /public/images/thumbnails/vaine.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/vaine.webp -------------------------------------------------------------------------------- /public/images/thumbnails/vizic.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/vizic.webp -------------------------------------------------------------------------------- /public/images/thumbnails/vizprog.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/vizprog.webp -------------------------------------------------------------------------------- /public/images/thumbnails/vizseq.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/vizseq.webp -------------------------------------------------------------------------------- /public/images/thumbnails/wandb.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/wandb.webp -------------------------------------------------------------------------------- /public/images/thumbnails/weedle.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/weedle.webp -------------------------------------------------------------------------------- /public/images/thumbnails/aequitas.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/aequitas.webp -------------------------------------------------------------------------------- /public/images/thumbnails/anteater.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/anteater.webp -------------------------------------------------------------------------------- /public/images/thumbnails/argo-lite.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/argo-lite.webp -------------------------------------------------------------------------------- /public/images/thumbnails/bamboolib.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/bamboolib.webp -------------------------------------------------------------------------------- /public/images/thumbnails/bertopic.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/bertopic.webp -------------------------------------------------------------------------------- /public/images/thumbnails/calibrate.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/calibrate.webp -------------------------------------------------------------------------------- /public/images/thumbnails/catboost.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/catboost.webp -------------------------------------------------------------------------------- /public/images/thumbnails/causalvis.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/causalvis.webp -------------------------------------------------------------------------------- /public/images/thumbnails/cyberhubs.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/cyberhubs.webp -------------------------------------------------------------------------------- /public/images/thumbnails/d3fdgraph.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/d3fdgraph.webp -------------------------------------------------------------------------------- /public/images/thumbnails/datapane.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/datapane.webp -------------------------------------------------------------------------------- /public/images/thumbnails/dataprep.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/dataprep.webp -------------------------------------------------------------------------------- /public/images/thumbnails/dea-tools.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/dea-tools.webp -------------------------------------------------------------------------------- /public/images/thumbnails/dea_tools.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/dea_tools.webp -------------------------------------------------------------------------------- /public/images/thumbnails/errudite.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/errudite.webp -------------------------------------------------------------------------------- /public/images/thumbnails/evidently.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/evidently.webp -------------------------------------------------------------------------------- /public/images/thumbnails/fiftyone.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/fiftyone.webp -------------------------------------------------------------------------------- /public/images/thumbnails/geopandas.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/geopandas.webp -------------------------------------------------------------------------------- /public/images/thumbnails/geoviews.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/geoviews.webp -------------------------------------------------------------------------------- /public/images/thumbnails/imolecule.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/imolecule.webp -------------------------------------------------------------------------------- /public/images/thumbnails/ipysheet.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/ipysheet.webp -------------------------------------------------------------------------------- /public/images/thumbnails/ipyvizzu.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/ipyvizzu.webp -------------------------------------------------------------------------------- /public/images/thumbnails/keplergl.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/keplergl.webp -------------------------------------------------------------------------------- /public/images/thumbnails/lightgbm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/lightgbm.webp -------------------------------------------------------------------------------- /public/images/thumbnails/lit-tool.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/lit-tool.webp -------------------------------------------------------------------------------- /public/images/thumbnails/mlprovlab.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/mlprovlab.webp -------------------------------------------------------------------------------- /public/images/thumbnails/mols2grid.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/mols2grid.webp -------------------------------------------------------------------------------- /public/images/thumbnails/networkit.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/networkit.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pandasgui.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pandasgui.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pixiedust.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pixiedust.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pyldavis.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pyldavis.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pypathway.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pypathway.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pypotree.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pypotree.webp -------------------------------------------------------------------------------- /public/images/thumbnails/quick-eda.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/quick-eda.webp -------------------------------------------------------------------------------- /public/images/thumbnails/sweetviz.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/sweetviz.webp -------------------------------------------------------------------------------- /public/images/thumbnails/symphony.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/symphony.webp -------------------------------------------------------------------------------- /public/images/thumbnails/vizsmith.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/vizsmith.webp -------------------------------------------------------------------------------- /public/images/thumbnails/whatlies.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/whatlies.webp -------------------------------------------------------------------------------- /public/images/thumbnails/witwidget.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/witwidget.webp -------------------------------------------------------------------------------- /public/images/thumbnails/apache-beam.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/apache-beam.webp -------------------------------------------------------------------------------- /public/images/thumbnails/apache_beam.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/apache_beam.webp -------------------------------------------------------------------------------- /public/images/thumbnails/autoprofiler.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/autoprofiler.webp -------------------------------------------------------------------------------- /public/images/thumbnails/cytoscapejs.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/cytoscapejs.webp -------------------------------------------------------------------------------- /public/images/thumbnails/data+shift.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/data+shift.webp -------------------------------------------------------------------------------- /public/images/thumbnails/datapurifier.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/datapurifier.webp -------------------------------------------------------------------------------- /public/images/thumbnails/edassistant.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/edassistant.webp -------------------------------------------------------------------------------- /public/images/thumbnails/gam-changer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/gam-changer.webp -------------------------------------------------------------------------------- /public/images/thumbnails/graphistry.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/graphistry.webp -------------------------------------------------------------------------------- /public/images/thumbnails/interpretml.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/interpretml.webp -------------------------------------------------------------------------------- /public/images/thumbnails/ipyannotate.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/ipyannotate.webp -------------------------------------------------------------------------------- /public/images/thumbnails/ipydatagrid.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/ipydatagrid.webp -------------------------------------------------------------------------------- /public/images/thumbnails/ipython-vega.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/ipython-vega.webp -------------------------------------------------------------------------------- /public/images/thumbnails/itkwidgets.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/itkwidgets.webp -------------------------------------------------------------------------------- /public/images/thumbnails/jupyter-dash.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/jupyter-dash.webp -------------------------------------------------------------------------------- /public/images/thumbnails/jupyterpidaq.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/jupyterpidaq.webp -------------------------------------------------------------------------------- /public/images/thumbnails/kaleidoscope.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/kaleidoscope.webp -------------------------------------------------------------------------------- /public/images/thumbnails/lightkurve.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/lightkurve.webp -------------------------------------------------------------------------------- /public/images/thumbnails/matplotlib.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/matplotlib.webp -------------------------------------------------------------------------------- /public/images/thumbnails/nbinteract.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/nbinteract.webp -------------------------------------------------------------------------------- /public/images/thumbnails/neo4jupyter.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/neo4jupyter.webp -------------------------------------------------------------------------------- /public/images/thumbnails/nvdashboard.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/nvdashboard.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pandas-bokeh.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pandas-bokeh.webp -------------------------------------------------------------------------------- /public/images/thumbnails/perspective.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/perspective.webp -------------------------------------------------------------------------------- /public/images/thumbnails/py2cytoscape.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/py2cytoscape.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pygeohydro.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pygeohydro.webp -------------------------------------------------------------------------------- /public/images/thumbnails/quantstats.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/quantstats.webp -------------------------------------------------------------------------------- /public/images/thumbnails/rai-widgets.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/rai-widgets.webp -------------------------------------------------------------------------------- /public/images/thumbnails/raiwidgets.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/raiwidgets.webp -------------------------------------------------------------------------------- /public/images/thumbnails/spatialtis.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/spatialtis.webp -------------------------------------------------------------------------------- /public/images/thumbnails/st-visions.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/st-visions.webp -------------------------------------------------------------------------------- /public/images/thumbnails/tensorboard.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/tensorboard.webp -------------------------------------------------------------------------------- /public/images/thumbnails/timbertrek.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/timbertrek.webp -------------------------------------------------------------------------------- /public/images/thumbnails/tissuumaps.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/tissuumaps.webp -------------------------------------------------------------------------------- /public/images/thumbnails/what-if-tool.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/what-if-tool.webp -------------------------------------------------------------------------------- /public/images/thumbnails/autovizwidget.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/autovizwidget.webp -------------------------------------------------------------------------------- /public/images/thumbnails/clustergrammar.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/clustergrammar.webp -------------------------------------------------------------------------------- /public/images/thumbnails/create_report.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/create_report.webp -------------------------------------------------------------------------------- /public/images/thumbnails/data-purifier.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/data-purifier.webp -------------------------------------------------------------------------------- /public/images/thumbnails/jyquickhelper.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/jyquickhelper.webp -------------------------------------------------------------------------------- /public/images/thumbnails/moving-pandas.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/moving-pandas.webp -------------------------------------------------------------------------------- /public/images/thumbnails/plotting-agent.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/plotting-agent.webp -------------------------------------------------------------------------------- /public/images/thumbnails/visjs2jupyter.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/visjs2jupyter.webp -------------------------------------------------------------------------------- /public/images/thumbnails/visual-auditor.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/visual-auditor.webp -------------------------------------------------------------------------------- /public/images/thumbnails/visual_auditor.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/visual_auditor.webp -------------------------------------------------------------------------------- /public/images/thumbnails/digautoprofiler.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/digautoprofiler.webp -------------------------------------------------------------------------------- /public/images/thumbnails/modelsketchbook.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/modelsketchbook.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pandas_profiling.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pandas_profiling.webp -------------------------------------------------------------------------------- /public/images/thumbnails/pipelineprofiler.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/pipelineprofiler.webp -------------------------------------------------------------------------------- /public/images/thumbnails/plotly-resampler.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/plotly-resampler.webp -------------------------------------------------------------------------------- /public/images/thumbnails/tf-model-analysis.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/tf-model-analysis.webp -------------------------------------------------------------------------------- /public/images/thumbnails/ydata-profiling.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/ydata-profiling.webp -------------------------------------------------------------------------------- /public/images/thumbnails/interpret-community.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/interpret-community.webp -------------------------------------------------------------------------------- /public/images/thumbnails/statcast-dashboard.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/statcast-dashboard.webp -------------------------------------------------------------------------------- /public/images/thumbnails/calling-context-tree.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/calling-context-tree.webp -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import App from '../App.svelte'; 2 | 3 | const app = new App({ 4 | target: document.getElementById('app'), 5 | }); 6 | 7 | export default app; 8 | -------------------------------------------------------------------------------- /public/images/thumbnails/tensorflow_model_analysis.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poloclub/supernova/HEAD/public/images/thumbnails/tensorflow_model_analysis.webp -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "none", 4 | "svelteSortOrder": "options-scripts-styles-markup", 5 | "arrowParens": "avoid", 6 | "svelteStrictMode": true 7 | } 8 | -------------------------------------------------------------------------------- /src/imgs/icon-caret-down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import sveltePreprocess from 'svelte-preprocess' 2 | 3 | export default { 4 | // Consult https://github.com/sveltejs/svelte-preprocess 5 | // for more information about preprocessors 6 | preprocess: sveltePreprocess() 7 | } 8 | -------------------------------------------------------------------------------- /public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | dataset 3 | /node_modules/ 4 | /public/build/ 5 | package-lock.json 6 | pnpm-lock.yaml 7 | .DS_Store 8 | *.swp 9 | 10 | .vercel 11 | deploy-gh-page.sh 12 | publish.sh 13 | publish* 14 | dist 15 | gh-page 16 | explorer 17 | lite 18 | __pycache__ 19 | 20 | metadata/*.html 21 | metadata/*.bib 22 | metadata/thumbnails 23 | metadata/resources 24 | metadata/github-issues 25 | metadata/stat* 26 | notebooks -------------------------------------------------------------------------------- /src/stores.ts: -------------------------------------------------------------------------------- 1 | import { writable } from 'svelte/store'; 2 | import type { ClipLabel } from './types/common-types'; 3 | 4 | export interface SearchStoreValue { 5 | selectedClips: Set; 6 | keyword: string; 7 | } 8 | 9 | export const getSearchStoreDefaultValue = (): SearchStoreValue => { 10 | return { 11 | selectedClips: new Set(), 12 | keyword: '' 13 | }; 14 | }; 15 | 16 | export const getSearchStore = () => { 17 | return writable(getSearchStoreDefaultValue()); 18 | }; 19 | -------------------------------------------------------------------------------- /App.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 |
17 | 18 |
19 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /src/components/search-panel/SearchPanel.ts: -------------------------------------------------------------------------------- 1 | import type { Writable } from 'svelte/store'; 2 | import d3 from '../../utils/d3-import'; 3 | import type { SearchBarStoreValue } from '../../stores'; 4 | import { getSearchBarStoreDefaultValue } from '../../stores'; 5 | 6 | export class SearchPanel { 7 | component: HTMLElement; 8 | SearchPanelUpdated: () => void; 9 | 10 | constructor(component: HTMLElement, SearchPanelUpdated: () => void) { 11 | this.component = component; 12 | this.SearchPanelUpdated = SearchPanelUpdated; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/imgs/icon-link-2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | # Triggers the workflow on push or pull request events but only for the main branch 5 | push: 6 | branches: [main] 7 | pull_request: 8 | branches: [main] 9 | #: Run the test every week 10 | schedule: 11 | - cron: '0 12 * * 1' 12 | 13 | jobs: 14 | build: 15 | runs-on: ${{ matrix.os }} 16 | 17 | strategy: 18 | matrix: 19 | node-version: [16] 20 | os: [ubuntu-latest] 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | - uses: actions/setup-node@v3 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - name: Install dependencies 28 | run: npm install 29 | - name: Build 30 | run: npm run build 31 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | - Closes 7 | 8 | ### Additional Details 9 | 13 | 14 | ### PR Tasks 15 | 19 | 20 | - [ ] Have you updated the [YAML file](https://github.com/poloclub/supernova/blob/main/src/data/supernova.yaml) with the relevant information for the VA tool? 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/svelte/tsconfig.json", 3 | "compilerOptions": { 4 | "target": "esnext", 5 | "useDefineForClassFields": true, 6 | "module": "esnext", 7 | "resolveJsonModule": true, 8 | "baseUrl": ".", 9 | "strict": true, 10 | /** 11 | * Typecheck JS in `.svelte` and `.js` files by default. 12 | * Disable checkJs if you'd like to use dynamic types in JS. 13 | * Note that setting allowJs false does not prevent the use 14 | * of JS in `.svelte` files. 15 | */ 16 | "allowJs": true, 17 | "checkJs": true 18 | }, 19 | "include": [ 20 | "src/**/*.d.ts", 21 | "src/**/*.ts", 22 | "src/**/*.js", 23 | "src/**/*.svelte", 24 | ], 25 | "references": [{ "path": "./tsconfig.node.json" }] 26 | } 27 | -------------------------------------------------------------------------------- /src/scripts/convert-img-format.py: -------------------------------------------------------------------------------- 1 | from glob import glob 2 | from os.path import join 3 | from PIL import Image 4 | 5 | 6 | def resize_images(): 7 | """ 8 | Resize all images in the folder to the target_size. 9 | """ 10 | counter = 0 11 | for img_name in glob(join("../../public/images/thumbnails", "*")): 12 | img = Image.open(img_name) 13 | target_length = 300 14 | 15 | if img.size[1] / img.size[0] > 2 or img.size[1] / img.size[0] < 0.5: 16 | target_length = 600 17 | 18 | if img.size[0] > target_length or img.size[1] > target_length: 19 | img.thumbnail([target_length, target_length], Image.Resampling.LANCZOS) 20 | img.save(img_name) 21 | counter += 1 22 | 23 | print(f"Resized {counter} images.") 24 | 25 | 26 | def main(): 27 | """ 28 | Convert all .png and .jpg images to .webp in the subfolders. 29 | """ 30 | resize_images() 31 | 32 | 33 | if __name__ == "__main__": 34 | main() 35 | -------------------------------------------------------------------------------- /src/imgs/icon-minus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/imgs/icon-github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/header/Header.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 |
11 |
12 |
13 |
14 | 15 | {@html iconSupernova} 16 | 17 |
18 |
19 | A Collection of 150 Interactive Visualization Tools for Computational 20 | Notebooks 21 |
22 |
23 | 24 |
25 | Code 28 | Paper 29 | Add New Tool 34 |
35 |
36 |
37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023, Jay Wang, David Munechika, Seongmin Lee, Polo Chau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: Deploy GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-22.04 12 | strategy: 13 | matrix: 14 | node-version: [16] 15 | os: [ubuntu-latest] 16 | permissions: 17 | contents: write 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | steps: 21 | - uses: actions/checkout@v3 22 | 23 | - uses: actions/setup-node@v3 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | 27 | - name: Install dependencies 28 | run: npm install 29 | 30 | - name: Build 31 | run: npm run build:github 32 | 33 | - name: Deploy with gh-pages 34 | run: | 35 | git remote set-url origin https://git:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git 36 | npx gh-pages -u "github-actions-bot " -m "Deploy $(git log '--format=format:%H' main -1)" -d ./gh-page 37 | if: ${{ github.ref == 'refs/heads/main' }} 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | -------------------------------------------------------------------------------- /src/imgs/icon-point.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/imgs/icon-play-solid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/imgs/icon-plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/supernova/SuperNOVA.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | 16 |
17 | 21 | 22 | 26 | 27 |
28 |
29 |
30 |
31 | 32 |
33 | 34 |
35 | 36 |
37 | 38 |
39 |
40 |
41 | -------------------------------------------------------------------------------- /src/imgs/icon-search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/imgs/icon-play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/components/header/Header.scss: -------------------------------------------------------------------------------- 1 | @import '../../define.scss'; 2 | 3 | .svg-icon { 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | width: 100%; 8 | height: 100%; 9 | color: currentColor; 10 | 11 | pointer-events: fill; 12 | 13 | :global(svg) { 14 | fill: currentColor; 15 | width: 100%; 16 | height: 100%; 17 | } 18 | } 19 | 20 | .header-wrapper { 21 | width: 100%; 22 | height: 100%; 23 | padding: $panel-v-padding $panel-h-padding; 24 | 25 | display: flex; 26 | flex-direction: row; 27 | justify-content: space-between; 28 | align-items: center; 29 | color: white; 30 | } 31 | 32 | .header-content { 33 | width: 100%; 34 | display: flex; 35 | flex-direction: row; 36 | justify-content: space-between; 37 | align-items: center; 38 | } 39 | 40 | .left-content { 41 | display: flex; 42 | align-items: baseline; 43 | gap: 8px; 44 | 45 | cursor: default; 46 | 47 | .app-title { 48 | font-size: 1.625rem; 49 | font-variant: small-caps; 50 | font-weight: 600; 51 | height: 27px; 52 | width: 200px; 53 | margin-top: 7px; 54 | color: white; 55 | } 56 | 57 | .app-tagline { 58 | font-size: 20px; 59 | } 60 | } 61 | 62 | .right-content { 63 | display: flex; 64 | font-size: $font-u2; 65 | gap: 16px; 66 | 67 | a { 68 | color: white; 69 | 70 | &:visited { 71 | color: white; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import { svelte } from '@sveltejs/vite-plugin-svelte'; 3 | import yaml from '@rollup/plugin-yaml'; 4 | 5 | // // https://vitejs.dev/config/ 6 | // export default defineConfig({ 7 | // plugins: [svelte()] 8 | // }); 9 | 10 | // https://vitejs.dev/config/ 11 | export default defineConfig(({ command, mode }) => { 12 | if (command === 'serve') { 13 | // Development 14 | return { 15 | plugins: [yaml(), svelte()] 16 | }; 17 | } else if (command === 'build') { 18 | switch (mode) { 19 | case 'production': { 20 | // Production: standard web page (default mode) 21 | return { 22 | build: { 23 | outDir: 'dist' 24 | }, 25 | plugins: [yaml(), svelte()] 26 | }; 27 | } 28 | 29 | case 'vercel': { 30 | // Production: for vercel demo 31 | return { 32 | build: { 33 | outDir: 'dist' 34 | }, 35 | plugins: [yaml(), svelte()] 36 | }; 37 | } 38 | 39 | case 'github': { 40 | // Production: github page 41 | return { 42 | base: '/supernova/', 43 | build: { 44 | outDir: 'gh-page' 45 | }, 46 | plugins: [yaml(), svelte()] 47 | }; 48 | } 49 | 50 | default: { 51 | console.error(`Unknown production mode ${mode}`); 52 | return null; 53 | } 54 | } 55 | } 56 | }); 57 | -------------------------------------------------------------------------------- /public/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/imgs/icon-check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/imgs/icon-time.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/imgs/icon-github-2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/text-width.ts: -------------------------------------------------------------------------------- 1 | // Compute the text width without adding it to DOM! 2 | // https://chrishewett.com/blog/calculating-text-width-programmatically/ 3 | 4 | import latoTextWidth from './font-width-data/lato.json'; 5 | 6 | const getTextWidth = (fontJson: object, text: string, fontSize = 16) => { 7 | // split the string up using the spread operator (to handle UTF-8) 8 | const letterMapSingle = new Map(fontJson.textWidth); 9 | const letterMapKern = new Map(fontJson.kerningWidth); 10 | 11 | const letterSplit = [...text]; 12 | let letterWidth = 0; 13 | 14 | // go through each letter 15 | for (const [key, letter] of letterSplit.entries()) { 16 | // add on the width of this letter to the sum 17 | letterWidth += 18 | letterMapSingle.get(letter) || letterMapSingle.get('_median'); 19 | 20 | if (key !== letterSplit.length - 1) { 21 | // add/remove the kerning modifier of this letter and the next one 22 | letterWidth += letterMapKern.get(`${letter}${letterSplit[key + 1]}`) || 0; 23 | } 24 | } 25 | 26 | // now you have your string width for font-size: 100px letters 27 | // divide by the ratio between 100 and your font-size 28 | return letterWidth / (100 / fontSize); 29 | }; 30 | 31 | /** 32 | * Get the text width in px 33 | * @param text Text string 34 | * @param fontSize Font size 35 | * @returns Text width in px 36 | */ 37 | export const getLatoTextWidth = (text: string, fontSize = 16) => { 38 | return getTextWidth(latoTextWidth, text, fontSize); 39 | }; 40 | -------------------------------------------------------------------------------- /src/imgs/icon-folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/imgs/icon-pause-solid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/imgs/icon-top.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/imgs/icon-grid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/imgs/icon-file.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/imgs/icon-link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/imgs/icon-cancel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/imgs/icon-home.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:@typescript-eslint/recommended-requiring-type-checking', 8 | 'prettier' 9 | ], 10 | parserOptions: { 11 | ecmaVersion: 'latest', 12 | sourceType: 'module', 13 | tsconfigRootDir: __dirname, 14 | project: ['./tsconfig.json', './tsconfig.node.json'], 15 | extraFileExtensions: ['.svelte', '.cjs'] 16 | }, 17 | env: { 18 | es6: true, 19 | browser: true 20 | }, 21 | overrides: [ 22 | { 23 | files: ['*.svelte'], 24 | processor: 'svelte3/svelte3' 25 | } 26 | ], 27 | settings: { 28 | 'svelte3/typescript': () => require('typescript'), 29 | 'svelte3/ignore-styles': () => true 30 | }, 31 | plugins: ['svelte3', '@typescript-eslint', 'prettier'], 32 | ignorePatterns: ['node_modules'], 33 | rules: { 34 | indent: 'off', 35 | 'linebreak-style': ['error', 'unix'], 36 | quotes: ['error', 'single'], 37 | 'prefer-const': ['error'], 38 | semi: ['error', 'always'], 39 | // 'max-len': [ 40 | // 'warn', 41 | // { 42 | // code: 80 43 | // } 44 | // ], 45 | 'no-constant-condition': ['error', { checkLoops: false }], 46 | 'prettier/prettier': 2, 47 | '@typescript-eslint/no-floating-promises': 'off', 48 | '@typescript-eslint/no-unsafe-return': 'off', 49 | '@typescript-eslint/ban-ts-comment': 'off', 50 | '@typescript-eslint/restrict-template-expressions': 'off', 51 | '@typescript-eslint/no-non-null-assertion': 'off', 52 | '@typescript-eslint/no-empty-function': 'off', 53 | '@typescript-eslint/no-unnecessary-type-assertion': 'off', 54 | 'no-self-assign': 'off' 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /src/imgs/icon-pin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/types/common-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Common types. 3 | */ 4 | 5 | export interface SuperNovaEntry { 6 | name: string; 7 | nameDisplay: string; 8 | githubURL: string; 9 | paperURL: string; 10 | otherURLs: string[]; 11 | description: string; 12 | bibtex: string; 13 | bibtexKey: string; 14 | bibtexJson: { [key: string]: string }; 15 | sourceType: SourceString; 16 | releaseYear: number; 17 | communication: CommunicationString; 18 | materials: MaterialString[]; 19 | layouts: layoutString[]; 20 | supportedNotebooks: NotebookString[]; 21 | modularity: ModularityString; 22 | user: UserString; 23 | implementation: ImplementationString; 24 | allClips: Set; 25 | thumbnail: string; 26 | } 27 | 28 | type SourceString = 'paper' | 'package'; 29 | type CommunicationString = 'no' | 'one-way' | 'two-way'; 30 | type MaterialString = 'runtime' | 'code' | 'external'; 31 | type layoutString = 'on-demand' | 'always-on'; 32 | type ModularityString = 'monolithic' | 'modular'; 33 | type UserString = 'data scientist' | 'scientist' | 'educator'; 34 | type NotebookString = 'jupyter' | 'lab' | 'colab' | 'jupyter+lab'; 35 | type ImplementationString = 36 | | 'ipywidget' 37 | | 'extension' 38 | | 'html' 39 | | 'nova' 40 | | 'other-package' 41 | | 'custom'; 42 | 43 | export type ClipLabel = 44 | | CommunicationString 45 | | MaterialString 46 | | layoutString 47 | | ModularityString 48 | | UserString 49 | | NotebookString 50 | | ImplementationString; 51 | 52 | export interface Padding { 53 | top: number; 54 | bottom: number; 55 | left: number; 56 | right: number; 57 | } 58 | 59 | export interface Rect { 60 | x: number; 61 | y: number; 62 | width: number; 63 | height: number; 64 | } 65 | 66 | export interface Point { 67 | x: number; 68 | y: number; 69 | } 70 | 71 | export interface Size { 72 | width: number; 73 | height: number; 74 | } 75 | -------------------------------------------------------------------------------- /src/imgs/icon-contour.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/imgs/icon-label.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | SuperNOVA — Interactive Notebook Visualization Browser 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/imgs/icon-gear-fill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/supernova/SuperNOVA.scss: -------------------------------------------------------------------------------- 1 | @import '../../define.scss'; 2 | 3 | .supernova-page { 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: center; 8 | height: 100vh; 9 | width: 100vw; 10 | box-sizing: border-box; 11 | overflow-x: hidden; 12 | overflow-y: hidden; 13 | 14 | position: relative; 15 | } 16 | 17 | .main-app { 18 | display: grid; 19 | grid-template-rows: 60px 1fr; 20 | grid-template-columns: 300px minmax(0px, 1fr); 21 | position: relative; 22 | 23 | width: 100%; 24 | height: 100%; 25 | 26 | overflow-x: hidden; 27 | overflow-y: hidden; 28 | } 29 | 30 | .header-container { 31 | grid-row: 1 / 2; 32 | grid-column: 1 / 3; 33 | 34 | display: flex; 35 | background-color: $teal-900; 36 | border-bottom: 1px solid hsla(0, 100%, 100%, 0.2); 37 | } 38 | 39 | .search-container { 40 | grid-row: 2 / 3; 41 | grid-column: 1 / 2; 42 | 43 | display: flex; 44 | padding: $panel-v-padding $panel-h-padding; 45 | background-color: $teal-900; 46 | overflow-y: auto; 47 | } 48 | 49 | .card-container { 50 | grid-row: 2 / 3; 51 | grid-column: 2 / 3; 52 | 53 | display: flex; 54 | overflow-y: auto; 55 | } 56 | 57 | .popper-tooltip { 58 | position: absolute; 59 | width: max-content; 60 | left: 0px; 61 | top: 0px; 62 | z-index: 20; 63 | background: #222; 64 | color: white; 65 | box-shadow: 0 0 1px hsla(0, 0%, 0%, 0.6), 0 0 3px hsla(0, 0%, 0%, 0.05); 66 | padding: 2px 6px 4px 6px; 67 | border-radius: 4px; 68 | font-size: $font-d2; 69 | 70 | display: flex; 71 | justify-content: center; 72 | box-sizing: border-box; 73 | pointer-events: none; 74 | text-align: center; 75 | 76 | opacity: 1; 77 | transition: opacity 150ms, visibility 150ms; 78 | 79 | &.hidden { 80 | opacity: 0; 81 | } 82 | 83 | &#popper-tooltip-bottom { 84 | z-index: 19; 85 | background: $purple-900; 86 | 87 | .popper-arrow { 88 | background: $purple-900; 89 | } 90 | } 91 | 92 | .popper-content { 93 | max-width: 300px; 94 | max-height: 200px; 95 | line-height: 1.5; 96 | overflow: hidden; 97 | } 98 | 99 | .popper-arrow { 100 | position: absolute; 101 | background: #222; 102 | width: 8px; 103 | height: 8px; 104 | transform: rotate(45deg); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /metadata/parse-issues.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 61, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np\n", 10 | "import pandas as pd\n", 11 | "import re\n", 12 | "import requests\n", 13 | "import io\n", 14 | "import yaml\n", 15 | "import gspread\n", 16 | "\n", 17 | "from glob import glob\n", 18 | "from os.path import exists, join, basename\n", 19 | "from bs4 import BeautifulSoup\n", 20 | "from shutil import copyfileobj, copyfile\n", 21 | "from PIL import Image\n", 22 | "from time import sleep\n", 23 | "from requests_ip_rotator import ApiGateway, EXTRA_REGIONS, ALL_REGIONS\n", 24 | "from tqdm import tqdm" 25 | ] 26 | }, 27 | { 28 | "attachments": {}, 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "## Parse Issues" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 56, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "repos = []\n", 42 | "descriptions = []\n", 43 | "\n", 44 | "for f in glob('./github-issues/*.txt'):\n", 45 | " with open(f) as fp:\n", 46 | " lines = [l.rstrip('\\n') for l in fp.readlines()]\n", 47 | " \n", 48 | " cur_repo = lines[0]\n", 49 | " cur_description = ''\n", 50 | " is_appending = False\n", 51 | " \n", 52 | " for l in lines:\n", 53 | " if l == '-' * 138:\n", 54 | " if is_appending:\n", 55 | " repos.append(cur_repo)\n", 56 | " descriptions.append(cur_description)\n", 57 | "\n", 58 | " cur_description = ''\n", 59 | " is_appending = True\n", 60 | " continue\n", 61 | " \n", 62 | " if is_appending:\n", 63 | " cur_description += l + '\\n'\n", 64 | " \n", 65 | " if is_appending:\n", 66 | " repos.append(cur_repo)\n", 67 | " descriptions.append(cur_description)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 62, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "# Save to a csv\n", 77 | "df = pd.DataFrame({'repo': repos, 'description': descriptions})\n", 78 | "df.to_csv('./issues.csv', index=False)" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": null, 84 | "metadata": {}, 85 | "outputs": [], 86 | "source": [] 87 | } 88 | ], 89 | "metadata": { 90 | "kernelspec": { 91 | "display_name": "gam", 92 | "language": "python", 93 | "name": "python3" 94 | }, 95 | "language_info": { 96 | "codemirror_mode": { 97 | "name": "ipython", 98 | "version": 3 99 | }, 100 | "file_extension": ".py", 101 | "mimetype": "text/x-python", 102 | "name": "python", 103 | "nbconvert_exporter": "python", 104 | "pygments_lexer": "ipython3", 105 | "version": "3.9.12" 106 | }, 107 | "orig_nbformat": 4 108 | }, 109 | "nbformat": 4, 110 | "nbformat_minor": 2 111 | } 112 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "supernova", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite --port 3000", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "build:github": "vite build --mode github", 11 | "check": "svelte-check --tsconfig ./tsconfig.json", 12 | "deploy:vercel": "sh ./publish-vercel.sh", 13 | "deploy:github": "pnpm run build:github && pnpm gh-pages -m \"Deploy $(git log '--format=format:%H' main -1)\" -d ./gh-page" 14 | }, 15 | "devDependencies": { 16 | "@orcid/bibtex-parse-js": "^0.0.25", 17 | "@rollup/plugin-commonjs": "^17.1.0", 18 | "@rollup/plugin-node-resolve": "^11.2.1", 19 | "@rollup/plugin-terser": "^0.4.1", 20 | "@rollup/plugin-typescript": "^8.5.0", 21 | "@rollup/plugin-yaml": "^3.1.0", 22 | "@sveltejs/vite-plugin-svelte": "^2.1.0", 23 | "@tsconfig/svelte": "^4.0.1", 24 | "@types/d3": "^7.4.0", 25 | "@types/d3-array": "^3.0.4", 26 | "@types/d3-axis": "^3.0.2", 27 | "@types/d3-brush": "^3.0.2", 28 | "@types/d3-color": "^3.1.0", 29 | "@types/d3-contour": "^3.0.2", 30 | "@types/d3-drag": "^3.0.2", 31 | "@types/d3-ease": "^3.0.0", 32 | "@types/d3-fetch": "^3.0.2", 33 | "@types/d3-format": "^3.0.1", 34 | "@types/d3-geo": "^3.0.3", 35 | "@types/d3-hierarchy": "^3.1.2", 36 | "@types/d3-interpolate": "^3.0.1", 37 | "@types/d3-path": "^3.0.0", 38 | "@types/d3-quadtree": "^3.0.2", 39 | "@types/d3-random": "^3.0.1", 40 | "@types/d3-scale": "^4.0.3", 41 | "@types/d3-scale-chromatic": "^3.0.0", 42 | "@types/d3-selection": "^3.0.5", 43 | "@types/d3-shape": "^3.1.1", 44 | "@types/d3-time-format": "^4.0.0", 45 | "@types/d3-timer": "^3.0.0", 46 | "@types/d3-transition": "^3.0.3", 47 | "@types/d3-zoom": "^3.0.2", 48 | "@types/flexsearch": "^0.7.3", 49 | "@typescript-eslint/eslint-plugin": "^5.59.0", 50 | "@typescript-eslint/parser": "^5.59.0", 51 | "apache-arrow": "^10.0.1", 52 | "d3-array": "^3.2.3", 53 | "d3-axis": "^3.0.0", 54 | "d3-brush": "^3.0.0", 55 | "d3-color": "^3.1.0", 56 | "d3-contour": "^4.0.2", 57 | "d3-drag": "^3.0.0", 58 | "d3-ease": "^3.0.1", 59 | "d3-fetch": "^3.0.1", 60 | "d3-format": "^3.1.0", 61 | "d3-geo": "^3.1.0", 62 | "d3-hierarchy": "^3.1.2", 63 | "d3-interpolate": "^3.0.1", 64 | "d3-path": "^3.1.0", 65 | "d3-quadtree": "^3.0.1", 66 | "d3-random": "^3.0.1", 67 | "d3-scale": "^4.0.2", 68 | "d3-scale-chromatic": "^3.0.0", 69 | "d3-selection": "^3.0.0", 70 | "d3-shape": "^3.2.0", 71 | "d3-time-format": "^4.1.0", 72 | "d3-timer": "^3.0.1", 73 | "d3-transition": "^3.0.1", 74 | "d3-zoom": "^3.0.0", 75 | "eslint": "^8.39.0", 76 | "eslint-config-prettier": "^8.8.0", 77 | "eslint-plugin-prettier": "^4.2.1", 78 | "eslint-plugin-svelte": "^2.26.0", 79 | "eslint-plugin-svelte3": "^3.4.1", 80 | "flexsearch": "^0.7.31", 81 | "gh-pages": "^5.0.0", 82 | "prettier": "^2.8.8", 83 | "rollup": "^2.79.1", 84 | "rollup-plugin-css-only": "^3.1.0", 85 | "rollup-plugin-livereload": "^2.0.5", 86 | "rollup-plugin-svelte": "^7.1.4", 87 | "sass": "^1.62.0", 88 | "svelte": "^3.58.0", 89 | "svelte-check": "^3.2.0", 90 | "svelte-preprocess": "^5.0.3", 91 | "tslib": "^2.5.0", 92 | "typescript": "^5.0.4", 93 | "vite": "^4.3.1" 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/utils/d3-import.ts: -------------------------------------------------------------------------------- 1 | import { select, selectAll } from 'd3-selection'; 2 | 3 | import { json } from 'd3-fetch'; 4 | 5 | import { 6 | scaleLinear, 7 | scaleSqrt, 8 | scalePoint, 9 | scaleBand, 10 | scalePow, 11 | scaleOrdinal, 12 | scaleLog, 13 | scaleSequential, 14 | scaleTime, 15 | scaleUtc 16 | } from 'd3-scale'; 17 | 18 | import { 19 | schemeTableau10, 20 | schemePastel1, 21 | interpolateRainbow, 22 | interpolateBlues 23 | } from 'd3-scale-chromatic'; 24 | 25 | import { lch, hsl, color } from 'd3-color'; 26 | 27 | import { 28 | quantize, 29 | interpolate, 30 | interpolateHsl, 31 | interpolateLab, 32 | interpolateRgb, 33 | interpolateRgbBasis, 34 | interpolateZoom 35 | } from 'd3-interpolate'; 36 | 37 | import { 38 | max, 39 | maxIndex, 40 | min, 41 | minIndex, 42 | extent, 43 | sum, 44 | bin, 45 | shuffle, 46 | quickselect 47 | } from 'd3-array'; 48 | 49 | import { timeout } from 'd3-timer'; 50 | 51 | import { transition } from 'd3-transition'; 52 | 53 | import { 54 | easeLinear, 55 | easePolyInOut, 56 | easeQuadInOut, 57 | easeCubicInOut, 58 | easeElasticOut 59 | } from 'd3-ease'; 60 | 61 | import { axisLeft, axisBottom } from 'd3-axis'; 62 | 63 | import { 64 | line, 65 | curveStepAfter, 66 | curveBasis, 67 | curveMonotoneX, 68 | curveMonotoneY, 69 | arc, 70 | linkHorizontal, 71 | linkVertical 72 | } from 'd3-shape'; 73 | 74 | import { path } from 'd3-path'; 75 | 76 | import { hierarchy, partition, tree, pack } from 'd3-hierarchy'; 77 | 78 | import { brush } from 'd3-brush'; 79 | 80 | import { zoom, zoomIdentity, zoomTransform } from 'd3-zoom'; 81 | 82 | import { drag } from 'd3-drag'; 83 | 84 | import { format } from 'd3-format'; 85 | 86 | import { timeFormat, utcFormat } from 'd3-time-format'; 87 | 88 | import { randomLcg, randomUniform, randomInt } from 'd3-random'; 89 | 90 | import { contours } from 'd3-contour'; 91 | 92 | import { geoPath } from 'd3-geo'; 93 | 94 | import { quadtree } from 'd3-quadtree'; 95 | 96 | export default { 97 | select, 98 | selectAll, 99 | json, 100 | scaleLinear, 101 | scaleSqrt, 102 | scalePoint, 103 | scaleBand, 104 | scalePow, 105 | scaleOrdinal, 106 | scaleLog, 107 | scaleSequential, 108 | scaleTime, 109 | scaleUtc, 110 | schemeTableau10, 111 | schemePastel1, 112 | interpolateRainbow, 113 | interpolateBlues, 114 | interpolateHsl, 115 | interpolateLab, 116 | interpolateRgb, 117 | interpolateRgbBasis, 118 | interpolateZoom, 119 | lch, 120 | hsl, 121 | color, 122 | quantize, 123 | interpolate, 124 | max, 125 | maxIndex, 126 | min, 127 | minIndex, 128 | extent, 129 | sum, 130 | bin, 131 | shuffle, 132 | quickselect, 133 | timeout, 134 | transition, 135 | easeLinear, 136 | easePolyInOut, 137 | easeQuadInOut, 138 | easeCubicInOut, 139 | easeElasticOut, 140 | axisLeft, 141 | axisBottom, 142 | line, 143 | curveStepAfter, 144 | brush, 145 | zoom, 146 | zoomIdentity, 147 | zoomTransform, 148 | drag, 149 | format, 150 | curveMonotoneX, 151 | curveMonotoneY, 152 | curveBasis, 153 | timeFormat, 154 | utcFormat, 155 | hierarchy, 156 | partition, 157 | tree, 158 | pack, 159 | arc, 160 | linkHorizontal, 161 | linkVertical, 162 | path, 163 | randomLcg, 164 | randomUniform, 165 | randomInt, 166 | contours, 167 | geoPath, 168 | quadtree 169 | }; 170 | -------------------------------------------------------------------------------- /src/imgs/icon-gear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /metadata/github-issues.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | access_token = '{GITHUB ACCESS TOKEN}' 4 | 5 | repos = [ 6 | 'agermanidis/pigeon', 7 | 'Autodesk/notebook-molecular-visualization', 8 | 'bmabey/pyLDAvis', 9 | 'bqplot/bqplot', 10 | 'carlos-gg/hciplot', 11 | 'centreborelli/pypotree', 12 | 'potree/potree/', 13 | 'cmudig/AutoProfiler', 14 | 'cuemacro/chartpy', 15 | 'dssg/aequitas', 16 | 'facebookresearch/hiplot', 17 | 'finos/perspective', 18 | 'google/brax', 19 | 'graphistry/pygraphistry', 20 | 'interpretml/interpret', 21 | 'interpretml/interpret-community', 22 | 'ipyannotate/ipyannotate', 23 | 'jessevig/bertviz', 24 | 'koaning/whatlies', 25 | 'merqurio/neo4jupyter', 26 | 'mwouts/itables', 27 | 'PatrikHlobil/Pandas-Bokeh', 28 | 'poliastro/czml3', 29 | 'poloclub/visual-auditor', 30 | 'python-visualization/folium', 31 | 'Quantomatic/pyzx', 32 | 'tensorflow/model-analysis', 33 | 'tensorflow/tensorboard' 34 | 'keplergl/kepler.gl', 35 | 'iseekwonderful/PyPathway', 36 | 'isl-org/Open3D', 37 | 'facebook/Ax', 38 | 'apache/beam', 39 | 'catboost/catboost', 40 | 'CQCL/pytket', 41 | 'sfu-db/dataprep', 42 | 'tkrabel/bamboolib', 43 | 'GeoscienceAustralia/dea-notebooks', 44 | 'enthought/mayavi', 45 | 'lightkurve/lightkurve', 46 | 'voxel51/fiftyone', 47 | 'eli5-org/eli5', 48 | 'zakandrewking/escher', 49 | 'keras-team/keras', 50 | 'flexxui/flexx', 51 | 'GateNLP/python-gatenlp', 52 | 'holoviz/geoviews', 53 | 'intake/intake', 54 | 'cytoscape/cytoscape.js', 55 | 'microsoft/LightGBM', 56 | 'MaartenGr/BERTopic', 57 | 'jupyter-incubator/sparkmagic' 58 | 'executablebooks/MyST-NB', 59 | 'nilearn/nilearn', 60 | 'QuSTaR/kaleidoscope', 61 | 'holoviz/panel', 62 | 'pixiedust/pixiedust', 63 | 'plotly/dash', 64 | 'cytoscape/py2cytoscape', 65 | 'pycaret/pycaret', 66 | 'pydgrid/pydgrid', 67 | 'InsightLab/PyMove', 68 | 'intuitivetextmining/d3fdgraph', 69 | 'Elysian01/Data-Purifier', 70 | 'datapane/datapane', 71 | 'igvteam/igv', 72 | 'patrickfuller/imolecule', 73 | 'InsightSoftwareConsortium/itkwidgets', 74 | 'JupyterPhysSciLab/JupyterPiDAQ', 75 | 'sdpython/jyquickhelper', 76 | 'cbouy/mols2grid', 77 | 'ydataai/ydata-profiling', 78 | 'adamerose/PandasGUI', 79 | 'VIDA-NYU/PipelineVis', 80 | 'visgl/deck.gl', 81 | 'hyriver/pygeohydro', 82 | 'quantopian/qgrid', 83 | 'ranaroussi/quantstats', 84 | 'sid-the-coder/QuickDA', 85 | 'microsoft/responsible-ai-toolbox', 86 | 'fbdesignpro/sweetviz', 87 | 'mikedh/trimesh', 88 | 'facebookresearch/vizseq', 89 | 'PAIR-code/what-if-tool', 90 | 'jnowak90/GraVisGUI', 91 | 'slundberg/shap', 92 | 'Mr-Milk/SpatialTis', 93 | 'sandialabs/toyplot', 94 | 'wandb/wandb', 95 | 'nengo/nengo', 96 | 'pathpy/pathpy' 97 | ] 98 | 99 | keywords = ['notebook', 'jupyter', 'colab', 'kaggle'] 100 | 101 | headers = { 102 | 'Authorization': f'token {access_token}' 103 | } 104 | 105 | for repo_name in repos: 106 | url = f'https://api.github.com/repos/{repo_name}/issues?state=all' 107 | response = requests.get(url, headers=headers) 108 | repo_name_string = repo_name.replace('/', '_') 109 | with open(f'{repo_name_string}-issues.txt', 'a') as f: 110 | f.write(f'{repo_name}\n') 111 | 112 | for issue in response.json(): 113 | try: 114 | comments_url = issue['comments_url'] 115 | comments_response = requests.get(comments_url, headers=headers) 116 | comments = comments_response.json() 117 | 118 | title = issue['title'] 119 | description = issue['body'] 120 | 121 | if any(keyword in title.lower() for keyword in keywords) or any(keyword in description.lower() for keyword in keywords): 122 | with open(f'{repo_name_string}-issues.txt', 'a') as f: 123 | f.write('\n------------------------------------------------------------------------------------------------------------------------------------------\n') 124 | f.write(f'{title}: {issue["html_url"]}\n') 125 | f.write(f'Description: {description}\n') 126 | for comment in comments: 127 | f.write(f'\t{comment["user"]["login"]}: {comment["body"]}\n') 128 | except: 129 | pass 130 | -------------------------------------------------------------------------------- /src/components/grid-panel/GridPanel.ts: -------------------------------------------------------------------------------- 1 | import type { Writable } from 'svelte/store'; 2 | import type { SearchStoreValue } from '../../stores'; 3 | import { getSearchStoreDefaultValue } from '../../stores'; 4 | import type { SuperNovaEntry } from '../../types/common-types'; 5 | import { setIntersect } from '../../utils/utils'; 6 | 7 | export class GridPanel { 8 | component: HTMLElement; 9 | gridPanelUpdated: () => void; 10 | allEntries: SuperNovaEntry[]; 11 | curEntries: SuperNovaEntry[]; 12 | searchStore: Writable; 13 | searchStoreValue = getSearchStoreDefaultValue(); 14 | 15 | constructor( 16 | component: HTMLElement, 17 | gridPanelUpdated: () => void, 18 | supernovaEntries: SuperNovaEntry[], 19 | searchStore: Writable 20 | ) { 21 | this.component = component; 22 | this.gridPanelUpdated = gridPanelUpdated; 23 | this.allEntries = supernovaEntries.map(d => d); 24 | this.curEntries = supernovaEntries.map(d => d); 25 | this.searchStore = searchStore; 26 | 27 | this.searchStore.subscribe(value => { 28 | this.searchStoreValue = value; 29 | 30 | this.filterEntries(); 31 | }); 32 | 33 | // Default sorting is date- 34 | this.sortEntries('date-'); 35 | } 36 | 37 | filterEntries = () => { 38 | // Check the selected clips 39 | this.curEntries = []; 40 | 41 | for (const entry of this.allEntries) { 42 | let addCurEntry = true; 43 | 44 | // Add this item if none of its clip is out of selection 45 | for (const clip of entry.allClips) { 46 | if (!this.searchStoreValue.selectedClips.has(clip)) { 47 | addCurEntry = false; 48 | break; 49 | } 50 | } 51 | 52 | // Check the search keyword 53 | if (this.searchStoreValue.keyword !== '') { 54 | const keyword = this.searchStoreValue.keyword.toLowerCase(); 55 | const entryString = JSON.stringify(entry).toLowerCase(); 56 | if (!entryString.includes(keyword)) { 57 | addCurEntry = false; 58 | } 59 | } 60 | 61 | if (addCurEntry) { 62 | this.curEntries.push(entry); 63 | } 64 | } 65 | 66 | this.gridPanelUpdated(); 67 | }; 68 | 69 | /** 70 | * Event handler for the sorting key selection chagne 71 | * @param e Select input event 72 | */ 73 | sortSelectChanged = (e: InputEvent) => { 74 | const target = e.target as HTMLInputElement; 75 | const sortKey = target.value; 76 | 77 | if ( 78 | sortKey === 'date+' || 79 | sortKey === 'date-' || 80 | sortKey === 'name+' || 81 | sortKey === 'name-' 82 | ) { 83 | this.sortEntries(sortKey); 84 | } 85 | }; 86 | 87 | sortEntries = (key: 'date+' | 'date-' | 'name+' | 'name-') => { 88 | switch (key) { 89 | case 'date+': { 90 | // Use name to break ties 91 | this.curEntries.sort((a, b) => a.name.localeCompare(b.name)); 92 | this.curEntries.sort((a, b) => a.releaseYear - b.releaseYear); 93 | 94 | this.allEntries.sort((a, b) => a.name.localeCompare(b.name)); 95 | this.allEntries.sort((a, b) => a.releaseYear - b.releaseYear); 96 | this.gridPanelUpdated(); 97 | break; 98 | } 99 | 100 | case 'date-': { 101 | // Use name to break ties 102 | this.curEntries.sort((a, b) => a.name.localeCompare(b.name)); 103 | this.curEntries.sort((a, b) => b.releaseYear - a.releaseYear); 104 | 105 | this.allEntries.sort((a, b) => a.name.localeCompare(b.name)); 106 | this.allEntries.sort((a, b) => b.releaseYear - a.releaseYear); 107 | this.gridPanelUpdated(); 108 | break; 109 | } 110 | 111 | case 'name+': { 112 | // Use year to break ties 113 | this.curEntries.sort((a, b) => b.releaseYear - a.releaseYear); 114 | this.curEntries.sort((a, b) => a.name.localeCompare(b.name)); 115 | 116 | this.allEntries.sort((a, b) => b.releaseYear - a.releaseYear); 117 | this.allEntries.sort((a, b) => a.name.localeCompare(b.name)); 118 | this.gridPanelUpdated(); 119 | break; 120 | } 121 | 122 | case 'name-': { 123 | // Use yar to break ties 124 | this.curEntries.sort((a, b) => b.releaseYear - a.releaseYear); 125 | this.curEntries.sort((a, b) => b.name.localeCompare(a.name)); 126 | 127 | this.allEntries.sort((a, b) => b.releaseYear - a.releaseYear); 128 | this.allEntries.sort((a, b) => b.name.localeCompare(a.name)); 129 | this.gridPanelUpdated(); 130 | break; 131 | } 132 | 133 | default: { 134 | console.error('Unknown sorting key', key); 135 | break; 136 | } 137 | } 138 | }; 139 | } 140 | -------------------------------------------------------------------------------- /src/components/search-panel/SearchPanel.scss: -------------------------------------------------------------------------------- 1 | @import '../../define.scss'; 2 | 3 | $button-border-radius: 5px; 4 | 5 | .search-panel-wrapper { 6 | position: relative; 7 | display: flex; 8 | flex-direction: column; 9 | align-items: center; 10 | height: 100%; 11 | width: 100%; 12 | color: white; 13 | 14 | gap: 12px; 15 | } 16 | 17 | .svg-icon { 18 | display: flex; 19 | justify-content: center; 20 | align-items: center; 21 | width: 1em; 22 | height: 1em; 23 | color: currentColor; 24 | 25 | pointer-events: fill; 26 | 27 | :global(svg) { 28 | fill: currentColor; 29 | width: 100%; 30 | height: 100%; 31 | } 32 | } 33 | 34 | $search-h-margin: 8px; 35 | $search-input-height: 15px; 36 | $search-input-v-padding: 10px; 37 | 38 | $logo-icon-width: 24px; 39 | $cancel-icon-width: 14px; 40 | $cancel-icon-margin: 8px; 41 | 42 | $search-bar-h-padding: 12px; 43 | $search-bar-gap: 8px; 44 | 45 | .search-bar { 46 | color: $gray-600; 47 | margin: $search-h-margin 0 0 0; 48 | display: flex; 49 | flex-direction: row; 50 | gap: $search-bar-gap; 51 | align-items: center; 52 | pointer-events: all; 53 | 54 | width: 100%; 55 | padding: 0 $search-bar-h-padding; 56 | border-radius: $button-border-radius; 57 | background-color: change-color($color: white, $alpha: 1); 58 | transition: box-shadow 150ms ease-in-out; 59 | box-shadow: 0 2px 4px hsla(0, 0%, 0%, 0.2), 0 -1px 0 hsla(0, 0%, 0%, 0.02); 60 | 61 | &.focused { 62 | box-shadow: 0 2px 4px hsla(0, 0%, 0%, 0.1), 0 -1px 0 hsla(0, 0%, 0%, 0.02); 63 | } 64 | 65 | &:focus { 66 | background-color: red; 67 | } 68 | 69 | #search-bar-input { 70 | border: none; 71 | margin: $search-input-v-padding 0; 72 | width: 100%; 73 | height: $search-input-height; 74 | 75 | &:focus { 76 | border: none; 77 | outline: none; 78 | } 79 | 80 | &::placeholder { 81 | color: $gray-600; 82 | } 83 | } 84 | 85 | .logo-icon { 86 | width: $logo-icon-width; 87 | height: $logo-icon-width; 88 | } 89 | 90 | .end-button { 91 | position: relative; 92 | margin-left: $cancel-icon-margin; 93 | width: 1em; 94 | height: 1em; 95 | 96 | .search-icon { 97 | position: absolute; 98 | width: 1em; 99 | height: 1em; 100 | left: 50%; 101 | top: 50%; 102 | transform: translate(-50%, -50%); 103 | 104 | color: currentColor; 105 | transition: color 150ms ease-in-out, opacity 150ms ease-in-out; 106 | opacity: 1; 107 | 108 | &.hidden { 109 | opacity: 0; 110 | pointer-events: none; 111 | } 112 | } 113 | 114 | .cancel-icon { 115 | position: absolute; 116 | width: $cancel-icon-width; 117 | height: $cancel-icon-width; 118 | left: 50%; 119 | top: 50%; 120 | transform: translate(-50%, -50%); 121 | 122 | color: $gray-500; 123 | transition: color 150ms ease-in-out, opacity 150ms ease-in-out; 124 | opacity: 1; 125 | cursor: default; 126 | 127 | &:hover { 128 | color: adjust-color($color: $gray-500, $lightness: -10%); 129 | } 130 | 131 | &:active { 132 | color: adjust-color($color: $gray-500, $lightness: 10%); 133 | } 134 | 135 | &.hidden { 136 | opacity: 0; 137 | pointer-events: none; 138 | } 139 | } 140 | } 141 | } 142 | 143 | .filter-container { 144 | display: flex; 145 | flex-direction: column; 146 | align-items: center; 147 | height: 100%; 148 | width: 100%; 149 | gap: 12px; 150 | overflow-y: auto; 151 | } 152 | 153 | .category-block { 154 | display: flex; 155 | flex-direction: column; 156 | align-items: flex-start; 157 | width: 100%; 158 | 159 | .name { 160 | font-size: $font-u1; 161 | font-weight: 600; 162 | } 163 | } 164 | 165 | .chips-container { 166 | display: flex; 167 | flex-direction: row; 168 | flex-wrap: wrap; 169 | row-gap: 6px; 170 | column-gap: 6px; 171 | font-size: $font-d1; 172 | padding: 5px 0; 173 | 174 | .chip { 175 | padding: 1px 7px; 176 | border-radius: 5px; 177 | border: 1px dashed hsla(0, 100%, 100%, 0.5); 178 | 179 | user-select: none; 180 | -webkit-user-select: none; 181 | 182 | transition: background-color 75ms, border 75ms; 183 | 184 | &:hover { 185 | background-color: change-color($color: $teal-400, $lightness: 20%); 186 | } 187 | 188 | $chip-selected-color: hsl(174, 60%, 27%); 189 | 190 | &.selected { 191 | background-color: $chip-selected-color; 192 | border: 1px solid $chip-selected-color; 193 | 194 | &:hover { 195 | background-color: change-color($color: $teal-400, $lightness: 28%); 196 | } 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/imgs/supernova-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SuperNOVA 2 | 3 | [![Github Actions Status](https://github.com/poloclub/supernova/workflows/build/badge.svg)](https://github.com/poloclub/supernova/actions/workflows/build.yml) 4 | [![license](https://img.shields.io/badge/License-MIT-blue)](https://github.com/poloclub/supernova/blob/master/LICENSE) 5 | [![arxiv badge](https://img.shields.io/badge/arXiv-2305.03039-red)](http://arxiv.org/abs/2305.03039) 6 | [![10.1145/3613905.3650848](https://img.shields.io/badge/DOI-10.1145/3613905.3650848-blue)](https://doi.org/10.1145/3613905.3650848) 7 | 8 | Design Strategies and Opportunities for Interactive Visualization in Computational Notebooks 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
🚀 Live Demo: Explore 160+ notebook visualization tools!👨🏻‍🏫 Conference Talk📖 Research Paper
22 | 23 | ## Overview 24 | 25 | SuperNOVA is an interactive tool to help researchers explore existing notebook VA tools and search for design inspiration and implementation references. Anyone can easily add new notebook VA tools to this open-source explorer. 26 | 27 | 28 | 29 | ## SuperNOVA Details 30 | 31 | Computational notebooks such as Jupyter Notebook have become data scientists' de facto programming environments. Many visualization researchers and practitioners have developed interactive visualization tools that support notebooks. However, little is known about the appropriate design of visual analytics (VA) tools in notebooks. To bridge this critical research gap, we investigate the design strategies in this space by analyzing 159 notebook VA tools and their users' feedback. SuperNOVA is an interactive browsers to help researchers explore the landscape of notebook VA tools and search for related work. 32 | 33 | ## Live Demo 34 | 35 | For a live web demo of SuperNOVA, visit: . 36 | 37 | ## How to add an entry to SuperNOVA 38 | 39 | To add a new notebook VA tool to the SuperNOVA collection, please submit a [pull request](https://github.com/poloclub/supernova/pulls). You can add your VA tool to the [YAML file](https://github.com/poloclub/supernova/blob/main/src/data/supernova.yaml) with the following steps: 40 | 41 | Make sure you have the necessary information for the entry you want to add, including the tool's title, authors, publication or release year, DOI or URL, and a brief description of the paper's content. 42 | 43 | 1. Open the [YAML file](https://github.com/poloclub/supernova/blob/main/src/data/supernova.yaml) where the existing entries are stored. 44 | 2. Use the following YAML template, and paste it below the last entry. For the definition details of each entry, please check out the [SuperNOVA paper](https://arxiv.org/abs/2305.03039). 45 | 46 | ```yaml 47 | - # {string} The bibtex of this entry 48 | bibtex: '' 49 | 50 | # {string} The bibtex key 51 | bibtexKey: '' 52 | 53 | # {'no' | 'one-way' | 'two-way'} VA-notebook communication style 54 | communication: '' 55 | 56 | # {string} A description of the tool, can be the abstract of its paper 57 | description: '' 58 | 59 | # {string?} GitHub repository URL 60 | githubURL: '' 61 | 62 | # {'ipywidget'| 'extension' | 'html' | 'nova' | 'other-package' | 'custom'} Implementation strategy 63 | implementation: '' 64 | 65 | # {'on-demand' | 'always-on'} The display style of the VA tool 66 | layouts: '' 67 | 68 | # {['runtime' | 'code' | 'external']} Types of data this VA tool uses 69 | materials: [''] 70 | 71 | # {'monolithic' | 'modular'} The modularity of this VA tool 72 | modularity: '' 73 | 74 | # {string} Name of this tool in lowercase. It has to match the thumbnail file name. 75 | name: '' 76 | 77 | # {string} The name of this tool 78 | nameDisplay: '' 79 | 80 | # {string[]?} Other URLs of this tool 81 | otherURLs: [] 82 | 83 | # {string?} Paper URL 84 | paperURL: '' 85 | 86 | # {number} The release/publication year 87 | releaseYear: 2023 88 | 89 | # {'paper' | 'package'} If this tool has a related paper, use 'paper'. 90 | sourceType: '' 91 | 92 | # {['jupyter' | 'lab' | 'colab' | 'vscode']} List of supported notebook platforms 93 | supportedNotebooks: [''] 94 | 95 | # {string} The thumbnail file name 96 | thumbnail: '' 97 | 98 | # {'data scientist' | 'scientist' | 'educator'} The main targeted users 99 | user: '' 100 | ``` 101 | 102 | 3. Save a thumbnail image in the [`./public/images/thumbnails/`](./public/images/thumbnails/) directory. Please resize the image so that both width and height are smaller than 300px and compress the image to be smaller than 20kb. 103 | 4. Submit a [pull request](https://github.com/poloclub/supernova/pulls) to this repository. 104 | 105 | ## Data Collection 106 | 107 | Code for data collection and cleaned GitHub issues are at [`./metadata`](./metadata). 108 | 109 | ## Credits 110 | 111 | SuperNOVA is created by Jay Wang, David Munechika, Seongmin Lee, and Polo Chau. 112 | 113 | ## Citation 114 | 115 | To learn more about SuperNOVA, please read our [research paper](https://arxiv.org/abs/2305.03039) (published at [CHI 2024](https://chi2024.acm.org)). 116 | 117 | ```bibTeX 118 | @article{wangSuperNOVADesignStrategies2023, 119 | title = {{{SuperNOVA}}: {{Design Strategies}} and {{Opportunities}} for {{Interactive Visualization}} in {{Computational Notebooks}}}, 120 | shorttitle = {{{SuperNOVA}}}, 121 | author = {Wang, Zijie J. and Munechika, David and Lee, Seongmin and Chau, Duen Horng}, 122 | year = {2023}, 123 | url = {http://arxiv.org/abs/2305.03039}, 124 | urldate = {2023-05-05}, 125 | archiveprefix = {arxiv}, 126 | journal = {arXiv 2305.03039} 127 | } 128 | ``` 129 | 130 | ## License 131 | 132 | The code is available under the [MIT License](https://github.com/poloclub/supernova/blob/master/LICENSE). 133 | 134 | ## Contact 135 | 136 | If you have any questions, feel free to [open an issue](https://github.com/poloclub/supernova/issues/new) or contact [Jay Wang](https://zijie.wang). 137 | -------------------------------------------------------------------------------- /metadata/paper-count.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import requests\n", 10 | "import pathlib\n", 11 | "import yaml\n", 12 | "import re\n", 13 | "import os\n", 14 | "import sys\n", 15 | "\n", 16 | "from json import load, dump\n", 17 | "from typing import Set\n", 18 | "from os.path import join, exists, basename\n", 19 | "from tqdm import tqdm" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 18, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "with open('./resources/supernova.yaml', 'r') as fp:\n", 29 | " data = yaml.safe_load(fp)" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 26, 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [ 38 | "bibtex_key_to_name = {}\n", 39 | "for item in data:\n", 40 | " bibtex_key_to_name[item['bibtexKey']] = item['name']" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 3, 46 | "metadata": {}, 47 | "outputs": [ 48 | { 49 | "data": { 50 | "text/plain": [ 51 | "193" 52 | ] 53 | }, 54 | "execution_count": 3, 55 | "metadata": {}, 56 | "output_type": "execute_result" 57 | } 58 | ], 59 | "source": [ 60 | "with open('./notebook-va.bib', 'r') as fp:\n", 61 | " lines = [l for l in fp.readlines()]\n", 62 | "\n", 63 | "bibtex_entries = []\n", 64 | "cur_entry = ''\n", 65 | "for line in lines:\n", 66 | " if line == '\\n':\n", 67 | " bibtex_entries.append(cur_entry)\n", 68 | " cur_entry = ''\n", 69 | "\n", 70 | " else:\n", 71 | " cur_entry += line\n", 72 | "\n", 73 | "bibtex_entries.append(cur_entry)\n", 74 | "\n", 75 | "# Create a dictionary that maps bibtex key to the entry\n", 76 | "bibtex_dict = {}\n", 77 | "\n", 78 | "for i, entry in enumerate(bibtex_entries):\n", 79 | " first_line = entry.split('\\n')[0]\n", 80 | " key = re.sub(r'^@.+{(.+),.*$', r'\\1', first_line)\n", 81 | "\n", 82 | " # Also parse the year\n", 83 | " year = int(re.sub(r'^.*(\\d{4})[a-z]?$', r'\\1', key))\n", 84 | "\n", 85 | " bibtex_dict[key] = {\n", 86 | " 'bibtex': entry,\n", 87 | " 'year': year\n", 88 | " }\n", 89 | "\n", 90 | "len(bibtex_entries)" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 60, 96 | "metadata": {}, 97 | "outputs": [], 98 | "source": [ 99 | "doi_map = {}\n", 100 | "year_map = {}\n", 101 | "\n", 102 | "for entry in bibtex_entries:\n", 103 | " first_line = entry.split('\\n')[0]\n", 104 | " key = re.sub(r'^@.+{(.+),.*$', r'\\1', first_line)\n", 105 | " year = int(re.sub(r'^.*(\\d{4})[a-z]?$', r'\\1', key))\n", 106 | "\n", 107 | " if key not in bibtex_key_to_name:\n", 108 | " continue\n", 109 | "\n", 110 | " name = bibtex_key_to_name[key]\n", 111 | " year_map[name] = year\n", 112 | "\n", 113 | " match = re.search(r'.*doi = {(.*?)}.*', entry)\n", 114 | " if match:\n", 115 | " doi = match.group(1)\n", 116 | " doi_map[name] = doi\n", 117 | " continue\n", 118 | " else:\n", 119 | " match = re.search(r'.*url = {(.*?)}.*', entry)\n", 120 | " if match:\n", 121 | " url = match.group(1)\n", 122 | " if 'arxiv' in url:\n", 123 | " arxiv = 'arXiv:' + url.split('/')[-1]\n", 124 | " doi_map[name] = arxiv" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 30, 130 | "metadata": {}, 131 | "outputs": [ 132 | { 133 | "data": { 134 | "text/plain": [ 135 | "81" 136 | ] 137 | }, 138 | "execution_count": 30, 139 | "metadata": {}, 140 | "output_type": "execute_result" 141 | } 142 | ], 143 | "source": [ 144 | "len(doi_map)" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": {}, 150 | "source": [ 151 | "## Query Citation Count" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 48, 157 | "metadata": {}, 158 | "outputs": [], 159 | "source": [ 160 | "url = 'https://api.semanticscholar.org/graph/v1/paper/'" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 54, 166 | "metadata": {}, 167 | "outputs": [], 168 | "source": [ 169 | "# Query citation count from semantic scholar\n", 170 | "citation_map = {}\n", 171 | "failed_dois = []\n", 172 | "\n", 173 | "for name in doi_map:\n", 174 | " doi = doi_map[name]\n", 175 | " cur_url = url + doi\n", 176 | " parameter = {\n", 177 | " 'fields': 'citationCount'\n", 178 | " }\n", 179 | " response = requests.get(cur_url, parameter).json()\n", 180 | "\n", 181 | " if 'citationCount' in response:\n", 182 | " count = response['citationCount']\n", 183 | " citation_map[name] = count\n", 184 | " else:\n", 185 | " failed_dois.append(doi)" 186 | ] 187 | }, 188 | { 189 | "cell_type": "code", 190 | "execution_count": 58, 191 | "metadata": {}, 192 | "outputs": [ 193 | { 194 | "name": "stdout", 195 | "output_type": "stream", 196 | "text": [ 197 | "networkit 10.1109/IPDPSW55747.2022.00055\n", 198 | "mols2grid 10.5281/zenodo.6591473\n", 199 | "ivpy 10.11588/DAH.2019.4.66401\n", 200 | "cytoscapejs 10.5281/ZENODO.6828253\n", 201 | "geopandas 10.5281/ZENODO.7422493\n", 202 | "dea-tools 10.26186/145234\n", 203 | "shap 10.48550/arXiv.1705.07874\n", 204 | "itkwidgets 10.5281/ZENODO.7489693\n", 205 | "data+shift 10.2312/EVS.20221097\n", 206 | "tissuumaps 10.1101/2022.01.28.478131\n" 207 | ] 208 | } 209 | ], 210 | "source": [ 211 | "for doi in failed_dois:\n", 212 | " cur_name = ''\n", 213 | " for name in doi_map:\n", 214 | " if doi_map[name] == doi:\n", 215 | " cur_name = name\n", 216 | " break\n", 217 | "\n", 218 | " print(cur_name, doi)\n", 219 | " # print(f\"citation_map['{cur_name}'] = 0\")" 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": 59, 225 | "metadata": {}, 226 | "outputs": [], 227 | "source": [ 228 | "# Manually add citation for failed papers\n", 229 | "citation_map['networkit'] = 1\n", 230 | "citation_map['mols2grid'] = 0\n", 231 | "citation_map['ivpy'] = 6\n", 232 | "citation_map['cytoscapejs'] = 0\n", 233 | "citation_map['geopandas'] = 0\n", 234 | "citation_map['dea-tools'] = 0\n", 235 | "citation_map['shap'] = 11652\n", 236 | "citation_map['itkwidgets'] = 0\n", 237 | "citation_map['data+shift'] = 3\n", 238 | "citation_map['tissuumaps'] = 0" 239 | ] 240 | }, 241 | { 242 | "cell_type": "code", 243 | "execution_count": 61, 244 | "metadata": {}, 245 | "outputs": [], 246 | "source": [ 247 | "citation_info = {}\n", 248 | "\n", 249 | "for name in citation_map:\n", 250 | " citation_info[name] = {\n", 251 | " 'citation': citation_map[name],\n", 252 | " 'year': year_map[name]\n", 253 | " }" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": 63, 259 | "metadata": {}, 260 | "outputs": [], 261 | "source": [ 262 | "dump(citation_info, open('./resources/citation_info.json', 'w'))" 263 | ] 264 | } 265 | ], 266 | "metadata": { 267 | "kernelspec": { 268 | "display_name": "nlp", 269 | "language": "python", 270 | "name": "python3" 271 | }, 272 | "language_info": { 273 | "codemirror_mode": { 274 | "name": "ipython", 275 | "version": 3 276 | }, 277 | "file_extension": ".py", 278 | "mimetype": "text/x-python", 279 | "name": "python", 280 | "nbconvert_exporter": "python", 281 | "pygments_lexer": "ipython3", 282 | "version": "3.9.13" 283 | } 284 | }, 285 | "nbformat": 4, 286 | "nbformat_minor": 2 287 | } 288 | -------------------------------------------------------------------------------- /src/utils/font-width-data/lato.json: -------------------------------------------------------------------------------- 1 | {"textWidth":[[" ",19.3],["!",34.3],["\"",39.7],["#",58],["$",58],["%",78.6],["&",70.3],["'",23],["(",30],[")",30],["*",40],["+",58],[",",21.2],["-",34.7],[".",21.2],["/",37.3],["0",58],["1",58],["2",58],["3",58],["4",58],["5",58],["6",58],["7",58],["8",58],["9",58],[":",25.2],[";",25.2],["<",58],["=",58],[">",58],["?",39.8],["@",82.2],["A",68],["B",64.7],["C",68.5],["D",75.3],["E",58.1],["F",56.6],["G",73.4],["H",75.6],["I",30.7],["J",44.4],["K",68.1],["L",51.4],["M",92],["N",75.6],["O",79.8],["P",61.1],["Q",79.8],["R",64.4],["S",53],["T",59],["U",73],["V",68],["W",101.9],["X",64.3],["Y",62.9],["Z",62.4],["[",30],["\\",37.5],["]",30],["^",58],["_",39.4],["`",30.7],["a",50.7],["b",55.9],["c",46.7],["d",55.9],["e",52.4],["f",33.7],["g",51.1],["h",55.6],["i",25.6],["j",25.4],["k",52.4],["l",25.6],["m",82.1],["n",55.6],["o",55.6],["p",55.2],["q",55.9],["r",40.3],["s",43.4],["t",37.3],["u",55.6],["v",51.2],["w",76.6],["x",50.4],["y",51.2],["z",46.2],["{",30],["|",30],["}",30],["~",58],["_median",55.9]],"kerningWidth":[["\"&",-9.1],["\",",-11.4],["\"-",-8.9],["\".",-11.4],["\"/",-9.1],["\"@",-2.3],["\"A",-9.1],["\"C",-2.3],["\"G",-2.3],["\"O",-2.3],["\"Q",-2.3],["\"V",2.4],["\"W",2.4],["\"Y",1.5],["\"\\",2.4],["\"a",-3.2],["\"c",-4.6],["\"d",-4.6],["\"e",-4.6],["\"o",-4.6],["\"q",-4.6],["'&",-9.1],["',",-11.4],["'-",-8.9],["'.",-11.4],["'/",-9.1],["'@",-2.3],["'A",-9.1],["'C",-2.3],["'G",-2.3],["'O",-2.3],["'Q",-2.3],["'V",2.4],["'W",2.4],["'Y",1.5],["'\\",2.4],["'a",-3.2],["'c",-4.6],["'d",-4.6],["'e",-4.6],["'o",-4.6],["'q",-4.6],["(@",-2],["(C",-2],["(G",-2],["(O",-2],["(Q",-2],["(c",-1.6],["(d",-1.6],["(e",-1.6],["(o",-1.6],["(q",-1.6],["*&",-9.1],["*,",-11.4],["*-",-8.9],["*.",-11.4],["*/",-9.1],["*@",-2.3],["*A",-9.1],["*C",-2.3],["*G",-2.3],["*O",-2.3],["*Q",-2.3],["*V",2.4],["*W",2.4],["*Y",1.5],["*\\",2.4],["*a",-3.2],["*c",-4.6],["*d",-4.6],["*e",-4.6],["*o",-4.6],["*q",-4.6],[",\"",-11.4],[",'",-11.4],[",*",-11.4],[",-",-6.8],[",@",-2.8],[",C",-2.8],[",G",-2.8],[",O",-2.8],[",Q",-2.8],[",T",-9],[",V",-9],[",W",-6.1],[",Y",-7.6],[",\\",-9],[",v",-6.6],[",w",-3.1],[",y",-6.6],["-\"",-8.9],["-&",-2.6],["-'",-8.9],["-*",-8.9],["-,",-6.8],["-.",-6.8],["-/",-2.6],["-A",-2.6],["-T",-9],["-V",-5.6],["-W",-1.6],["-X",-3.1],["-Y",-8],["-Z",-2.3],["-\\",-5.6],[".\"",-11.4],[".'",-11.4],[".*",-11.4],[".-",-6.8],[".@",-2.8],[".C",-2.8],[".G",-2.8],[".O",-2.8],[".Q",-2.8],[".T",-9],[".V",-9],[".W",-6.1],[".Y",-7.6],[".\\",-9],[".v",-6.6],[".w",-3.1],[".y",-6.6],["/\"",2.4],["/&",-6.8],["/'",2.4],["/*",2.4],["/,",-9.6],["/-",-5.6],["/.",-9.6],["//",-6.8],["/:",-4.4],["/;",-4.4],["/?",2.4],["/@",-2.6],["/A",-6.8],["/C",-2.6],["/G",-2.6],["/J",-7.6],["/O",-2.6],["/Q",-2.6],["/a",-5.8],["/c",-5.8],["/d",-5.8],["/e",-5.8],["/f",-1.5],["/g",-6.8],["/m",-4.4],["/n",-4.4],["/o",-5.8],["/p",-4.4],["/q",-5.8],["/r",-4.4],["/s",-5.3],["/t",-2.1],["/u",-4.4],["/v",-2.4],["/x",-2.6],["/y",-2.4],["/z",-4.1],["@\"",-2.3],["@&",-2.1],["@'",-2.3],["@)",-2],["@*",-2.3],["@,",-2.8],["@.",-2.8],["@/",-2.1],["@A",-2.1],["@T",-4.9],["@V",-2.6],["@X",-1.5],["@Y",-4],["@Z",-3.5],["@\\",-2.6],["@]",-2],["@}",-2],["A\"",-9.1],["A'",-9.1],["A*",-9.1],["A-",-2.6],["A?",-2.8],["A@",-2.1],["AC",-2.1],["AG",-2.1],["AJ",2.5],["AO",-2.1],["AQ",-2.1],["AT",-6.6],["AU",-2.8],["AV",-6.8],["AW",-4.2],["AY",-8.2],["A\\",-6.8],["Av",-4.1],["Ay",-4.1],["C-",-7.5],["D\"",-2.3],["D&",-2.1],["D'",-2.3],["D)",-2],["D*",-2.3],["D,",-2.8],["D.",-2.8],["D/",-2.1],["DA",-2.1],["DT",-4.9],["DV",-2.6],["DX",-1.5],["DY",-4],["DZ",-3.5],["D\\",-2.6],["D]",-2],["D}",-2],["F&",-6.6],["F,",-9],["F.",-9],["F/",-6.6],["F:",-3],["F;",-3],["F?",1.5],["FA",-6.6],["FJ",-9.9],["Fc",-3.5],["Fd",-3.5],["Fe",-3.5],["Fm",-3],["Fn",-3],["Fo",-3.5],["Fp",-3],["Fq",-3.5],["Fr",-3],["Fu",-3],["J&",-2.8],["J,",-2.5],["J.",-2.5],["J/",-2.8],["JA",-2.8],["K-",-3.1],["K@",-1.5],["KC",-1.5],["KG",-1.5],["KO",-1.5],["KQ",-1.5],["Kc",-1.8],["Kd",-1.8],["Ke",-1.8],["Kf",-2.6],["Ko",-1.8],["Kq",-1.8],["Kt",-4.1],["Kv",-3.3],["Kw",-2.8],["Ky",-3.3],["L\"",-14.5],["L'",-14.5],["L*",-14.5],["L,",2.7],["L-",-9.9],["L.",2.7],["L?",-2.5],["L@",-4],["LC",-4],["LG",-4],["LO",-4],["LQ",-4],["LT",-8.6],["LV",-9.1],["LW",-7.6],["LY",-10.6],["L\\",-9.1],["Lc",-1.8],["Ld",-1.8],["Le",-1.8],["Lo",-1.8],["Lq",-1.8],["Lv",-5.4],["Lw",-4],["Ly",-5.4],["O\"",-2.3],["O&",-2.1],["O'",-2.3],["O)",-2],["O*",-2.3],["O,",-2.8],["O.",-2.8],["O/",-2.1],["OA",-2.1],["OT",-4.9],["OV",-2.6],["OX",-1.5],["OY",-4],["OZ",-3.5],["O\\",-2.6],["O]",-2],["O}",-2],["P&",-6.9],["P,",-12.4],["P.",-12.4],["P/",-6.9],["PA",-6.9],["PJ",-9.1],["Pa",-2.5],["Pc",-1.5],["Pd",-1.5],["Pe",-1.5],["Po",-1.5],["Pq",-1.5],["Q\"",-2.3],["Q&",-2.1],["Q'",-2.3],["Q)",-2],["Q*",-2.3],["Q,",-2.8],["Q.",-2.8],["Q/",-2.1],["QA",-2.1],["QT",-4.9],["QV",-2.6],["QX",-1.5],["QY",-4],["QZ",-3.5],["Q\\",-2.6],["Q]",-2],["Q}",-2],["R@",-2.3],["RC",-2.3],["RG",-2.3],["RO",-2.3],["RQ",-2.3],["RT",-2.6],["RU",-2.1],["T&",-6.6],["T,",-9],["T-",-9],["T.",-9],["T/",-6.6],["T:",-8],["T;",-8],["T@",-4.9],["TA",-6.6],["TC",-4.9],["TG",-4.9],["TJ",-10],["TO",-4.9],["TQ",-4.9],["Ta",-12.5],["Tc",-10.5],["Td",-10.5],["Te",-10.5],["Tg",-9.4],["Tm",-8],["Tn",-8],["To",-10.5],["Tp",-8],["Tq",-10.5],["Tr",-8],["Ts",-8.1],["Tu",-8],["Tv",-9],["Tw",-7],["Tx",-7.2],["Ty",-9],["Tz",-6],["U&",-2.8],["U,",-2.5],["U.",-2.5],["U/",-2.8],["UA",-2.8],["V\"",2.4],["V&",-6.8],["V'",2.4],["V*",2.4],["V,",-9.6],["V-",-5.6],["V.",-9.6],["V/",-6.8],["V:",-4.4],["V;",-4.4],["V?",2.4],["V@",-2.6],["VA",-6.8],["VC",-2.6],["VG",-2.6],["VJ",-7.6],["VO",-2.6],["VQ",-2.6],["Va",-5.8],["Vc",-5.8],["Vd",-5.8],["Ve",-5.8],["Vf",-1.5],["Vg",-6.8],["Vm",-4.4],["Vn",-4.4],["Vo",-5.8],["Vp",-4.4],["Vq",-5.8],["Vr",-4.4],["Vs",-5.3],["Vt",-2.1],["Vu",-4.4],["Vv",-2.4],["Vx",-2.6],["Vy",-2.4],["Vz",-4.1],["W\"",2.4],["W&",-4.7],["W'",2.4],["W*",2.4],["W,",-6.1],["W-",-1.6],["W.",-6.1],["W/",-4.7],["W?",1.7],["WA",-4.7],["WJ",-5.1],["Wa",-4.4],["Wc",-1.6],["Wd",-1.6],["We",-1.6],["Wg",-4.9],["Wo",-1.6],["Wq",-1.6],["Ws",-2.3],["X-",-3.1],["X@",-1.5],["XC",-1.5],["XG",-1.5],["XO",-1.5],["XQ",-1.5],["Xc",-1.8],["Xd",-1.8],["Xe",-1.8],["Xf",-2.6],["Xo",-1.8],["Xq",-1.8],["Xt",-4.1],["Xv",-3.3],["Xw",-2.8],["Xy",-3.3],["Y\"",1.5],["Y&",-8.2],["Y'",1.5],["Y*",1.5],["Y,",-7.6],["Y-",-8],["Y.",-7.6],["Y/",-8.2],["Y:",-6.1],["Y;",-6.1],["Y?",1.7],["Y@",-4],["YA",-8.2],["YC",-4],["YG",-4],["YJ",-10],["YO",-4],["YQ",-4],["Ya",-6.4],["Yc",-8],["Yd",-8],["Ye",-8],["Yg",-8.6],["Ym",-6.1],["Yn",-6.1],["Yo",-8],["Yp",-6.1],["Yq",-8],["Yr",-6.1],["Ys",-6.4],["Yu",-6.1],["Yv",-5],["Yw",-4.6],["Yx",-6.6],["Yy",-5],["Z-",-3.5],["Z?",1.7],["Z@",-2.9],["ZC",-2.9],["ZG",-2.9],["ZO",-2.9],["ZQ",-2.9],["Zc",-1.9],["Zd",-1.9],["Ze",-1.9],["Zo",-1.9],["Zq",-1.9],["Zs",-1.4],["Zv",-2],["Zy",-2],["[@",-2],["[C",-2],["[G",-2],["[O",-2],["[Q",-2],["[c",-1.6],["[d",-1.6],["[e",-1.6],["[o",-1.6],["[q",-1.6],["\\\"",-9.1],["\\'",-9.1],["\\*",-9.1],["\\-",-2.6],["\\?",-2.8],["\\@",-2.1],["\\C",-2.1],["\\G",-2.1],["\\J",2.5],["\\O",-2.1],["\\Q",-2.1],["\\T",-6.6],["\\U",-2.8],["\\V",-6.8],["\\W",-4.2],["\\Y",-8.2],["\\\\",-6.8],["\\v",-4.1],["\\y",-4.1],["a\"",-3.6],["a'",-3.6],["a*",-3.6],["av",-1.6],["aw",-0.8],["ay",-1.6],["b\"",-4.6],["b'",-4.6],["b)",-1.6],["b*",-4.6],["bV",-5.8],["bW",-1.6],["b\\",-5.8],["b]",-1.6],["bv",-1.3],["bx",-3],["by",-1.3],["b}",-1.6],["e\"",-4.6],["e'",-4.6],["e)",-1.6],["e*",-4.6],["eV",-5.8],["eW",-1.6],["e\\",-5.8],["e]",-1.6],["ev",-1.3],["ex",-3],["ey",-1.3],["e}",-1.6],["f\"",3.4],["f'",3.4],["f*",3.4],["f,",-6.5],["f.",-6.5],["fi",-2.3],["h\"",-3.6],["h'",-3.6],["h*",-3.6],["hv",-1.6],["hw",-0.8],["hy",-1.6],["kc",-3],["kd",-3],["ke",-3],["ko",-3],["kq",-3],["m\"",-3.6],["m'",-3.6],["m*",-3.6],["mv",-1.6],["mw",-0.8],["my",-1.6],["n\"",-3.6],["n'",-3.6],["n*",-3.6],["nv",-1.6],["nw",-0.8],["ny",-1.6],["o\"",-4.6],["o'",-4.6],["o)",-1.6],["o*",-4.6],["oV",-5.8],["oW",-1.6],["o\\",-5.8],["o]",-1.6],["ov",-1.3],["ox",-3],["oy",-1.3],["o}",-1.6],["p\"",-4.6],["p'",-4.6],["p)",-1.6],["p*",-4.6],["pV",-5.8],["pW",-1.6],["p\\",-5.8],["p]",-1.6],["pv",-1.3],["px",-3],["py",-1.3],["p}",-1.6],["r,",-6.6],["r.",-6.6],["ra",-1.9],["v&",-4.1],["v,",-6.6],["v.",-6.6],["v/",-4.1],["vA",-4.1],["vc",-1.3],["vd",-1.3],["ve",-1.3],["vo",-1.3],["vq",-1.3],["w,",-3.1],["w.",-3.1],["xc",-3],["xd",-3],["xe",-3],["xo",-3],["xq",-3],["y&",-4.1],["y,",-6.6],["y.",-6.6],["y/",-4.1],["yA",-4.1],["yc",-1.3],["yd",-1.3],["ye",-1.3],["yo",-1.3],["yq",-1.3],["{@",-2],["{C",-2],["{G",-2],["{O",-2],["{Q",-2],["{c",-1.6],["{d",-1.6],["{e",-1.6],["{o",-1.6],["{q",-1.6]]} -------------------------------------------------------------------------------- /src/components/grid-panel/GridPanel.scss: -------------------------------------------------------------------------------- 1 | @import '../../define.scss'; 2 | 3 | $button-border-radius: 5px; 4 | 5 | .grid-panel-wrapper { 6 | position: relative; 7 | display: flex; 8 | flex-direction: column; 9 | height: 100%; 10 | width: 100%; 11 | overflow-y: auto; 12 | padding-bottom: $panel-h-padding; 13 | background-color: hsl(0, 0%, 97%); 14 | } 15 | 16 | .svg-icon { 17 | display: flex; 18 | justify-content: center; 19 | align-items: center; 20 | width: 1em; 21 | height: 1em; 22 | color: currentColor; 23 | 24 | pointer-events: fill; 25 | 26 | :global(svg) { 27 | fill: currentColor; 28 | width: 100%; 29 | height: 100%; 30 | } 31 | } 32 | 33 | .row-header { 34 | display: flex; 35 | flex-direction: row; 36 | justify-content: flex-end; 37 | align-items: center; 38 | width: 100%; 39 | 40 | background-color: white; 41 | opacity: 0.93; 42 | 43 | border-bottom: 1px solid $gray-200; 44 | padding: 8px $panel-h-padding 6px $panel-h-padding; 45 | gap: 4px; 46 | 47 | position: sticky; 48 | top: 0px; 49 | z-index: 2; 50 | 51 | .label { 52 | font-size: 1rem; 53 | font-weight: 400; 54 | color: $gray-600; 55 | display: flex; 56 | flex-direction: row; 57 | align-items: center; 58 | } 59 | 60 | #hidden-select { 61 | display: none; 62 | 63 | &::after { 64 | display: none; 65 | } 66 | } 67 | 68 | .select { 69 | position: relative; 70 | border-radius: 4px; 71 | border: 1px solid $gray-light-border; 72 | margin: 0 0 0 4px; 73 | line-height: 1.2; 74 | 75 | select { 76 | padding: 0 16px 0 6px; 77 | margin: 0px; 78 | border: none; 79 | position: relative; 80 | background-color: transparent; 81 | color: $gray-600; 82 | background-color: white; 83 | font-weight: 400; 84 | 85 | -moz-appearance: none; 86 | -webkit-appearance: none; 87 | } 88 | 89 | &::after { 90 | right: 6px; 91 | 92 | $select-border-color: $gray-600; 93 | border-right: 2px solid $select-border-color; 94 | border-top: 2px solid $select-border-color; 95 | 96 | content: ''; 97 | display: block; 98 | height: 6px; 99 | width: 6px; 100 | pointer-events: none; 101 | position: absolute; 102 | top: 50%; 103 | transform: translateY(-50%) rotate(135deg); 104 | transform-origin: center; 105 | } 106 | } 107 | 108 | .svg-icon { 109 | fill: $gray-400; 110 | position: relative; 111 | display: flex; 112 | justify-content: center; 113 | align-items: center; 114 | margin-top: 2px; 115 | 116 | :global(svg) { 117 | width: 1rem; 118 | height: 1rem; 119 | } 120 | } 121 | } 122 | 123 | .card-panel { 124 | display: flex; 125 | flex-wrap: wrap; 126 | gap: 20px; 127 | 128 | width: 100%; 129 | padding: $panel-h-padding $panel-h-padding; 130 | background-color: hsl(0, 0%, 97%); 131 | 132 | .card { 133 | width: 165px; 134 | box-shadow: 0px 0px 6px hsla(0, 0%, 0%, 0.07); 135 | border: 1px solid hsla(0, 0%, 0%, 0.1); 136 | border-radius: 6px; 137 | overflow: hidden; 138 | 139 | display: flex; 140 | flex-direction: column; 141 | align-items: center; 142 | cursor: pointer; 143 | 144 | transition: transform 100ms ease-in-out, box-shadow 100ms ease-in-out; 145 | 146 | &:hover { 147 | transform: scale(1.02); 148 | transform-origin: center; 149 | box-shadow: 0px 0px 8px hsla(0, 0%, 0%, 0.13); 150 | } 151 | 152 | &:active { 153 | transform: scale(1.02) translateY(1px); 154 | } 155 | 156 | .thumbnail-container { 157 | width: 100%; 158 | aspect-ratio: 1 / 1; 159 | border-bottom: 1px solid $gray-300; 160 | } 161 | 162 | .thumbnail { 163 | width: 100%; 164 | height: 100%; 165 | object-fit: cover; 166 | object-position: top left; 167 | transition: object-position 700ms linear; 168 | 169 | &:hover { 170 | object-position: bottom right; 171 | transition: object-position 1400ms linear; 172 | } 173 | } 174 | 175 | .name { 176 | width: 100%; 177 | padding: 0 5px; 178 | font-size: $font-d1; 179 | font-weight: 600; 180 | background-color: white; 181 | text-align: center; 182 | white-space: nowrap; 183 | text-overflow: ellipsis; 184 | overflow: hidden; 185 | } 186 | } 187 | } 188 | 189 | @keyframes fade-in { 190 | from { 191 | opacity: 0; 192 | } 193 | to { 194 | opacity: 1; 195 | } 196 | } 197 | 198 | dialog[open] { 199 | border-radius: 8px; 200 | border: none; 201 | display: flex; 202 | flex-direction: column; 203 | align-items: center; 204 | gap: 16px; 205 | padding: 0; 206 | pointer-events: all; 207 | 208 | max-height: 600px; 209 | max-width: 600px; 210 | padding-bottom: 16px; 211 | 212 | &::backdrop { 213 | background-color: hsla(0, 0%, 0%, 0.75); 214 | animation: fade-in 300ms; 215 | } 216 | 217 | .header { 218 | padding: 16px 20px 0px 20px; 219 | margin: 0; 220 | line-height: 1; 221 | font-size: $font-u3; 222 | font-weight: 600; 223 | width: 100%; 224 | display: flex; 225 | flex-direction: row; 226 | justify-content: space-between; 227 | align-items: center; 228 | min-width: 500px; 229 | 230 | .left { 231 | display: flex; 232 | gap: 7px; 233 | align-items: center; 234 | 235 | .svg-icon { 236 | height: 16px; 237 | width: 16px; 238 | color: $gray-900; 239 | transition: color 100ms ease-in-out; 240 | cursor: pointer; 241 | 242 | &:hover { 243 | color: $gray-800; 244 | } 245 | 246 | &:active { 247 | color: $gray-700; 248 | } 249 | } 250 | } 251 | } 252 | 253 | .close-button { 254 | color: $gray-500; 255 | transition: color 150ms ease-in-out; 256 | 257 | &:hover { 258 | color: $gray-600; 259 | } 260 | 261 | &:active { 262 | color: $gray-700; 263 | } 264 | } 265 | 266 | button.button { 267 | background-color: $gray-200; 268 | padding: 3px 8px; 269 | border-radius: 5px; 270 | display: flex; 271 | align-items: center; 272 | gap: 5px; 273 | flex-grow: 0; 274 | transition: background-color 150ms ease-in-out; 275 | 276 | &:hover { 277 | background-color: $gray-300; 278 | } 279 | 280 | &:active { 281 | background-color: $gray-400; 282 | } 283 | 284 | &.add-button { 285 | background-color: $blue-500; 286 | color: white; 287 | border-color: $blue-500; 288 | 289 | &:hover { 290 | background-color: $blue-400; 291 | } 292 | 293 | &:active { 294 | background-color: $blue-600; 295 | } 296 | } 297 | } 298 | 299 | .button { 300 | background-color: $gray-200; 301 | color: $gray-800; 302 | padding: 3px 8px; 303 | border-radius: 5px; 304 | display: flex; 305 | align-items: center; 306 | gap: 5px; 307 | flex-grow: 0; 308 | transition: background-color 150ms ease-in-out; 309 | border: 1px solid $gray-400; 310 | 311 | &:hover { 312 | background-color: $gray-300; 313 | } 314 | 315 | &:active { 316 | background-color: $gray-400; 317 | } 318 | } 319 | 320 | .content { 321 | display: flex; 322 | // align-items: stretch; 323 | 324 | padding: 0px 20px 0 20px; 325 | gap: 10px; 326 | 327 | max-height: 200px; 328 | max-width: 100%; 329 | 330 | .description { 331 | flex: 1; 332 | max-width: 100%; 333 | max-height: 100%; 334 | overflow-y: auto; 335 | 336 | font-size: $font-d1; 337 | } 338 | 339 | .thumbnail-container { 340 | flex: 1; 341 | display: flex; 342 | justify-content: center; 343 | align-items: flex-start; 344 | 345 | .thumbnail { 346 | max-width: 100%; 347 | max-height: 100%; 348 | width: auto; 349 | height: auto; 350 | 351 | border: 1px solid $gray-border; 352 | border-radius: 5px; 353 | } 354 | } 355 | } 356 | 357 | .info-bar { 358 | display: flex; 359 | flex-direction: row; 360 | width: 100%; 361 | padding: 0px 20px 0 20px; 362 | font-size: $font-d2; 363 | flex-wrap: wrap; 364 | gap: 6px; 365 | 366 | .clip { 367 | background-color: $teal-600; 368 | color: white; 369 | padding: 1px 3px; 370 | border-radius: 5px; 371 | } 372 | } 373 | 374 | .bibtex-bar { 375 | width: 100%; 376 | display: flex; 377 | padding: 0px 20px 0 20px; 378 | font-size: $font-d2; 379 | flex-wrap: wrap; 380 | } 381 | 382 | .bibtex-short { 383 | color: $gray-800; 384 | 385 | .copy-text { 386 | padding-left: 4px; 387 | color: $teal-900; 388 | cursor: pointer; 389 | user-select: none; 390 | -webkit-user-select: none; 391 | 392 | &:hover { 393 | text-decoration: underline; 394 | } 395 | 396 | &:active { 397 | color: $teal-700; 398 | } 399 | } 400 | 401 | .svg-icon.copied-icon { 402 | display: inline-block; 403 | vertical-align: text-top; 404 | color: $teal-600; 405 | opacity: 0; 406 | transition: opacity 500ms; 407 | 408 | &:global(.shown) { 409 | opacity: 1; 410 | } 411 | } 412 | } 413 | } 414 | -------------------------------------------------------------------------------- /src/components/search-panel/SearchPanel.svelte: -------------------------------------------------------------------------------- 1 | 161 | 162 | 165 | 166 |
167 | 204 | 205 |
206 |
207 |
Notebook Communication
208 |
209 | {#each commClips as clip, i} 210 | 215 | {/each} 216 |
217 |
218 | 219 |
220 |
Visualization Material
221 |
222 | {#each materialClips as clip, i} 223 | 228 | {/each} 229 |
230 |
231 | 232 |
233 |
Visualization Presentation
234 |
235 | {#each layoutClips as clip, i} 236 | 241 | {/each} 242 |
243 |
244 | 245 |
246 |
Modularity
247 |
248 | {#each modularityClips as clip, i} 249 | 254 | {/each} 255 |
256 |
257 | 258 |
259 |
Targeted Users
260 |
261 | {#each userClips as clip, i} 262 | 267 | {/each} 268 |
269 |
270 | 271 |
272 |
Supported Notebooks
273 |
274 | {#each notebookClips as clip, i} 275 | 280 | {/each} 281 |
282 |
283 | 284 |
285 |
Implementation Method
286 |
287 | {#each implementationClips as clip, i} 288 | 293 | {/each} 294 |
295 |
296 |
297 |
298 | -------------------------------------------------------------------------------- /metadata/github-stars.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 64, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import requests\n", 10 | "import pathlib\n", 11 | "import yaml\n", 12 | "import re\n", 13 | "import os\n", 14 | "import sys\n", 15 | "\n", 16 | "from json import load, dump\n", 17 | "from typing import Set\n", 18 | "from os.path import join, exists, basename\n", 19 | "from tqdm import tqdm" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 16, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "TOKEN = input('github token')" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 72, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "with open('./resources/supernova.yaml', 'r') as fp:\n", 38 | " data = yaml.safe_load(fp)" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 73, 44 | "metadata": {}, 45 | "outputs": [], 46 | "source": [ 47 | "repo_names = []\n", 48 | "repo_name_map = {}\n", 49 | "\n", 50 | "for item in data:\n", 51 | " if item['githubURL'] != '':\n", 52 | " parts = item['githubURL'].split('/')\n", 53 | " cur_repo_name = '/'.join(parts[-2:])\n", 54 | " repo_name_map[cur_repo_name] = item['name']\n", 55 | " repo_names.append(cur_repo_name)\n" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 70, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "def get_star_response(search_string):\n", 65 | " # Query the stars\n", 66 | " URL = \"https://api.github.com/graphql\"\n", 67 | " USER = \"xiaohk\"\n", 68 | "\n", 69 | " query = \"\"\"\n", 70 | " query {\n", 71 | " rateLimit {\n", 72 | " limit\n", 73 | " cost\n", 74 | " remaining\n", 75 | " }\n", 76 | " search(query: \"SEARCH_STRING\", type: REPOSITORY, first: 100) {\n", 77 | " edges {\n", 78 | " node {\n", 79 | " ... on Repository {\n", 80 | " owner {\n", 81 | " login\n", 82 | " }\n", 83 | " name\n", 84 | " stargazers {\n", 85 | " totalCount\n", 86 | " }\n", 87 | " defaultBranchRef {\n", 88 | " target {\n", 89 | " ... on Commit {\n", 90 | " history(first: 1) {\n", 91 | " edges {\n", 92 | " node {\n", 93 | " committedDate\n", 94 | " }\n", 95 | " }\n", 96 | " totalCount\n", 97 | " pageInfo {\n", 98 | " endCursor\n", 99 | " }\n", 100 | " }\n", 101 | " }\n", 102 | " }\n", 103 | " }\n", 104 | " }\n", 105 | " }\n", 106 | " }\n", 107 | " }\n", 108 | " }\n", 109 | " \"\"\"\n", 110 | " query = query.replace(\"SEARCH_STRING\", search_string)\n", 111 | "\n", 112 | " response = requests.post(\n", 113 | " URL, json={\"query\": query}, auth=(USER, TOKEN), timeout=600\n", 114 | " )\n", 115 | "\n", 116 | " if not response.ok:\n", 117 | " print(\"Request error!\")\n", 118 | " print(response)\n", 119 | " print(response.text)\n", 120 | "\n", 121 | " return response" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 74, 127 | "metadata": {}, 128 | "outputs": [], 129 | "source": [ 130 | "# Create a query search string to query only related users\n", 131 | "i = 0\n", 132 | "gap = 100\n", 133 | "star_responses = []\n", 134 | "\n", 135 | "while i < len(repo_names):\n", 136 | " search_string = \"\"\n", 137 | " for name in repo_names[i: i + gap]:\n", 138 | " search_string += f\"repo:{name} \"\n", 139 | "\n", 140 | " response = get_star_response(search_string)\n", 141 | " star_responses.append(response.json())\n", 142 | " i += gap" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": 77, 148 | "metadata": {}, 149 | "outputs": [], 150 | "source": [ 151 | "star_counts = {}\n", 152 | "cursor_info = {}\n", 153 | "repo_date_map = {}\n", 154 | "\n", 155 | "def parse_star_response(star_response):\n", 156 | " # Parse the query result\n", 157 | " data = star_response[\"data\"]\n", 158 | "\n", 159 | "\n", 160 | " for node in data[\"search\"][\"edges\"]:\n", 161 | " node = node[\"node\"]\n", 162 | "\n", 163 | " # Get the query results\n", 164 | " owner = node[\"owner\"][\"login\"]\n", 165 | " name = node[\"name\"]\n", 166 | " star = node[\"stargazers\"][\"totalCount\"]\n", 167 | "\n", 168 | " repo_name = f\"{owner}/{name}\"\n", 169 | " star_counts[repo_name] = star\n", 170 | "\n", 171 | " # Get the cursor info\n", 172 | " info = {\n", 173 | " 'committedDate': node[\"defaultBranchRef\"][\"target\"]['history'][\"edges\"][0][\"node\"][\"committedDate\"],\n", 174 | " 'totalCount': node[\"defaultBranchRef\"][\"target\"]['history'][\"totalCount\"],\n", 175 | " 'endCursor': node[\"defaultBranchRef\"][\"target\"]['history'][\"pageInfo\"][\"endCursor\"]\n", 176 | " }\n", 177 | " cursor_info[repo_name] = info\n", 178 | "\n", 179 | "for star_response in star_responses:\n", 180 | " parse_star_response(star_response)" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 81, 186 | "metadata": {}, 187 | "outputs": [ 188 | { 189 | "name": "stderr", 190 | "output_type": "stream", 191 | "text": [ 192 | "100%|██████████| 135/135 [00:08<00:00, 15.11it/s]\n" 193 | ] 194 | } 195 | ], 196 | "source": [ 197 | "# Get the first commit date\n", 198 | "query = \"\"\"\n", 199 | "query ($name: String!, $owner: String!){\n", 200 | " repository(name: $name, owner: $owner) {\n", 201 | " defaultBranchRef {\n", 202 | " target {\n", 203 | " ... on Commit {\n", 204 | " history(first: 1, after: %s) {\n", 205 | " nodes {\n", 206 | " message\n", 207 | " committedDate\n", 208 | " authoredDate\n", 209 | " oid\n", 210 | " author {\n", 211 | " email\n", 212 | " name\n", 213 | " }\n", 214 | " }\n", 215 | " totalCount\n", 216 | " pageInfo {\n", 217 | " endCursor\n", 218 | " }\n", 219 | " }\n", 220 | " }\n", 221 | " }\n", 222 | " }\n", 223 | " }\n", 224 | "}\n", 225 | "\"\"\"\n", 226 | "\n", 227 | "def getDate(cursor):\n", 228 | " r = requests.post(\"https://api.github.com/graphql\",\n", 229 | " headers = {\n", 230 | " \"Authorization\": f\"Bearer {TOKEN}\"\n", 231 | " },\n", 232 | " json = {\n", 233 | " \"query\": query % cursor,\n", 234 | " \"variables\": {\n", 235 | " \"name\": name,\n", 236 | " \"owner\": owner,\n", 237 | " }\n", 238 | " })\n", 239 | " return r.json()[\"data\"][\"repository\"][\"defaultBranchRef\"][\"target\"][\"history\"][\"nodes\"][0][\"committedDate\"]\n", 240 | "\n", 241 | "for key in tqdm(cursor_info):\n", 242 | " if key in repo_date_map:\n", 243 | " continue\n", 244 | "\n", 245 | " info = cursor_info[key]\n", 246 | " owner, name = key.split('/')\n", 247 | " totalCount = info['totalCount']\n", 248 | "\n", 249 | " if totalCount > 1:\n", 250 | " cursor = info['endCursor'].split(' ')\n", 251 | " cursor[1] = str(totalCount - 2)\n", 252 | " date = getDate(f\"\\\"{' '.join(cursor)}\\\"\")\n", 253 | " repo_date_map[key] = date\n", 254 | " else:\n", 255 | " repo_date_map[key] = info['committedDate']" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": 85, 261 | "metadata": {}, 262 | "outputs": [], 263 | "source": [ 264 | "# Remap the repo name back to their data source name\n", 265 | "\n", 266 | "star_info = {}\n", 267 | "for key in star_counts:\n", 268 | " name = repo_name_map[key]\n", 269 | " star_info[name] = {\n", 270 | " 'star': star_counts[key],\n", 271 | " 'date': repo_date_map[key]\n", 272 | " }" 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": 87, 278 | "metadata": {}, 279 | "outputs": [], 280 | "source": [ 281 | "star_info\n", 282 | "\n", 283 | "dump(star_info, open('./resources/star_info.json', 'w'))" 284 | ] 285 | } 286 | ], 287 | "metadata": { 288 | "kernelspec": { 289 | "display_name": "nlp", 290 | "language": "python", 291 | "name": "python3" 292 | }, 293 | "language_info": { 294 | "codemirror_mode": { 295 | "name": "ipython", 296 | "version": 3 297 | }, 298 | "file_extension": ".py", 299 | "mimetype": "text/x-python", 300 | "name": "python", 301 | "nbconvert_exporter": "python", 302 | "pygments_lexer": "ipython3", 303 | "version": "3.9.13" 304 | } 305 | }, 306 | "nbformat": 4, 307 | "nbformat_minor": 2 308 | } 309 | -------------------------------------------------------------------------------- /src/utils/utils.ts: -------------------------------------------------------------------------------- 1 | // Author: Jay Wang (jay@zijie.wang) 2 | // License: MIT 3 | 4 | import d3 from './d3-import'; 5 | 6 | // import type { SvelteComponent } from 'svelte'; 7 | 8 | /** 9 | * Round a number to a given decimal. 10 | * @param {number} num Number to round 11 | * @param {number} decimal Decimal place 12 | * @returns number 13 | */ 14 | export const round = (num: number, decimal: number) => { 15 | return Math.round((num + Number.EPSILON) * 10 ** decimal) / 10 ** decimal; 16 | }; 17 | 18 | /** 19 | * Get a random number between [min, max], inclusive 20 | * @param {number} min Min value 21 | * @param {number} max Max value 22 | * @returns number 23 | */ 24 | export const random = (min: number, max: number) => { 25 | return Math.floor(Math.random() * (max - min)) + min; 26 | }; 27 | 28 | /** 29 | * Download a JSON file 30 | * @param {any} object 31 | * @param {HTMLElement | null} [dlAnchorElem] 32 | * @param {string} [fileName] 33 | */ 34 | 35 | export const downloadJSON = ( 36 | object: object, 37 | dlAnchorElem: HTMLElement | null = null, 38 | fileName = 'download.json' 39 | ) => { 40 | const dataStr = 41 | 'data:text/json;charset=utf-8,' + 42 | encodeURIComponent(JSON.stringify(object)); 43 | 44 | // Create dlAnchor if it is not given 45 | let myDlAnchorElem = dlAnchorElem; 46 | let needToRemoveAnchor = false; 47 | 48 | if (dlAnchorElem === null) { 49 | myDlAnchorElem = document.createElement('a'); 50 | myDlAnchorElem.classList.add('download-anchor'); 51 | myDlAnchorElem.style.display = 'none'; 52 | needToRemoveAnchor = true; 53 | } 54 | 55 | myDlAnchorElem?.setAttribute('href', dataStr); 56 | myDlAnchorElem?.setAttribute('download', `${fileName}`); 57 | myDlAnchorElem?.click(); 58 | 59 | if (needToRemoveAnchor) { 60 | myDlAnchorElem?.remove(); 61 | } 62 | }; 63 | 64 | /** 65 | * Download a text file 66 | * @param {string} textString 67 | * @param {HTMLElement | null} [dlAnchorElem] 68 | * @param {string} [fileName] 69 | */ 70 | 71 | export const downloadText = ( 72 | textString: string, 73 | dlAnchorElem: HTMLElement | null, 74 | fileName = 'download.json' 75 | ) => { 76 | const dataStr = 77 | 'data:text/plain;charset=utf-8,' + encodeURIComponent(textString); 78 | 79 | // Create dlAnchor if it is not given 80 | let myDlAnchorElem = dlAnchorElem; 81 | let needToRemoveAnchor = false; 82 | 83 | if (dlAnchorElem === null) { 84 | myDlAnchorElem = document.createElement('a'); 85 | myDlAnchorElem.style.display = 'none'; 86 | needToRemoveAnchor = true; 87 | } 88 | 89 | myDlAnchorElem?.setAttribute('href', dataStr); 90 | myDlAnchorElem?.setAttribute('download', `${fileName}`); 91 | myDlAnchorElem?.click(); 92 | 93 | if (needToRemoveAnchor) { 94 | myDlAnchorElem?.remove(); 95 | } 96 | }; 97 | 98 | /** 99 | * Compute the luminance of a RGB color 100 | * https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio 101 | * @param color [R, G, B in 0..255] 102 | * @returns number 103 | */ 104 | 105 | export const getLuminance = (color: number[]) => { 106 | const r = color[0]; 107 | const g = color[1]; 108 | const b = color[2]; 109 | 110 | // Some strange required transformations 111 | const transformedRGB = [r, g, b].map(v => { 112 | v /= 255; 113 | return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); 114 | }); 115 | 116 | return ( 117 | transformedRGB[0] * 0.2126 + 118 | transformedRGB[1] * 0.7152 + 119 | transformedRGB[2] * 0.0722 120 | ); 121 | }; 122 | 123 | /** 124 | * Compute color contrast ratio 125 | * @param color1 [r, g, b] in 255 scale 126 | * @param color2 [r, g, b] in 255 scale 127 | * @returns Contrast ratio 128 | */ 129 | 130 | export const getContrastRatio = (color1: number[], color2: number[]) => { 131 | const color1L = getLuminance(color1); 132 | const color2L = getLuminance(color2); 133 | const ratio = 134 | color1L > color2L 135 | ? (color2L + 0.05) / (color1L + 0.05) 136 | : (color1L + 0.05) / (color2L + 0.05); 137 | return ratio; 138 | }; 139 | 140 | /** 141 | * Check if two colors have enough contrast 142 | * @param color1 [r, g, b] in 255 scale 143 | * @param color2 [r, g, b] in 255 scale 144 | * @param condition 'AA' or 'AAA' 145 | * @param smallText If it is small text 146 | * @returns If two colors have enough contrast 147 | */ 148 | 149 | export const haveContrast = ( 150 | color1: number[], 151 | color2: number[], 152 | condition = 'AAA', 153 | smallText = true 154 | ) => { 155 | const ratio = getContrastRatio(color1, color2); 156 | 157 | // Compare the ratio with different thresholds 158 | if (condition === 'AA') { 159 | if (smallText) { 160 | return ratio <= 1 / 4.5; 161 | } else { 162 | return ratio <= 1 / 3; 163 | } 164 | } else { 165 | if (smallText) { 166 | return ratio <= 1 / 7; 167 | } else { 168 | return ratio <= 1 / 4.5; 169 | } 170 | } 171 | }; 172 | 173 | /** 174 | * Check if two sets are the same 175 | * @param set1 Set 1 176 | * @param set2 Set 2 177 | */ 178 | export const setsAreEqual = (set1: Set, set2: Set): boolean => { 179 | return set1.size === set2.size && [...set1].every(d => set2.has(d)); 180 | }; 181 | 182 | /** 183 | * Get the intersect of two sets 184 | * @param set1 Set 1 185 | * @param set2 Set 2 186 | * @returns Intersect 187 | */ 188 | export const setIntersect = (set1: Set, set2: Set): Set => { 189 | const intersect = new Set(); 190 | for (const item of set1) { 191 | if (set2.has(item)) { 192 | intersect.add(item); 193 | } 194 | } 195 | return intersect; 196 | }; 197 | 198 | /** 199 | * Get the file name and file extension from a File object 200 | * @param {File} file File object 201 | * @returns [file name, file extension] 202 | */ 203 | 204 | export const splitFileName = (file: File) => { 205 | const name = file.name; 206 | const lastDot = name.lastIndexOf('.'); 207 | const value = name.slice(0, lastDot); 208 | const extension = name.slice(lastDot + 1); 209 | return [value, extension]; 210 | }; 211 | 212 | /** 213 | * Split the reader stream text by a string 214 | * @param sep String used to separate the input string 215 | * @returns TransformStream 216 | */ 217 | export const splitStreamTransform = (sep: string) => { 218 | let buffer = ''; 219 | 220 | const transform = new TransformStream({ 221 | transform: (chunk, controller) => { 222 | buffer += chunk; 223 | const parts = buffer.split(sep); 224 | parts.slice(0, -1).forEach(part => controller.enqueue(part)); 225 | buffer = parts[parts.length - 1]; 226 | }, 227 | flush: controller => { 228 | if (buffer) { 229 | controller.enqueue(buffer); 230 | } 231 | } 232 | }); 233 | 234 | return transform; 235 | }; 236 | 237 | /** 238 | * Parse the input stream as JSON 239 | * @returns TransformStream 240 | */ 241 | export const parseJSONTransform = () => { 242 | const transform = new TransformStream({ 243 | transform: (chunk, controller) => { 244 | controller.enqueue(JSON.parse(chunk as string)); 245 | } 246 | }); 247 | return transform; 248 | }; 249 | 250 | const timeitQueue = new Set(); 251 | /** 252 | * Trace the execution time 253 | * @param label Label for the time tracer 254 | * @param show Whether to printout the output in console 255 | */ 256 | export const timeit = (label: string, show: boolean) => { 257 | if (show) { 258 | if (timeitQueue.has(label)) { 259 | console.timeEnd(label); 260 | timeitQueue.delete(label); 261 | } else { 262 | console.time(label); 263 | timeitQueue.add(label); 264 | } 265 | } 266 | }; 267 | 268 | /** 269 | * Convert a color from rgb to hex 270 | * @param r Value in the red channel 271 | * @param g Value in the green channel 272 | * @param b Value in the blue channel 273 | * @returns Hex string 274 | */ 275 | export const rgbToHex = (r: number, g: number, b: number) => { 276 | const numToHex = (number: number) => { 277 | const hex = number.toString(16); 278 | if (hex.length == 1) { 279 | return `0${hex}`; 280 | } else { 281 | return hex; 282 | } 283 | }; 284 | return `#${numToHex(r)}${numToHex(g)}${numToHex(b)}`; 285 | }; 286 | 287 | interface Rect { 288 | x: number; 289 | y: number; 290 | width: number; 291 | height: number; 292 | } 293 | 294 | /** 295 | * Detect if two rectangles overlap. 296 | * https://stackoverflow.com/a/306332 297 | * 298 | * @param rect1 Rectangle 1 299 | * @param rect2 Rectangle 2 300 | * @returns True if these two rectangles overlap. 301 | */ 302 | export const rectsIntersect = (rect1: Rect, rect2: Rect) => { 303 | const right1 = rect1.x + rect1.width; 304 | const right2 = rect2.x + rect2.width; 305 | 306 | const bottom1 = rect1.y + rect1.height; 307 | const bottom2 = rect2.y + rect2.height; 308 | 309 | return ( 310 | rect1.x < right2 && 311 | right1 > rect2.x && 312 | rect1.y < bottom2 && 313 | bottom1 > rect2.y 314 | ); 315 | }; 316 | 317 | /** 318 | * Get a uniformly random sample from a list. 319 | * @param items Array of items to sample from 320 | * @param size Target size of the sample 321 | * @param seed Random seed (default to 1212) 322 | * @param replace True if sample with replace 323 | * @returns Sampled items 324 | */ 325 | export const getRandomSamples = ( 326 | items: Array, 327 | size: number, 328 | seed = 1212, 329 | replace = false 330 | ) => { 331 | const targetSize = Math.min(size, items.length); 332 | const threshold = targetSize / items.length; 333 | const randomUniform = d3.randomUniform.source(d3.randomLcg(seed))(0, 1); 334 | 335 | const sampledItems: Array = []; 336 | const sampledIndexes: Set = new Set(); 337 | 338 | // Repeat sampling until we have enough points sampled 339 | while (sampledItems.length < targetSize) { 340 | for (const [i, item] of items.entries()) { 341 | if ((replace || !sampledIndexes.has(i)) && randomUniform() <= threshold) { 342 | sampledIndexes.add(i); 343 | sampledItems.push(item); 344 | 345 | // Exit early if we have enough points 346 | if (sampledItems.length >= targetSize) break; 347 | } 348 | } 349 | } 350 | 351 | return sampledItems; 352 | }; 353 | 354 | /** 355 | * A helper function to break up a long function into multiple tasks 356 | * https://web.dev/optimize-long-tasks/ 357 | * @returns A promise equivalent to sleep(0) 358 | */ 359 | export const yieldToMain = () => { 360 | return new Promise(resolve => { 361 | setTimeout(resolve, 0); 362 | }); 363 | }; 364 | -------------------------------------------------------------------------------- /metadata/notebook-script.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import json 4 | import ast 5 | import _thread 6 | 7 | ### IDENTIFYING ALL INTERACTIVE NOTEBOOKS 8 | def getInteractiveNotebooks(directory): 9 | for filename in os.listdir(f"notebooks/{directory}"): 10 | try: 11 | if filename.endswith('.json'): 12 | with open(f"notebooks/{directory}/{filename}", 'r') as f: 13 | data = json.load(f) 14 | cells = data['cells'] 15 | for cell in cells: 16 | if 'outputs' not in cell: 17 | break 18 | outputs = cell['outputs'] 19 | for output in outputs: 20 | if output['output_type'] == 'display_data' or output['output_type'] == 'execute_result': 21 | data = output['data'] 22 | for key in data: 23 | if key == 'text/html': 24 | html = data[key] 25 | if '' in html: 26 | shutil.copy(f"notebooks/{directory}/{filename}", f"{directory}/script/{filename}") 27 | except Exception as e: 28 | print(f"Error {str(filename)}: {str(e)}") 29 | 30 | ### CONVERTING ALL INTERACTIVE NOTEBOOKS FROM JSON TO IPYNB 31 | def jsonToNotebook(directory): 32 | for filename in os.listdir(directory + '/script'): 33 | os.system(f"jupyter nbconvert --to notebook --inplace --ExecutePreprocessor.timeout=600 --output-dir={directory}/script-nb {directory}/script/{filename}") 34 | 35 | ### COUNTING THE NUMBER OF INTERACTIVE NOTEBOOKS 36 | def countInteractive(directory): 37 | countInteractive = len(os.listdir(directory + '/script')) // 2 38 | countTotal = len(os.listdir('notebooks/' + directory)) 39 | print("Number of interactive notebooks: " + str(countInteractive)) 40 | print("Total number of notebooks: " + str(countTotal)) 41 | print("Percentage of interactive notebooks: " + str((1.0 * countInteractive / countTotal) * 100) + "%") 42 | with open(f"{directory}/statistics.txt", 'w') as w: 43 | w.write("Number of interactive notebooks: " + str(countInteractive) + "\n") 44 | w.write("Total number of notebooks: " + str(countTotal) + "\n") 45 | w.write("Percentage of interactive notebooks: " + str((1.0 * countInteractive / countTotal) * 100) + "%") 46 | 47 | ### CONVERTING THE IPYNB FILES TO PYTHON FILES 48 | def notebookToPython(directory): 49 | if not os.path.exists(f"{directory}/script-py"): 50 | os.makedirs(f"{directory}/script-py") 51 | for filename in os.listdir(directory + '/script'): 52 | if filename.endswith('.ipynb'): 53 | os.system(f"jupyter nbconvert --to python --output-dir={directory}/script-py {directory}/script/{filename}") 54 | 55 | ### IDENTIFYING THE SOURCE CODE FOR INTERACTIVE CELLS 56 | def extractSourceCode(directory): 57 | if not os.path.exists(f"{directory}/script"): 58 | os.makedirs(f"{directory}/script") 59 | if not os.path.exists(f"{directory}/source"): 60 | os.makedirs(f"{directory}/source") 61 | for filename in os.listdir(f"notebooks/{directory}"): 62 | try: 63 | if filename.endswith('.json'): 64 | with open(f"notebooks/{directory}/{filename}", 'r') as f: 65 | data = json.load(f) 66 | cells = data['cells'] 67 | for cell in cells: 68 | found = False 69 | if 'outputs' not in cell: 70 | continue 71 | outputs = cell['outputs'] 72 | for output in outputs: 73 | if output['output_type'] == 'display_data' or output['output_type'] == 'execute_result': 74 | data = output['data'] 75 | for key in data: 76 | print(key) 77 | if key == 'text/html': 78 | html = ''.join(data[key]) 79 | if '/script' in html: 80 | found = True 81 | print("Found interactive: ", filename) 82 | shutil.copy(f"notebooks/{directory}/{filename}", f"{directory}/script/{filename}") 83 | if found: 84 | if 'source' in cell: 85 | source = ''.join(cell['source']) 86 | if len(source) > 0: 87 | with open(f"{directory}/source/{filename[:-5]}.py", 'w') as w: 88 | w.write(source) 89 | except Exception as e: 90 | print("Error " + str(filename) + ": " + str(e)) 91 | 92 | ### FOR ALL PYTHON FILES, WRITE A .TXT FILE OF THE IMPORTS 93 | def identifyImports(directory): 94 | if not os.path.exists(f"{directory}/imports"): 95 | os.makedirs(f"{directory}/imports") 96 | for filename in os.listdir(f"{directory}/script-py"): 97 | try: 98 | with open(f"{directory}/script-py/{filename}", 'r') as f: 99 | tree = ast.parse(f.read()) 100 | imports = [] 101 | for node in ast.walk(tree): 102 | if isinstance(node, ast.Import): 103 | for alias in node.names: 104 | imports.append(alias.name) 105 | if alias.asname is not None: 106 | imports.append(alias.asname) 107 | imports.append("ALIAS") 108 | if isinstance(node, ast.ImportFrom): 109 | for alias in node.names: 110 | if node.module is not None: 111 | imports.append(node.module) 112 | imports.append(alias.name) 113 | if node.module is not None: 114 | imports.append("ALIAS") 115 | imports.append("END") 116 | with open(f"{directory}/imports/{filename[:-3]}.txt", 'w') as w: 117 | for imp in imports: 118 | w.write(imp + '\n') 119 | except Exception as e: 120 | print(f"Error{str(filename)}: {str(e)} ") 121 | 122 | ### CHECK IF THE VARIABLE IN THE LAST LINE OF THE SOURCE CODE IS ONE OF THE IMPORTS 123 | def findModule(directory): 124 | if not os.path.exists(f"{directory}/source-imports"): 125 | os.makedirs(f"{directory}/source-imports") 126 | for filename in os.listdir(f"{directory}/source"): 127 | try: 128 | with open(f"{directory}/source/{filename}", 'r') as f: 129 | lines = [line.strip() for line in f.readlines()] 130 | lastLine = lines[-1] 131 | 132 | lastLine = lastLine.replace(')', '') 133 | lastLine = lastLine.replace(']', '') 134 | 135 | lastLine = lastLine.replace('.', ' ') 136 | lastLine = lastLine.replace(',', ' ') 137 | lastLine = lastLine.replace('(', ' ') 138 | lastLine = lastLine.replace('[', ' ') 139 | lastLine = lastLine.replace('=', ' ') 140 | 141 | lastLine = lastLine.split() 142 | print('LAST LINE: ', lastLine) 143 | 144 | filePrefix = filename[:-3] 145 | 146 | with open(f"{directory}/imports/{filePrefix}.txt", 'r') as r: 147 | imports = r.readlines() 148 | imports = [imp.strip() for imp in imports] 149 | print("IMPORTS: ", imports) 150 | for var in lastLine: 151 | var = var.strip() 152 | if var in imports: 153 | index = imports.index(var) 154 | if imports[index+1] == "ALIAS": 155 | module = imports[index-1] 156 | else: 157 | module = var 158 | with open(f"{directory}/source-imports/{filePrefix}.txt", 'w') as w: 159 | w.write(module) 160 | with open("all-modules.txt", 'a') as w: 161 | w.write(module + '\n') 162 | except Exception as e: 163 | print(f"Error{str(filename)}: {str(e)} ") 164 | 165 | ## GENERATE A SET OF ALL MODULES 166 | def generateModuleSet(): 167 | lines_seen = set() 168 | outfile = open("modules-set.txt", "w") 169 | for line in open("all-modules.txt", "r"): 170 | if line not in lines_seen: 171 | outfile.write(line) 172 | lines_seen.add(line) 173 | outfile.close() 174 | 175 | ## COUNT THE TOTAL NUMBER OF NOTEBOOKS 176 | def countTotalNotebooks(directories): 177 | total = 0 178 | for directory in directories: 179 | files = os.listdir(f"{directory}/source-imports") 180 | total += len(files) 181 | return total 182 | 183 | ## COUNT THE FREQUENCIES OF MODULES 184 | def countFrequencies(directories): 185 | modules = {} 186 | for directory in directories: 187 | for filename in os.listdir(f"{directory}/source-imports"): 188 | with open(f"{directory}/source-imports/{filename}", 'r') as f: 189 | module = f.readline().strip() 190 | if module in modules: 191 | modules[module] += 1 192 | else: 193 | modules[module] = 1 194 | modules = {k: v for k, v in sorted(modules.items(), key=lambda item: item[1], reverse=True)} 195 | with open("modules-frequencies.txt", 'w') as w: 196 | for module in modules: 197 | w.write(module + ": " + str(modules[module]) + '\n') 198 | 199 | directories = ["gh-1000000-1100000", "gh-1100000-1200000", "gh-1600000-1800000", "gh-24145-40000", "gh-40000000-500000000", "gh-5000000-8000000", "gh-8000000-11000000", "gh-100000-255623", "gh-1300000-1600000", "gh-1800000-2000000", "gh-255623-300000", "gh-400000-500000", "gh-500000-600000", "gh-9058-12000", "gh-1000-1475", "gh-14195-20000", "gh-20000000-30000000", "gh-3000-3187", "gh-40000-45539", "gh-6749-9000", "gh-11000000-15000000", "gh-1475-3000", "gh-2000000-5000000", "gh-3655-6000", "gh-45539-60000", "gh-79521-80000"] 200 | 201 | for directory in directories: 202 | try: 203 | print("Starting with directory: " + directory) 204 | shutil.copytree(f"/project/zwang3049/notebooks/{directory}", f"/nvmescratch/david/notebooks/{directory}") 205 | extractSourceCode(directory) 206 | jsonToNotebook(directory) 207 | countInteractive(directory) 208 | shutil.rmtree(f"notebooks/{directory}") 209 | notebookToPython(directory) 210 | identifyImports(directory) 211 | findModule(directory) 212 | except: 213 | pass 214 | 215 | generateModuleSet() 216 | 217 | countFrequencies(directories) 218 | --------------------------------------------------------------------------------