{"id":29055060,"url":"https://github.com/ywatanabe1989/scitex-code","last_synced_at":"2026-01-17T18:27:28.739Z","repository":{"id":300325207,"uuid":"1001456268","full_name":"ywatanabe1989/scitex-code","owner":"ywatanabe1989","description":"Python Framework for Scientific Research","archived":false,"fork":false,"pushed_at":"2026-01-10T10:12:36.000Z","size":49034,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-11T02:32:48.490Z","etag":null,"topics":["logging","python","reproducibility","scientific-computing","scientific-visualization"],"latest_commit_sha":null,"homepage":"https://scitex.ai","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ywatanabe1989.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-13T12:12:28.000Z","updated_at":"2026-01-08T12:17:23.000Z","dependencies_parsed_at":"2026-01-07T12:03:29.222Z","dependency_job_id":null,"html_url":"https://github.com/ywatanabe1989/scitex-code","commit_stats":null,"previous_names":["ywatanabe1989/scitex-code"],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/ywatanabe1989/scitex-code","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ywatanabe1989%2Fscitex-code","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ywatanabe1989%2Fscitex-code/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ywatanabe1989%2Fscitex-code/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ywatanabe1989%2Fscitex-code/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ywatanabe1989","download_url":"https://codeload.github.com/ywatanabe1989/scitex-code/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ywatanabe1989%2Fscitex-code/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28515494,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T17:57:59.192Z","status":"ssl_error","status_checked_at":"2026-01-17T17:57:52.527Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["logging","python","reproducibility","scientific-computing","scientific-visualization"],"created_at":"2025-06-27T03:39:37.909Z","updated_at":"2026-01-17T18:27:28.699Z","avatar_url":"https://github.com/ywatanabe1989.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- ---\n!-- Timestamp: 2026-01-05 16:58:59\n!-- Author: ywatanabe\n!-- File: /home/ywatanabe/proj/scitex-code/README.md\n!-- --- --\u003e\n\n# SciTeX\n\nA Python framework for scientific research that makes the entire research pipeline more standardized, structured, and reproducible by automating repetitive processes.\n\nPart of the fully open-source SciTeX project: https://scitex.ai\n\n\u003c!-- badges --\u003e\n[![PyPI version](https://badge.fury.io/py/scitex.svg)](https://badge.fury.io/py/scitex)\n[![Python Versions](https://img.shields.io/pypi/pyversions/scitex.svg)](https://pypi.org/project/scitex/)\n[![License](https://img.shields.io/github/license/ywatanabe1989/SciTeX-Code)](https://github.com/ywatanabe1989/SciTeX-Code/blob/main/LICENSE)\n[![Documentation](https://readthedocs.org/projects/scitex/badge/?version=latest)](https://scitex.readthedocs.io/en/latest/?badge=latest)\n[![Code Style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![Pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white)](https://github.com/pre-commit/pre-commit)\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eModule Test Status (v2.10.0) - 41 modules\u003c/strong\u003e\u003c/summary\u003e\n\n**Core Modules**\n\n[![io](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-io.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-io.yml)\n[![path](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-path.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-path.yml)\n[![str](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-str.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-str.yml)\n[![dict](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-dict.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-dict.yml)\n[![types](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-types.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-types.yml)\n[![config](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-config.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-config.yml)\n[![utils](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-utils.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-utils.yml)\n[![decorators](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-decorators.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-decorators.yml)\n[![logging](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-logging.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-logging.yml)\n[![stats](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-stats.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-stats.yml)\n[![pd](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-pd.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-pd.yml)\n[![linalg](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-linalg.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-linalg.yml)\n[![torch](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-torch.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-torch.yml)\n[![gen](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-gen.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-gen.yml)\n\n**Extended Modules**\n\n[![nn](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-nn.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-nn.yml)\n[![ai](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-ai.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-ai.yml)\n[![writer](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-writer.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-writer.yml)\n[![audio](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-audio.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-audio.yml)\n[![capture](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-capture.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-capture.yml)\n[![cli](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-cli.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-cli.yml)\n[![sh](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-sh.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-sh.yml)\n[![git](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-git.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-git.yml)\n[![session](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-session.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-session.yml)\n[![diagram](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-diagram.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-diagram.yml)\n[![resource](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-resource.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-resource.yml)\n[![repro](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-repro.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-repro.yml)\n[![benchmark](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-benchmark.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-benchmark.yml)\n[![security](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-security.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-security.yml)\n[![tex](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-tex.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-tex.yml)\n[![msword](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-msword.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-msword.yml)\n[![web](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-web.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-web.yml)\n[![dev](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-dev.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-dev.yml)\n[![dt](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-dt.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-dt.yml)\n[![scholar](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-scholar.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-scholar.yml)\n\n**Pending Modules**\n\n[![dsp](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-dsp.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-dsp.yml)\n[![db](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-db.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-db.yml)\n[![browser](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-browser.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-browser.yml)\n[![plt](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-plt.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-plt.yml)\n[![schema](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-schema.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-schema.yml)\n[![bridge](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-bridge.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-bridge.yml)\n[![fts](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-fts.yml/badge.svg)](https://github.com/ywatanabe1989/scitex-code/actions/workflows/test-fts.yml)\n\n\u003c/details\u003e\n\n## 📦 Installation\n\n``` bash\npip install scitex[all]   # Recommended: Full installation with all modules\npip install scitex        # Core only (numpy, pandas, PyYAML, tqdm)\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eModule Overview\u003c/strong\u003e\u003c/summary\u003e\n\nSciTeX is organized into focused modules for different aspects of scientific computing:\n\n**Modular Installation** (See [./src/scitex](./src/scitex) for all available modules):\n``` bash\n# Install specific modules\npip install scitex[ai]              # AI/ML module\npip install scitex[ai,audio,writer] # Multiple modules\npip install scitex[all]             # Everything\n```\n\n## 📦 Module Overview\n\n### 🔧 Core Utilities\n| Module                                          | Description                                                         |\n|-------------------------------------------------|---------------------------------------------------------------------|\n| [`scitex.gen`](./src/scitex/gen#readme)         | Project setup, session management, and experiment tracking          |\n| [`scitex.io`](./src/scitex/io#readme)           | Universal I/O for 30+ formats (CSV, JSON, HDF5, Zarr, pickle, etc.) |\n| [`scitex.path`](./src/scitex/path#readme)       | Path manipulation and project structure utilities                   |\n| [`scitex.logging`](./src/scitex/logging#readme) | Structured logging with color support and context                   |\n\n### 📊 Data Science \u0026 Statistics\n| Module                                      | Description                                                              |\n|---------------------------------------------|--------------------------------------------------------------------------|\n| [`scitex.stats`](./src/scitex/stats#readme) | 16 statistical tests, effect sizes, power analysis, multiple corrections |\n| [`scitex.plt`](./src/scitex/plt#readme)     | Enhanced matplotlib with auto-export and scientific captions             |\n| [`scitex.pd`](./src/scitex/pd#readme)       | Pandas extensions for research workflows                                 |\n\n### 🧠 AI \u0026 Machine Learning\n| Module                                      | Description                                             |\n|---------------------------------------------|---------------------------------------------------------|\n| [`scitex.ai`](./src/scitex/ai#readme)       | GenAI (7 providers), classification, training utilities |\n| [`scitex.torch`](./src/scitex/torch#readme) | PyTorch training loops, metrics, and utilities          |\n| [`scitex.nn`](./src/scitex/nn#readme)       | Custom neural network layers                            |\n\n### 🌊 Signal Processing\n| Module                                  | Description                                                   |\n|-----------------------------------------|---------------------------------------------------------------|\n| [`scitex.dsp`](./src/scitex/dsp#readme) | Filtering, spectral analysis, wavelets, PAC, ripple detection |\n\n### 📚 Literature Management\n| Module                                          | Description                                                     |\n|-------------------------------------------------|-----------------------------------------------------------------|\n| [`scitex.scholar`](./src/scitex/scholar#readme) | Paper search, PDF download, BibTeX enrichment with IF/citations |\n\n### 🌐 Web \u0026 Browser\n| Module                                          | Description                                                |\n|-------------------------------------------------|------------------------------------------------------------|\n| [`scitex.browser`](./src/scitex/browser#readme) | Playwright automation with debugging, PDF handling, popups |\n\n### 🗄️ Data Management\n| Module                                | Description                         |\n|---------------------------------------|-------------------------------------|\n| [`scitex.db`](./src/scitex/db#readme) | SQLite3 and PostgreSQL abstractions |\n\n### 🛠️ Utilities\n| Module                                                | Description                                         |\n|-------------------------------------------------------|-----------------------------------------------------|\n| [`scitex.decorators`](./src/scitex/decorators#readme) | Function decorators for caching, timing, validation |\n| [`scitex.rng`](./src/scitex/rng#readme)               | Reproducible random number generation               |\n| [`scitex.resource`](./src/scitex/resource#readme)     | System resource monitoring (CPU, memory, GPU)       |\n| [`scitex.dict`](./src/scitex/dict#readme)             | Dictionary manipulation and nested access           |\n| [`scitex.str`](./src/scitex/str#readme)               | String utilities for scientific text processing     |\n\n## 📖 Documentation\n\n### Online Documentation\n- **[Read the Docs](https://scitex.readthedocs.io/)**: Complete API reference and guides\n- **[Interactive Examples](https://scitex.readthedocs.io/en/latest/examples/index.html)**: Browse all tutorial notebooks\n- **[Quick Start Guide](https://scitex.readthedocs.io/en/latest/getting_started.html)**: Get up and running quickly\n\n### Local Resources\n- **[Master Tutorial Index](./examples/00_SCITEX_MASTER_INDEX.ipynb)**: Comprehensive guide to all features\n- **[Examples Directory](./examples/)**: 25+ Jupyter notebooks covering all modules\n- **[Module List](./docs/scitex_modules.csv)**: Complete list of all functions\n- **(Experimental) [MCP Servers Documentation](./mcp_servers/README.md)**\n\n### Key Tutorials\n1. **[I/O Operations](./examples/01_scitex_io.ipynb)**: Essential file handling (start here!)\n2. **[Plotting](./examples/14_scitex_plt.ipynb)**: Publication-ready visualizations\n3. **[Statistics](./examples/11_scitex_stats.ipynb)**: Research-grade statistical analysis\n4. **[Scholar](./examples/16_scitex_scholar.ipynb)**: Literature management with impact factors\n5. **[AI/ML](./examples/16_scitex_ai.ipynb)**: Complete machine learning toolkit\n\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eArial Font Setup\u003c/strong\u003e\u003c/summary\u003e\n\n``` bash\n# Ubuntu\nsudo apt update\nsudo apt-get install ttf-mscorefonts-installer\nsudo DEBIAN_FRONTEND=noninteractive \\\n    apt install -y ttf-mscorefonts-installer\nsudo mkdir -p /usr/share/fonts/truetype/custom\nsudo cp /mnt/c/Windows/Fonts/arial*.ttf /usr/share/fonts/truetype/custom/\nsudo fc-cache -fv\nrm ~/.cache/matplotlib -rf\n\n# WSL\nmkdir -p ~/.local/share/fonts/windows\ncp /mnt/c/Windows/Fonts/arial*.ttf ~/.local/share/fonts/windows/\nfc-cache -fv ~/.local/share/fonts/windows\nrm ~/.cache/matplotlib -rf\n```\n\n``` python\n# Check\nimport matplotlib\nprint(matplotlib.rcParams['font.family'])\n\nimport matplotlib.font_manager as fm\nfonts = fm.findSystemFonts()\nprint(\"Arial found:\", any(\"Arial\" in f or \"arial\" in f for f in fonts))\n[a for a in fonts if \"Arial\" in a or \"arial\" in a][:5]\n\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\n\nmpl.rcParams[\"font.family\"] = \"Arial\"\nmpl.rcParams[\"font.sans-serif\"] = [\"Arial\"]  # 念のため\n\nfig, ax = plt.subplots(figsize=(3, 2))\nax.text(0.5, 0.5, \"Arial Test\", fontsize=32, ha=\"center\", va=\"center\")\nax.set_axis_off()\n\nfig.savefig(\"arial_test.png\", dpi=300)\nplt.close(fig)\n```\n\n\u003c/details\u003e\n\n## 🚀 Quick Start\n\n\n### The SciTeX Advantage: **70% Less Code**\n\nCompare these two implementations that produce **identical research outputs**:\n\n#### With SciTeX ([57 Lines of Code]((./examples/demo_session_plt_io.py)))\n\n```python\n#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# Timestamp: \"2025-11-18 09:34:36 (ywatanabe)\"\n# File: /home/ywatanabe/proj/scitex-code/examples/demo_session_plt_io.py\n\n\n\"\"\"Minimal Demonstration for scitex.{session,io,plt}\"\"\"\n\nimport numpy as np\nimport scitex as stx\n\n\ndef demo(filename, verbose=False):\n    \"\"\"Show metadata without QR code (just embedded).\"\"\"\n\n    # matplotlib.pyplot wrapper.\n    fig, ax = stx.plt.subplots()\n\n    t = np.linspace(0, 2, 1000)\n    signal = np.sin(2 * np.pi * 5 * t) * np.exp(-t / 2)\n\n    ax.plot_line(t, signal)  # Original plot for automatic CSV export\n    ax.set_xyt(\n        \"Time (s)\",\n        \"Amplitude\",\n        \"Clean Figure (metadata embedded, no QR overlay)\",\n    )\n\n    # Saving: stx.io.save(obj, rel_path, **kwargs)\n    stx.io.save(\n        fig,\n        filename,\n        metadata={\"exp\": \"s01\", \"subj\": \"S001\"},  # with meatadata embedding\n        symlink_to=\"./data\",  # Symlink for centralized outputs\n        verbose=verbose,  # Automatic terminal logging (no manual print())\n    )\n    fig.close()\n\n    # Loading: stx.io.load(path)\n    ldir = __file__.replace(\".py\", \"_out\")\n    img, meta = stx.io.load(\n        f\"{ldir}/{filename}\",\n        verbose=verbose,\n    )\n\n\n@stx.session\ndef main(filename=\"demo.jpg\", verbose=True):\n    \"\"\"Run demo for scitex.{session,plt,io}.\"\"\"\n\n    demo(filename, verbose=verbose)\n\n    return 0\n\n\nif __name__ == \"__main__\":\n    main()\n```\n\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eEquivalent without SciTeX ([188 Lines of Code](./examples/demo_session_plt_io_pure_python.py)), requiring 3.3× more code\u003c/strong\u003e\u003c/summary\u003e\n\n```python\n#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# Timestamp: \"2025-11-18 09:34:51 (ywatanabe)\"\n# File: /home/ywatanabe/proj/scitex-code/examples/demo_session_plt_io_pure_python.py\n\n\n\"\"\"Minimal Demonstration - Pure Python Version\"\"\"\n\nimport argparse\nimport json\nimport logging\nimport os\nimport shutil\nimport sys\nfrom datetime import datetime\nfrom pathlib import Path\nimport random\nimport string\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom PIL import Image\nfrom PIL.PngImagePlugin import PngInfo\n\n\ndef generate_session_id():\n    \"\"\"Generate unique session ID.\"\"\"\n    timestamp = datetime.now().strftime(\"%Y-%m-%d_%H-%M-%S\")\n    random_suffix = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))\n    return f\"{timestamp}_{random_suffix}\"\n\n\ndef setup_logging(log_dir):\n    \"\"\"Set up logging infrastructure.\"\"\"\n    log_dir.mkdir(parents=True, exist_ok=True)\n    logger = logging.getLogger(__name__)\n    logger.setLevel(logging.INFO)\n    \n    stdout_handler = logging.FileHandler(log_dir / \"stdout.log\")\n    stderr_handler = logging.FileHandler(log_dir / \"stderr.log\")\n    console_handler = logging.StreamHandler(sys.stdout)\n    \n    formatter = logging.Formatter('%(levelname)s: %(message)s')\n    stdout_handler.setFormatter(formatter)\n    stderr_handler.setFormatter(formatter)\n    console_handler.setFormatter(formatter)\n    \n    logger.addHandler(stdout_handler)\n    logger.addHandler(stderr_handler)\n    logger.addHandler(console_handler)\n    \n    return logger\n\n\ndef save_plot_data_to_csv(fig, output_path):\n    \"\"\"Extract and save plot data.\"\"\"\n    csv_path = output_path.with_suffix('.csv')\n    data_lines = [\"ax_00_plot_line_0_line_x,ax_00_plot_line_0_line_y\"]\n    \n    for ax in fig.get_axes():\n        for line in ax.get_lines():\n            x_data = line.get_xdata()\n            y_data = line.get_ydata()\n            for x, y in zip(x_data, y_data):\n                data_lines.append(f\"{x},{y}\")\n    \n    csv_path.write_text('\\n'.join(data_lines))\n    return csv_path, csv_path.stat().st_size / 1024\n\n\ndef embed_metadata_in_image(image_path, metadata):\n    \"\"\"Embed metadata into image file.\"\"\"\n    img = Image.open(image_path)\n    \n    if image_path.suffix.lower() in ['.png']:\n        pnginfo = PngInfo()\n        for key, value in metadata.items():\n            pnginfo.add_text(key, str(value))\n        img.save(image_path, pnginfo=pnginfo)\n    elif image_path.suffix.lower() in ['.jpg', '.jpeg']:\n        json_path = image_path.with_suffix(image_path.suffix + '.meta.json')\n        json_path.write_text(json.dumps(metadata, indent=2))\n        img.save(image_path, quality=95)\n\n\ndef save_figure(fig, output_path, metadata=None, symlink_to=None, logger=None):\n    \"\"\"Save figure with metadata and symlink.\"\"\"\n    output_path = Path(output_path)\n    output_path.parent.mkdir(parents=True, exist_ok=True)\n    \n    if metadata is None:\n        metadata = {}\n    metadata['url'] = 'https://scitex.ai'\n    \n    if logger:\n        logger.info(f\"📝 Saving figure with metadata to: {output_path}\")\n        logger.info(f\"  • Embedded metadata: {metadata}\")\n    \n    csv_path, csv_size = save_plot_data_to_csv(fig, output_path)\n    if logger:\n        logger.info(f\"✅ Saved to: {csv_path} ({csv_size:.1f} KiB)\")\n    \n    fig.savefig(output_path, dpi=150, bbox_inches='tight')\n    embed_metadata_in_image(output_path, metadata)\n    \n    if symlink_to:\n        symlink_dir = Path(symlink_to)\n        symlink_dir.mkdir(parents=True, exist_ok=True)\n        symlink_path = symlink_dir / output_path.name\n        if symlink_path.exists() or symlink_path.is_symlink():\n            symlink_path.unlink()\n        symlink_path.symlink_to(output_path.resolve())\n\n\ndef demo(output_dir, filename, verbose=False, logger=None):\n    \"\"\"Generate, plot, and save signal.\"\"\"\n    fig, ax = plt.subplots(figsize=(8, 6))\n    \n    t = np.linspace(0, 2, 1000)\n    signal = np.sin(2 * np.pi * 5 * t) * np.exp(-t / 2)\n    \n    ax.plot(t, signal)\n    ax.set_xlabel(\"Time (s)\")\n    ax.set_ylabel(\"Amplitude\")\n    ax.set_title(\"Damped Oscillation\")\n    ax.grid(True, alpha=0.3)\n    \n    output_path = output_dir / filename\n    save_figure(fig, output_path, metadata={\"exp\": \"s01\", \"subj\": \"S001\"},\n                symlink_to=output_dir.parent / \"data\", logger=logger)\n    plt.close(fig)\n    \n    return 0\n\n\ndef main():\n    \"\"\"Run demo - Pure Python Version.\"\"\"\n    parser = argparse.ArgumentParser(description=\"Run demo - Pure Python Version\")\n    parser.add_argument('-f', '--filename', default='demo.jpg')\n    parser.add_argument('-v', '--verbose', type=bool, default=True)\n    args = parser.parse_args()\n    \n    session_id = generate_session_id()\n    script_path = Path(__file__).resolve()\n    output_base = script_path.parent / (script_path.stem + \"_out\")\n    running_dir = output_base / \"RUNNING\" / session_id\n    logs_dir = running_dir / \"logs\"\n    config_dir = running_dir / \"CONFIGS\"\n    \n    logger = setup_logging(logs_dir)\n    \n    print(\"=\" * 40)\n    print(f\"Pure Python Demo\")\n    print(f\"{session_id} (PID: {os.getpid()})\")\n    print(f\"\\n{script_path}\")\n    print(f\"\\nArguments:\")\n    print(f\"    filename: {args.filename}\")\n    print(f\"    verbose: {args.verbose}\")\n    print(\"=\" * 40)\n    \n    config_dir.mkdir(parents=True, exist_ok=True)\n    config_data = {\n        'ID': session_id,\n        'FILE': str(script_path),\n        'SDIR_OUT': str(output_base),\n        'SDIR_RUN': str(running_dir),\n        'PID': os.getpid(),\n        'ARGS': vars(args)\n    }\n    (config_dir / \"CONFIG.json\").write_text(json.dumps(config_data, indent=2))\n    \n    try:\n        result = demo(output_base, args.filename, args.verbose, logger)\n        success_dir = output_base / \"FINISHED_SUCCESS\" / session_id\n        success_dir.parent.mkdir(parents=True, exist_ok=True)\n        shutil.move(str(running_dir), str(success_dir))\n        logger.info(f\"\\n✅ Script completed: {success_dir}\")\n        return result\n    except Exception as e:\n        error_dir = output_base / \"FINISHED_ERROR\" / session_id\n        error_dir.parent.mkdir(parents=True, exist_ok=True)\n        shutil.move(str(running_dir), str(error_dir))\n        logger.error(f\"\\n❌ Error: {e}\", exc_info=True)\n        raise\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n```\n\n\u003c/details\u003e\n\n### What You Get With `@stx.session`\n\nBoth implementations produce **identical outputs**, but SciTeX eliminates 131 lines of boilerplate:\n```bash\ndemo_session_plt_io_out/\n├── demo.csv              # Auto-extracted plot data\n├── demo.jpg              # With embedded metadata\n└── FINISHED_SUCCESS/\n    └── 2025Y-11M-18D-09h12m03s_HmH5-main/\n        ├── CONFIGS/\n        │   ├── CONFIG.pkl    # Python object\n        │   └── CONFIG.yaml   # Human-readable\n        └── logs/\n            ├── stderr.log\n            └── stdout.log\n```\n\n**What SciTeX Automates:**\n- ✅ Session ID generation and tracking\n- ✅ Output directory management (`RUNNING/` → `FINISHED_SUCCESS/`)\n- ✅ Argument parsing with auto-generated help\n- ✅ Logging to files and console\n- ✅ Config serialization (YAML + pickle)\n- ✅ CSV export from matplotlib plots\n- ✅ Metadata embedding in images\n- ✅ Symlink management for centralized outputs\n- ✅ Error handling and directory cleanup\n- ✅ Global variable injection (CONFIG, plt, COLORS, logger, rng_manager)\n\n**Research Benefits:**\n- 📊 **Figures + data always together** - CSV auto-exported from every plot\n- 🔄 **Perfect reproducibility** - Every run tracked with unique session ID\n- 🌍 **Universal format** - CSV data readable anywhere\n- 📝 **Zero manual work** - Metadata embedded automatically\n- 🎯 **3.3× less code** - Focus on research, not infrastructure\n\n## 🤝 Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n\n## 📄 License\n\nAGPL-3.0.\n\n## 📧 Contact\n\nYusuke Watanabe (ywatanabe@scitex.ai)\n\n\u003c!-- EOF --\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fywatanabe1989%2Fscitex-code","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fywatanabe1989%2Fscitex-code","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fywatanabe1989%2Fscitex-code/lists"}