scitex 2.13.0__py3-none-any.whl → 2.15.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scitex/__init__.py +80 -2
- scitex/__version__.py +11 -8
- scitex/_env_loader.py +156 -0
- scitex/_mcp_resources/__init__.py +37 -0
- scitex/_mcp_resources/_cheatsheet.py +135 -0
- scitex/_mcp_resources/_figrecipe.py +138 -0
- scitex/_mcp_resources/_formats.py +102 -0
- scitex/_mcp_resources/_modules.py +337 -0
- scitex/_mcp_resources/_session.py +149 -0
- scitex/_mcp_tools/__init__.py +40 -0
- scitex/_mcp_tools/audio.py +200 -0
- scitex/_mcp_tools/canvas.py +128 -0
- scitex/_mcp_tools/capture.py +174 -0
- scitex/_mcp_tools/diagram.py +22 -0
- scitex/_mcp_tools/introspect.py +191 -0
- scitex/_mcp_tools/plt.py +305 -0
- scitex/_mcp_tools/scholar.py +447 -0
- scitex/_mcp_tools/social.py +244 -0
- scitex/_mcp_tools/stats.py +206 -0
- scitex/_mcp_tools/template.py +66 -0
- scitex/_mcp_tools/ui.py +80 -0
- scitex/_mcp_tools/writer.py +37 -0
- scitex/ai/_gen_ai/_PARAMS.py +10 -7
- scitex/ai/classification/reporters/_ClassificationReporter.py +0 -0
- scitex/ai/classification/reporters/_SingleClassificationReporter.py +45 -1603
- scitex/ai/classification/reporters/_mixins/__init__.py +36 -0
- scitex/ai/classification/reporters/_mixins/_constants.py +67 -0
- scitex/ai/classification/reporters/_mixins/_cv_summary.py +387 -0
- scitex/ai/classification/reporters/_mixins/_feature_importance.py +119 -0
- scitex/ai/classification/reporters/_mixins/_metrics.py +275 -0
- scitex/ai/classification/reporters/_mixins/_plotting.py +179 -0
- scitex/ai/classification/reporters/_mixins/_reports.py +153 -0
- scitex/ai/classification/reporters/_mixins/_storage.py +160 -0
- scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +0 -0
- scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +0 -0
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +0 -0
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +0 -0
- scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +0 -0
- scitex/ai/classification/timeseries/_normalize_timestamp.py +0 -0
- scitex/ai/metrics/_calc_seizure_prediction_metrics.py +0 -0
- scitex/ai/plt/_plot_feature_importance.py +0 -0
- scitex/ai/plt/_plot_learning_curve.py +0 -0
- scitex/ai/plt/_plot_optuna_study.py +0 -0
- scitex/ai/plt/_plot_pre_rec_curve.py +0 -0
- scitex/ai/plt/_plot_roc_curve.py +0 -0
- scitex/ai/plt/_stx_conf_mat.py +0 -0
- scitex/ai/training/_LearningCurveLogger.py +0 -0
- scitex/audio/README.md +88 -7
- scitex/audio/__init__.py +127 -60
- scitex/audio/__main__.py +17 -21
- scitex/audio/_branding.py +185 -0
- scitex/audio/_mcp/__init__.py +36 -0
- scitex/audio/_mcp/handlers.py +419 -0
- scitex/audio/_mcp/speak_handlers.py +238 -0
- scitex/audio/_mcp/tool_schemas.py +203 -0
- scitex/audio/_relay.py +225 -0
- scitex/audio/engines/elevenlabs_engine.py +6 -1
- scitex/audio/mcp_server.py +355 -337
- scitex/bridge/_figrecipe.py +40 -8
- scitex/bridge/_stats_plt.py +2 -4
- scitex/bridge/_stats_vis.py +7 -5
- scitex/browser/automation/CookieHandler.py +0 -0
- scitex/browser/collaboration/__init__.py +0 -1
- scitex/browser/core/BrowserMixin.py +0 -0
- scitex/browser/core/ChromeProfileManager.py +10 -3
- scitex/browser/debugging/_browser_logger.py +6 -9
- scitex/browser/debugging/_highlight_element.py +0 -0
- scitex/browser/debugging/_show_grid.py +0 -0
- scitex/browser/interaction/click_center.py +0 -0
- scitex/browser/interaction/click_with_fallbacks.py +0 -0
- scitex/browser/interaction/close_popups.py +0 -0
- scitex/browser/interaction/fill_with_fallbacks.py +0 -0
- scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +0 -0
- scitex/browser/pdf/detect_chrome_pdf_viewer.py +0 -0
- scitex/browser/stealth/HumanBehavior.py +0 -0
- scitex/browser/stealth/StealthManager.py +0 -0
- scitex/canvas/README.md +1 -1
- scitex/canvas/_mcp/__init__.py +4 -0
- scitex/canvas/_mcp/handlers.py +372 -0
- scitex/canvas/_mcp/tool_schemas.py +219 -0
- scitex/canvas/editor/_dearpygui/__init__.py +25 -0
- scitex/canvas/editor/_dearpygui/_editor.py +147 -0
- scitex/canvas/editor/_dearpygui/_handlers.py +476 -0
- scitex/canvas/editor/_dearpygui/_panels/__init__.py +17 -0
- scitex/canvas/editor/_dearpygui/_panels/_control.py +119 -0
- scitex/canvas/editor/_dearpygui/_panels/_element_controls.py +190 -0
- scitex/canvas/editor/_dearpygui/_panels/_preview.py +43 -0
- scitex/canvas/editor/_dearpygui/_panels/_sections.py +390 -0
- scitex/canvas/editor/_dearpygui/_plotting.py +187 -0
- scitex/canvas/editor/_dearpygui/_rendering.py +504 -0
- scitex/canvas/editor/_dearpygui/_selection.py +295 -0
- scitex/canvas/editor/_dearpygui/_state.py +93 -0
- scitex/canvas/editor/_dearpygui/_utils.py +61 -0
- scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
- scitex/canvas/mcp_server.py +2 -2
- scitex/capture/__init__.py +0 -1
- scitex/capture/_mcp/__init__.py +11 -0
- scitex/capture/_mcp/handlers.py +438 -0
- scitex/capture/_mcp/tool_schemas.py +270 -0
- scitex/cli/__init__.py +44 -2
- scitex/cli/audio.py +150 -3
- scitex/cli/browser.py +310 -0
- scitex/cli/capture.py +14 -3
- scitex/cli/introspect.py +443 -0
- scitex/cli/main.py +230 -103
- scitex/cli/mcp.py +362 -0
- scitex/cli/repro.py +18 -0
- scitex/cli/resource.py +18 -0
- scitex/cli/scholar/__init__.py +97 -0
- scitex/cli/scholar/_crossref_scitex.py +296 -0
- scitex/cli/scholar/_fetch.py +369 -0
- scitex/cli/scholar/_jobs.py +306 -0
- scitex/cli/scholar/_library.py +152 -0
- scitex/cli/scholar/_utils.py +35 -0
- scitex/cli/social.py +314 -0
- scitex/cli/stats.py +18 -0
- scitex/cli/template.py +18 -0
- scitex/cli/tex.py +18 -0
- scitex/cli/writer.py +190 -20
- scitex/compat/__init__.py +74 -0
- scitex/config/README.md +1 -1
- scitex/config/__init__.py +16 -2
- scitex/config/_env_registry.py +191 -0
- scitex/config/default.yaml +31 -0
- scitex/cv/__init__.py +87 -0
- scitex/cv/_draw.py +236 -0
- scitex/cv/_filters.py +217 -0
- scitex/cv/_io.py +157 -0
- scitex/cv/_transform.py +184 -0
- scitex/dev/__init__.py +2 -0
- scitex/dev/cv/__init__.py +60 -0
- scitex/dev/cv/_compose.py +330 -0
- scitex/dev/cv/_title_card.py +351 -0
- scitex/dev/plt/__init__.py +0 -0
- scitex/dev/plt/demo_plotters/__init__.py +0 -0
- scitex/dev/plt/mpl/get_dir_ax.py +0 -0
- scitex/dev/plt/mpl/get_signatures.py +0 -0
- scitex/dev/plt/mpl/get_signatures_details.py +0 -0
- scitex/diagram/__init__.py +42 -19
- scitex/diagram/mcp_server.py +13 -125
- scitex/dt/_normalize_timestamp.py +0 -0
- scitex/gen/__init__.py +0 -0
- scitex/gen/misc.py +0 -0
- scitex/git/_init.py +2 -2
- scitex/git/_session.py +0 -0
- scitex/introspect/__init__.py +75 -0
- scitex/introspect/_call_graph.py +303 -0
- scitex/introspect/_class_hierarchy.py +163 -0
- scitex/introspect/_core.py +42 -0
- scitex/introspect/_docstring.py +131 -0
- scitex/introspect/_examples.py +113 -0
- scitex/introspect/_imports.py +271 -0
- scitex/introspect/_mcp/__init__.py +37 -0
- scitex/introspect/_mcp/handlers.py +208 -0
- scitex/introspect/_members.py +151 -0
- scitex/introspect/_resolve.py +89 -0
- scitex/introspect/_signature.py +131 -0
- scitex/introspect/_source.py +80 -0
- scitex/introspect/_type_hints.py +172 -0
- scitex/io/bundle/README.md +1 -1
- scitex/io/bundle/kinds/__init__.py +0 -0
- scitex/io/bundle/kinds/_figure/__init__.py +0 -0
- scitex/io/bundle/kinds/_plot/__init__.py +0 -0
- scitex/io/bundle/kinds/_shape/__init__.py +0 -0
- scitex/io/bundle/kinds/_text/__init__.py +0 -0
- scitex/logging/_context.py +5 -4
- scitex/mcp_server.py +170 -145
- scitex/plt/__init__.py +249 -548
- scitex/plt/_figrecipe_integration.py +121 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +5 -10
- scitex/plt/_subplots/_FigWrapper.py +139 -88
- scitex/plt/_subplots/_export_as_csv_formatters/_format_pcolormesh.py +0 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stackplot.py +0 -0
- scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/plt/gallery/README.md +1 -1
- scitex/plt/styles/_plot_postprocess.py +35 -117
- scitex/plt/styles/_postprocess_helpers.py +158 -0
- scitex/plt/utils/_hitmap/__init__.py +82 -0
- scitex/plt/utils/_hitmap/_artist_extraction.py +343 -0
- scitex/plt/utils/_hitmap/_color_application.py +346 -0
- scitex/plt/utils/_hitmap/_color_conversion.py +121 -0
- scitex/plt/utils/_hitmap/_constants.py +40 -0
- scitex/plt/utils/_hitmap/_hitmap_core.py +334 -0
- scitex/plt/utils/_hitmap/_path_extraction.py +357 -0
- scitex/plt/utils/_hitmap/_query.py +113 -0
- scitex/plt/utils/_hitmap.py +46 -1616
- scitex/plt/utils/_metadata/__init__.py +80 -0
- scitex/plt/utils/_metadata/_artists/__init__.py +25 -0
- scitex/plt/utils/_metadata/_artists/_base.py +195 -0
- scitex/plt/utils/_metadata/_artists/_collections.py +356 -0
- scitex/plt/utils/_metadata/_artists/_extract.py +57 -0
- scitex/plt/utils/_metadata/_artists/_images.py +80 -0
- scitex/plt/utils/_metadata/_artists/_lines.py +261 -0
- scitex/plt/utils/_metadata/_artists/_patches.py +247 -0
- scitex/plt/utils/_metadata/_artists/_text.py +106 -0
- scitex/plt/utils/_metadata/_csv.py +416 -0
- scitex/plt/utils/_metadata/_detect.py +225 -0
- scitex/plt/utils/_metadata/_legend.py +127 -0
- scitex/plt/utils/_metadata/_rounding.py +117 -0
- scitex/plt/utils/_metadata/_verification.py +202 -0
- scitex/repro/_RandomStateManager.py +0 -0
- scitex/repro/_gen_ID.py +0 -0
- scitex/repro/_gen_timestamp.py +0 -0
- scitex/repro/_hash_array.py +0 -0
- scitex/schema/README.md +1 -1
- scitex/scholar/__init__.py +8 -0
- scitex/scholar/_mcp/__init__.py +4 -0
- scitex/scholar/_mcp/all_handlers.py +74 -0
- scitex/scholar/_mcp/crossref_handlers.py +265 -0
- scitex/scholar/_mcp/handlers.py +1478 -0
- scitex/scholar/_mcp/job_handlers.py +172 -0
- scitex/scholar/_mcp/job_tool_schemas.py +166 -0
- scitex/scholar/_mcp/tool_schemas.py +505 -0
- scitex/scholar/auth/core/BrowserAuthenticator.py +126 -9
- scitex/scholar/auth/providers/OpenAthensAuthenticator.py +55 -210
- scitex/scholar/auth/providers/_notifications.py +417 -0
- scitex/scholar/auth/sso/BaseSSOAutomator.py +36 -17
- scitex/scholar/auth/sso/UniversityOfMelbourneSSOAutomator.py +8 -15
- scitex/scholar/citation_graph/__init__.py +0 -1
- scitex/scholar/config/core/_PathManager.py +5 -1
- scitex/scholar/config/default.yaml +1 -1
- scitex/scholar/core/Paper.py +19 -41
- scitex/scholar/core/Scholar.py +64 -1688
- scitex/scholar/core/_mixins/__init__.py +36 -0
- scitex/scholar/core/_mixins/_enrichers.py +270 -0
- scitex/scholar/core/_mixins/_library_handlers.py +100 -0
- scitex/scholar/core/_mixins/_loaders.py +103 -0
- scitex/scholar/core/_mixins/_pdf_download.py +375 -0
- scitex/scholar/core/_mixins/_pipeline.py +312 -0
- scitex/scholar/core/_mixins/_project_handlers.py +125 -0
- scitex/scholar/core/_mixins/_savers.py +69 -0
- scitex/scholar/core/_mixins/_search.py +103 -0
- scitex/scholar/core/_mixins/_services.py +88 -0
- scitex/scholar/core/_mixins/_url_finding.py +105 -0
- scitex/scholar/core/journal_normalizer.py +36 -25
- scitex/scholar/crossref_scitex.py +367 -0
- scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/scholar/examples/00_run_all.sh +120 -0
- scitex/scholar/examples/07_storage_integration.py +0 -0
- scitex/scholar/impact_factor/estimation/__init__.py +0 -1
- scitex/scholar/impact_factor/jcr/ImpactFactorJCREngine.py +19 -6
- scitex/scholar/impact_factor/jcr/build_database.py +0 -0
- scitex/scholar/jobs/_Job.py +266 -0
- scitex/scholar/jobs/_JobManager.py +458 -0
- scitex/scholar/jobs/__init__.py +74 -0
- scitex/scholar/jobs/_errors.py +346 -0
- scitex/scholar/jobs/_executors.py +397 -0
- scitex/scholar/mcp_server.py +52 -2
- scitex/scholar/pdf_download/ScholarPDFDownloader.py +38 -416
- scitex/scholar/pdf_download/_cli.py +154 -0
- scitex/scholar/pdf_download/strategies/__init__.py +11 -8
- scitex/scholar/pdf_download/strategies/chrome_pdf_viewer.py +11 -11
- scitex/scholar/pdf_download/strategies/manual_download_fallback.py +80 -3
- scitex/scholar/pipelines/ScholarPipelineBibTeX.py +73 -121
- scitex/scholar/pipelines/ScholarPipelineParallel.py +83 -140
- scitex/scholar/pipelines/ScholarPipelineSearchParallel.py +11 -13
- scitex/scholar/pipelines/ScholarPipelineSingle.py +83 -656
- scitex/scholar/pipelines/_single_steps.py +465 -0
- scitex/scholar/storage/BibTeXHandler.py +71 -23
- scitex/scholar/storage/PaperIO.py +53 -18
- scitex/scholar/storage/_BibTeXValidator.py +571 -0
- scitex/scholar/storage/_LibraryManager.py +97 -1695
- scitex/scholar/storage/__init__.py +17 -3
- scitex/scholar/storage/_mixins/__init__.py +30 -0
- scitex/scholar/storage/_mixins/_bibtex_handlers.py +128 -0
- scitex/scholar/storage/_mixins/_library_operations.py +218 -0
- scitex/scholar/storage/_mixins/_metadata_conversion.py +226 -0
- scitex/scholar/storage/_mixins/_paper_saving.py +456 -0
- scitex/scholar/storage/_mixins/_resolution.py +376 -0
- scitex/scholar/storage/_mixins/_storage_helpers.py +121 -0
- scitex/scholar/storage/_mixins/_symlink_handlers.py +226 -0
- scitex/scholar/url_finder/translators/individual/cell_press.py +131 -4
- scitex/security/README.md +3 -3
- scitex/security/__init__.py +0 -1
- scitex/session/README.md +1 -1
- scitex/session/__init__.py +0 -0
- scitex/session/_decorator.py +0 -0
- scitex/session/_lifecycle.py +0 -0
- scitex/sh/README.md +1 -1
- scitex/social/__init__.py +153 -0
- scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/stats/__init__.py +14 -2
- scitex/stats/__main__.py +2 -2
- scitex/stats/_figrecipe_integration.py +116 -0
- scitex/stats/_mcp/__init__.py +4 -0
- scitex/stats/_mcp/handlers.py +1191 -0
- scitex/stats/_mcp/tool_schemas.py +384 -0
- scitex/stats/auto/__init__.py +0 -1
- scitex/stats/correct/_correct_bonferroni.py +0 -0
- scitex/stats/correct/_correct_fdr.py +0 -0
- scitex/stats/correct/_correct_fdr_.py +0 -0
- scitex/stats/correct/_correct_holm.py +0 -0
- scitex/stats/correct/_correct_sidak.py +0 -0
- scitex/stats/effect_sizes/_cliffs_delta.py +0 -0
- scitex/stats/effect_sizes/_cohens_d.py +0 -0
- scitex/stats/effect_sizes/_epsilon_squared.py +0 -0
- scitex/stats/effect_sizes/_eta_squared.py +0 -0
- scitex/stats/effect_sizes/_prob_superiority.py +0 -0
- scitex/stats/mcp_server.py +2 -2
- scitex/stats/posthoc/_dunnett.py +0 -0
- scitex/stats/posthoc/_games_howell.py +0 -0
- scitex/stats/posthoc/_tukey_hsd.py +0 -0
- scitex/stats/power/_power.py +0 -0
- scitex/stats/utils/_effect_size.py +0 -0
- scitex/stats/utils/_formatters.py +0 -0
- scitex/stats/utils/_power.py +0 -0
- scitex/template/README.md +1 -1
- scitex/template/_mcp/__init__.py +4 -0
- scitex/template/_mcp/handlers.py +259 -0
- scitex/template/_mcp/tool_schemas.py +112 -0
- scitex/template/clone_writer_directory.py +6 -6
- scitex/template/mcp_server.py +2 -2
- scitex/ui/__init__.py +173 -0
- scitex/ui/_backends/__init__.py +66 -0
- scitex/ui/_backends/_audio.py +86 -0
- scitex/ui/_backends/_config.py +250 -0
- scitex/ui/_backends/_desktop.py +184 -0
- scitex/ui/_backends/_emacs.py +210 -0
- scitex/ui/_backends/_email.py +78 -0
- scitex/ui/_backends/_matplotlib.py +118 -0
- scitex/ui/_backends/_playwright.py +109 -0
- scitex/ui/_backends/_types.py +58 -0
- scitex/ui/_backends/_webhook.py +77 -0
- scitex/ui/_backends.py +37 -0
- scitex/ui/_mcp/__init__.py +23 -0
- scitex/ui/_mcp/handlers.py +260 -0
- scitex/ui/_mcp/tool_schemas.py +107 -0
- scitex/ui/mcp_server.py +151 -0
- scitex/utils/_email.py +85 -7
- scitex/utils/_notify.py +16 -5
- scitex/utils/_search.py +11 -9
- scitex/utils/_verify_scitex_format.py +0 -0
- scitex/writer/README.md +1 -1
- scitex/writer/Writer.py +110 -111
- scitex/writer/__init__.py +26 -48
- scitex/writer/_clone_writer_project.py +0 -0
- scitex/writer/_compile/__init__.py +5 -4
- scitex/writer/_compile/_compile_async.py +130 -0
- scitex/writer/_compile/_compile_unified.py +148 -0
- scitex/writer/_compile/_runner.py +2 -2
- scitex/writer/_compile/_validator.py +3 -3
- scitex/writer/_compile/manuscript.py +1 -1
- scitex/writer/_compile/revision.py +1 -1
- scitex/writer/_compile/supplementary.py +1 -1
- scitex/writer/_dataclasses/config/_WriterConfig.py +175 -0
- scitex/writer/_dataclasses/contents/_ManuscriptContents.py +236 -0
- scitex/writer/_dataclasses/core/_Document.py +146 -0
- scitex/writer/_dataclasses/core/_DocumentSection.py +546 -0
- scitex/writer/_dataclasses/results/_CompilationResult.py +165 -0
- scitex/writer/_dataclasses/results/_LaTeXIssue.py +102 -0
- scitex/writer/_dataclasses/tree/MINIMUM_FILES.md +121 -0
- scitex/writer/_mcp/__init__.py +4 -0
- scitex/writer/_mcp/handlers.py +32 -0
- scitex/writer/_mcp/tool_schemas.py +33 -0
- scitex/writer/_project/_trees.py +2 -2
- scitex/writer/utils/__init__.py +19 -2
- scitex/writer/utils/_converters.py +635 -0
- scitex/writer/utils/_parse_latex_logs.py +1 -1
- scitex/writer/utils/_verify_tree_structure.py +205 -0
- scitex-2.15.1.dist-info/METADATA +648 -0
- scitex-2.15.1.dist-info/RECORD +2553 -0
- scitex-2.15.1.dist-info/entry_points.txt +12 -0
- scitex/audio/_mcp_handlers.py +0 -256
- scitex/audio/_mcp_tool_schemas.py +0 -203
- scitex/canvas/_mcp_handlers.py +0 -372
- scitex/canvas/_mcp_tool_schemas.py +0 -219
- scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
- scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
- scitex/capture/mcp_handlers.py +0 -401
- scitex/capture/mcp_tool_defs.py +0 -192
- scitex/capture/mcp_tools.py +0 -241
- scitex/capture/mcp_utils.py +0 -30
- scitex/cli/scholar.py +0 -313
- scitex/diagram/_compile.py +0 -312
- scitex/diagram/_diagram.py +0 -355
- scitex/diagram/_mcp_handlers.py +0 -400
- scitex/diagram/_mcp_tool_schemas.py +0 -157
- scitex/diagram/_presets.py +0 -173
- scitex/diagram/_schema.py +0 -182
- scitex/diagram/_split.py +0 -278
- scitex/plt/_mcp_handlers.py +0 -361
- scitex/plt/_mcp_tool_schemas.py +0 -169
- scitex/plt/mcp_server.py +0 -205
- scitex/scholar/.legacy/Scholar.py +0 -400
- scitex/scholar/.legacy/_Scholar.py +0 -1763
- scitex/scholar/.legacy/_ScholarAPI.py +0 -316
- scitex/scholar/.legacy/_tmp/search_engine/_BaseSearchEngine.py +0 -101
- scitex/scholar/.legacy/_tmp/search_engine/_UnifiedSearcher.py +0 -392
- scitex/scholar/.legacy/_tmp/search_engine/__init__.py +0 -53
- scitex/scholar/.legacy/_tmp/search_engine/local/_LocalSearchEngine.py +0 -134
- scitex/scholar/.legacy/_tmp/search_engine/local/_VectorSearchEngine.py +0 -129
- scitex/scholar/.legacy/_tmp/search_engine/web/_ArxivSearchEngine.py +0 -279
- scitex/scholar/.legacy/_tmp/search_engine/web/_CrossRefSearchEngine.py +0 -319
- scitex/scholar/.legacy/_tmp/search_engine/web/_GoogleScholarSearchEngine.py +0 -209
- scitex/scholar/.legacy/_tmp/search_engine/web/_PubMedSearchEngine.py +0 -374
- scitex/scholar/.legacy/_tmp/search_engine/web/_SemanticScholarSearchEngine.py +0 -362
- scitex/scholar/.legacy/database/README.md +0 -121
- scitex/scholar/.legacy/database/README_CONCURRENT_ACCESS.md +0 -103
- scitex/scholar/.legacy/database/_DatabaseEntry.py +0 -232
- scitex/scholar/.legacy/database/_DatabaseIndex.py +0 -426
- scitex/scholar/.legacy/database/_LibraryManager.py +0 -276
- scitex/scholar/.legacy/database/_PaperDatabase.py +0 -543
- scitex/scholar/.legacy/database/_ScholarDatabaseIntegration.py +0 -391
- scitex/scholar/.legacy/database/_StorageIntegratedDB.py +0 -619
- scitex/scholar/.legacy/database/_ZoteroCompatibleDB.py +0 -1194
- scitex/scholar/.legacy/database/__init__.py +0 -28
- scitex/scholar/.legacy/database/manage.py +0 -274
- scitex/scholar/.legacy/lookup/_LookupIndex.py +0 -470
- scitex/scholar/.legacy/lookup/__init__.py +0 -22
- scitex/scholar/.legacy/metadata/README.md +0 -62
- scitex/scholar/.legacy/metadata/__init__.py +0 -1
- scitex/scholar/.legacy/metadata/doi/README.md +0 -368
- scitex/scholar/.legacy/metadata/doi/__init__.py +0 -7
- scitex/scholar/.legacy/metadata/doi/batch/_MetadataHandlerForBatchDOIResolution.py +0 -304
- scitex/scholar/.legacy/metadata/doi/batch/_ProgressManagerForBatchDOIResolution.py +0 -304
- scitex/scholar/.legacy/metadata/doi/batch/_SourceStatsManagerForBatchDOIResolution.py +0 -299
- scitex/scholar/.legacy/metadata/doi/batch/__init__.py +0 -26
- scitex/scholar/.legacy/metadata/doi/resolvers/_BatchDOIResolver.py +0 -586
- scitex/scholar/.legacy/metadata/doi/resolvers/_BibTeXDOIResolver.py +0 -609
- scitex/scholar/.legacy/metadata/doi/resolvers/_DOIResolver.py +0 -192
- scitex/scholar/.legacy/metadata/doi/resolvers/_SingleDOIResolver.py +0 -395
- scitex/scholar/.legacy/metadata/doi/resolvers/__init__.py +0 -2
- scitex/scholar/.legacy/metadata/doi/sources/.combined-SemanticScholarSource/_SemanticScholarSource.py +0 -289
- scitex/scholar/.legacy/metadata/doi/sources/.combined-SemanticScholarSource/_SemanticScholarSourceEnhanced.py +0 -229
- scitex/scholar/.legacy/metadata/doi/sources/_ArXivSource.py +0 -306
- scitex/scholar/.legacy/metadata/doi/sources/_BaseDOISource.py +0 -347
- scitex/scholar/.legacy/metadata/doi/sources/_CrossRefLocalSource.py +0 -79
- scitex/scholar/.legacy/metadata/doi/sources/_CrossRefSource.py +0 -225
- scitex/scholar/.legacy/metadata/doi/sources/_OpenAlexSource.py +0 -306
- scitex/scholar/.legacy/metadata/doi/sources/_PubMedSource.py +0 -302
- scitex/scholar/.legacy/metadata/doi/sources/_SemanticScholarSource.py +0 -341
- scitex/scholar/.legacy/metadata/doi/sources/_SourceManager.py +0 -317
- scitex/scholar/.legacy/metadata/doi/sources/_SourceResolutionStrategy.py +0 -595
- scitex/scholar/.legacy/metadata/doi/sources/_SourceRotationManager.py +0 -585
- scitex/scholar/.legacy/metadata/doi/sources/_URLDOISource.py +0 -394
- scitex/scholar/.legacy/metadata/doi/sources/_UnifiedSource.py +0 -412
- scitex/scholar/.legacy/metadata/doi/sources/__init__.py +0 -38
- scitex/scholar/.legacy/metadata/doi/utils/_PubMedConverter.py +0 -465
- scitex/scholar/.legacy/metadata/doi/utils/_RateLimitHandler.py +0 -707
- scitex/scholar/.legacy/metadata/doi/utils/_TextNormalizer.py +0 -587
- scitex/scholar/.legacy/metadata/doi/utils/_URLDOIExtractor.py +0 -278
- scitex/scholar/.legacy/metadata/doi/utils/__init__.py +0 -40
- scitex/scholar/.legacy/metadata/doi/utils/_to_complete_metadata_structure.py +0 -315
- scitex/scholar/.legacy/metadata/enrichment/README.md +0 -51
- scitex/scholar/.legacy/metadata/enrichment/_LibraryEnricher.py +0 -99
- scitex/scholar/.legacy/metadata/enrichment/__init__.py +0 -2
- scitex/scholar/.legacy/metadata/enrichment/enrichers/_ImpactFactorEnricher.py +0 -107
- scitex/scholar/.legacy/metadata/enrichment/enrichers/_SmartEnricher.py +0 -164
- scitex/scholar/.legacy/metadata/enrichment/enrichers/__init__.py +0 -4
- scitex/scholar/.legacy/metadata/enrichment/sources/_UnifiedMetadataSource.py +0 -126
- scitex/scholar/.legacy/metadata/enrichment/sources/__init__.py +0 -3
- scitex/scholar/.legacy/metadata/query_to_full_meta_json.py +0 -184
- scitex/scholar/.legacy/metadata/urls/.tmp/open_url/KNOWN_RESOLVERS.py +0 -462
- scitex/scholar/.legacy/metadata/urls/.tmp/open_url/README.md +0 -223
- scitex/scholar/.legacy/metadata/urls/.tmp/open_url/_DOIToURLResolver.py +0 -694
- scitex/scholar/.legacy/metadata/urls/.tmp/open_url/_OpenURLResolver.py +0 -1160
- scitex/scholar/.legacy/metadata/urls/.tmp/open_url/_ResolverLinkFinder.py +0 -344
- scitex/scholar/.legacy/metadata/urls/.tmp/open_url/__init__.py +0 -24
- scitex/scholar/.legacy/metadata/urls/README.md +0 -142
- scitex/scholar/.legacy/metadata/urls/_URLMetadataHandler.py +0 -383
- scitex/scholar/.legacy/metadata/urls/_ZoteroTranslatorRunner.py +0 -294
- scitex/scholar/.legacy/metadata/urls/__init__.py +0 -39
- scitex/scholar/.legacy/metadata/urls/_finder.py +0 -319
- scitex/scholar/.legacy/metadata/urls/_handler.py +0 -326
- scitex/scholar/.legacy/metadata/urls/_resolver.py +0 -287
- scitex/scholar/.legacy/metadata/urls/docs/CORE_URL_TYPES.md +0 -187
- scitex/scholar/.legacy/metadata/urls/docs/URL_SCHEMA.md +0 -223
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/.eslintrc +0 -11
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/AGPL +0 -22
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/checkDeletedTxt.sh +0 -46
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/eslint-plugin-zotero-translator/bin/teslint.js +0 -9
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/eslint-plugin-zotero-translator/index.js +0 -15
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/eslint-plugin-zotero-translator/package-lock.json +0 -151
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/eslint-plugin-zotero-translator/package.json +0 -21
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/eslint-plugin-zotero-translator/processor.js +0 -257
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/helper.sh +0 -29
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/lint.sh +0 -12
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/pull-request-check/check-pull-request.sh +0 -39
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/pull-request-check/selenium-test.js +0 -147
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/pull-request-check/translator-server.js +0 -72
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.ci/updateTypes.mjs +0 -75
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.editorconfig +0 -8
- scitex/scholar/.legacy/metadata/urls/zotero_translators/.eslintrc +0 -70
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ABC News Australia.js +0 -224
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ACLS Humanities EBook.js +0 -165
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ACLWeb.js +0 -600
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ACM Digital Library.js +0 -710
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ACS Publications.js +0 -633
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ADS Bibcode.js +0 -664
- scitex/scholar/.legacy/metadata/urls/zotero_translators/AEA Web.js +0 -450
- scitex/scholar/.legacy/metadata/urls/zotero_translators/AGRIS.js +0 -311
- scitex/scholar/.legacy/metadata/urls/zotero_translators/AIP.js +0 -295
- scitex/scholar/.legacy/metadata/urls/zotero_translators/AMS Journals.js +0 -136
- scitex/scholar/.legacy/metadata/urls/zotero_translators/AMS MathSciNet (Legacy).js +0 -313
- scitex/scholar/.legacy/metadata/urls/zotero_translators/AMS MathSciNet.js +0 -288
- scitex/scholar/.legacy/metadata/urls/zotero_translators/APA PsycNET.js +0 -915
- scitex/scholar/.legacy/metadata/urls/zotero_translators/APN.ru.js +0 -132
- scitex/scholar/.legacy/metadata/urls/zotero_translators/APS-Physics.js +0 -204
- scitex/scholar/.legacy/metadata/urls/zotero_translators/APS.js +0 -542
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ARTFL Encyclopedie.js +0 -283
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ARTnews.js +0 -155
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ARTstor.js +0 -619
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ASCE.js +0 -199
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ASCO Meeting Library.js +0 -153
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ASTIS.js +0 -337
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ATS International Journal.js +0 -290
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Access Engineering.js +0 -384
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Access Medicine.js +0 -343
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Access Science.js +0 -391
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Adam Matthew Digital.js +0 -405
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Agencia del ISBN.js +0 -77
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Ahval News.js +0 -309
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Air University Journals.js +0 -236
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Airiti.js +0 -423
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Alexander Street Press.js +0 -198
- scitex/scholar/.legacy/metadata/urls/zotero_translators/AllAfrica.js +0 -291
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Alsharekh.js +0 -242
- scitex/scholar/.legacy/metadata/urls/zotero_translators/AlterNet.js +0 -134
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Aluka.js +0 -261
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Amazon.js +0 -1043
- scitex/scholar/.legacy/metadata/urls/zotero_translators/American Archive of Public Broadcasting.js +0 -592
- scitex/scholar/.legacy/metadata/urls/zotero_translators/American Institute of Aeronautics and Astronautics.js +0 -210
- scitex/scholar/.legacy/metadata/urls/zotero_translators/American Prospect.js +0 -114
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Ancestry.com US Federal Census.js +0 -164
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Annual Reviews.js +0 -329
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Antikvarium.hu.js +0 -280
- scitex/scholar/.legacy/metadata/urls/zotero_translators/AquaDocs.js +0 -390
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Archeion.js +0 -249
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Archiv fuer Sozialgeschichte.js +0 -157
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Archive Ouverte en Sciences de l'Information et de la Communication (AOSIC).js +0 -179
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Archives Canada.js +0 -142
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Ariana News.js +0 -203
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Art Institute of Chicago.js +0 -279
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Artefacts Canada.js +0 -192
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Artforum.js +0 -438
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Atlanta Journal-Constitution.js +0 -311
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Atypon Journals.js +0 -1204
- scitex/scholar/.legacy/metadata/urls/zotero_translators/AustLII and NZLII.js +0 -604
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Australian Dictionary of Biography.js +0 -196
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BAILII.js +0 -176
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BBC Genome.js +0 -254
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BBC.js +0 -430
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BIBSYS.js +0 -112
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BOCC.js +0 -217
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BOE.js +0 -229
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BOFiP-Impots.js +0 -132
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Baidu Scholar.js +0 -276
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bangkok Post.js +0 -216
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Baruch Foundation.js +0 -175
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Beobachter.js +0 -175
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bezneng Gajit.js +0 -92
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BibLaTeX.js +0 -888
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BibTeX.js +0 -4236
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Biblio.com.js +0 -216
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bibliontology RDF.js +0 -1166
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Biblioteca Nacional de Maestros.js +0 -213
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bibliotheque et Archives Nationale du Quebec (Pistard).js +0 -147
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bibliotheque et Archives Nationales du Quebec.js +0 -266
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bibliotheque nationale de France.js +0 -872
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BioMed Central.js +0 -585
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BioOne.js +0 -233
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bioconductor.js +0 -343
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Blaetter.js +0 -192
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Blogger.js +0 -244
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bloomberg.js +0 -205
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bloomsbury Food Library.js +0 -296
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bluesky.js +0 -195
- scitex/scholar/.legacy/metadata/urls/zotero_translators/BnF ISBN.js +0 -129
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bookmarks.js +0 -282
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bookshop.org.js +0 -223
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Boston Review.js +0 -332
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bosworth Toller's Anglo-Saxon Dictionary Online.js +0 -496
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bracero History Archive.js +0 -200
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Brill.js +0 -434
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Brukerhandboken.js +0 -153
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bryn Mawr Classical Review.js +0 -303
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Bundesgesetzblatt.js +0 -231
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Business Standard.js +0 -151
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CABI - CAB Abstracts.js +0 -317
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CAOD.js +0 -260
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CBC.js +0 -439
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CCfr (BnF).js +0 -162
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CERN Document Server.js +0 -277
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CEUR Workshop Proceedings.js +0 -145
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CFF References.js +0 -170
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CFF.js +0 -113
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CIA World Factbook.js +0 -128
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CLACSO.js +0 -226
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CLASE.js +0 -135
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CNKI.js +0 -731
- scitex/scholar/.legacy/metadata/urls/zotero_translators/COBISS.js +0 -1945
- scitex/scholar/.legacy/metadata/urls/zotero_translators/COinS.js +0 -336
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CQ Press.js +0 -418
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CROSBI.js +0 -227
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CSIRO Publishing.js +0 -139
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CSL JSON.js +0 -203
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CSV.js +0 -294
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Cairn.info.js +0 -368
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CalMatters.js +0 -228
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Calisphere.js +0 -355
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Camara Brasileira do Livro ISBN.js +0 -842
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Cambridge Core.js +0 -580
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Cambridge Engage Preprints.js +0 -276
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CanLII.js +0 -284
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Canada.com.js +0 -171
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Canadian Letters and Images.js +0 -148
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Canadiana.ca.js +0 -196
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Cascadilla Proceedings Project.js +0 -390
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Cell Press.js +0 -516
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Central and Eastern European Online Library Journals.js +0 -313
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Champlain Society - Collection.js +0 -220
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Chicago Journal of Theoretical Computer Science.js +0 -203
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Christian Science Monitor.js +0 -148
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Chronicling America.js +0 -131
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CiNii Research.js +0 -168
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Citavi 5 XML.js +0 -516
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CiteSeer.js +0 -196
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Citizen Lab.js +0 -347
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Civilization.ca.js +0 -146
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Climate Change and Human Health Literature Portal.js +0 -283
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Clinical Key.js +0 -367
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Code4Lib Journal.js +0 -143
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Colorado State Legislature.js +0 -215
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Columbia University Press.js +0 -238
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Common-Place.js +0 -218
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Computer History Museum Archive.js +0 -1319
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Copernicus.js +0 -461
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Cornell LII.js +0 -252
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Cornell University Press.js +0 -235
- scitex/scholar/.legacy/metadata/urls/zotero_translators/CourtListener.js +0 -265
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Crossref REST.js +0 -1757
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Crossref Unixref XML.js +0 -965
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Current Affairs.js +0 -160
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DABI.js +0 -476
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DAI-Zenon.js +0 -392
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DART-Europe.js +0 -176
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DBLP Computer Science Bibliography.js +0 -462
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DBpia.js +0 -233
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DEPATISnet.js +0 -373
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DOAJ.js +0 -242
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DOI Content Negotiation.js +0 -352
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DOI.js +0 -322
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DPLA.js +0 -425
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DSpace Intermediate Metadata.js +0 -208
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Dagens Nyheter.js +0 -369
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Dagstuhl Research Online Publication Server.js +0 -278
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Dar Almandumah.js +0 -253
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Data.gov.js +0 -225
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Databrary.js +0 -184
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Datacite JSON.js +0 -1182
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Dataverse.js +0 -418
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Daum News.js +0 -139
- scitex/scholar/.legacy/metadata/urls/zotero_translators/De Gruyter Brill.js +0 -674
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Defense Technical Information Center.js +0 -146
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Delpher.js +0 -413
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Demographic Research.js +0 -164
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Denik CZ.js +0 -273
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Der Freitag.js +0 -236
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Der Spiegel.js +0 -479
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Desiring God.js +0 -216
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Deutsche Fotothek.js +0 -364
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Deutsche Nationalbibliothek.js +0 -594
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Dialnet.js +0 -258
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Die Zeit.js +0 -378
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DigiZeitschriften.js +0 -269
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Digital Humanities Quarterly.js +0 -207
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Digital Spy.js +0 -215
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Dimensions.js +0 -233
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Douban.js +0 -316
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Dreier Neuerscheinungsdienst.js +0 -209
- scitex/scholar/.legacy/metadata/urls/zotero_translators/DrugBank.ca.js +0 -209
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Dryad Digital Repository.js +0 -323
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Duke University Press Books.js +0 -250
- scitex/scholar/.legacy/metadata/urls/zotero_translators/E-periodica Switzerland.js +0 -347
- scitex/scholar/.legacy/metadata/urls/zotero_translators/EBSCO Discovery Layer.js +0 -147
- scitex/scholar/.legacy/metadata/urls/zotero_translators/EBSCOhost.js +0 -592
- scitex/scholar/.legacy/metadata/urls/zotero_translators/EIDR.js +0 -184
- scitex/scholar/.legacy/metadata/urls/zotero_translators/EPA National Library Catalog.js +0 -245
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ERIC.js +0 -986
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ESpacenet.js +0 -465
- scitex/scholar/.legacy/metadata/urls/zotero_translators/EUR-Lex.js +0 -423
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Eastview.js +0 -336
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Edinburgh University Press Journals.js +0 -178
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Education Week.js +0 -197
- scitex/scholar/.legacy/metadata/urls/zotero_translators/El Comercio (Peru).js +0 -347
- scitex/scholar/.legacy/metadata/urls/zotero_translators/El Pais.js +0 -262
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Electronic Colloquium on Computational Complexity.js +0 -230
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Elicit.js +0 -120
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Elsevier Health Journals.js +0 -531
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Elsevier Pure.js +0 -420
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Embedded Metadata.js +0 -1951
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Emerald Insight.js +0 -626
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Encyclopedia of Chicago.js +0 -162
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Encyclopedia of Korean Culture.js +0 -221
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Endnote XML.js +0 -1407
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Engineering Village.js +0 -139
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Envidat.js +0 -331
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Epicurious.js +0 -144
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Erudit.js +0 -272
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Euclid.js +0 -220
- scitex/scholar/.legacy/metadata/urls/zotero_translators/EurasiaNet.js +0 -109
- scitex/scholar/.legacy/metadata/urls/zotero_translators/EurogamerUSgamer.js +0 -380
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Europe PMC.js +0 -448
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Evernote.js +0 -104
- scitex/scholar/.legacy/metadata/urls/zotero_translators/F1000 Research.js +0 -655
- scitex/scholar/.legacy/metadata/urls/zotero_translators/FAO Publications.js +0 -1139
- scitex/scholar/.legacy/metadata/urls/zotero_translators/FAZ.NET.js +0 -231
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Fachportal Padagogik.js +0 -839
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Factiva.js +0 -302
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Failed Architecture.js +0 -114
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Fairfax Australia.js +0 -200
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Fatcat.js +0 -425
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Figshare.js +0 -191
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Financial Times.js +0 -187
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Finna.js +0 -357
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Flickr.js +0 -318
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Foreign Affairs.js +0 -485
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Foreign Policy.js +0 -146
- scitex/scholar/.legacy/metadata/urls/zotero_translators/FreeCite.js +0 -95
- scitex/scholar/.legacy/metadata/urls/zotero_translators/FreePatentsOnline.js +0 -265
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Frieze.js +0 -243
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Frontiers.js +0 -667
- scitex/scholar/.legacy/metadata/urls/zotero_translators/GMS German Medical Science.js +0 -319
- scitex/scholar/.legacy/metadata/urls/zotero_translators/GPO Access e-CFR.js +0 -134
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Gale Databases.js +0 -324
- scitex/scholar/.legacy/metadata/urls/zotero_translators/GaleGDC.js +0 -189
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Galegroup.js +0 -327
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Gallica.js +0 -194
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Game Studies.js +0 -155
- scitex/scholar/.legacy/metadata/urls/zotero_translators/GameSpot.js +0 -199
- scitex/scholar/.legacy/metadata/urls/zotero_translators/GameStar GamePro.js +0 -198
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Gasyrlar Awazy.js +0 -156
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Gemeinsamer Bibliotheksverbund ISBN.js +0 -23
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Gene Ontology.js +0 -128
- scitex/scholar/.legacy/metadata/urls/zotero_translators/GitHub.js +0 -501
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Globes.js +0 -243
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Gmail.js +0 -64
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Goodreads.js +0 -219
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Google Books.js +0 -552
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Google Patents.js +0 -959
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Google Play.js +0 -186
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Google Presentation.js +0 -104
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Google Research.js +0 -221
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Google Scholar.js +0 -1361
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Gulag Many Days, Many Lives.js +0 -179
- scitex/scholar/.legacy/metadata/urls/zotero_translators/HAL Archives Ouvertes.js +0 -429
- scitex/scholar/.legacy/metadata/urls/zotero_translators/HCSP.js +0 -312
- scitex/scholar/.legacy/metadata/urls/zotero_translators/HUDOC.js +0 -650
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Haaretz.js +0 -562
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Habr.js +0 -232
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Handelszeitung.js +0 -273
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Hanrei Watch.js +0 -123
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Harper's Magazine.js +0 -365
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Harvard Business Review.js +0 -326
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Harvard Caselaw Access Project.js +0 -244
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Harvard University Press Books.js +0 -286
- scitex/scholar/.legacy/metadata/urls/zotero_translators/HathiTrust.js +0 -311
- scitex/scholar/.legacy/metadata/urls/zotero_translators/HeinOnline.js +0 -266
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Heise.js +0 -200
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Herder.js +0 -236
- scitex/scholar/.legacy/metadata/urls/zotero_translators/HighBeam.js +0 -198
- scitex/scholar/.legacy/metadata/urls/zotero_translators/HighWire 2.0.js +0 -1355
- scitex/scholar/.legacy/metadata/urls/zotero_translators/HighWire.js +0 -209
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Hindawi Publishers.js +0 -177
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Hispanic-American Periodical Index.js +0 -236
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Homeland Security Digital Library.js +0 -426
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Huff Post.js +0 -223
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Human Rights Watch.js +0 -450
- scitex/scholar/.legacy/metadata/urls/zotero_translators/IBISWorld.js +0 -171
- scitex/scholar/.legacy/metadata/urls/zotero_translators/IDEA ALM.js +0 -536
- scitex/scholar/.legacy/metadata/urls/zotero_translators/IEEE Computer Society.js +0 -429
- scitex/scholar/.legacy/metadata/urls/zotero_translators/IEEE Xplore.js +0 -1000
- scitex/scholar/.legacy/metadata/urls/zotero_translators/IETF.js +0 -451
- scitex/scholar/.legacy/metadata/urls/zotero_translators/IGN.js +0 -136
- scitex/scholar/.legacy/metadata/urls/zotero_translators/IMDb.js +0 -566
- scitex/scholar/.legacy/metadata/urls/zotero_translators/INSPIRE.js +0 -247
- scitex/scholar/.legacy/metadata/urls/zotero_translators/IPCC.js +0 -757
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ISTC.js +0 -181
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Idref.js +0 -179
- scitex/scholar/.legacy/metadata/urls/zotero_translators/In These Times.js +0 -196
- scitex/scholar/.legacy/metadata/urls/zotero_translators/InfoTrac.js +0 -279
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Informationssystem Medienpaedagogik.js +0 -305
- scitex/scholar/.legacy/metadata/urls/zotero_translators/IngentaConnect.js +0 -312
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Inside Higher Ed.js +0 -167
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Insignia OPAC.js +0 -114
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Institute of Contemporary Art.js +0 -180
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Institute of Physics.js +0 -340
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Integrum.js +0 -173
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Intellixir.js +0 -264
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Inter-Research Science Center.js +0 -185
- scitex/scholar/.legacy/metadata/urls/zotero_translators/International Nuclear Information System.js +0 -285
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Internet Archive Scholar.js +0 -106
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Internet Archive Wayback Machine.js +0 -152
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Internet Archive.js +0 -552
- scitex/scholar/.legacy/metadata/urls/zotero_translators/InvenioRDM.js +0 -1260
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Isidore.js +0 -235
- scitex/scholar/.legacy/metadata/urls/zotero_translators/J-Stage.js +0 -272
- scitex/scholar/.legacy/metadata/urls/zotero_translators/JETS.js +0 -122
- scitex/scholar/.legacy/metadata/urls/zotero_translators/JISC Historical Texts.js +0 -273
- scitex/scholar/.legacy/metadata/urls/zotero_translators/JRC Publications Repository.js +0 -569
- scitex/scholar/.legacy/metadata/urls/zotero_translators/JSTOR.js +0 -821
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Jahrbuch.js +0 -213
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Japan Times Online.js +0 -138
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Journal of Electronic Publishing.js +0 -147
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Journal of Extension.js +0 -288
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Journal of Machine Learning Research.js +0 -441
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Journal of Religion and Society.js +0 -174
- scitex/scholar/.legacy/metadata/urls/zotero_translators/JurPC.js +0 -274
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Juricaf.js +0 -141
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Juris.js +0 -728
- scitex/scholar/.legacy/metadata/urls/zotero_translators/K10plus ISBN.js +0 -386
- scitex/scholar/.legacy/metadata/urls/zotero_translators/KStudy.js +0 -632
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Kanopy.js +0 -358
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Khaama Press.js +0 -249
- scitex/scholar/.legacy/metadata/urls/zotero_translators/KitapYurdu.com.js +0 -376
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Kommersant.js +0 -174
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Korean National Library.js +0 -621
- scitex/scholar/.legacy/metadata/urls/zotero_translators/L'Annee Philologique.js +0 -267
- scitex/scholar/.legacy/metadata/urls/zotero_translators/LA Times.js +0 -239
- scitex/scholar/.legacy/metadata/urls/zotero_translators/LIBRIS ISBN.js +0 -103
- scitex/scholar/.legacy/metadata/urls/zotero_translators/LIVIVO.js +0 -260
- scitex/scholar/.legacy/metadata/urls/zotero_translators/LWN.net.js +0 -315
- scitex/scholar/.legacy/metadata/urls/zotero_translators/La Croix.js +0 -237
- scitex/scholar/.legacy/metadata/urls/zotero_translators/La Nacion (Argentina).js +0 -231
- scitex/scholar/.legacy/metadata/urls/zotero_translators/La Presse.js +0 -218
- scitex/scholar/.legacy/metadata/urls/zotero_translators/La Republica (Peru).js +0 -174
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Lagen.nu.js +0 -214
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Landesbibliographie Baden-Wurttemberg.js +0 -324
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Lapham's Quarterly.js +0 -1062
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Le Devoir.js +0 -167
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Le Figaro.js +0 -225
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Le Maitron.js +0 -484
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Le Monde.js +0 -258
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Le monde diplomatique.js +0 -200
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Legifrance.js +0 -641
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Legislative Insight.js +0 -406
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Lexis+.js +0 -264
- scitex/scholar/.legacy/metadata/urls/zotero_translators/LexisNexis.js +0 -505
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Libraries Tasmania.js +0 -778
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Aleph).js +0 -385
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Amicus).js +0 -254
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Aquabrowser).js +0 -253
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (BiblioCommons).js +0 -249
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Blacklight).js +0 -341
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Capita Prism).js +0 -162
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (DRA).js +0 -203
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Dynix).js +0 -315
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Encore).js +0 -211
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (InnoPAC).js +0 -305
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Koha).js +0 -225
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Mango).js +0 -285
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (OPALS).js +0 -200
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (PICA).js +0 -2120
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (PICA2).js +0 -331
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Pika).js +0 -488
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Polaris).js +0 -183
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Quolto).js +0 -320
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (RERO ILS).js +0 -754
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (SIRSI eLibrary).js +0 -407
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (SIRSI).js +0 -452
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (SLIMS).js +0 -146
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (TIND ILS).js +0 -773
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (TLCYouSeeMore).js +0 -132
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (TinREAD).js +0 -277
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (VTLS).js +0 -125
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Visual Library 2021).js +0 -765
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Voyager 7).js +0 -199
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Catalog (Voyager).js +0 -212
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Genesis.js +0 -337
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library Hub Discover.js +0 -359
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library of Congress Digital Collections.js +0 -869
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Library of Congress ISBN.js +0 -86
- scitex/scholar/.legacy/metadata/urls/zotero_translators/LingBuzz.js +0 -359
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Lippincott Williams and Wilkins.js +0 -341
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Literary Hub.js +0 -950
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Litres.js +0 -236
- scitex/scholar/.legacy/metadata/urls/zotero_translators/LiveJournal.js +0 -219
- scitex/scholar/.legacy/metadata/urls/zotero_translators/London Review of Books.js +0 -291
- scitex/scholar/.legacy/metadata/urls/zotero_translators/LookUs.js +0 -260
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Lulu.js +0 -264
- scitex/scholar/.legacy/metadata/urls/zotero_translators/MAB2.js +0 -373
- scitex/scholar/.legacy/metadata/urls/zotero_translators/MARC.js +0 -1080
- scitex/scholar/.legacy/metadata/urls/zotero_translators/MARCXML.js +0 -489
- scitex/scholar/.legacy/metadata/urls/zotero_translators/MCV.js +0 -258
- scitex/scholar/.legacy/metadata/urls/zotero_translators/MDPI Journals.js +0 -356
- scitex/scholar/.legacy/metadata/urls/zotero_translators/MEDLINEnbib.js +0 -1561
- scitex/scholar/.legacy/metadata/urls/zotero_translators/METS.js +0 -384
- scitex/scholar/.legacy/metadata/urls/zotero_translators/MIDAS Journals.js +0 -343
- scitex/scholar/.legacy/metadata/urls/zotero_translators/MIT Press Books.js +0 -637
- scitex/scholar/.legacy/metadata/urls/zotero_translators/MODS.js +0 -2545
- scitex/scholar/.legacy/metadata/urls/zotero_translators/MPG PuRe.js +0 -541
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Mailman.js +0 -136
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Mainichi Daily News.js +0 -189
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Mastodon.js +0 -198
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Matbugat.ru.js +0 -110
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Max Planck Institute for the History of Science Virtual Laboratory Library.js +0 -136
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Medium.js +0 -208
- scitex/scholar/.legacy/metadata/urls/zotero_translators/MetaLib.js +0 -126
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Microbiology Society Journals.js +0 -343
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Microsoft Academic.js +0 -424
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Mikromarc.js +0 -207
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Milli Kutuphane.js +0 -244
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Musee du Louvre.js +0 -265
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NASA ADS.js +0 -889
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NASA NTRS.js +0 -610
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NCBI Nucleotide.js +0 -227
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NPR.js +0 -341
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NRC Research Press.js +0 -181
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NRC.nl.js +0 -226
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NTSB Accident Reports.js +0 -226
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NYPL Menus.js +0 -275
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NYPL Research Catalog.js +0 -458
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NYTimes.com.js +0 -858
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NZZ.ch.js +0 -272
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Nagoya University OPAC.js +0 -336
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Academies Press.js +0 -243
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Agriculture Library.js +0 -524
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Archives of Australia.js +0 -522
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Archives of South Africa.js +0 -122
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Bureau of Economic Research.js +0 -363
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Diet Library Catalogue.js +0 -333
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Gallery of Art - USA.js +0 -149
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Gallery of Australia.js +0 -252
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Library of Australia (new catalog).js +0 -223
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Library of Belarus.js +0 -171
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Library of Norway.js +0 -310
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Library of Poland ISBN.js +0 -140
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Post.js +0 -186
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Technical Reports Library.js +0 -276
- scitex/scholar/.legacy/metadata/urls/zotero_translators/National Transportation Library ROSA P.js +0 -562
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Nature Publishing Group.js +0 -3394
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Neural Information Processing Systems.js +0 -385
- scitex/scholar/.legacy/metadata/urls/zotero_translators/New Left Review.js +0 -245
- scitex/scholar/.legacy/metadata/urls/zotero_translators/New Zealand Herald.js +0 -282
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Newlines Magazine.js +0 -190
- scitex/scholar/.legacy/metadata/urls/zotero_translators/News Corp Australia.js +0 -251
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NewsBank.js +0 -202
- scitex/scholar/.legacy/metadata/urls/zotero_translators/NewsnetTamedia.js +0 -509
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Noor Digital Library.js +0 -267
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Note HTML.js +0 -206
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Note Markdown.js +0 -1638
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Notre Dame Philosophical Reviews.js +0 -201
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OAPEN.js +0 -331
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OCLC WorldCat FirstSearch.js +0 -213
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OECD.js +0 -216
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ORCID.js +0 -104
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OSF Preprints.js +0 -417
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OSTI Energy Citations.js +0 -202
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OVID Tagged.js +0 -1226
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OZON.ru.js +0 -465
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OhioLINK.js +0 -43
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Old Bailey Online.js +0 -315
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Open Conf.js +0 -172
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Open Knowledge Repository.js +0 -811
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Open WorldCat.js +0 -1401
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OpenAlex JSON.js +0 -740
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OpenAlex.js +0 -444
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OpenEdition Books.js +0 -155
- scitex/scholar/.legacy/metadata/urls/zotero_translators/OpenEdition Journals.js +0 -432
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Optical Society of America.js +0 -562
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Optimization Online.js +0 -418
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Ovid.js +0 -302
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Oxford Dictionaries Premium.js +0 -194
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Oxford English Dictionary.js +0 -122
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Oxford Music and Art Online.js +0 -120
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Oxford Reference.js +0 -202
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Oxford University Press.js +0 -277
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PC Gamer.js +0 -302
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PC Games.js +0 -128
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PEI Archival Information Network.js +0 -242
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PEP Web.js +0 -165
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PKP Catalog Systems.js +0 -1455
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PLoS Journals.js +0 -284
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PRC History Review.js +0 -298
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Pajhwok Afghan News.js +0 -198
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Papers Past.js +0 -297
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Paris Review.js +0 -227
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Pastebin.js +0 -199
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Patents - USPTO.js +0 -210
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Peeters.js +0 -587
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Perceiving Systems.js +0 -350
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Perlego.js +0 -416
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PhilPapers.js +0 -249
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Philosopher's Imprint.js +0 -169
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Pleade.js +0 -329
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Polygon.js +0 -270
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Potsdamer Neueste Nachrichten.js +0 -188
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Preprints.org.js +0 -305
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Primo 2018.js +0 -126
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Primo Normalized XML.js +0 -987
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Primo.js +0 -322
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ProMED.js +0 -66
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ProQuest Ebook Central.js +0 -226
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ProQuest PolicyFile.js +0 -115
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ProQuest.js +0 -2210
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Probing the Past.js +0 -151
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Project Gutenberg.js +0 -191
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Project MUSE.js +0 -451
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Protein Data Bank.js +0 -445
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PubFactory Journals.js +0 -712
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PubMed Central.js +0 -577
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PubMed XML.js +0 -1139
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PubMed.js +0 -1317
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PubPub.js +0 -530
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Public Record Office Victoria.js +0 -252
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Publications Office of the European Union.js +0 -540
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Publications du Quebec.js +0 -225
- scitex/scholar/.legacy/metadata/urls/zotero_translators/PyPI.js +0 -288
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Qatar Digital Library.js +0 -802
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Queensland State Archives.js +0 -303
- scitex/scholar/.legacy/metadata/urls/zotero_translators/R-Packages.js +0 -410
- scitex/scholar/.legacy/metadata/urls/zotero_translators/RAND.js +0 -283
- scitex/scholar/.legacy/metadata/urls/zotero_translators/RDF.js +0 -1777
- scitex/scholar/.legacy/metadata/urls/zotero_translators/REDALYC.js +0 -196
- scitex/scholar/.legacy/metadata/urls/zotero_translators/RIS.js +0 -7265
- scitex/scholar/.legacy/metadata/urls/zotero_translators/RSC Publishing.js +0 -250
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Radio Free Europe Radio Liberty.js +0 -706
- scitex/scholar/.legacy/metadata/urls/zotero_translators/RePEc - Econpapers.js +0 -725
- scitex/scholar/.legacy/metadata/urls/zotero_translators/RePEc - IDEAS.js +0 -337
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Rechtspraak.nl.js +0 -295
- scitex/scholar/.legacy/metadata/urls/zotero_translators/RefWorks Tagged.js +0 -1185
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ReferBibIX.js +0 -463
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Regeringskansliet.js +0 -89
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Research Square.js +0 -335
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ResearchGate.js +0 -394
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Retsinformation.js +0 -348
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Reuters.js +0 -255
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Rock, Paper, Shotgun.js +0 -304
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Roll Call.js +0 -173
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Russian State Library.js +0 -1517
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SAE Papers.js +0 -241
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SAGE Journals.js +0 -427
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SAGE Knowledge.js +0 -505
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SAILDART.js +0 -364
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SALT Research Archives.js +0 -196
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SFU IPinCH.js +0 -946
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SIPRI.js +0 -256
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SIRS Knowledge Source.js +0 -546
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SLUB Dresden.js +0 -300
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SORA.js +0 -340
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SSOAR.js +0 -399
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SSRN.js +0 -235
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SVT Nyheter.js +0 -381
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Sacramento Bee.js +0 -274
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Safari Books Online.js +0 -391
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Scholars Portal Journals.js +0 -220
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Scholia.js +0 -189
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Schweizer Radio und Fernsehen SRF.js +0 -152
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SciELO.js +0 -440
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ScienceDirect.js +0 -1304
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Scopus.js +0 -418
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Semantic Scholar.js +0 -513
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Silverchair.js +0 -886
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Slate.js +0 -228
- scitex/scholar/.legacy/metadata/urls/zotero_translators/SlideShare.js +0 -112
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Springer Link.js +0 -696
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Stack Exchange.js +0 -134
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Standard Ebooks.js +0 -198
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Stanford Encyclopedia of Philosophy.js +0 -285
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Stanford University Press.js +0 -343
- scitex/scholar/.legacy/metadata/urls/zotero_translators/State Records Office of Western Australia.js +0 -439
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Stitcher.js +0 -141
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Store norske leksikon.js +0 -291
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Stuff.co.nz.js +0 -446
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Substack.js +0 -237
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Sud Ouest.js +0 -181
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Sueddeutsche.de.js +0 -205
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Summon 2.js +0 -117
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Superlib.js +0 -647
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Svenska Dagbladet.js +0 -274
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Sveriges radio.js +0 -416
- scitex/scholar/.legacy/metadata/urls/zotero_translators/TEI.js +0 -648
- scitex/scholar/.legacy/metadata/urls/zotero_translators/TV by the Numbers.js +0 -194
- scitex/scholar/.legacy/metadata/urls/zotero_translators/TVNZ.js +0 -165
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Tagesspiegel.js +0 -249
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Talis Aspire.js +0 -316
- scitex/scholar/.legacy/metadata/urls/zotero_translators/TalisPrism.js +0 -445
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Tatknigafund.js +0 -174
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Tatpressa.ru.js +0 -121
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Taylor & Francis eBooks.js +0 -334
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Taylor and Francis+NEJM.js +0 -813
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Tesis Doctorals en Xarxa.js +0 -233
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Art Newspaper.js +0 -268
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Atlantic.js +0 -535
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Boston Globe.js +0 -285
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Chronicle of Higher Education.js +0 -308
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Daily Beast.js +0 -183
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Economic Times - The Times of India.js +0 -305
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Economist.js +0 -207
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Free Dictionary.js +0 -58
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Globe and Mail.js +0 -241
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Guardian.js +0 -717
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Hamilton Spectator.js +0 -129
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Hindu.js +0 -318
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Independent.js +0 -184
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Intercept.js +0 -258
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Met.js +0 -300
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Microfinance Gateway.js +0 -174
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Nation.js +0 -188
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The National Archives (UK).js +0 -242
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The New Republic.js +0 -160
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The New York Review of Books.js +0 -467
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The New Yorker.js +0 -360
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Open Library.js +0 -220
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Straits Times.js +0 -528
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Telegraph.js +0 -337
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Times and Sunday Times.js +0 -180
- scitex/scholar/.legacy/metadata/urls/zotero_translators/The Times of Israel.js +0 -151
- scitex/scholar/.legacy/metadata/urls/zotero_translators/TheMarker.js +0 -108
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Theory of Computing.js +0 -488
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ThesesFR.js +0 -298
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Thieme.js +0 -326
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Time.com.js +0 -557
- scitex/scholar/.legacy/metadata/urls/zotero_translators/TimesMachine.js +0 -222
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Tony Blair Institute for Global Change.js +0 -195
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Toronto Star.js +0 -331
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Transportation Research Board.js +0 -253
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Treesearch.js +0 -535
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Trove.js +0 -616
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Tumblr.js +0 -179
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Twitter.js +0 -413
- scitex/scholar/.legacy/metadata/urls/zotero_translators/UChicago VuFind.js +0 -907
- scitex/scholar/.legacy/metadata/urls/zotero_translators/UNZ Print Archive.js +0 -276
- scitex/scholar/.legacy/metadata/urls/zotero_translators/UPCommons.js +0 -227
- scitex/scholar/.legacy/metadata/urls/zotero_translators/US National Archives Research Catalog.js +0 -275
- scitex/scholar/.legacy/metadata/urls/zotero_translators/USENIX.js +0 -151
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Ubiquity Journals.js +0 -228
- scitex/scholar/.legacy/metadata/urls/zotero_translators/University Press Scholarship.js +0 -301
- scitex/scholar/.legacy/metadata/urls/zotero_translators/University of California Press Books.js +0 -403
- scitex/scholar/.legacy/metadata/urls/zotero_translators/University of Chicago Press Books.js +0 -378
- scitex/scholar/.legacy/metadata/urls/zotero_translators/University of Wisconsin-Madison Libraries Catalog.js +0 -298
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Unqualified Dublin Core RDF.js +0 -153
- scitex/scholar/.legacy/metadata/urls/zotero_translators/UpToDate References.js +0 -203
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Vanity Fair.js +0 -242
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Verniana-Jules Verne Studies.js +0 -190
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Verso Books.js +0 -311
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Vice.js +0 -445
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Victoria & Albert Museum.js +0 -277
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Vimeo.js +0 -188
- scitex/scholar/.legacy/metadata/urls/zotero_translators/VoxEU.js +0 -151
- scitex/scholar/.legacy/metadata/urls/zotero_translators/WHO.js +0 -458
- scitex/scholar/.legacy/metadata/urls/zotero_translators/WIPO.js +0 -189
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wall Street Journal.js +0 -525
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wanfang Data.js +0 -310
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Washington Monthly.js +0 -195
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Washington Post.js +0 -447
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Web of Science Nextgen.js +0 -715
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Web of Science Tagged.js +0 -1242
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Web of Science.js +0 -228
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Welt Online.js +0 -161
- scitex/scholar/.legacy/metadata/urls/zotero_translators/WestLaw UK.js +0 -190
- scitex/scholar/.legacy/metadata/urls/zotero_translators/WikiLeaks PlusD.js +0 -182
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wikidata QuickStatements.js +0 -306
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wikidata.js +0 -911
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wikimedia Commons.js +0 -285
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wikipedia Citation Templates.js +0 -432
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wikipedia.js +0 -385
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wikisource.js +0 -399
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wikiwand.js +0 -122
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wiktionary.js +0 -141
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wildlife Biology in Practice.js +0 -172
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wiley Online Library.js +0 -1412
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wilson Center Digital Archive.js +0 -321
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Winnipeg Free Press.js +0 -204
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Wired.js +0 -249
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Womennews.js +0 -230
- scitex/scholar/.legacy/metadata/urls/zotero_translators/World Digital Library.js +0 -403
- scitex/scholar/.legacy/metadata/urls/zotero_translators/World History Connected.js +0 -185
- scitex/scholar/.legacy/metadata/urls/zotero_translators/World Shakespeare Bibliography Online.js +0 -595
- scitex/scholar/.legacy/metadata/urls/zotero_translators/WorldCat Discovery Service.js +0 -630
- scitex/scholar/.legacy/metadata/urls/zotero_translators/XML ContextObject.js +0 -274
- scitex/scholar/.legacy/metadata/urls/zotero_translators/YPSF.js +0 -224
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Yandex Books.js +0 -265
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Ynet.js +0 -171
- scitex/scholar/.legacy/metadata/urls/zotero_translators/YouTube.js +0 -209
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ZIPonline.js +0 -267
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ZOBODAT.js +0 -341
- scitex/scholar/.legacy/metadata/urls/zotero_translators/Zotero RDF.js +0 -583
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ZoteroBib.js +0 -94
- scitex/scholar/.legacy/metadata/urls/zotero_translators/arXiv.org.js +0 -1099
- scitex/scholar/.legacy/metadata/urls/zotero_translators/artnet.js +0 -207
- scitex/scholar/.legacy/metadata/urls/zotero_translators/beck-online.js +0 -1339
- scitex/scholar/.legacy/metadata/urls/zotero_translators/clinicaltrials.gov.js +0 -331
- scitex/scholar/.legacy/metadata/urls/zotero_translators/dLibra.js +0 -367
- scitex/scholar/.legacy/metadata/urls/zotero_translators/dejure.org.js +0 -242
- scitex/scholar/.legacy/metadata/urls/zotero_translators/deleted.txt +0 -132
- scitex/scholar/.legacy/metadata/urls/zotero_translators/dhistory.js +0 -103
- scitex/scholar/.legacy/metadata/urls/zotero_translators/digibib.net.js +0 -245
- scitex/scholar/.legacy/metadata/urls/zotero_translators/eLibrary.ru.js +0 -867
- scitex/scholar/.legacy/metadata/urls/zotero_translators/eLife.js +0 -462
- scitex/scholar/.legacy/metadata/urls/zotero_translators/eMJA.js +0 -246
- scitex/scholar/.legacy/metadata/urls/zotero_translators/eMedicine.js +0 -123
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ePrint IACR.js +0 -608
- scitex/scholar/.legacy/metadata/urls/zotero_translators/ebrary.js +0 -140
- scitex/scholar/.legacy/metadata/urls/zotero_translators/etatar.ru.js +0 -104
- scitex/scholar/.legacy/metadata/urls/zotero_translators/feb-web.ru.js +0 -167
- scitex/scholar/.legacy/metadata/urls/zotero_translators/fishpond.co.nz.js +0 -224
- scitex/scholar/.legacy/metadata/urls/zotero_translators/fr-online.de.js +0 -209
- scitex/scholar/.legacy/metadata/urls/zotero_translators/govinfo.js +0 -189
- scitex/scholar/.legacy/metadata/urls/zotero_translators/index.d.ts +0 -1646
- scitex/scholar/.legacy/metadata/urls/zotero_translators/informIT database.js +0 -248
- scitex/scholar/.legacy/metadata/urls/zotero_translators/io-port.js +0 -68
- scitex/scholar/.legacy/metadata/urls/zotero_translators/jsconfig.json +0 -10
- scitex/scholar/.legacy/metadata/urls/zotero_translators/jurion.js +0 -377
- scitex/scholar/.legacy/metadata/urls/zotero_translators/mEDRA.js +0 -597
- scitex/scholar/.legacy/metadata/urls/zotero_translators/magazines.russ.ru.js +0 -120
- scitex/scholar/.legacy/metadata/urls/zotero_translators/medes.js +0 -284
- scitex/scholar/.legacy/metadata/urls/zotero_translators/newshub.co.nz.js +0 -206
- scitex/scholar/.legacy/metadata/urls/zotero_translators/newspapers.com.js +0 -335
- scitex/scholar/.legacy/metadata/urls/zotero_translators/openJur.js +0 -161
- scitex/scholar/.legacy/metadata/urls/zotero_translators/package-lock.json +0 -2345
- scitex/scholar/.legacy/metadata/urls/zotero_translators/package.json +0 -24
- scitex/scholar/.legacy/metadata/urls/zotero_translators/reddit.js +0 -275
- scitex/scholar/.legacy/metadata/urls/zotero_translators/sbn.it.js +0 -186
- scitex/scholar/.legacy/metadata/urls/zotero_translators/scinapse.js +0 -273
- scitex/scholar/.legacy/metadata/urls/zotero_translators/semantics Visual Library.js +0 -643
- scitex/scholar/.legacy/metadata/urls/zotero_translators/taz.de.js +0 -200
- scitex/scholar/.legacy/metadata/urls/zotero_translators/unAPI.js +0 -481
- scitex/scholar/.legacy/metadata/urls/zotero_translators/wiso.js +0 -314
- scitex/scholar/.legacy/metadata/urls/zotero_translators/zbMATH.js +0 -278
- scitex/scholar/.legacy/metadata/urls/zotero_translators/zotero.org.js +0 -311
- scitex/scholar/.legacy/search/README.md +0 -205
- scitex/scholar/.legacy/search/_Embedder.py +0 -329
- scitex/scholar/.legacy/search/_SemanticSearch.py +0 -278
- scitex/scholar/.legacy/search/_SemanticSearchEngine.py +0 -452
- scitex/scholar/.legacy/search/_UnifiedSearcher.py +0 -1353
- scitex/scholar/.legacy/search/_VectorDatabase.py +0 -443
- scitex/scholar/.legacy/search/__init__.py +0 -25
- scitex/scholar/.legacy/storage/_EnhancedStorageManager.py +0 -617
- scitex/scholar/.legacy/storage/__init__.py +0 -19
- scitex/scholar/CLAUDE.md +0 -257
- scitex/scholar/TODO.md +0 -174
- scitex/scholar/_mcp_handlers.py +0 -685
- scitex/scholar/_mcp_tool_schemas.py +0 -339
- scitex/scholar/docs/backup/papers-orig.bib +0 -698
- scitex/scholar/docs/backup/papers.bib.zip +0 -0
- scitex/scholar/docs/to_claude/bin/elisp/check_parens.sh +0 -56
- scitex/scholar/docs/to_claude/bin/elisp/elisp-ci/README.md +0 -412
- scitex/scholar/docs/to_claude/bin/elisp/elisp-ci/elisp-ci +0 -622
- scitex/scholar/docs/to_claude/bin/elisp/elisp-ci/elisp-ci-simple +0 -105
- scitex/scholar/docs/to_claude/bin/elisp/find_incorrect_require_provide_statements.sh +0 -113
- scitex/scholar/docs/to_claude/bin/elisp/run_tests_elisp.sh +0 -532
- scitex/scholar/docs/to_claude/bin/elisp/run_tests_elisp_v02.sh +0 -555
- scitex/scholar/docs/to_claude/bin/elisp/sync_elisp_tdd.sh +0 -626
- scitex/scholar/docs/to_claude/bin/general/claude_emacs_server.sh +0 -192
- scitex/scholar/docs/to_claude/bin/general/create_github_release.sh +0 -36
- scitex/scholar/docs/to_claude/bin/general/find_errors.sh +0 -75
- scitex/scholar/docs/to_claude/bin/general/rename.sh +0 -145
- scitex/scholar/docs/to_claude/bin/general/render_mermaid.sh +0 -116
- scitex/scholar/docs/to_claude/bin/general/safe_rm.sh +0 -75
- scitex/scholar/docs/to_claude/bin/general/view_repo.sh +0 -4
- scitex/scholar/docs/to_claude/bin/general/wsl2-buzzer.sh +0 -73
- scitex/scholar/docs/to_claude/bin/python/black_all.sh +0 -41
- scitex/scholar/docs/to_claude/bin/python/run_tests_python_pip_package.sh +0 -291
- scitex/scholar/docs/to_claude/bin/safe_rm.sh +0 -3
- scitex/scholar/docs/to_claude/bin/slurm/README.md +0 -54
- scitex/scholar/docs/to_claude/bin/slurm/login.sh +0 -23
- scitex/scholar/docs/to_claude/bin/slurm/request.sh +0 -62
- scitex/scholar/docs/to_claude/bin/slurm/run.sh +0 -73
- scitex/scholar/docs/to_claude/examples/README.md +0 -9
- scitex/scholar/docs/to_claude/examples/example-elisp-project-emacs-hello-world/ELISP-TEST-REPORT-20250513-012234-48-PASSED-49-TOTAL-97-PERCENT.org +0 -105
- scitex/scholar/docs/to_claude/examples/example-elisp-project-emacs-hello-world/LATEST-ELISP-REPORT.org +0 -105
- scitex/scholar/docs/to_claude/examples/example-elisp-project-emacs-hello-world/README.md +0 -11
- scitex/scholar/docs/to_claude/examples/example-elisp-project-emacs-hello-world/run_tests.sh +0 -652
- scitex/scholar/docs/to_claude/examples/example-elisp-project-emacs-hello-world/tests/test-ehw-core/ELISP-TEST-REPORT-20250512-235622-0-SUCCESS-4-TOTAL-0-PERCENT.org +0 -25
- scitex/scholar/docs/to_claude/examples/example-elisp-project-emacs-hello-world/tests/test-ehw-friends/ELISP-TEST-REPORT-20250512-235622-0-SUCCESS-34-TOTAL-0-PERCENT.org +0 -66
- scitex/scholar/docs/to_claude/examples/example-elisp-project-emacs-hello-world/tests/test-ehw-prep/ELISP-TEST-REPORT-20250512-235622-0-SUCCESS-5-TOTAL-0-PERCENT.org +0 -26
- scitex/scholar/docs/to_claude/examples/example-elisp-project-emacs-hello-world/tests/test-ehw-utils/ELISP-TEST-REPORT-20250512-235622-0-SUCCESS-4-TOTAL-0-PERCENT.org +0 -25
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/.gitignore +0 -626
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/README.md +0 -155
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/config/MNIST.yaml +0 -24
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/config/PATH.yaml +0 -30
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/data/.gitkeep +0 -0
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/clf_svm.py +0 -124
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/download.py +0 -165
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/main.sh +0 -26
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/plot_conf_mat.py +0 -86
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/plot_digits.py +0 -118
- scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/plot_umap_space.py +0 -110
- scitex/scholar/docs/to_claude/guidelines/README.md +0 -9
- scitex/scholar/docs/to_claude/guidelines/USER_PHILOSOPHY/01_DEVELOPMENT_CYCLE.md +0 -47
- scitex/scholar/docs/to_claude/guidelines/USER_PHILOSOPHY/02_NAMING_CONVENSIONS.md +0 -91
- scitex/scholar/docs/to_claude/guidelines/USER_PHILOSOPHY/03_ARCHITECTUAL_AGREEMENT_PROCESS.md +0 -86
- scitex/scholar/docs/to_claude/guidelines/USER_PHILOSOPHY/04_ARCHITECTURE_PREDEFINED.md +0 -77
- scitex/scholar/docs/to_claude/guidelines/USER_PHILOSOPHY/05_PRIORITY_CONFIG.md +0 -22
- scitex/scholar/docs/to_claude/guidelines/USER_PHILOSOPHY/06_MULTIPLE_SPECIAL_AGENTS.md +0 -35
- scitex/scholar/docs/to_claude/guidelines/USER_PHILOSOPHY/07_DEBUGGING_TECHNIQUES.md +0 -153
- scitex/scholar/docs/to_claude/guidelines/command/IMPORTANT-rm.md +0 -69
- scitex/scholar/docs/to_claude/guidelines/command/IMPORTANT-tree.md +0 -162
- scitex/scholar/docs/to_claude/guidelines/elisp/IMPORTANT-ELISP-01-basic.md +0 -65
- scitex/scholar/docs/to_claude/guidelines/elisp/IMPORTANT-ELISP-02-project-structure.md +0 -97
- scitex/scholar/docs/to_claude/guidelines/elisp/IMPORTANT-ELISP-03-file-template.md +0 -70
- scitex/scholar/docs/to_claude/guidelines/elisp/IMPORTANT-ELISP-04-coding-style.md +0 -42
- scitex/scholar/docs/to_claude/guidelines/elisp/IMPORTANT-ELISP-05-testing-guide.md +0 -190
- scitex/scholar/docs/to_claude/guidelines/elisp/IMPORTANT-ELISP-99-example-project.md +0 -15
- scitex/scholar/docs/to_claude/guidelines/elisp/ci.md +0 -650
- scitex/scholar/docs/to_claude/guidelines/elisp/testing-with-docker.md +0 -243
- scitex/scholar/docs/to_claude/guidelines/programming_common/EXAMPLE-README-MODULE-ROOT.md +0 -32
- scitex/scholar/docs/to_claude/guidelines/programming_common/EXAMPLE-README-REPOSITORY-ROOT.md +0 -60
- scitex/scholar/docs/to_claude/guidelines/programming_common/IMPORTANT-art-of-readable-code.md +0 -1317
- scitex/scholar/docs/to_claude/guidelines/programming_common/IMPORTANT-art-of-testing.md +0 -799
- scitex/scholar/docs/to_claude/guidelines/programming_common/IMPORTANT-cleanliness.md +0 -18
- scitex/scholar/docs/to_claude/guidelines/programming_common/IMPORTANT-documentation-performance-claims.md +0 -163
- scitex/scholar/docs/to_claude/guidelines/programming_common/IMPORTANT-general.md +0 -156
- scitex/scholar/docs/to_claude/guidelines/programming_common/IMPORTANT-refactoring.md +0 -32
- scitex/scholar/docs/to_claude/guidelines/programming_common/IMPORTANT-regression-prevention.md +0 -14
- scitex/scholar/docs/to_claude/guidelines/programming_common/IMPORTANT-slurm.md +0 -73
- scitex/scholar/docs/to_claude/guidelines/programming_common/IMPORTANT-start-from-small.md +0 -30
- scitex/scholar/docs/to_claude/guidelines/programming_common/IMPORTANT-test-driven-workflow.md +0 -80
- scitex/scholar/docs/to_claude/guidelines/programming_common/IMPORTANT-version-control.md +0 -47
- scitex/scholar/docs/to_claude/guidelines/programming_common/clean-code.md +0 -305
- scitex/scholar/docs/to_claude/guidelines/programming_common/debugging-message.md +0 -52
- scitex/scholar/docs/to_claude/guidelines/programming_common/do-not-repeat-yourself.md +0 -27
- scitex/scholar/docs/to_claude/guidelines/programming_common/emacs-server.md +0 -39
- scitex/scholar/docs/to_claude/guidelines/programming_common/keep-it-simple-stupid.md +0 -19
- scitex/scholar/docs/to_claude/guidelines/programming_common/renaming-and-cleaning-workflow.md +0 -311
- scitex/scholar/docs/to_claude/guidelines/programming_common/screen.md +0 -32
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-CLAUDE_ID.md +0 -15
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-beyond-control.md +0 -14
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-bug-report.md +0 -43
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-cleanliness.md +0 -162
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-communication.md +0 -13
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-do-not-create-any-new-file-nor-directory-in-project-root.md +0 -9
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-documentation.md +0 -11
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-feature-request.md +0 -33
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-general-multi-agent-coordination.md +0 -311
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-multi-agent-protocol.md +0 -97
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-project-management-bulletin-board.md +0 -48
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-project-management-markdown.md +0 -156
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-project-management-org.org +0 -161
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-tools.md +0 -10
- scitex/scholar/docs/to_claude/guidelines/project/IMPORTANT-understand-message-in-filename.md +0 -12
- scitex/scholar/docs/to_claude/guidelines/project/general.md +0 -7
- scitex/scholar/docs/to_claude/guidelines/project/report.md +0 -50
- scitex/scholar/docs/to_claude/guidelines/project/timeline-gantt-chart.md +0 -49
- scitex/scholar/docs/to_claude/guidelines/python/CHECKLIST.md +0 -51
- scitex/scholar/docs/to_claude/guidelines/python/HOW-TO-DEBUG-with-MULTIPLE_AGENTS.md +0 -191
- scitex/scholar/docs/to_claude/guidelines/python/Machine-Learning.md +0 -15
- scitex/scholar/docs/to_claude/guidelines/python/NOT-FULL-PYTEST-BUT-PARTIAL-PYTEST.md +0 -21
- scitex/scholar/docs/to_claude/guidelines/python/django.md +0 -217
- scitex/scholar/docs/to_claude/guidelines/python/env.md +0 -10
- scitex/scholar/docs/to_claude/guidelines/python/general.md +0 -55
- scitex/scholar/docs/to_claude/guidelines/python/official/cipdb-README.md +0 -219
- scitex/scholar/docs/to_claude/guidelines/python/official/fastmcp-README.md +0 -442
- scitex/scholar/docs/to_claude/guidelines/python/official/fastmcp-TESTING.md +0 -146
- scitex/scholar/docs/to_claude/guidelines/python/official/icecream-README.md +0 -433
- scitex/scholar/docs/to_claude/guidelines/python/official/priority_config-README.md +0 -126
- scitex/scholar/docs/to_claude/guidelines/python/scitex/01-basic.md +0 -42
- scitex/scholar/docs/to_claude/guidelines/python/scitex/02-file-template.md +0 -132
- scitex/scholar/docs/to_claude/guidelines/python/scitex/03-configuration.md +0 -53
- scitex/scholar/docs/to_claude/guidelines/python/scitex/04-coding-style.md +0 -126
- scitex/scholar/docs/to_claude/guidelines/python/scitex/05-testing-guide.md +0 -56
- scitex/scholar/docs/to_claude/guidelines/python/scitex/06-examples-guide.md +0 -42
- scitex/scholar/docs/to_claude/guidelines/python/scitex/11-gen-module.md +0 -15
- scitex/scholar/docs/to_claude/guidelines/python/scitex/11-session-module.md +0 -24
- scitex/scholar/docs/to_claude/guidelines/python/scitex/12-io-module.md +0 -112
- scitex/scholar/docs/to_claude/guidelines/python/scitex/13-plt-module.md +0 -101
- scitex/scholar/docs/to_claude/guidelines/python/scitex/14-dsp-module.md +0 -78
- scitex/scholar/docs/to_claude/guidelines/python/scitex/15-pd-module.md +0 -24
- scitex/scholar/docs/to_claude/guidelines/python/scitex/16-stats-module.md +0 -79
- scitex/scholar/docs/to_claude/guidelines/python/scitex/17-other-modules.md +0 -23
- scitex/scholar/docs/to_claude/guidelines/python/scitex/17-str-module.md +0 -24
- scitex/scholar/docs/to_claude/guidelines/python/scitex/18-directory-structure-for-scientific-work.md +0 -48
- scitex/scholar/docs/to_claude/guidelines/python/scitex/19-directory-structure-for-pip-package.md +0 -234
- scitex/scholar/docs/to_claude/guidelines/python/scitex/99-example-project.md +0 -19
- scitex/scholar/docs/to_claude/guidelines/python/zen_of_python.md +0 -82
- scitex/scholar/docs/to_claude/guidelines/science/IMPORTANT-general.md +0 -16
- scitex/scholar/docs/to_claude/guidelines/science/IMPORTANT-scientific-attitude.md +0 -25
- scitex/scholar/docs/to_claude/guidelines/science/scientific-writing-abstract.md +0 -93
- scitex/scholar/docs/to_claude/guidelines/science/scientific-writing-discussion.md +0 -116
- scitex/scholar/docs/to_claude/guidelines/science/scientific-writing-general-1.md +0 -157
- scitex/scholar/docs/to_claude/guidelines/science/scientific-writing-general-2.md +0 -83
- scitex/scholar/docs/to_claude/guidelines/science/scientific-writing-introduction.md +0 -123
- scitex/scholar/docs/to_claude/guidelines/science/scientific-writing-methods.md +0 -88
- scitex/scholar/docs/to_claude/guidelines/shell/IMPORTANT-general.md +0 -196
- scitex/scholar/examples/SUGGESTIONS.md +0 -865
- scitex/scholar/examples/dev.py +0 -38
- scitex/scholar/library/neurovista/info/bibtex/seizure_prediction_enriched.bib +0 -1092
- scitex/stats/_mcp_handlers.py +0 -1191
- scitex/stats/_mcp_tool_schemas.py +0 -384
- scitex/template/.legacy/_clone_project.py +0 -267
- scitex/template/_mcp_handlers.py +0 -259
- scitex/template/_mcp_tool_schemas.py +0 -112
- scitex/writer/.legacy/Writer_v01-refactored.py +0 -189
- scitex/writer/.legacy/_compile.py +0 -342
- scitex/writer/_compile_async.py +0 -126
- scitex/writer/_validate_tree_structures.py +0 -197
- scitex/writer/dataclasses/config/_WriterConfig.py +0 -175
- scitex/writer/dataclasses/contents/_ManuscriptContents.py +0 -236
- scitex/writer/dataclasses/core/_Document.py +0 -146
- scitex/writer/dataclasses/core/_DocumentSection.py +0 -546
- scitex/writer/dataclasses/results/_CompilationResult.py +0 -165
- scitex/writer/dataclasses/results/_LaTeXIssue.py +0 -102
- scitex/writer/dataclasses/tree/MINIMUM_FILES.md +0 -121
- scitex/writer/tests/__init__.py +0 -3
- scitex/writer/tests/test_diff_between.py +0 -451
- scitex/writer/tests/test_document_section.py +0 -311
- scitex/writer/tests/test_document_workflow.py +0 -393
- scitex/writer/tests/test_writer.py +0 -361
- scitex/writer/tests/test_writer_integration.py +0 -303
- scitex-2.13.0.dist-info/METADATA +0 -1231
- scitex-2.13.0.dist-info/RECORD +0 -3402
- scitex-2.13.0.dist-info/entry_points.txt +0 -11
- /scitex/scholar/docs/{SUMMARY.md → 00_SUMMARY.md} +0 -0
- /scitex/scholar/docs/{STORAGE_ARCHITECTURE.md → 01_STORAGE_ARCHITECTURE.md} +0 -0
- /scitex/scholar/docs/{PIPELINE_ORGANIZATION.md → 02_PIPELINE_ORGANIZATION.md} +0 -0
- /scitex/scholar/docs/{PIPELINE_IMPLEMENTATION_PLAN.md → 03_PIPELINE_IMPLEMENTATION_PLAN.md} +0 -0
- /scitex/scholar/docs/{PIPELINE_IMPLEMENTATION_COMPLETE.md → 04_PIPELINE_IMPLEMENTATION_COMPLETE.md} +0 -0
- /scitex/scholar/docs/{DETAILS_FOR_DEVELOPERS.md → 05_DETAILS_FOR_DEVELOPERS.md} +0 -0
- /scitex/scholar/docs/{IMPACT_FACTOR_CITATION_INTEGRATION.md → 06_IMPACT_FACTOR_CITATION_INTEGRATION.md} +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/__init__.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/config/_CONSTANTS.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/config/__init__.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/contents/_RevisionContents.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/contents/_SupplementaryContents.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/contents/__init__.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/core/__init__.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/results/_SaveSectionsResponse.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/results/_SectionReadResponse.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/results/__init__.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/tree/_ConfigTree.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/tree/_ManuscriptTree.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/tree/_RevisionTree.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/tree/_ScriptsTree.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/tree/_SharedTree.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/tree/_SupplementaryTree.py +0 -0
- /scitex/writer/{dataclasses → _dataclasses}/tree/__init__.py +0 -0
- {scitex-2.13.0.dist-info → scitex-2.15.1.dist-info}/WHEEL +0 -0
- {scitex-2.13.0.dist-info → scitex-2.15.1.dist-info}/licenses/LICENSE +0 -0
scitex/plt/utils/_hitmap.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
# File: scitex/plt/utils/_hitmap.py
|
|
2
|
+
# Timestamp: "2026-01-24 (ywatanabe)"
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-python/src/scitex/plt/utils/_hitmap.py
|
|
5
4
|
|
|
6
5
|
"""
|
|
7
6
|
Hit map generation utilities for interactive element selection.
|
|
@@ -20,1624 +19,55 @@ Based on experimental results (see FIGZ_PLTZ_STATSZ.md):
|
|
|
20
19
|
Reserved colors:
|
|
21
20
|
- Black (#000000, ID=0): Background/no element
|
|
22
21
|
- Dark gray (#010101, ID=65793): Non-selectable axes elements (spines, labels, ticks)
|
|
22
|
+
|
|
23
|
+
This module re-exports all functions from the _hitmap package for backward
|
|
24
|
+
compatibility. The actual implementation is in the _hitmap/ subpackage.
|
|
23
25
|
"""
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
from
|
|
27
|
-
|
|
27
|
+
# Re-export all public API from the _hitmap package
|
|
28
|
+
from ._hitmap import (
|
|
29
|
+
HITMAP_AXES_COLOR,
|
|
30
|
+
HITMAP_BACKGROUND_COLOR,
|
|
31
|
+
_apply_id_color,
|
|
32
|
+
_id_to_rgb,
|
|
33
|
+
_prepare_hitmap_figure,
|
|
34
|
+
_restore_figure_props,
|
|
35
|
+
_rgb_to_id_lookup,
|
|
36
|
+
_to_native,
|
|
37
|
+
apply_hitmap_colors,
|
|
38
|
+
detect_logical_groups,
|
|
39
|
+
extract_path_data,
|
|
40
|
+
extract_selectable_regions,
|
|
41
|
+
generate_hitmap_id_colors,
|
|
42
|
+
generate_hitmap_with_bbox_tight,
|
|
43
|
+
get_all_artists,
|
|
44
|
+
get_all_artists_with_groups,
|
|
45
|
+
query_hitmap_neighborhood,
|
|
46
|
+
restore_original_colors,
|
|
47
|
+
save_hitmap_png,
|
|
48
|
+
)
|
|
28
49
|
|
|
29
50
|
__all__ = [
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
"get_all_artists",
|
|
52
|
+
"get_all_artists_with_groups",
|
|
53
|
+
"detect_logical_groups",
|
|
54
|
+
"generate_hitmap_id_colors",
|
|
55
|
+
"extract_path_data",
|
|
56
|
+
"extract_selectable_regions",
|
|
57
|
+
"query_hitmap_neighborhood",
|
|
58
|
+
"save_hitmap_png",
|
|
59
|
+
"apply_hitmap_colors",
|
|
60
|
+
"restore_original_colors",
|
|
61
|
+
"generate_hitmap_with_bbox_tight",
|
|
62
|
+
"HITMAP_BACKGROUND_COLOR",
|
|
63
|
+
"HITMAP_AXES_COLOR",
|
|
64
|
+
"_rgb_to_id_lookup",
|
|
65
|
+
"_to_native",
|
|
66
|
+
"_id_to_rgb",
|
|
67
|
+
"_apply_id_color",
|
|
68
|
+
"_prepare_hitmap_figure",
|
|
69
|
+
"_restore_figure_props",
|
|
44
70
|
]
|
|
45
71
|
|
|
46
72
|
|
|
47
|
-
def _to_native(obj: Any) -> Any:
|
|
48
|
-
"""Convert numpy types to native Python types for JSON serialization."""
|
|
49
|
-
if isinstance(obj, np.integer):
|
|
50
|
-
return int(obj)
|
|
51
|
-
elif isinstance(obj, np.floating):
|
|
52
|
-
return float(obj)
|
|
53
|
-
elif isinstance(obj, np.ndarray):
|
|
54
|
-
return obj.tolist()
|
|
55
|
-
elif isinstance(obj, dict):
|
|
56
|
-
return {k: _to_native(v) for k, v in obj.items()}
|
|
57
|
-
elif isinstance(obj, list):
|
|
58
|
-
return [_to_native(v) for v in obj]
|
|
59
|
-
return obj
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def get_all_artists(fig, include_text: bool = False) -> List[Tuple[Any, int, str]]:
|
|
63
|
-
"""
|
|
64
|
-
Extract all selectable artists from a figure.
|
|
65
|
-
|
|
66
|
-
Parameters
|
|
67
|
-
----------
|
|
68
|
-
fig : matplotlib.figure.Figure
|
|
69
|
-
The figure to extract artists from.
|
|
70
|
-
include_text : bool
|
|
71
|
-
Whether to include text elements.
|
|
72
|
-
|
|
73
|
-
Returns
|
|
74
|
-
-------
|
|
75
|
-
list of tuple
|
|
76
|
-
List of (artist, axes_index, artist_type) tuples.
|
|
77
|
-
"""
|
|
78
|
-
artists = []
|
|
79
|
-
|
|
80
|
-
for ax_idx, ax in enumerate(fig.axes):
|
|
81
|
-
# Lines (Line2D)
|
|
82
|
-
for line in ax.get_lines():
|
|
83
|
-
label = line.get_label()
|
|
84
|
-
if not label.startswith('_'): # Skip internal lines
|
|
85
|
-
artists.append((line, ax_idx, 'line'))
|
|
86
|
-
|
|
87
|
-
# Scatter plots (PathCollection)
|
|
88
|
-
for coll in ax.collections:
|
|
89
|
-
coll_type = type(coll).__name__
|
|
90
|
-
if 'PathCollection' in coll_type:
|
|
91
|
-
artists.append((coll, ax_idx, 'scatter'))
|
|
92
|
-
elif 'PolyCollection' in coll_type or 'FillBetween' in coll_type:
|
|
93
|
-
artists.append((coll, ax_idx, 'fill'))
|
|
94
|
-
elif 'QuadMesh' in coll_type:
|
|
95
|
-
artists.append((coll, ax_idx, 'mesh'))
|
|
96
|
-
|
|
97
|
-
# Bars (Rectangle patches in containers)
|
|
98
|
-
for container in ax.containers:
|
|
99
|
-
if hasattr(container, 'patches') and container.patches:
|
|
100
|
-
artists.append((container, ax_idx, 'bar'))
|
|
101
|
-
|
|
102
|
-
# Individual patches (rectangles, circles, etc.)
|
|
103
|
-
for patch in ax.patches:
|
|
104
|
-
patch_type = type(patch).__name__
|
|
105
|
-
if patch_type == 'Rectangle':
|
|
106
|
-
artists.append((patch, ax_idx, 'rectangle'))
|
|
107
|
-
elif patch_type in ('Circle', 'Ellipse'):
|
|
108
|
-
artists.append((patch, ax_idx, 'circle'))
|
|
109
|
-
elif patch_type == 'Polygon':
|
|
110
|
-
artists.append((patch, ax_idx, 'polygon'))
|
|
111
|
-
|
|
112
|
-
# Images
|
|
113
|
-
for img in ax.images:
|
|
114
|
-
artists.append((img, ax_idx, 'image'))
|
|
115
|
-
|
|
116
|
-
# Text (optional)
|
|
117
|
-
if include_text:
|
|
118
|
-
for text in ax.texts:
|
|
119
|
-
if text.get_text():
|
|
120
|
-
artists.append((text, ax_idx, 'text'))
|
|
121
|
-
|
|
122
|
-
return artists
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def detect_logical_groups(fig) -> Dict[str, Dict[str, Any]]:
|
|
126
|
-
"""
|
|
127
|
-
Detect logical groups in a matplotlib figure.
|
|
128
|
-
|
|
129
|
-
Logical groups represent high-level plot elements that may consist of
|
|
130
|
-
multiple physical matplotlib artists. For example:
|
|
131
|
-
- Histogram: Many Rectangle patches grouped as one "histogram"
|
|
132
|
-
- Bar series: BarContainer with multiple bars
|
|
133
|
-
- Box plot: Box, whiskers, caps, median, fliers as one "boxplot"
|
|
134
|
-
- Error bars: Line + error caps as one "errorbar"
|
|
135
|
-
|
|
136
|
-
Parameters
|
|
137
|
-
----------
|
|
138
|
-
fig : matplotlib.figure.Figure
|
|
139
|
-
The figure to analyze.
|
|
140
|
-
|
|
141
|
-
Returns
|
|
142
|
-
-------
|
|
143
|
-
dict
|
|
144
|
-
Dictionary mapping group_id to group info:
|
|
145
|
-
{
|
|
146
|
-
"histogram_0": {
|
|
147
|
-
"type": "histogram",
|
|
148
|
-
"label": "...",
|
|
149
|
-
"axes_index": 0,
|
|
150
|
-
"artists": [list of matplotlib artists],
|
|
151
|
-
"role": "logical"
|
|
152
|
-
},
|
|
153
|
-
...
|
|
154
|
-
}
|
|
155
|
-
"""
|
|
156
|
-
groups = {}
|
|
157
|
-
group_counter = {} # Track count per type for unique IDs
|
|
158
|
-
|
|
159
|
-
def get_group_id(group_type: str, ax_idx: int) -> str:
|
|
160
|
-
"""Generate unique group ID."""
|
|
161
|
-
key = f"{group_type}_{ax_idx}"
|
|
162
|
-
if key not in group_counter:
|
|
163
|
-
group_counter[key] = 0
|
|
164
|
-
idx = group_counter[key]
|
|
165
|
-
group_counter[key] += 1
|
|
166
|
-
return f"{group_type}_{ax_idx}_{idx}"
|
|
167
|
-
|
|
168
|
-
for ax_idx, ax in enumerate(fig.axes):
|
|
169
|
-
# 1. Detect BarContainers (covers bar charts and histograms)
|
|
170
|
-
# First, count how many BarContainers exist on this axis
|
|
171
|
-
bar_containers = [c for c in ax.containers if 'BarContainer' in type(c).__name__]
|
|
172
|
-
n_bar_containers = len(bar_containers)
|
|
173
|
-
|
|
174
|
-
for container in ax.containers:
|
|
175
|
-
container_type = type(container).__name__
|
|
176
|
-
|
|
177
|
-
if 'BarContainer' in container_type:
|
|
178
|
-
# Determine if it's a histogram, grouped bar series, or simple categorical bar
|
|
179
|
-
patches = list(container.patches) if hasattr(container, 'patches') else []
|
|
180
|
-
if not patches:
|
|
181
|
-
continue
|
|
182
|
-
|
|
183
|
-
# Check if bars are adjacent (histogram) or spaced (bar chart)
|
|
184
|
-
is_histogram = False
|
|
185
|
-
if len(patches) > 1:
|
|
186
|
-
# Check if bars are adjacent (no gaps between them)
|
|
187
|
-
widths = [p.get_width() for p in patches]
|
|
188
|
-
x_positions = [p.get_x() for p in patches]
|
|
189
|
-
if len(x_positions) > 1:
|
|
190
|
-
gaps = [x_positions[i+1] - (x_positions[i] + widths[i])
|
|
191
|
-
for i in range(len(x_positions)-1)]
|
|
192
|
-
# If gaps are very small relative to bar width, it's a histogram
|
|
193
|
-
avg_width = sum(widths) / len(widths)
|
|
194
|
-
is_histogram = all(abs(g) < avg_width * 0.1 for g in gaps)
|
|
195
|
-
|
|
196
|
-
if is_histogram:
|
|
197
|
-
# Histogram: group all bins together
|
|
198
|
-
group_type = 'histogram'
|
|
199
|
-
group_id = get_group_id(group_type, ax_idx)
|
|
200
|
-
|
|
201
|
-
label = ''
|
|
202
|
-
if hasattr(container, 'get_label'):
|
|
203
|
-
label = container.get_label()
|
|
204
|
-
if not label or label.startswith('_'):
|
|
205
|
-
label = f"{group_type}_{len([g for g in groups if group_type in g])}"
|
|
206
|
-
|
|
207
|
-
groups[group_id] = {
|
|
208
|
-
'type': group_type,
|
|
209
|
-
'label': label,
|
|
210
|
-
'axes_index': ax_idx,
|
|
211
|
-
'artists': patches,
|
|
212
|
-
'artist_types': ['rectangle'] * len(patches),
|
|
213
|
-
'role': 'logical',
|
|
214
|
-
'member_count': len(patches),
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
elif n_bar_containers > 1:
|
|
218
|
-
# Multiple bar containers = grouped bar chart
|
|
219
|
-
# Group bars by series (each container is a series)
|
|
220
|
-
group_type = 'bar_series'
|
|
221
|
-
group_id = get_group_id(group_type, ax_idx)
|
|
222
|
-
|
|
223
|
-
label = ''
|
|
224
|
-
if hasattr(container, 'get_label'):
|
|
225
|
-
label = container.get_label()
|
|
226
|
-
if not label or label.startswith('_'):
|
|
227
|
-
label = f"{group_type}_{len([g for g in groups if group_type in g])}"
|
|
228
|
-
|
|
229
|
-
groups[group_id] = {
|
|
230
|
-
'type': group_type,
|
|
231
|
-
'label': label,
|
|
232
|
-
'axes_index': ax_idx,
|
|
233
|
-
'artists': patches,
|
|
234
|
-
'artist_types': ['rectangle'] * len(patches),
|
|
235
|
-
'role': 'logical',
|
|
236
|
-
'member_count': len(patches),
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
# else: Single bar container with spaced bars = simple categorical bar chart
|
|
240
|
-
# Don't create a group - each bar is standalone and selectable individually
|
|
241
|
-
|
|
242
|
-
elif 'ErrorbarContainer' in container_type:
|
|
243
|
-
# Error bar container
|
|
244
|
-
group_id = get_group_id('errorbar', ax_idx)
|
|
245
|
-
artists = []
|
|
246
|
-
artist_types = []
|
|
247
|
-
|
|
248
|
-
if hasattr(container, 'lines'):
|
|
249
|
-
data_line, caplines, barlinecols = container.lines
|
|
250
|
-
if data_line:
|
|
251
|
-
artists.append(data_line)
|
|
252
|
-
artist_types.append('line')
|
|
253
|
-
artists.extend(caplines)
|
|
254
|
-
artist_types.extend(['line'] * len(caplines))
|
|
255
|
-
artists.extend(barlinecols)
|
|
256
|
-
artist_types.extend(['line_collection'] * len(barlinecols))
|
|
257
|
-
|
|
258
|
-
label = container.get_label() if hasattr(container, 'get_label') else ''
|
|
259
|
-
if not label or label.startswith('_'):
|
|
260
|
-
label = f"errorbar_{len([g for g in groups if 'errorbar' in g])}"
|
|
261
|
-
|
|
262
|
-
groups[group_id] = {
|
|
263
|
-
'type': 'errorbar',
|
|
264
|
-
'label': label,
|
|
265
|
-
'axes_index': ax_idx,
|
|
266
|
-
'artists': artists,
|
|
267
|
-
'artist_types': artist_types,
|
|
268
|
-
'role': 'logical',
|
|
269
|
-
'member_count': len(artists),
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
# 2. Detect box plots (look for specific pattern of artists)
|
|
273
|
-
# Box plots create: boxes (Rectangle), whiskers (Line2D), caps (Line2D),
|
|
274
|
-
# medians (Line2D), fliers (Line2D)
|
|
275
|
-
# They are typically created via ax.bxp() or ax.boxplot()
|
|
276
|
-
if hasattr(ax, '_boxplot_info'):
|
|
277
|
-
# Some matplotlib versions store boxplot info
|
|
278
|
-
pass # Handle if available
|
|
279
|
-
|
|
280
|
-
# 3. Detect pie charts (Wedge patches)
|
|
281
|
-
wedges = [p for p in ax.patches if type(p).__name__ == 'Wedge']
|
|
282
|
-
if wedges:
|
|
283
|
-
group_id = get_group_id('pie', ax_idx)
|
|
284
|
-
groups[group_id] = {
|
|
285
|
-
'type': 'pie',
|
|
286
|
-
'label': 'Pie Chart',
|
|
287
|
-
'axes_index': ax_idx,
|
|
288
|
-
'artists': wedges,
|
|
289
|
-
'artist_types': ['wedge'] * len(wedges),
|
|
290
|
-
'role': 'logical',
|
|
291
|
-
'member_count': len(wedges),
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
# 4. Detect contour sets (multiple PolyCollections from same contour call)
|
|
295
|
-
# Contours typically have collections with increasing/decreasing levels
|
|
296
|
-
poly_collections = [c for c in ax.collections
|
|
297
|
-
if 'PolyCollection' in type(c).__name__
|
|
298
|
-
and hasattr(c, 'get_array')
|
|
299
|
-
and c.get_array() is not None]
|
|
300
|
-
if len(poly_collections) > 2:
|
|
301
|
-
# Likely a contour plot
|
|
302
|
-
group_id = get_group_id('contour', ax_idx)
|
|
303
|
-
groups[group_id] = {
|
|
304
|
-
'type': 'contour',
|
|
305
|
-
'label': 'Contour Plot',
|
|
306
|
-
'axes_index': ax_idx,
|
|
307
|
-
'artists': poly_collections,
|
|
308
|
-
'artist_types': ['poly_collection'] * len(poly_collections),
|
|
309
|
-
'role': 'logical',
|
|
310
|
-
'member_count': len(poly_collections),
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return groups
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
def get_all_artists_with_groups(
|
|
317
|
-
fig,
|
|
318
|
-
include_text: bool = False
|
|
319
|
-
) -> Tuple[List[Tuple[Any, int, str, Optional[str]]], Dict[str, Dict[str, Any]]]:
|
|
320
|
-
"""
|
|
321
|
-
Extract all selectable artists from a figure with logical group information.
|
|
322
|
-
|
|
323
|
-
This is an enhanced version of get_all_artists() that also detects and
|
|
324
|
-
returns logical groups (e.g., histogram bins grouped as one element).
|
|
325
|
-
|
|
326
|
-
Parameters
|
|
327
|
-
----------
|
|
328
|
-
fig : matplotlib.figure.Figure
|
|
329
|
-
The figure to extract artists from.
|
|
330
|
-
include_text : bool
|
|
331
|
-
Whether to include text elements.
|
|
332
|
-
|
|
333
|
-
Returns
|
|
334
|
-
-------
|
|
335
|
-
tuple
|
|
336
|
-
(artists_list, groups_dict) where:
|
|
337
|
-
- artists_list: List of (artist, axes_index, artist_type, group_id) tuples
|
|
338
|
-
- groups_dict: Dictionary of logical groups
|
|
339
|
-
|
|
340
|
-
Examples
|
|
341
|
-
--------
|
|
342
|
-
>>> artists, groups = get_all_artists_with_groups(fig)
|
|
343
|
-
>>> for artist, ax_idx, atype, group_id in artists:
|
|
344
|
-
... if group_id:
|
|
345
|
-
... print(f"{atype} belongs to group {group_id}")
|
|
346
|
-
"""
|
|
347
|
-
# First, detect logical groups
|
|
348
|
-
groups = detect_logical_groups(fig)
|
|
349
|
-
|
|
350
|
-
# Create a mapping from artist to group_id
|
|
351
|
-
artist_to_group = {}
|
|
352
|
-
for group_id, group_info in groups.items():
|
|
353
|
-
for artist in group_info['artists']:
|
|
354
|
-
artist_to_group[id(artist)] = group_id
|
|
355
|
-
|
|
356
|
-
# Now get all artists with group information
|
|
357
|
-
artists_with_groups = []
|
|
358
|
-
|
|
359
|
-
for ax_idx, ax in enumerate(fig.axes):
|
|
360
|
-
# Lines (Line2D)
|
|
361
|
-
for line in ax.get_lines():
|
|
362
|
-
label = line.get_label()
|
|
363
|
-
if not label.startswith('_'): # Skip internal lines
|
|
364
|
-
group_id = artist_to_group.get(id(line))
|
|
365
|
-
artists_with_groups.append((line, ax_idx, 'line', group_id))
|
|
366
|
-
|
|
367
|
-
# Scatter plots (PathCollection)
|
|
368
|
-
for coll in ax.collections:
|
|
369
|
-
coll_type = type(coll).__name__
|
|
370
|
-
group_id = artist_to_group.get(id(coll))
|
|
371
|
-
if 'PathCollection' in coll_type:
|
|
372
|
-
artists_with_groups.append((coll, ax_idx, 'scatter', group_id))
|
|
373
|
-
elif 'PolyCollection' in coll_type or 'FillBetween' in coll_type:
|
|
374
|
-
artists_with_groups.append((coll, ax_idx, 'fill', group_id))
|
|
375
|
-
elif 'QuadMesh' in coll_type:
|
|
376
|
-
artists_with_groups.append((coll, ax_idx, 'mesh', group_id))
|
|
377
|
-
|
|
378
|
-
# Bars - handle both container level and individual patches
|
|
379
|
-
processed_patches = set()
|
|
380
|
-
for container in ax.containers:
|
|
381
|
-
if hasattr(container, 'patches') and container.patches:
|
|
382
|
-
# Check if first patch belongs to a group
|
|
383
|
-
group_id = artist_to_group.get(id(container.patches[0]))
|
|
384
|
-
|
|
385
|
-
if group_id:
|
|
386
|
-
# Grouped bars (histogram or bar_series): add container as single element
|
|
387
|
-
artists_with_groups.append((container, ax_idx, 'bar', group_id))
|
|
388
|
-
# Mark patches as processed
|
|
389
|
-
for patch in container.patches:
|
|
390
|
-
processed_patches.add(id(patch))
|
|
391
|
-
else:
|
|
392
|
-
# Simple categorical bar: add each patch individually (standalone)
|
|
393
|
-
for patch in container.patches:
|
|
394
|
-
artists_with_groups.append((patch, ax_idx, 'rectangle', None))
|
|
395
|
-
processed_patches.add(id(patch))
|
|
396
|
-
|
|
397
|
-
# Individual patches (rectangles, circles, etc.) not in containers
|
|
398
|
-
for patch in ax.patches:
|
|
399
|
-
if id(patch) in processed_patches:
|
|
400
|
-
continue
|
|
401
|
-
patch_type = type(patch).__name__
|
|
402
|
-
group_id = artist_to_group.get(id(patch))
|
|
403
|
-
if patch_type == 'Rectangle':
|
|
404
|
-
artists_with_groups.append((patch, ax_idx, 'rectangle', group_id))
|
|
405
|
-
elif patch_type in ('Circle', 'Ellipse'):
|
|
406
|
-
artists_with_groups.append((patch, ax_idx, 'circle', group_id))
|
|
407
|
-
elif patch_type == 'Polygon':
|
|
408
|
-
artists_with_groups.append((patch, ax_idx, 'polygon', group_id))
|
|
409
|
-
elif patch_type == 'Wedge':
|
|
410
|
-
artists_with_groups.append((patch, ax_idx, 'wedge', group_id))
|
|
411
|
-
|
|
412
|
-
# Images
|
|
413
|
-
for img in ax.images:
|
|
414
|
-
group_id = artist_to_group.get(id(img))
|
|
415
|
-
artists_with_groups.append((img, ax_idx, 'image', group_id))
|
|
416
|
-
|
|
417
|
-
# Text (optional)
|
|
418
|
-
if include_text:
|
|
419
|
-
for text in ax.texts:
|
|
420
|
-
if text.get_text():
|
|
421
|
-
group_id = artist_to_group.get(id(text))
|
|
422
|
-
artists_with_groups.append((text, ax_idx, 'text', group_id))
|
|
423
|
-
|
|
424
|
-
return artists_with_groups, groups
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
def _id_to_rgb(element_id: int) -> Tuple[int, int, int]:
|
|
428
|
-
"""
|
|
429
|
-
Convert element ID to unique, human-readable RGB color using hash-based generation.
|
|
430
|
-
|
|
431
|
-
Uses a hash function to generate visually distinct colors that are:
|
|
432
|
-
1. Deterministic (same ID always gives same color)
|
|
433
|
-
2. Visually distinct (spread across the color space)
|
|
434
|
-
3. Bright and saturated (easy to see)
|
|
435
|
-
|
|
436
|
-
The first 12 elements use a hand-picked palette for maximum distinctness.
|
|
437
|
-
Beyond that, uses hash-based HSV generation with high saturation.
|
|
438
|
-
|
|
439
|
-
Parameters
|
|
440
|
-
----------
|
|
441
|
-
element_id : int
|
|
442
|
-
Element ID (1-based). ID 0 is reserved for background.
|
|
443
|
-
|
|
444
|
-
Returns
|
|
445
|
-
-------
|
|
446
|
-
tuple
|
|
447
|
-
(R, G, B) values (0-255)
|
|
448
|
-
|
|
449
|
-
Notes
|
|
450
|
-
-----
|
|
451
|
-
The hash ensures:
|
|
452
|
-
- Same element_id always maps to the same color
|
|
453
|
-
- Colors are well-distributed across the spectrum
|
|
454
|
-
- Avoids dark colors (reserved for background/axes)
|
|
455
|
-
"""
|
|
456
|
-
import colorsys
|
|
457
|
-
import hashlib
|
|
458
|
-
|
|
459
|
-
if element_id <= 0:
|
|
460
|
-
return (0, 0, 0) # Background
|
|
461
|
-
|
|
462
|
-
# Hand-picked palette for first 12 elements (most common case)
|
|
463
|
-
# These are maximally distinct primary/secondary colors
|
|
464
|
-
DISTINCT_COLORS = [
|
|
465
|
-
(255, 0, 0), # 1: Red
|
|
466
|
-
(0, 200, 0), # 2: Green (slightly darker for visibility)
|
|
467
|
-
(0, 100, 255), # 3: Blue (lighter for visibility)
|
|
468
|
-
(255, 200, 0), # 4: Yellow/Gold
|
|
469
|
-
(255, 0, 200), # 5: Magenta/Pink
|
|
470
|
-
(0, 220, 220), # 6: Cyan
|
|
471
|
-
(255, 100, 0), # 7: Orange
|
|
472
|
-
(150, 0, 255), # 8: Purple
|
|
473
|
-
(0, 255, 100), # 9: Spring Green
|
|
474
|
-
(255, 100, 150), # 10: Salmon/Rose
|
|
475
|
-
(100, 255, 0), # 11: Lime
|
|
476
|
-
(100, 150, 255), # 12: Sky Blue
|
|
477
|
-
]
|
|
478
|
-
|
|
479
|
-
if element_id <= len(DISTINCT_COLORS):
|
|
480
|
-
return DISTINCT_COLORS[element_id - 1]
|
|
481
|
-
|
|
482
|
-
# For IDs > 12, use hash-based color generation
|
|
483
|
-
# Hash the ID to get a pseudo-random but deterministic value
|
|
484
|
-
hash_bytes = hashlib.md5(str(element_id).encode()).digest()
|
|
485
|
-
|
|
486
|
-
# Use hash bytes to generate HSV values
|
|
487
|
-
# Hue: full range (0-1) for variety
|
|
488
|
-
hue = int.from_bytes(hash_bytes[0:2], 'big') / 65535.0
|
|
489
|
-
|
|
490
|
-
# Saturation: high (0.7-1.0) for vivid colors
|
|
491
|
-
saturation = 0.7 + (int.from_bytes(hash_bytes[2:3], 'big') / 255.0) * 0.3
|
|
492
|
-
|
|
493
|
-
# Value: high (0.75-1.0) to avoid dark colors
|
|
494
|
-
value = 0.75 + (int.from_bytes(hash_bytes[3:4], 'big') / 255.0) * 0.25
|
|
495
|
-
|
|
496
|
-
r, g, b = colorsys.hsv_to_rgb(hue, saturation, value)
|
|
497
|
-
return (int(r * 255), int(g * 255), int(b * 255))
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
def _rgb_to_id_lookup(r: int, g: int, b: int, color_map: dict) -> int:
|
|
501
|
-
"""
|
|
502
|
-
Convert RGB color back to element ID using the color map.
|
|
503
|
-
|
|
504
|
-
Since we use human-readable colors, we need to look up in the map.
|
|
505
|
-
|
|
506
|
-
Parameters
|
|
507
|
-
----------
|
|
508
|
-
r, g, b : int
|
|
509
|
-
RGB values (0-255)
|
|
510
|
-
color_map : dict
|
|
511
|
-
Color map from generate_hitmap_id_colors (maps ID -> info with 'rgb' key)
|
|
512
|
-
|
|
513
|
-
Returns
|
|
514
|
-
-------
|
|
515
|
-
int
|
|
516
|
-
Element ID, or 0 if not found
|
|
517
|
-
"""
|
|
518
|
-
rgb = [r, g, b]
|
|
519
|
-
for element_id, info in color_map.items():
|
|
520
|
-
if info.get('rgb') == rgb:
|
|
521
|
-
return element_id
|
|
522
|
-
return 0
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
# Reserved colors for hitmap (human-readable)
|
|
526
|
-
HITMAP_BACKGROUND_COLOR = '#1a1a1a' # Dark gray (not pure black, easier to see)
|
|
527
|
-
HITMAP_AXES_COLOR = '#404040' # Medium gray (non-selectable axes elements)
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
def _rgb_to_id(r: int, g: int, b: int) -> int:
|
|
531
|
-
"""Convert RGB color back to element ID."""
|
|
532
|
-
return (r << 16) | (g << 8) | b
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
def generate_hitmap_id_colors(
|
|
536
|
-
fig,
|
|
537
|
-
dpi: int = 100,
|
|
538
|
-
include_text: bool = False,
|
|
539
|
-
) -> Tuple[np.ndarray, Dict[int, Dict[str, Any]]]:
|
|
540
|
-
"""
|
|
541
|
-
Generate a hit map using unique ID colors (fastest method).
|
|
542
|
-
|
|
543
|
-
Assigns unique RGB colors to each element, renders once, and creates
|
|
544
|
-
a pixel-perfect hit map where each pixel's RGB values encode the
|
|
545
|
-
element ID using 24-bit color space (~16.7M unique IDs).
|
|
546
|
-
|
|
547
|
-
Parameters
|
|
548
|
-
----------
|
|
549
|
-
fig : matplotlib.figure.Figure
|
|
550
|
-
The figure to generate hit map for.
|
|
551
|
-
dpi : int
|
|
552
|
-
Resolution for hit map rendering.
|
|
553
|
-
include_text : bool
|
|
554
|
-
Whether to include text elements in hit map.
|
|
555
|
-
|
|
556
|
-
Returns
|
|
557
|
-
-------
|
|
558
|
-
tuple
|
|
559
|
-
(hitmap_array, color_map) where:
|
|
560
|
-
- hitmap_array: uint32 array with element IDs (0 = background)
|
|
561
|
-
- color_map: dict mapping ID to element info
|
|
562
|
-
|
|
563
|
-
Notes
|
|
564
|
-
-----
|
|
565
|
-
Performance: ~89ms for complex figures (33x faster than sequential)
|
|
566
|
-
Uses RGB 24-bit encoding for up to ~16.7 million unique element IDs.
|
|
567
|
-
"""
|
|
568
|
-
import matplotlib.pyplot as plt
|
|
569
|
-
import copy
|
|
570
|
-
|
|
571
|
-
# Get all artists
|
|
572
|
-
artists = get_all_artists(fig, include_text)
|
|
573
|
-
|
|
574
|
-
if not artists:
|
|
575
|
-
h = int(fig.get_figheight() * dpi)
|
|
576
|
-
w = int(fig.get_figwidth() * dpi)
|
|
577
|
-
return np.zeros((h, w), dtype=np.uint32), {}
|
|
578
|
-
|
|
579
|
-
# Store original properties for restoration
|
|
580
|
-
original_props = []
|
|
581
|
-
|
|
582
|
-
# Build color map
|
|
583
|
-
color_map = {}
|
|
584
|
-
|
|
585
|
-
for i, (artist, ax_idx, artist_type) in enumerate(artists):
|
|
586
|
-
element_id = i + 1
|
|
587
|
-
# Use full RGB 24-bit encoding for unique ID colors
|
|
588
|
-
r, g, b = _id_to_rgb(element_id)
|
|
589
|
-
hex_color = f"#{r:02x}{g:02x}{b:02x}"
|
|
590
|
-
|
|
591
|
-
# Store original properties
|
|
592
|
-
props = {'artist': artist, 'type': artist_type}
|
|
593
|
-
try:
|
|
594
|
-
if hasattr(artist, 'get_color'):
|
|
595
|
-
props['color'] = artist.get_color()
|
|
596
|
-
if hasattr(artist, 'get_facecolor'):
|
|
597
|
-
props['facecolor'] = artist.get_facecolor()
|
|
598
|
-
if hasattr(artist, 'get_edgecolor'):
|
|
599
|
-
props['edgecolor'] = artist.get_edgecolor()
|
|
600
|
-
if hasattr(artist, 'get_alpha'):
|
|
601
|
-
props['alpha'] = artist.get_alpha()
|
|
602
|
-
if hasattr(artist, 'get_antialiased'):
|
|
603
|
-
props['antialiased'] = artist.get_antialiased()
|
|
604
|
-
except Exception:
|
|
605
|
-
pass
|
|
606
|
-
original_props.append(props)
|
|
607
|
-
|
|
608
|
-
# Build color map entry (use element_id as key)
|
|
609
|
-
label = ''
|
|
610
|
-
if hasattr(artist, 'get_label'):
|
|
611
|
-
label = artist.get_label()
|
|
612
|
-
if label.startswith('_'):
|
|
613
|
-
label = f'{artist_type}_{i}'
|
|
614
|
-
|
|
615
|
-
color_map[element_id] = {
|
|
616
|
-
'id': element_id,
|
|
617
|
-
'type': artist_type,
|
|
618
|
-
'label': label,
|
|
619
|
-
'axes_index': ax_idx,
|
|
620
|
-
'rgb': [r, g, b],
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
# Apply ID color and disable anti-aliasing
|
|
624
|
-
try:
|
|
625
|
-
_apply_id_color(artist, hex_color)
|
|
626
|
-
except Exception:
|
|
627
|
-
pass
|
|
628
|
-
|
|
629
|
-
# Make non-artist elements the reserved axes color (NOT black)
|
|
630
|
-
# This distinguishes axes from background while making them non-selectable
|
|
631
|
-
axes_color = HITMAP_AXES_COLOR
|
|
632
|
-
for ax in fig.axes:
|
|
633
|
-
ax.grid(False)
|
|
634
|
-
for spine in ax.spines.values():
|
|
635
|
-
spine.set_color(axes_color)
|
|
636
|
-
ax.set_facecolor(HITMAP_BACKGROUND_COLOR)
|
|
637
|
-
ax.tick_params(colors=axes_color, labelcolor=axes_color)
|
|
638
|
-
ax.xaxis.label.set_color(axes_color)
|
|
639
|
-
ax.yaxis.label.set_color(axes_color)
|
|
640
|
-
ax.title.set_color(axes_color)
|
|
641
|
-
if ax.get_legend():
|
|
642
|
-
ax.get_legend().set_visible(False)
|
|
643
|
-
|
|
644
|
-
fig.patch.set_facecolor(HITMAP_BACKGROUND_COLOR)
|
|
645
|
-
|
|
646
|
-
# Render
|
|
647
|
-
fig.canvas.draw()
|
|
648
|
-
img = np.array(fig.canvas.buffer_rgba())
|
|
649
|
-
# Convert RGB to element ID using 24-bit encoding
|
|
650
|
-
hitmap = (img[:, :, 0].astype(np.uint32) << 16) | \
|
|
651
|
-
(img[:, :, 1].astype(np.uint32) << 8) | \
|
|
652
|
-
img[:, :, 2].astype(np.uint32)
|
|
653
|
-
|
|
654
|
-
# Restore original properties
|
|
655
|
-
for props in original_props:
|
|
656
|
-
artist = props['artist']
|
|
657
|
-
try:
|
|
658
|
-
if 'color' in props and hasattr(artist, 'set_color'):
|
|
659
|
-
artist.set_color(props['color'])
|
|
660
|
-
if 'facecolor' in props and hasattr(artist, 'set_facecolor'):
|
|
661
|
-
artist.set_facecolor(props['facecolor'])
|
|
662
|
-
if 'edgecolor' in props and hasattr(artist, 'set_edgecolor'):
|
|
663
|
-
artist.set_edgecolor(props['edgecolor'])
|
|
664
|
-
if 'alpha' in props and hasattr(artist, 'set_alpha'):
|
|
665
|
-
artist.set_alpha(props['alpha'])
|
|
666
|
-
if 'antialiased' in props and hasattr(artist, 'set_antialiased'):
|
|
667
|
-
artist.set_antialiased(props['antialiased'])
|
|
668
|
-
except Exception:
|
|
669
|
-
pass
|
|
670
|
-
|
|
671
|
-
return hitmap, color_map
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
def _apply_id_color(artist, hex_color: str):
|
|
675
|
-
"""Apply ID color to an artist, handling different artist types."""
|
|
676
|
-
artist_type = type(artist).__name__
|
|
677
|
-
|
|
678
|
-
if hasattr(artist, 'set_color'):
|
|
679
|
-
artist.set_color(hex_color)
|
|
680
|
-
if hasattr(artist, 'set_antialiased'):
|
|
681
|
-
artist.set_antialiased(False)
|
|
682
|
-
|
|
683
|
-
elif hasattr(artist, 'set_facecolor'):
|
|
684
|
-
artist.set_facecolor(hex_color)
|
|
685
|
-
if hasattr(artist, 'set_edgecolor'):
|
|
686
|
-
artist.set_edgecolor(hex_color)
|
|
687
|
-
if hasattr(artist, 'set_alpha'):
|
|
688
|
-
artist.set_alpha(1.0)
|
|
689
|
-
if hasattr(artist, 'set_antialiased'):
|
|
690
|
-
artist.set_antialiased(False)
|
|
691
|
-
|
|
692
|
-
# Handle BarContainer
|
|
693
|
-
if hasattr(artist, 'patches'):
|
|
694
|
-
for patch in artist.patches:
|
|
695
|
-
patch.set_facecolor(hex_color)
|
|
696
|
-
patch.set_edgecolor(hex_color)
|
|
697
|
-
if hasattr(patch, 'set_antialiased'):
|
|
698
|
-
patch.set_antialiased(False)
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
def _prepare_hitmap_figure(
|
|
702
|
-
fig,
|
|
703
|
-
include_text: bool = False,
|
|
704
|
-
) -> Tuple[Dict[int, Dict[str, Any]], List[Dict[str, Any]]]:
|
|
705
|
-
"""
|
|
706
|
-
Prepare a figure for hitmap rendering by coloring elements with unique IDs.
|
|
707
|
-
|
|
708
|
-
This function modifies the figure in-place by:
|
|
709
|
-
1. Assigning unique RGB colors to each artist (24-bit ID encoding)
|
|
710
|
-
2. Hiding non-selectable elements (axes, spines, grid, etc.)
|
|
711
|
-
3. Setting background to black (ID = 0)
|
|
712
|
-
|
|
713
|
-
Parameters
|
|
714
|
-
----------
|
|
715
|
-
fig : matplotlib.figure.Figure
|
|
716
|
-
The figure to prepare for hitmap rendering.
|
|
717
|
-
include_text : bool
|
|
718
|
-
Whether to include text elements.
|
|
719
|
-
|
|
720
|
-
Returns
|
|
721
|
-
-------
|
|
722
|
-
tuple
|
|
723
|
-
(color_map, original_props) where:
|
|
724
|
-
- color_map: dict mapping ID to element info
|
|
725
|
-
- original_props: list of dicts with original artist properties (for restoration)
|
|
726
|
-
|
|
727
|
-
Notes
|
|
728
|
-
-----
|
|
729
|
-
After calling this function, you can render the figure using savefig()
|
|
730
|
-
with bbox_inches='tight' to get a pixel-perfect hitmap.
|
|
731
|
-
Call _restore_figure_props(original_props) to restore the figure.
|
|
732
|
-
"""
|
|
733
|
-
artists = get_all_artists(fig, include_text)
|
|
734
|
-
|
|
735
|
-
if not artists:
|
|
736
|
-
return {}, []
|
|
737
|
-
|
|
738
|
-
# Store original properties for restoration
|
|
739
|
-
original_props = []
|
|
740
|
-
|
|
741
|
-
# Build color map
|
|
742
|
-
color_map = {}
|
|
743
|
-
|
|
744
|
-
for i, (artist, ax_idx, artist_type) in enumerate(artists):
|
|
745
|
-
element_id = i + 1
|
|
746
|
-
# Use full RGB 24-bit encoding for unique ID colors
|
|
747
|
-
r, g, b = _id_to_rgb(element_id)
|
|
748
|
-
hex_color = f"#{r:02x}{g:02x}{b:02x}"
|
|
749
|
-
|
|
750
|
-
# Store original properties
|
|
751
|
-
props = {'artist': artist, 'type': artist_type}
|
|
752
|
-
try:
|
|
753
|
-
if hasattr(artist, 'get_color'):
|
|
754
|
-
props['color'] = artist.get_color()
|
|
755
|
-
if hasattr(artist, 'get_facecolor'):
|
|
756
|
-
props['facecolor'] = artist.get_facecolor()
|
|
757
|
-
if hasattr(artist, 'get_edgecolor'):
|
|
758
|
-
props['edgecolor'] = artist.get_edgecolor()
|
|
759
|
-
if hasattr(artist, 'get_alpha'):
|
|
760
|
-
props['alpha'] = artist.get_alpha()
|
|
761
|
-
if hasattr(artist, 'get_antialiased'):
|
|
762
|
-
props['antialiased'] = artist.get_antialiased()
|
|
763
|
-
except Exception:
|
|
764
|
-
pass
|
|
765
|
-
original_props.append(props)
|
|
766
|
-
|
|
767
|
-
# Build color map entry
|
|
768
|
-
label = ''
|
|
769
|
-
if hasattr(artist, 'get_label'):
|
|
770
|
-
label = artist.get_label()
|
|
771
|
-
if label.startswith('_'):
|
|
772
|
-
label = f'{artist_type}_{i}'
|
|
773
|
-
|
|
774
|
-
color_map[element_id] = {
|
|
775
|
-
'id': element_id,
|
|
776
|
-
'type': artist_type,
|
|
777
|
-
'label': label,
|
|
778
|
-
'axes_index': ax_idx,
|
|
779
|
-
'rgb': [r, g, b],
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
# Apply ID color and disable anti-aliasing
|
|
783
|
-
try:
|
|
784
|
-
_apply_id_color(artist, hex_color)
|
|
785
|
-
except Exception:
|
|
786
|
-
pass
|
|
787
|
-
|
|
788
|
-
# Hide non-artist elements (we need to save these for restoration too)
|
|
789
|
-
axes_props = []
|
|
790
|
-
for ax in fig.axes:
|
|
791
|
-
ax_props = {
|
|
792
|
-
'ax': ax,
|
|
793
|
-
'grid_visible': ax.xaxis.get_gridlines()[0].get_visible() if ax.xaxis.get_gridlines() else False,
|
|
794
|
-
'facecolor': ax.get_facecolor(),
|
|
795
|
-
'spines_visible': {k: v.get_visible() for k, v in ax.spines.items()},
|
|
796
|
-
'xlabel': ax.get_xlabel(),
|
|
797
|
-
'ylabel': ax.get_ylabel(),
|
|
798
|
-
'title': ax.get_title(),
|
|
799
|
-
'legend_visible': ax.get_legend().get_visible() if ax.get_legend() else None,
|
|
800
|
-
'tick_params': {}, # Complex to save/restore, skip for now
|
|
801
|
-
}
|
|
802
|
-
axes_props.append(ax_props)
|
|
803
|
-
|
|
804
|
-
ax.grid(False)
|
|
805
|
-
for spine in ax.spines.values():
|
|
806
|
-
spine.set_color(HITMAP_AXES_COLOR)
|
|
807
|
-
ax.set_facecolor(HITMAP_BACKGROUND_COLOR)
|
|
808
|
-
ax.tick_params(colors=HITMAP_AXES_COLOR, labelcolor=HITMAP_AXES_COLOR)
|
|
809
|
-
ax.xaxis.label.set_color(HITMAP_AXES_COLOR)
|
|
810
|
-
ax.yaxis.label.set_color(HITMAP_AXES_COLOR)
|
|
811
|
-
ax.title.set_color(HITMAP_AXES_COLOR)
|
|
812
|
-
if ax.get_legend():
|
|
813
|
-
ax.get_legend().set_visible(False)
|
|
814
|
-
|
|
815
|
-
# Save figure background
|
|
816
|
-
original_props.append({
|
|
817
|
-
'type': '_figure_patch',
|
|
818
|
-
'facecolor': fig.patch.get_facecolor(),
|
|
819
|
-
'axes_props': axes_props,
|
|
820
|
-
})
|
|
821
|
-
fig.patch.set_facecolor(HITMAP_BACKGROUND_COLOR)
|
|
822
|
-
|
|
823
|
-
return color_map, original_props
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
def _restore_figure_props(original_props: List[Dict[str, Any]]):
|
|
827
|
-
"""
|
|
828
|
-
Restore figure properties after hitmap rendering.
|
|
829
|
-
|
|
830
|
-
Parameters
|
|
831
|
-
----------
|
|
832
|
-
original_props : list
|
|
833
|
-
List of property dicts from _prepare_hitmap_figure().
|
|
834
|
-
"""
|
|
835
|
-
for props in original_props:
|
|
836
|
-
if props.get('type') == '_figure_patch':
|
|
837
|
-
# Restore axes and figure background
|
|
838
|
-
if 'axes_props' in props:
|
|
839
|
-
for ax_props in props['axes_props']:
|
|
840
|
-
ax = ax_props['ax']
|
|
841
|
-
ax.set_facecolor(ax_props['facecolor'])
|
|
842
|
-
for spine_name, visible in ax_props['spines_visible'].items():
|
|
843
|
-
ax.spines[spine_name].set_visible(visible)
|
|
844
|
-
ax.set_xlabel(ax_props['xlabel'])
|
|
845
|
-
ax.set_ylabel(ax_props['ylabel'])
|
|
846
|
-
ax.set_title(ax_props['title'])
|
|
847
|
-
if ax_props['legend_visible'] is not None and ax.get_legend():
|
|
848
|
-
ax.get_legend().set_visible(ax_props['legend_visible'])
|
|
849
|
-
continue
|
|
850
|
-
|
|
851
|
-
artist = props.get('artist')
|
|
852
|
-
if not artist:
|
|
853
|
-
continue
|
|
854
|
-
|
|
855
|
-
try:
|
|
856
|
-
if 'color' in props and hasattr(artist, 'set_color'):
|
|
857
|
-
artist.set_color(props['color'])
|
|
858
|
-
if 'facecolor' in props and hasattr(artist, 'set_facecolor'):
|
|
859
|
-
artist.set_facecolor(props['facecolor'])
|
|
860
|
-
if 'edgecolor' in props and hasattr(artist, 'set_edgecolor'):
|
|
861
|
-
artist.set_edgecolor(props['edgecolor'])
|
|
862
|
-
if 'alpha' in props and hasattr(artist, 'set_alpha'):
|
|
863
|
-
artist.set_alpha(props['alpha'])
|
|
864
|
-
if 'antialiased' in props and hasattr(artist, 'set_antialiased'):
|
|
865
|
-
artist.set_antialiased(props['antialiased'])
|
|
866
|
-
except Exception:
|
|
867
|
-
pass
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
def extract_path_data(
|
|
871
|
-
fig,
|
|
872
|
-
include_text: bool = False,
|
|
873
|
-
) -> Dict[str, Any]:
|
|
874
|
-
"""
|
|
875
|
-
Extract path/geometry data for client-side hit testing.
|
|
876
|
-
|
|
877
|
-
Extracts bounding boxes and path coordinates for all selectable elements,
|
|
878
|
-
enabling JavaScript-based hit testing in web editors.
|
|
879
|
-
|
|
880
|
-
Parameters
|
|
881
|
-
----------
|
|
882
|
-
fig : matplotlib.figure.Figure
|
|
883
|
-
The figure to extract data from.
|
|
884
|
-
include_text : bool
|
|
885
|
-
Whether to include text elements.
|
|
886
|
-
|
|
887
|
-
Returns
|
|
888
|
-
-------
|
|
889
|
-
dict
|
|
890
|
-
Exported data structure with figure info and artist geometries.
|
|
891
|
-
|
|
892
|
-
Notes
|
|
893
|
-
-----
|
|
894
|
-
Performance: ~192ms extraction, ~0.01ms client-side queries
|
|
895
|
-
Supports: resize/zoom (transform coordinates client-side)
|
|
896
|
-
"""
|
|
897
|
-
with warnings.catch_warnings():
|
|
898
|
-
warnings.filterwarnings("ignore", message=".*tight_layout.*")
|
|
899
|
-
fig.canvas.draw() # Ensure transforms are computed
|
|
900
|
-
|
|
901
|
-
artists = get_all_artists(fig, include_text)
|
|
902
|
-
|
|
903
|
-
dpi = fig.dpi
|
|
904
|
-
fig_width_px = int(fig.get_figwidth() * dpi)
|
|
905
|
-
fig_height_px = int(fig.get_figheight() * dpi)
|
|
906
|
-
|
|
907
|
-
export = {
|
|
908
|
-
'figure': {
|
|
909
|
-
'width_px': fig_width_px,
|
|
910
|
-
'height_px': fig_height_px,
|
|
911
|
-
'dpi': dpi,
|
|
912
|
-
},
|
|
913
|
-
'axes': [],
|
|
914
|
-
'artists': [],
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
# Export axes info
|
|
918
|
-
for ax in fig.axes:
|
|
919
|
-
bbox = ax.get_position()
|
|
920
|
-
export['axes'].append({
|
|
921
|
-
'xlim': list(ax.get_xlim()),
|
|
922
|
-
'ylim': list(ax.get_ylim()),
|
|
923
|
-
'bbox_norm': {
|
|
924
|
-
'x0': bbox.x0,
|
|
925
|
-
'y0': bbox.y0,
|
|
926
|
-
'x1': bbox.x1,
|
|
927
|
-
'y1': bbox.y1,
|
|
928
|
-
},
|
|
929
|
-
'bbox_px': {
|
|
930
|
-
'x0': int(bbox.x0 * fig_width_px),
|
|
931
|
-
'y0': int((1 - bbox.y1) * fig_height_px),
|
|
932
|
-
'x1': int(bbox.x1 * fig_width_px),
|
|
933
|
-
'y1': int((1 - bbox.y0) * fig_height_px),
|
|
934
|
-
},
|
|
935
|
-
})
|
|
936
|
-
|
|
937
|
-
# Export artist geometries
|
|
938
|
-
renderer = fig.canvas.get_renderer()
|
|
939
|
-
|
|
940
|
-
for i, (artist, ax_idx, artist_type) in enumerate(artists):
|
|
941
|
-
artist_data = {
|
|
942
|
-
'id': i,
|
|
943
|
-
'type': artist_type,
|
|
944
|
-
'axes_index': ax_idx,
|
|
945
|
-
'label': '',
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
# Get label
|
|
949
|
-
if hasattr(artist, 'get_label'):
|
|
950
|
-
label = artist.get_label()
|
|
951
|
-
artist_data['label'] = label if not label.startswith('_') else f'{artist_type}_{i}'
|
|
952
|
-
|
|
953
|
-
# Get bounding box
|
|
954
|
-
try:
|
|
955
|
-
bbox = artist.get_window_extent(renderer)
|
|
956
|
-
artist_data['bbox_px'] = {
|
|
957
|
-
'x0': float(bbox.x0),
|
|
958
|
-
'y0': float(fig_height_px - bbox.y1), # Flip Y
|
|
959
|
-
'x1': float(bbox.x1),
|
|
960
|
-
'y1': float(fig_height_px - bbox.y0),
|
|
961
|
-
}
|
|
962
|
-
except Exception:
|
|
963
|
-
artist_data['bbox_px'] = None
|
|
964
|
-
|
|
965
|
-
# Extract type-specific geometry
|
|
966
|
-
try:
|
|
967
|
-
if artist_type == 'line' and hasattr(artist, 'get_xydata'):
|
|
968
|
-
xy = artist.get_xydata()
|
|
969
|
-
transform = artist.get_transform()
|
|
970
|
-
xy_px = transform.transform(xy)
|
|
971
|
-
# Flip Y and limit points for JSON size
|
|
972
|
-
xy_px[:, 1] = fig_height_px - xy_px[:, 1]
|
|
973
|
-
# Sample if too many points
|
|
974
|
-
if len(xy_px) > 100:
|
|
975
|
-
indices = np.linspace(0, len(xy_px) - 1, 100, dtype=int)
|
|
976
|
-
xy_px = xy_px[indices]
|
|
977
|
-
artist_data['path_px'] = xy_px.tolist()
|
|
978
|
-
artist_data['linewidth'] = artist.get_linewidth()
|
|
979
|
-
|
|
980
|
-
elif artist_type == 'scatter' and hasattr(artist, 'get_offsets'):
|
|
981
|
-
offsets = artist.get_offsets()
|
|
982
|
-
transform = artist.get_transform()
|
|
983
|
-
offsets_px = transform.transform(offsets)
|
|
984
|
-
offsets_px[:, 1] = fig_height_px - offsets_px[:, 1]
|
|
985
|
-
artist_data['points_px'] = offsets_px.tolist()
|
|
986
|
-
sizes = artist.get_sizes()
|
|
987
|
-
artist_data['sizes'] = sizes.tolist() if len(sizes) > 0 else [36]
|
|
988
|
-
|
|
989
|
-
elif artist_type == 'fill' and hasattr(artist, 'get_paths'):
|
|
990
|
-
paths = artist.get_paths()
|
|
991
|
-
if paths:
|
|
992
|
-
transform = artist.get_transform()
|
|
993
|
-
vertices = paths[0].vertices
|
|
994
|
-
vertices_px = transform.transform(vertices)
|
|
995
|
-
vertices_px[:, 1] = fig_height_px - vertices_px[:, 1]
|
|
996
|
-
# Sample if too many vertices
|
|
997
|
-
if len(vertices_px) > 100:
|
|
998
|
-
indices = np.linspace(0, len(vertices_px) - 1, 100, dtype=int)
|
|
999
|
-
vertices_px = vertices_px[indices]
|
|
1000
|
-
artist_data['polygon_px'] = vertices_px.tolist()
|
|
1001
|
-
|
|
1002
|
-
elif artist_type == 'bar' and hasattr(artist, 'patches'):
|
|
1003
|
-
bars = []
|
|
1004
|
-
ax = fig.axes[ax_idx]
|
|
1005
|
-
for patch in artist.patches:
|
|
1006
|
-
# Get data coordinates
|
|
1007
|
-
x_data = patch.get_x()
|
|
1008
|
-
y_data = patch.get_y()
|
|
1009
|
-
w_data = patch.get_width()
|
|
1010
|
-
h_data = patch.get_height()
|
|
1011
|
-
bars.append({
|
|
1012
|
-
'x': x_data,
|
|
1013
|
-
'y': y_data,
|
|
1014
|
-
'width': w_data,
|
|
1015
|
-
'height': h_data,
|
|
1016
|
-
})
|
|
1017
|
-
artist_data['bars_data'] = bars
|
|
1018
|
-
|
|
1019
|
-
elif artist_type == 'rectangle':
|
|
1020
|
-
artist_data['rectangle'] = {
|
|
1021
|
-
'x': artist.get_x(),
|
|
1022
|
-
'y': artist.get_y(),
|
|
1023
|
-
'width': artist.get_width(),
|
|
1024
|
-
'height': artist.get_height(),
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
except Exception as e:
|
|
1028
|
-
artist_data['error'] = str(e)
|
|
1029
|
-
|
|
1030
|
-
export['artists'].append(artist_data)
|
|
1031
|
-
|
|
1032
|
-
# Convert all numpy types to native Python for JSON serialization
|
|
1033
|
-
return _to_native(export)
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
def extract_selectable_regions(fig) -> Dict[str, Any]:
|
|
1037
|
-
"""
|
|
1038
|
-
Extract bounding boxes for axis/annotation elements (non-data elements).
|
|
1039
|
-
|
|
1040
|
-
This provides a complementary approach to the color-based hitmap:
|
|
1041
|
-
- Data elements: Use hitmap color lookup (pixel-perfect)
|
|
1042
|
-
- Axis elements: Use bounding box hit testing (calculated)
|
|
1043
|
-
|
|
1044
|
-
The client-side hit test logic:
|
|
1045
|
-
1. Check selectable_regions bounding boxes first (fast rectangle test)
|
|
1046
|
-
2. If no match, sample hitmap color for data elements
|
|
1047
|
-
|
|
1048
|
-
Parameters
|
|
1049
|
-
----------
|
|
1050
|
-
fig : matplotlib.figure.Figure
|
|
1051
|
-
The figure to extract regions from.
|
|
1052
|
-
|
|
1053
|
-
Returns
|
|
1054
|
-
-------
|
|
1055
|
-
dict
|
|
1056
|
-
Dictionary with selectable regions:
|
|
1057
|
-
{
|
|
1058
|
-
"axes": [{
|
|
1059
|
-
"index": 0,
|
|
1060
|
-
"title": {"bbox_px": [x0, y0, x1, y1], "text": "..."},
|
|
1061
|
-
"xlabel": {"bbox_px": [...], "text": "..."},
|
|
1062
|
-
"ylabel": {"bbox_px": [...], "text": "..."},
|
|
1063
|
-
"xaxis": {
|
|
1064
|
-
"spine": {"bbox_px": [...]},
|
|
1065
|
-
"ticks": [{"bbox_px": [...], "position": 0.0}, ...],
|
|
1066
|
-
"ticklabels": [{"bbox_px": [...], "text": "0"}, ...]
|
|
1067
|
-
},
|
|
1068
|
-
"yaxis": {...},
|
|
1069
|
-
"legend": {
|
|
1070
|
-
"bbox_px": [...],
|
|
1071
|
-
"entries": [{"bbox_px": [...], "label": "Series A"}, ...]
|
|
1072
|
-
}
|
|
1073
|
-
}]
|
|
1074
|
-
}
|
|
1075
|
-
"""
|
|
1076
|
-
with warnings.catch_warnings():
|
|
1077
|
-
warnings.filterwarnings("ignore", message=".*tight_layout.*")
|
|
1078
|
-
fig.canvas.draw() # Ensure transforms are computed
|
|
1079
|
-
|
|
1080
|
-
dpi = fig.dpi
|
|
1081
|
-
fig_width_px = int(fig.get_figwidth() * dpi)
|
|
1082
|
-
fig_height_px = int(fig.get_figheight() * dpi)
|
|
1083
|
-
|
|
1084
|
-
renderer = fig.canvas.get_renderer()
|
|
1085
|
-
|
|
1086
|
-
def get_bbox_px(artist) -> Optional[List[float]]:
|
|
1087
|
-
"""Get bounding box in pixels (y-flipped for image coordinates)."""
|
|
1088
|
-
try:
|
|
1089
|
-
bbox = artist.get_window_extent(renderer)
|
|
1090
|
-
if bbox.width > 0 and bbox.height > 0:
|
|
1091
|
-
return [
|
|
1092
|
-
float(bbox.x0),
|
|
1093
|
-
float(fig_height_px - bbox.y1), # Flip Y
|
|
1094
|
-
float(bbox.x1),
|
|
1095
|
-
float(fig_height_px - bbox.y0),
|
|
1096
|
-
]
|
|
1097
|
-
except Exception:
|
|
1098
|
-
pass
|
|
1099
|
-
return None
|
|
1100
|
-
|
|
1101
|
-
def get_text_info(text_artist) -> Optional[Dict[str, Any]]:
|
|
1102
|
-
"""Extract text element info with bounding box."""
|
|
1103
|
-
if text_artist is None:
|
|
1104
|
-
return None
|
|
1105
|
-
text = text_artist.get_text()
|
|
1106
|
-
if not text or not text.strip():
|
|
1107
|
-
return None
|
|
1108
|
-
bbox = get_bbox_px(text_artist)
|
|
1109
|
-
if bbox is None:
|
|
1110
|
-
return None
|
|
1111
|
-
return {
|
|
1112
|
-
"bbox_px": bbox,
|
|
1113
|
-
"text": text,
|
|
1114
|
-
"fontsize": text_artist.get_fontsize(),
|
|
1115
|
-
"color": text_artist.get_color(),
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
regions = {"axes": []}
|
|
1119
|
-
|
|
1120
|
-
for ax_idx, ax in enumerate(fig.axes):
|
|
1121
|
-
ax_region = {"index": ax_idx}
|
|
1122
|
-
|
|
1123
|
-
# Title
|
|
1124
|
-
title_info = get_text_info(ax.title)
|
|
1125
|
-
if title_info:
|
|
1126
|
-
ax_region["title"] = title_info
|
|
1127
|
-
|
|
1128
|
-
# X label
|
|
1129
|
-
xlabel_info = get_text_info(ax.xaxis.label)
|
|
1130
|
-
if xlabel_info:
|
|
1131
|
-
ax_region["xlabel"] = xlabel_info
|
|
1132
|
-
|
|
1133
|
-
# Y label
|
|
1134
|
-
ylabel_info = get_text_info(ax.yaxis.label)
|
|
1135
|
-
if ylabel_info:
|
|
1136
|
-
ax_region["ylabel"] = ylabel_info
|
|
1137
|
-
|
|
1138
|
-
# X axis elements
|
|
1139
|
-
xaxis_info = {"spine": None, "ticks": [], "ticklabels": []}
|
|
1140
|
-
|
|
1141
|
-
# X spine (bottom)
|
|
1142
|
-
if ax.spines['bottom'].get_visible():
|
|
1143
|
-
spine_bbox = get_bbox_px(ax.spines['bottom'])
|
|
1144
|
-
if spine_bbox:
|
|
1145
|
-
xaxis_info["spine"] = {"bbox_px": spine_bbox}
|
|
1146
|
-
|
|
1147
|
-
# X ticks and tick labels
|
|
1148
|
-
for tick in ax.xaxis.get_major_ticks():
|
|
1149
|
-
# Tick mark
|
|
1150
|
-
if tick.tick1line.get_visible():
|
|
1151
|
-
tick_bbox = get_bbox_px(tick.tick1line)
|
|
1152
|
-
if tick_bbox:
|
|
1153
|
-
xaxis_info["ticks"].append({
|
|
1154
|
-
"bbox_px": tick_bbox,
|
|
1155
|
-
"position": float(tick.get_loc()) if hasattr(tick, 'get_loc') else None,
|
|
1156
|
-
})
|
|
1157
|
-
|
|
1158
|
-
# Tick label
|
|
1159
|
-
if tick.label1.get_visible():
|
|
1160
|
-
label_info = get_text_info(tick.label1)
|
|
1161
|
-
if label_info:
|
|
1162
|
-
xaxis_info["ticklabels"].append(label_info)
|
|
1163
|
-
|
|
1164
|
-
if xaxis_info["spine"] or xaxis_info["ticks"] or xaxis_info["ticklabels"]:
|
|
1165
|
-
ax_region["xaxis"] = xaxis_info
|
|
1166
|
-
|
|
1167
|
-
# Y axis elements
|
|
1168
|
-
yaxis_info = {"spine": None, "ticks": [], "ticklabels": []}
|
|
1169
|
-
|
|
1170
|
-
# Y spine (left)
|
|
1171
|
-
if ax.spines['left'].get_visible():
|
|
1172
|
-
spine_bbox = get_bbox_px(ax.spines['left'])
|
|
1173
|
-
if spine_bbox:
|
|
1174
|
-
yaxis_info["spine"] = {"bbox_px": spine_bbox}
|
|
1175
|
-
|
|
1176
|
-
# Y ticks and tick labels
|
|
1177
|
-
for tick in ax.yaxis.get_major_ticks():
|
|
1178
|
-
# Tick mark
|
|
1179
|
-
if tick.tick1line.get_visible():
|
|
1180
|
-
tick_bbox = get_bbox_px(tick.tick1line)
|
|
1181
|
-
if tick_bbox:
|
|
1182
|
-
yaxis_info["ticks"].append({
|
|
1183
|
-
"bbox_px": tick_bbox,
|
|
1184
|
-
"position": float(tick.get_loc()) if hasattr(tick, 'get_loc') else None,
|
|
1185
|
-
})
|
|
1186
|
-
|
|
1187
|
-
# Tick label
|
|
1188
|
-
if tick.label1.get_visible():
|
|
1189
|
-
label_info = get_text_info(tick.label1)
|
|
1190
|
-
if label_info:
|
|
1191
|
-
yaxis_info["ticklabels"].append(label_info)
|
|
1192
|
-
|
|
1193
|
-
if yaxis_info["spine"] or yaxis_info["ticks"] or yaxis_info["ticklabels"]:
|
|
1194
|
-
ax_region["yaxis"] = yaxis_info
|
|
1195
|
-
|
|
1196
|
-
# Legend
|
|
1197
|
-
legend = ax.get_legend()
|
|
1198
|
-
if legend and legend.get_visible():
|
|
1199
|
-
legend_info = {"bbox_px": None, "entries": []}
|
|
1200
|
-
|
|
1201
|
-
legend_bbox = get_bbox_px(legend)
|
|
1202
|
-
if legend_bbox:
|
|
1203
|
-
legend_info["bbox_px"] = legend_bbox
|
|
1204
|
-
|
|
1205
|
-
# Legend entries
|
|
1206
|
-
for text in legend.get_texts():
|
|
1207
|
-
entry_info = get_text_info(text)
|
|
1208
|
-
if entry_info:
|
|
1209
|
-
legend_info["entries"].append(entry_info)
|
|
1210
|
-
|
|
1211
|
-
# Legend handles (the visual markers)
|
|
1212
|
-
try:
|
|
1213
|
-
handles = legend.legendHandles
|
|
1214
|
-
for i, handle in enumerate(handles):
|
|
1215
|
-
handle_bbox = get_bbox_px(handle)
|
|
1216
|
-
if handle_bbox and i < len(legend_info["entries"]):
|
|
1217
|
-
legend_info["entries"][i]["handle_bbox_px"] = handle_bbox
|
|
1218
|
-
except Exception:
|
|
1219
|
-
pass
|
|
1220
|
-
|
|
1221
|
-
if legend_info["bbox_px"] or legend_info["entries"]:
|
|
1222
|
-
ax_region["legend"] = legend_info
|
|
1223
|
-
|
|
1224
|
-
regions["axes"].append(ax_region)
|
|
1225
|
-
|
|
1226
|
-
# Convert all numpy types to native Python for JSON serialization
|
|
1227
|
-
return _to_native(regions)
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
def query_hitmap_neighborhood(
|
|
1231
|
-
hitmap: np.ndarray,
|
|
1232
|
-
x: int,
|
|
1233
|
-
y: int,
|
|
1234
|
-
color_map: Dict[int, Dict[str, Any]],
|
|
1235
|
-
radius: int = 2,
|
|
1236
|
-
) -> List[Dict[str, Any]]:
|
|
1237
|
-
"""
|
|
1238
|
-
Query hit map with neighborhood sampling for smart selection.
|
|
1239
|
-
|
|
1240
|
-
Finds all element IDs in a neighborhood around the click point,
|
|
1241
|
-
enabling selection of overlapping elements and thin lines.
|
|
1242
|
-
|
|
1243
|
-
Parameters
|
|
1244
|
-
----------
|
|
1245
|
-
hitmap : np.ndarray
|
|
1246
|
-
Hit map array (uint32, element IDs from RGB encoding).
|
|
1247
|
-
x : int
|
|
1248
|
-
X coordinate (column) of click point.
|
|
1249
|
-
y : int
|
|
1250
|
-
Y coordinate (row) of click point.
|
|
1251
|
-
color_map : dict
|
|
1252
|
-
Mapping from element ID to element info.
|
|
1253
|
-
radius : int
|
|
1254
|
-
Sampling radius (e.g., 2 = 5×5 neighborhood).
|
|
1255
|
-
|
|
1256
|
-
Returns
|
|
1257
|
-
-------
|
|
1258
|
-
list of dict
|
|
1259
|
-
List of element info dicts for all elements found in neighborhood,
|
|
1260
|
-
sorted by distance from click point (closest first).
|
|
1261
|
-
|
|
1262
|
-
Notes
|
|
1263
|
-
-----
|
|
1264
|
-
Use cases:
|
|
1265
|
-
- Alt+Click to select objects underneath (lower z-order)
|
|
1266
|
-
- Click on thin lines that might be missed with exact pixel
|
|
1267
|
-
- Show candidate list when multiple elements overlap
|
|
1268
|
-
"""
|
|
1269
|
-
h, w = hitmap.shape
|
|
1270
|
-
found_ids = set()
|
|
1271
|
-
id_distances = {}
|
|
1272
|
-
|
|
1273
|
-
# Sample neighborhood
|
|
1274
|
-
for dy in range(-radius, radius + 1):
|
|
1275
|
-
for dx in range(-radius, radius + 1):
|
|
1276
|
-
ny, nx = y + dy, x + dx
|
|
1277
|
-
if 0 <= ny < h and 0 <= nx < w:
|
|
1278
|
-
element_id = int(hitmap[ny, nx])
|
|
1279
|
-
if element_id > 0 and element_id in color_map:
|
|
1280
|
-
found_ids.add(element_id)
|
|
1281
|
-
# Track minimum distance for each ID
|
|
1282
|
-
dist = abs(dx) + abs(dy) # Manhattan distance
|
|
1283
|
-
if element_id not in id_distances or dist < id_distances[element_id]:
|
|
1284
|
-
id_distances[element_id] = dist
|
|
1285
|
-
|
|
1286
|
-
# Sort by distance (closest first), then by ID for stability
|
|
1287
|
-
sorted_ids = sorted(found_ids, key=lambda eid: (id_distances[eid], eid))
|
|
1288
|
-
|
|
1289
|
-
return [color_map[eid] for eid in sorted_ids]
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
def save_hitmap_png(hitmap: np.ndarray, path: str, color_map: Dict = None):
|
|
1293
|
-
"""
|
|
1294
|
-
Save hit map as a PNG file (RGB encoding for 24-bit IDs).
|
|
1295
|
-
|
|
1296
|
-
Parameters
|
|
1297
|
-
----------
|
|
1298
|
-
hitmap : np.ndarray
|
|
1299
|
-
Hit map array (uint32, element IDs from 24-bit RGB encoding).
|
|
1300
|
-
path : str
|
|
1301
|
-
Output path for PNG file.
|
|
1302
|
-
color_map : dict, optional
|
|
1303
|
-
Color map for visualization.
|
|
1304
|
-
"""
|
|
1305
|
-
import matplotlib.pyplot as plt
|
|
1306
|
-
from PIL import Image
|
|
1307
|
-
|
|
1308
|
-
# Convert 24-bit IDs back to RGB for PNG storage
|
|
1309
|
-
h, w = hitmap.shape
|
|
1310
|
-
rgb = np.zeros((h, w, 3), dtype=np.uint8)
|
|
1311
|
-
rgb[:, :, 0] = (hitmap >> 16) & 0xFF # R
|
|
1312
|
-
rgb[:, :, 1] = (hitmap >> 8) & 0xFF # G
|
|
1313
|
-
rgb[:, :, 2] = hitmap & 0xFF # B
|
|
1314
|
-
|
|
1315
|
-
# Save as RGB PNG (preserves exact ID values)
|
|
1316
|
-
img = Image.fromarray(rgb, mode='RGB')
|
|
1317
|
-
img.save(path)
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
def apply_hitmap_colors(
|
|
1321
|
-
fig,
|
|
1322
|
-
include_text: bool = False,
|
|
1323
|
-
) -> Tuple[List[Dict[str, Any]], Dict[int, Dict[str, Any]], Dict[str, Dict[str, Any]]]:
|
|
1324
|
-
"""
|
|
1325
|
-
Apply unique ID colors to data elements in a figure.
|
|
1326
|
-
|
|
1327
|
-
This function modifies data elements (lines, patches, etc.) to have unique
|
|
1328
|
-
RGB colors for hit testing, while keeping axes/spines/labels unchanged.
|
|
1329
|
-
This preserves the bbox_inches='tight' bounding box calculation.
|
|
1330
|
-
|
|
1331
|
-
Also detects logical groups (histogram, bar_series, etc.) and assigns
|
|
1332
|
-
group_id to each element for hierarchical selection.
|
|
1333
|
-
|
|
1334
|
-
Parameters
|
|
1335
|
-
----------
|
|
1336
|
-
fig : matplotlib.figure.Figure
|
|
1337
|
-
The figure to modify.
|
|
1338
|
-
include_text : bool
|
|
1339
|
-
Whether to include text elements.
|
|
1340
|
-
|
|
1341
|
-
Returns
|
|
1342
|
-
-------
|
|
1343
|
-
tuple
|
|
1344
|
-
(original_props, color_map, groups) where:
|
|
1345
|
-
- original_props: list of dicts with original artist properties for restoration
|
|
1346
|
-
- color_map: dict mapping ID to element info (includes group_id, role)
|
|
1347
|
-
- groups: dict mapping group_id to logical group info
|
|
1348
|
-
"""
|
|
1349
|
-
# Get artists with group information
|
|
1350
|
-
artists_with_groups, groups = get_all_artists_with_groups(fig, include_text)
|
|
1351
|
-
|
|
1352
|
-
original_props = []
|
|
1353
|
-
color_map = {}
|
|
1354
|
-
|
|
1355
|
-
for i, (artist, ax_idx, artist_type, group_id) in enumerate(artists_with_groups):
|
|
1356
|
-
element_id = i + 1
|
|
1357
|
-
r, g, b = _id_to_rgb(element_id)
|
|
1358
|
-
hex_color = f"#{r:02x}{g:02x}{b:02x}"
|
|
1359
|
-
|
|
1360
|
-
# Store original properties
|
|
1361
|
-
props = {'artist': artist, 'type': artist_type}
|
|
1362
|
-
try:
|
|
1363
|
-
if hasattr(artist, 'get_color'):
|
|
1364
|
-
props['color'] = artist.get_color()
|
|
1365
|
-
if hasattr(artist, 'get_facecolor'):
|
|
1366
|
-
props['facecolor'] = artist.get_facecolor()
|
|
1367
|
-
if hasattr(artist, 'get_edgecolor'):
|
|
1368
|
-
props['edgecolor'] = artist.get_edgecolor()
|
|
1369
|
-
if hasattr(artist, 'get_alpha'):
|
|
1370
|
-
props['alpha'] = artist.get_alpha()
|
|
1371
|
-
if hasattr(artist, 'get_antialiased'):
|
|
1372
|
-
props['antialiased'] = artist.get_antialiased()
|
|
1373
|
-
if hasattr(artist, 'get_linewidth'):
|
|
1374
|
-
props['linewidth'] = artist.get_linewidth()
|
|
1375
|
-
except Exception:
|
|
1376
|
-
pass
|
|
1377
|
-
original_props.append(props)
|
|
1378
|
-
|
|
1379
|
-
# Build color map entry with group information
|
|
1380
|
-
label = ''
|
|
1381
|
-
if hasattr(artist, 'get_label'):
|
|
1382
|
-
label = artist.get_label()
|
|
1383
|
-
if label.startswith('_'):
|
|
1384
|
-
label = f'{artist_type}_{i}'
|
|
1385
|
-
|
|
1386
|
-
# Determine role based on group membership
|
|
1387
|
-
role = 'physical' if group_id else 'standalone'
|
|
1388
|
-
|
|
1389
|
-
color_map[element_id] = {
|
|
1390
|
-
'id': element_id,
|
|
1391
|
-
'type': artist_type,
|
|
1392
|
-
'label': label,
|
|
1393
|
-
'axes_index': ax_idx,
|
|
1394
|
-
'rgb': [r, g, b],
|
|
1395
|
-
'group_id': group_id, # NEW: logical group this element belongs to
|
|
1396
|
-
'role': role, # NEW: 'physical' (part of group), 'standalone' (no group), or 'logical' (is a group)
|
|
1397
|
-
}
|
|
1398
|
-
|
|
1399
|
-
# Apply ID color
|
|
1400
|
-
try:
|
|
1401
|
-
_apply_id_color(artist, hex_color)
|
|
1402
|
-
except Exception:
|
|
1403
|
-
pass
|
|
1404
|
-
|
|
1405
|
-
# Add RGB color to groups for logical selection
|
|
1406
|
-
# Groups get IDs starting after all physical elements
|
|
1407
|
-
group_id_start = len(artists_with_groups) + 1
|
|
1408
|
-
groups_with_colors = {}
|
|
1409
|
-
for i, (gid, ginfo) in enumerate(groups.items()):
|
|
1410
|
-
logical_id = group_id_start + i
|
|
1411
|
-
r, g, b = _id_to_rgb(logical_id)
|
|
1412
|
-
|
|
1413
|
-
# Find member element IDs
|
|
1414
|
-
member_ids = []
|
|
1415
|
-
for elem_id, elem_info in color_map.items():
|
|
1416
|
-
if elem_info.get('group_id') == gid:
|
|
1417
|
-
member_ids.append(elem_id)
|
|
1418
|
-
|
|
1419
|
-
groups_with_colors[gid] = {
|
|
1420
|
-
'id': logical_id,
|
|
1421
|
-
'type': ginfo['type'],
|
|
1422
|
-
'label': ginfo['label'],
|
|
1423
|
-
'axes_index': ginfo['axes_index'],
|
|
1424
|
-
'rgb': [r, g, b],
|
|
1425
|
-
'role': 'logical',
|
|
1426
|
-
'member_ids': member_ids,
|
|
1427
|
-
'member_count': ginfo['member_count'],
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
return original_props, color_map, groups_with_colors
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
def restore_original_colors(original_props: List[Dict[str, Any]]):
|
|
1434
|
-
"""
|
|
1435
|
-
Restore original colors to artists after hitmap generation.
|
|
1436
|
-
|
|
1437
|
-
Parameters
|
|
1438
|
-
----------
|
|
1439
|
-
original_props : list
|
|
1440
|
-
List of dicts with original artist properties (from apply_hitmap_colors).
|
|
1441
|
-
"""
|
|
1442
|
-
for props in original_props:
|
|
1443
|
-
artist = props['artist']
|
|
1444
|
-
try:
|
|
1445
|
-
if 'color' in props and hasattr(artist, 'set_color'):
|
|
1446
|
-
artist.set_color(props['color'])
|
|
1447
|
-
if 'facecolor' in props and hasattr(artist, 'set_facecolor'):
|
|
1448
|
-
artist.set_facecolor(props['facecolor'])
|
|
1449
|
-
if 'edgecolor' in props and hasattr(artist, 'set_edgecolor'):
|
|
1450
|
-
artist.set_edgecolor(props['edgecolor'])
|
|
1451
|
-
if 'alpha' in props and hasattr(artist, 'set_alpha'):
|
|
1452
|
-
artist.set_alpha(props['alpha'])
|
|
1453
|
-
if 'antialiased' in props and hasattr(artist, 'set_antialiased'):
|
|
1454
|
-
artist.set_antialiased(props['antialiased'])
|
|
1455
|
-
if 'linewidth' in props and hasattr(artist, 'set_linewidth'):
|
|
1456
|
-
artist.set_linewidth(props['linewidth'])
|
|
1457
|
-
except Exception:
|
|
1458
|
-
pass
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
def generate_hitmap_with_bbox_tight(
|
|
1462
|
-
fig,
|
|
1463
|
-
dpi: int = 150,
|
|
1464
|
-
include_text: bool = False,
|
|
1465
|
-
) -> Tuple['Image.Image', Dict[int, Dict[str, Any]]]:
|
|
1466
|
-
"""
|
|
1467
|
-
Generate a hitmap image with bbox_inches='tight' to match PNG output.
|
|
1468
|
-
|
|
1469
|
-
This function generates a hitmap that exactly matches the PNG saved with
|
|
1470
|
-
bbox_inches='tight'. The key insight is that both PNG and hitmap must use
|
|
1471
|
-
the same savefig parameters to have identical cropping.
|
|
1472
|
-
|
|
1473
|
-
Parameters
|
|
1474
|
-
----------
|
|
1475
|
-
fig : matplotlib.figure.Figure
|
|
1476
|
-
The figure to generate hit map for.
|
|
1477
|
-
dpi : int
|
|
1478
|
-
Resolution for hit map rendering.
|
|
1479
|
-
include_text : bool
|
|
1480
|
-
Whether to include text elements in hit map.
|
|
1481
|
-
|
|
1482
|
-
Returns
|
|
1483
|
-
-------
|
|
1484
|
-
tuple
|
|
1485
|
-
(hitmap_image, color_map) where:
|
|
1486
|
-
- hitmap_image: PIL.Image.Image with RGB-encoded element IDs
|
|
1487
|
-
- color_map: dict mapping ID to element info
|
|
1488
|
-
"""
|
|
1489
|
-
import matplotlib.pyplot as plt
|
|
1490
|
-
from PIL import Image
|
|
1491
|
-
import io
|
|
1492
|
-
import tempfile
|
|
1493
|
-
|
|
1494
|
-
# Get all artists
|
|
1495
|
-
artists = get_all_artists(fig, include_text)
|
|
1496
|
-
|
|
1497
|
-
if not artists:
|
|
1498
|
-
# Return empty black image with same size as PNG would have
|
|
1499
|
-
buf = io.BytesIO()
|
|
1500
|
-
fig.savefig(buf, format='png', dpi=dpi, bbox_inches='tight')
|
|
1501
|
-
buf.seek(0)
|
|
1502
|
-
img = Image.open(buf).convert('RGB')
|
|
1503
|
-
# Create black image of same size
|
|
1504
|
-
black_img = Image.new('RGB', img.size, (0, 0, 0))
|
|
1505
|
-
return black_img, {}
|
|
1506
|
-
|
|
1507
|
-
# Store original properties for restoration
|
|
1508
|
-
original_props = []
|
|
1509
|
-
original_ax_props = []
|
|
1510
|
-
|
|
1511
|
-
# Store original axes properties
|
|
1512
|
-
for ax in fig.axes:
|
|
1513
|
-
ax_props = {
|
|
1514
|
-
'ax': ax,
|
|
1515
|
-
'facecolor': ax.get_facecolor(),
|
|
1516
|
-
'grid_visible': ax.xaxis.get_gridlines()[0].get_visible() if ax.xaxis.get_gridlines() else False,
|
|
1517
|
-
'spines': {name: spine.get_visible() for name, spine in ax.spines.items()},
|
|
1518
|
-
'xlabel': ax.get_xlabel(),
|
|
1519
|
-
'ylabel': ax.get_ylabel(),
|
|
1520
|
-
'title': ax.get_title(),
|
|
1521
|
-
'tick_params': {
|
|
1522
|
-
'left': ax.yaxis.get_tick_params()['left'] if hasattr(ax.yaxis.get_tick_params(), '__getitem__') else True,
|
|
1523
|
-
'bottom': ax.xaxis.get_tick_params()['bottom'] if hasattr(ax.xaxis.get_tick_params(), '__getitem__') else True,
|
|
1524
|
-
},
|
|
1525
|
-
}
|
|
1526
|
-
if ax.get_legend():
|
|
1527
|
-
ax_props['legend_visible'] = ax.get_legend().get_visible()
|
|
1528
|
-
original_ax_props.append(ax_props)
|
|
1529
|
-
|
|
1530
|
-
original_fig_facecolor = fig.patch.get_facecolor()
|
|
1531
|
-
|
|
1532
|
-
# Build color map
|
|
1533
|
-
color_map = {}
|
|
1534
|
-
|
|
1535
|
-
for i, (artist, ax_idx, artist_type) in enumerate(artists):
|
|
1536
|
-
element_id = i + 1
|
|
1537
|
-
r, g, b = _id_to_rgb(element_id)
|
|
1538
|
-
hex_color = f"#{r:02x}{g:02x}{b:02x}"
|
|
1539
|
-
|
|
1540
|
-
# Store original properties
|
|
1541
|
-
props = {'artist': artist, 'type': artist_type}
|
|
1542
|
-
try:
|
|
1543
|
-
if hasattr(artist, 'get_color'):
|
|
1544
|
-
props['color'] = artist.get_color()
|
|
1545
|
-
if hasattr(artist, 'get_facecolor'):
|
|
1546
|
-
props['facecolor'] = artist.get_facecolor()
|
|
1547
|
-
if hasattr(artist, 'get_edgecolor'):
|
|
1548
|
-
props['edgecolor'] = artist.get_edgecolor()
|
|
1549
|
-
if hasattr(artist, 'get_alpha'):
|
|
1550
|
-
props['alpha'] = artist.get_alpha()
|
|
1551
|
-
if hasattr(artist, 'get_antialiased'):
|
|
1552
|
-
props['antialiased'] = artist.get_antialiased()
|
|
1553
|
-
except Exception:
|
|
1554
|
-
pass
|
|
1555
|
-
original_props.append(props)
|
|
1556
|
-
|
|
1557
|
-
# Build color map entry
|
|
1558
|
-
label = ''
|
|
1559
|
-
if hasattr(artist, 'get_label'):
|
|
1560
|
-
label = artist.get_label()
|
|
1561
|
-
if label.startswith('_'):
|
|
1562
|
-
label = f'{artist_type}_{i}'
|
|
1563
|
-
|
|
1564
|
-
color_map[element_id] = {
|
|
1565
|
-
'id': element_id,
|
|
1566
|
-
'type': artist_type,
|
|
1567
|
-
'label': label,
|
|
1568
|
-
'axes_index': ax_idx,
|
|
1569
|
-
'rgb': [r, g, b],
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
# Apply ID color
|
|
1573
|
-
try:
|
|
1574
|
-
_apply_id_color(artist, hex_color)
|
|
1575
|
-
except Exception:
|
|
1576
|
-
pass
|
|
1577
|
-
|
|
1578
|
-
# Make non-artist elements a reserved "axes" color (NOT black/invisible)
|
|
1579
|
-
# This preserves bbox_inches='tight' bounds while distinguishing from background
|
|
1580
|
-
# Use HITMAP_AXES_COLOR (#010101) which maps to ID 65793 (non-selectable)
|
|
1581
|
-
axes_color = HITMAP_AXES_COLOR
|
|
1582
|
-
for ax in fig.axes:
|
|
1583
|
-
ax.grid(False)
|
|
1584
|
-
# Make spines the reserved axes color instead of black
|
|
1585
|
-
for spine in ax.spines.values():
|
|
1586
|
-
spine.set_color(axes_color)
|
|
1587
|
-
ax.set_facecolor(HITMAP_BACKGROUND_COLOR) # Keep facecolor as background
|
|
1588
|
-
# Make tick labels the reserved axes color
|
|
1589
|
-
ax.tick_params(colors=axes_color, labelcolor=axes_color)
|
|
1590
|
-
# Make axis labels the reserved axes color
|
|
1591
|
-
ax.xaxis.label.set_color(axes_color)
|
|
1592
|
-
ax.yaxis.label.set_color(axes_color)
|
|
1593
|
-
# Make title the reserved axes color
|
|
1594
|
-
ax.title.set_color(axes_color)
|
|
1595
|
-
if ax.get_legend():
|
|
1596
|
-
ax.get_legend().set_visible(False)
|
|
1597
|
-
|
|
1598
|
-
fig.patch.set_facecolor(HITMAP_BACKGROUND_COLOR)
|
|
1599
|
-
|
|
1600
|
-
# Save hitmap with bbox_inches='tight' - SAME as PNG
|
|
1601
|
-
buf = io.BytesIO()
|
|
1602
|
-
fig.savefig(buf, format='png', dpi=dpi, bbox_inches='tight', facecolor=HITMAP_BACKGROUND_COLOR)
|
|
1603
|
-
buf.seek(0)
|
|
1604
|
-
hitmap_img = Image.open(buf).convert('RGB')
|
|
1605
|
-
|
|
1606
|
-
# Restore original properties
|
|
1607
|
-
for props in original_props:
|
|
1608
|
-
artist = props['artist']
|
|
1609
|
-
try:
|
|
1610
|
-
if 'color' in props and hasattr(artist, 'set_color'):
|
|
1611
|
-
artist.set_color(props['color'])
|
|
1612
|
-
if 'facecolor' in props and hasattr(artist, 'set_facecolor'):
|
|
1613
|
-
artist.set_facecolor(props['facecolor'])
|
|
1614
|
-
if 'edgecolor' in props and hasattr(artist, 'set_edgecolor'):
|
|
1615
|
-
artist.set_edgecolor(props['edgecolor'])
|
|
1616
|
-
if 'alpha' in props and hasattr(artist, 'set_alpha'):
|
|
1617
|
-
artist.set_alpha(props['alpha'])
|
|
1618
|
-
if 'antialiased' in props and hasattr(artist, 'set_antialiased'):
|
|
1619
|
-
artist.set_antialiased(props['antialiased'])
|
|
1620
|
-
except Exception:
|
|
1621
|
-
pass
|
|
1622
|
-
|
|
1623
|
-
# Restore axes properties
|
|
1624
|
-
for ax_props in original_ax_props:
|
|
1625
|
-
ax = ax_props['ax']
|
|
1626
|
-
try:
|
|
1627
|
-
ax.set_facecolor(ax_props['facecolor'])
|
|
1628
|
-
for name, visible in ax_props['spines'].items():
|
|
1629
|
-
ax.spines[name].set_visible(visible)
|
|
1630
|
-
ax.set_xlabel(ax_props['xlabel'])
|
|
1631
|
-
ax.set_ylabel(ax_props['ylabel'])
|
|
1632
|
-
ax.set_title(ax_props['title'])
|
|
1633
|
-
if 'legend_visible' in ax_props and ax.get_legend():
|
|
1634
|
-
ax.get_legend().set_visible(ax_props['legend_visible'])
|
|
1635
|
-
except Exception:
|
|
1636
|
-
pass
|
|
1637
|
-
|
|
1638
|
-
fig.patch.set_facecolor(original_fig_facecolor)
|
|
1639
|
-
|
|
1640
|
-
return hitmap_img, color_map
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
73
|
# EOF
|