├── .devcontainer └── devcontainer.json ├── .github ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── codeql-analysis.yml │ ├── issue-metrics.yml │ ├── pull-request.yml │ ├── pytest-docs.yml │ ├── release.yml │ ├── upgrade-dependencies.yml │ └── url-check.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CITATION.cff ├── Dockerfile ├── LICENSE ├── README.md ├── SECURITY.md ├── code-of-conduct.md ├── crystal_toolkit ├── __init__.py ├── apps │ ├── __init__.py │ ├── app_metadata.yaml │ ├── assets │ │ ├── crystaltoolkit.css │ │ ├── doi_cache.json │ │ ├── favicon.ico │ │ ├── favicon.png │ │ ├── fonts │ │ │ ├── fa-brands-400.eot │ │ │ ├── fa-brands-400.svg │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-brands-400.woff │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.eot │ │ │ ├── fa-regular-400.svg │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-regular-400.woff │ │ │ ├── fa-regular-400.woff2 │ │ │ ├── fa-solid-900.eot │ │ │ ├── fa-solid-900.svg │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-solid-900.woff │ │ │ └── fa-solid-900.woff2 │ │ ├── main.ecd1960277cfe37b135f.css │ │ └── task_ids_on_load.json │ ├── constants.py │ ├── examples │ │ ├── BaFe2As2_fs.json.gz │ │ ├── BaTiO3_ph_bs.json │ │ ├── BaTiO3_ph_dos.json │ │ ├── GaN_bs.json │ │ ├── GaN_dos.json │ │ ├── Si_bs.json │ │ ├── Si_dos.json │ │ ├── __init__.py │ │ ├── bandstructure.py │ │ ├── basic_hello_structure.py │ │ ├── basic_hello_structure_interactive.py │ │ ├── basic_hello_world.py │ │ ├── chgcar.py │ │ ├── diffraction.py │ │ ├── diffraction_dynamic.py │ │ ├── diffraction_empty.py │ │ ├── diffraction_tem.py │ │ ├── fermi_surface.py │ │ ├── kwarg_inputs.py │ │ ├── matbench_dielectric.json.gz │ │ ├── matbench_dielectric_datatable_xrd.py │ │ ├── matbench_dielectric_structure_on_hover.py │ │ ├── mpcontribs │ │ │ ├── adsorbate_choices.txt │ │ │ ├── catalysis.py │ │ │ ├── catalysis_columns.json │ │ │ └── catalysis_filter_groups.json │ │ ├── phase_diagram.py │ │ ├── phonon.py │ │ ├── pourbaix.py │ │ ├── relaxation_trajectory.py │ │ ├── structure.py │ │ ├── structure_magnetic.py │ │ ├── tests │ │ │ ├── __init__.py │ │ │ ├── readme.md │ │ │ ├── test_bandstructure.py │ │ │ ├── test_basic.py │ │ │ ├── test_diffraction.py │ │ │ ├── test_fermi_surface.py │ │ │ ├── test_structure.py │ │ │ └── typing.py │ │ ├── transformations.py │ │ ├── transformations_minimal.py │ │ ├── utils.py │ │ └── write_structure_screenshot_to_file.py │ ├── help.yaml │ ├── main.py │ └── tests │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_main.py │ │ ├── test_pourbaix.py │ │ └── test_structure.py ├── components │ ├── __init__.py │ ├── bandstructure.py │ ├── diffraction.py │ ├── diffraction_tem.py │ ├── fermi_surface.py │ ├── localenv.py │ ├── phase_diagram.py │ ├── phonon.py │ ├── pourbaix.py │ ├── robocrys.py │ ├── search.py │ ├── structure.py │ ├── submit_snl.py │ ├── symmetry.py │ ├── transformations │ │ ├── __init__.py │ │ ├── autooxistatedecoration.py │ │ ├── core.py │ │ ├── cubic.py │ │ ├── grainboundary.py │ │ ├── rattle.py │ │ ├── slab.py │ │ ├── substitution.py │ │ └── supercell.py │ ├── upload.py │ └── xas.py ├── core │ ├── ElementColorSchemes.yaml │ ├── __init__.py │ ├── jupyter.py │ ├── legend.py │ ├── mpapp.py │ ├── mpcomponent.py │ ├── panelcomponent.py │ ├── plugin.py │ └── scene.py ├── defaults.json ├── defaults.py ├── helpers │ ├── __init__.py │ ├── asymptote_renderer.py │ ├── layouts.py │ ├── povray_renderer.py │ ├── pretty_labels.py │ └── utils.py ├── mpid_cache.json ├── renderables │ ├── __init__.py │ ├── lattice.py │ ├── molecule.py │ ├── moleculegraph.py │ ├── phasediagram.py │ ├── site.py │ ├── structure.py │ ├── structuregraph.py │ ├── trajectory.py │ └── volumetric.py └── settings.py ├── docs ├── .buildinfo ├── .nojekyll ├── CNAME ├── _images │ ├── logo.png │ ├── structuremoleculecomponent.png │ └── structuremoleculecomponent_callbacks.png ├── _modules │ ├── crystal_toolkit.html │ ├── crystal_toolkit │ │ ├── components │ │ │ ├── bandstructure.html │ │ │ ├── diffraction.html │ │ │ ├── localenv.html │ │ │ ├── phase_diagram.html │ │ │ ├── pourbaix.html │ │ │ ├── robocrys.html │ │ │ ├── search.html │ │ │ ├── structure.html │ │ │ ├── symmetry.html │ │ │ ├── transformations │ │ │ │ ├── autooxistatedecoration.html │ │ │ │ ├── core.html │ │ │ │ ├── cubic.html │ │ │ │ ├── grainboundary.html │ │ │ │ ├── rattle.html │ │ │ │ ├── slab.html │ │ │ │ ├── substitution.html │ │ │ │ └── supercell.html │ │ │ ├── upload.html │ │ │ └── xas.html │ │ ├── core │ │ │ ├── legend.html │ │ │ ├── mpcomponent.html │ │ │ ├── panelcomponent.html │ │ │ ├── scene.html │ │ │ └── tests │ │ │ │ └── test_legend.html │ │ ├── helpers │ │ │ ├── asymptote_renderer.html │ │ │ ├── layouts.html │ │ │ ├── povray_renderer.html │ │ │ └── utils.html │ │ ├── renderables │ │ │ ├── lattice.html │ │ │ ├── molecule.html │ │ │ ├── moleculegraph.html │ │ │ ├── phasediagram.html │ │ │ ├── site.html │ │ │ ├── structure.html │ │ │ ├── structuregraph.html │ │ │ └── volumetric.html │ │ └── settings.html │ └── index.html ├── _sources │ ├── components.rst.txt │ ├── components │ │ ├── dash_components.rst.txt │ │ └── structuremoleculecomponent.rst.txt │ ├── first_component.rst.txt │ ├── first_web_app.rst.txt │ ├── helpers.rst.txt │ ├── index.rst.txt │ ├── introduction.rst.txt │ ├── jupyter.rst.txt │ ├── mp_app.rst.txt │ ├── source │ │ ├── crystal_toolkit.components.bandstructure.rst.txt │ │ ├── crystal_toolkit.components.diffraction.rst.txt │ │ ├── crystal_toolkit.components.localenv.rst.txt │ │ ├── crystal_toolkit.components.phase_diagram.rst.txt │ │ ├── crystal_toolkit.components.pourbaix.rst.txt │ │ ├── crystal_toolkit.components.robocrys.rst.txt │ │ ├── crystal_toolkit.components.rst.txt │ │ ├── crystal_toolkit.components.search.rst.txt │ │ ├── crystal_toolkit.components.structure.rst.txt │ │ ├── crystal_toolkit.components.submit_snl.rst.txt │ │ ├── crystal_toolkit.components.symmetry.rst.txt │ │ ├── crystal_toolkit.components.transformations.autooxistatedecoration.rst.txt │ │ ├── crystal_toolkit.components.transformations.core.rst.txt │ │ ├── crystal_toolkit.components.transformations.cubic.rst.txt │ │ ├── crystal_toolkit.components.transformations.grainboundary.rst.txt │ │ ├── crystal_toolkit.components.transformations.rattle.rst.txt │ │ ├── crystal_toolkit.components.transformations.rst.txt │ │ ├── crystal_toolkit.components.transformations.slab.rst.txt │ │ ├── crystal_toolkit.components.transformations.substitution.rst.txt │ │ ├── crystal_toolkit.components.transformations.supercell.rst.txt │ │ ├── crystal_toolkit.components.upload.rst.txt │ │ ├── crystal_toolkit.components.xas.rst.txt │ │ ├── crystal_toolkit.core.legend.rst.txt │ │ ├── crystal_toolkit.core.mpcomponent.rst.txt │ │ ├── crystal_toolkit.core.panelcomponent.rst.txt │ │ ├── crystal_toolkit.core.rst.txt │ │ ├── crystal_toolkit.core.scene.rst.txt │ │ ├── crystal_toolkit.core.tests.rst.txt │ │ ├── crystal_toolkit.core.tests.test_legend.rst.txt │ │ ├── crystal_toolkit.helpers.asymptote_renderer.rst.txt │ │ ├── crystal_toolkit.helpers.layouts.rst.txt │ │ ├── crystal_toolkit.helpers.povray_renderer.rst.txt │ │ ├── crystal_toolkit.helpers.rst.txt │ │ ├── crystal_toolkit.helpers.utils.rst.txt │ │ ├── crystal_toolkit.renderables.lattice.rst.txt │ │ ├── crystal_toolkit.renderables.molecule.rst.txt │ │ ├── crystal_toolkit.renderables.moleculegraph.rst.txt │ │ ├── crystal_toolkit.renderables.phasediagram.rst.txt │ │ ├── crystal_toolkit.renderables.rst.txt │ │ ├── crystal_toolkit.renderables.site.rst.txt │ │ ├── crystal_toolkit.renderables.structure.rst.txt │ │ ├── crystal_toolkit.renderables.structuregraph.rst.txt │ │ ├── crystal_toolkit.renderables.trajectory.rst.txt │ │ ├── crystal_toolkit.renderables.volumetric.rst.txt │ │ ├── crystal_toolkit.rst.txt │ │ ├── crystal_toolkit.settings.rst.txt │ │ └── modules.rst.txt │ └── troubleshooting.rst.txt ├── _static │ ├── _sphinx_javascript_frameworks_compat.js │ ├── basic.css │ ├── css │ │ ├── badge_only.css │ │ ├── fonts │ │ │ ├── Roboto-Slab-Bold.woff │ │ │ ├── Roboto-Slab-Bold.woff2 │ │ │ ├── Roboto-Slab-Regular.woff │ │ │ ├── Roboto-Slab-Regular.woff2 │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ ├── fontawesome-webfont.woff2 │ │ │ ├── lato-bold-italic.woff │ │ │ ├── lato-bold-italic.woff2 │ │ │ ├── lato-bold.woff │ │ │ ├── lato-bold.woff2 │ │ │ ├── lato-normal-italic.woff │ │ │ ├── lato-normal-italic.woff2 │ │ │ ├── lato-normal.woff │ │ │ └── lato-normal.woff2 │ │ └── theme.css │ ├── doctools.js │ ├── documentation_options.js │ ├── file.png │ ├── jquery-3.6.0.js │ ├── jquery.js │ ├── js │ │ ├── badge_only.js │ │ ├── html5shiv-printshiv.min.js │ │ ├── html5shiv.min.js │ │ └── theme.js │ ├── language_data.js │ ├── minus.png │ ├── plus.png │ ├── pygments.css │ ├── searchtools.js │ ├── underscore-1.13.1.js │ └── underscore.js ├── components.html ├── components │ ├── dash_components.html │ └── structuremoleculecomponent.html ├── first_component.html ├── first_web_app.html ├── genindex.html ├── helpers.html ├── index.html ├── introduction.html ├── jupyter.html ├── mp_app.html ├── objects.inv ├── py-modindex.html ├── search.html ├── searchindex.js ├── source │ ├── crystal_toolkit.components.bandstructure.html │ ├── crystal_toolkit.components.diffraction.html │ ├── crystal_toolkit.components.html │ ├── crystal_toolkit.components.localenv.html │ ├── crystal_toolkit.components.phase_diagram.html │ ├── crystal_toolkit.components.pourbaix.html │ ├── crystal_toolkit.components.robocrys.html │ ├── crystal_toolkit.components.search.html │ ├── crystal_toolkit.components.structure.html │ ├── crystal_toolkit.components.submit_snl.html │ ├── crystal_toolkit.components.symmetry.html │ ├── crystal_toolkit.components.transformations.autooxistatedecoration.html │ ├── crystal_toolkit.components.transformations.core.html │ ├── crystal_toolkit.components.transformations.cubic.html │ ├── crystal_toolkit.components.transformations.grainboundary.html │ ├── crystal_toolkit.components.transformations.html │ ├── crystal_toolkit.components.transformations.rattle.html │ ├── crystal_toolkit.components.transformations.slab.html │ ├── crystal_toolkit.components.transformations.substitution.html │ ├── crystal_toolkit.components.transformations.supercell.html │ ├── crystal_toolkit.components.upload.html │ ├── crystal_toolkit.components.xas.html │ ├── crystal_toolkit.core.html │ ├── crystal_toolkit.core.legend.html │ ├── crystal_toolkit.core.mpcomponent.html │ ├── crystal_toolkit.core.panelcomponent.html │ ├── crystal_toolkit.core.scene.html │ ├── crystal_toolkit.core.tests.html │ ├── crystal_toolkit.core.tests.test_legend.html │ ├── crystal_toolkit.helpers.asymptote_renderer.html │ ├── crystal_toolkit.helpers.html │ ├── crystal_toolkit.helpers.layouts.html │ ├── crystal_toolkit.helpers.povray_renderer.html │ ├── crystal_toolkit.helpers.utils.html │ ├── crystal_toolkit.html │ ├── crystal_toolkit.renderables.html │ ├── crystal_toolkit.renderables.lattice.html │ ├── crystal_toolkit.renderables.molecule.html │ ├── crystal_toolkit.renderables.moleculegraph.html │ ├── crystal_toolkit.renderables.phasediagram.html │ ├── crystal_toolkit.renderables.site.html │ ├── crystal_toolkit.renderables.structure.html │ ├── crystal_toolkit.renderables.structuregraph.html │ ├── crystal_toolkit.renderables.trajectory.html │ ├── crystal_toolkit.renderables.volumetric.html │ ├── crystal_toolkit.settings.html │ └── modules.html └── troubleshooting.html ├── docs_rst ├── CNAME ├── Makefile ├── _static │ ├── css │ │ ├── badge_only.css │ │ ├── fonts │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ │ └── theme.css │ └── js │ │ ├── badge_only.js │ │ ├── html5shiv-printshiv.min.js │ │ ├── html5shiv.min.js │ │ └── theme.js ├── components.rst ├── components │ ├── bulma_layouts.rst │ ├── dash_components.rst │ └── structuremoleculecomponent.rst ├── conf.py ├── first_component.rst ├── first_web_app.rst ├── helpers.rst ├── images │ ├── jupyter-demo.gif │ ├── logo.png │ ├── structuremoleculecomponent.png │ └── structuremoleculecomponent_callbacks.png ├── index.rst ├── introduction.rst ├── jupyter.rst ├── modernization.rst ├── mp_app.rst └── troubleshooting.rst ├── jupyterlab-extension ├── .eslintignore ├── .eslintrc.js ├── .github │ └── workflows │ │ └── build.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── LICENSE ├── MANIFEST.in ├── README.md ├── crystaltoolkit-extension │ ├── __init__.py │ └── _version.py ├── install.json ├── lib │ ├── index.d.ts │ └── index.js ├── package-lock.json ├── package.json ├── pyproject.toml ├── setup.py ├── src │ ├── index.ts │ └── types.d.ts ├── style │ ├── base.css │ ├── index.css │ └── index.js ├── tsconfig.json └── tsconfig.tsbuildinfo ├── pyproject.toml ├── requirements ├── ubuntu-latest_py3.11.txt ├── ubuntu-latest_py3.11_extras.txt ├── ubuntu-latest_py3.12.txt └── ubuntu-latest_py3.12_extras.txt └── tests ├── __init__.py ├── asy_test ├── core │ ├── __init__.py │ ├── test_jupyter.py │ └── test_legend.py ├── multi │ ├── AlN.asy │ ├── AlN.png │ ├── GaN.asy │ ├── GaN.png │ ├── InN.asy │ ├── InN.png │ └── Makefile ├── single │ ├── GaN.asy │ └── Makefile └── test_asymptote.py ├── conftest.py ├── requirements.txt ├── test_files └── chgcar.vasp ├── test_structure.py ├── test_utils.py └── test_volumetric.py /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "mcr.microsoft.com/devcontainers/universal:2", 3 | "waitFor": "onCreateCommand", 4 | "updateContentCommand": "pip install .[server]", 5 | "customizations": { 6 | "codespaces": { 7 | "openFiles": [ 8 | "crystal_toolkit/apps/examples/basic_hello_structure_interactive.py" 9 | ] 10 | }, 11 | "vscode": { 12 | "extensions": ["ms-toolsai.jupyter", "ms-python.python"] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 15 | 16 | ## Checklist 17 | 18 | Work-in-progress pull requests are encouraged but please [mark your PR as draft](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request#converting-a-pull-request-to-a-draft). 19 | 20 | Usually, the following items should be checked before merging a PR: 21 | 22 | - [ ] Doc strings have been added in the [Google docstring format](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings). 23 | - [ ] Type annotations are *highly* encouraged. Run [`mypy path/to/file.py`](https://github.com/python/mypy) to type-check your code. Type checks are run in CI. 24 | - [ ] Tests for any new functionality as well as bug fixes, where appropriate. 25 | - [ ] Create a new [Issue](https://github.com/materialsproject/crystaltoolkit/issues) for any TODO items that will result from merging the PR. 26 | 27 | We recommended installing [`pre-commit`](https://pre-commit.com) to run all our linters locally. That will increase your development speed since you don't have to wait for our CI to tell about errors, your code will be checked at commit time. 28 | 29 | ```sh 30 | pip install -U pre-commit 31 | pre-commit install 32 | ``` 33 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "Code scanning - action" 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [main] 9 | schedule: 10 | - cron: "0 13 * * 3" # run at 13:00 every Wednesday 11 | 12 | jobs: 13 | CodeQL-Build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v3 19 | with: 20 | # We must fetch at least the immediate parents so that if this is 21 | # a pull request then we can checkout the head. 22 | fetch-depth: 2 23 | 24 | # If this run was triggered by a pull request event, then checkout 25 | # the head of the pull request instead of the merge commit. 26 | - run: git checkout HEAD^2 27 | if: github.event_name == 'pull_request' 28 | 29 | # Initializes the CodeQL tools for scanning. 30 | - name: Initialize CodeQL 31 | uses: github/codeql-action/init@v2 32 | # Override language selection by uncommenting this and choosing your languages 33 | # with: 34 | # languages: go, javascript, csharp, python, cpp, java 35 | 36 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 37 | # If this step fails, then you should remove it and run the build manually (see below) 38 | - name: Autobuild 39 | uses: github/codeql-action/autobuild@v2 40 | 41 | # ℹ️ Command-line programs to run using the OS shell. 42 | # 📚 https://git.io/JvXDl 43 | 44 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 45 | # and modify them (or add more) to build your code if your project 46 | # uses a compiled language 47 | 48 | #- run: | 49 | # make bootstrap 50 | # make release 51 | 52 | - name: Perform CodeQL Analysis 53 | uses: github/codeql-action/analyze@v2 54 | -------------------------------------------------------------------------------- /.github/workflows/issue-metrics.yml: -------------------------------------------------------------------------------- 1 | name: Monthly issue metrics 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: '3 2 1 * *' 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | build: 12 | name: issue metrics 13 | runs-on: ubuntu-latest 14 | permissions: 15 | issues: write 16 | pull-requests: read 17 | steps: 18 | - name: Get dates for last month 19 | shell: bash 20 | run: | 21 | # Calculate the first day of the previous month 22 | first_day=$(date -d "last month" +%Y-%m-01) 23 | 24 | # Calculate the last day of the previous month 25 | last_day=$(date -d "$first_day +1 month -1 day" +%Y-%m-%d) 26 | 27 | #Set an environment variable with the date range 28 | echo "$first_day..$last_day" 29 | echo "last_month=$first_day..$last_day" >> "$GITHUB_ENV" 30 | 31 | - name: Run issue-metrics tool 32 | uses: github/issue-metrics@v3 33 | env: 34 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | SEARCH_QUERY: 'repo:materialsproject/crystaltoolkit is:issue created:${{ env.last_month }} -reason:"not planned"' 36 | 37 | - name: Create issue 38 | uses: peter-evans/create-issue-from-file@v5 39 | with: 40 | title: Monthly issue metrics report 41 | token: ${{ secrets.GITHUB_TOKEN }} 42 | content-filepath: ./issue_metrics.md 43 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yml: -------------------------------------------------------------------------------- 1 | name: Testing 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - "v*" 9 | pull_request: 10 | branches: 11 | - main 12 | 13 | permissions: 14 | contents: read 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | strategy: 20 | matrix: 21 | python-version: ["3.10"] 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | with: 26 | fetch-depth: 0 27 | - name: Set up Python ${{ matrix.python-version }} 28 | uses: actions/setup-python@v5 29 | with: 30 | python-version: ${{ matrix.python-version }} 31 | cache: "pip" 32 | cache-dependency-path: "**/pyproject.toml" 33 | - name: Install webdriver 34 | run: sudo apt-get update && sudo apt-get install chromium-chromedriver 35 | - name: Install dependencies 36 | run: | 37 | python${{ matrix.python-version }} -m pip install --upgrade pip packaging wheel cython setuptools 38 | python${{ matrix.python-version }} -m pip install `grep numpy== requirements/ubuntu-latest_py${{ matrix.python-version }}_extras.txt` 39 | python${{ matrix.python-version }} -m pip install -r requirements/ubuntu-latest_py${{ matrix.python-version }}_extras.txt 40 | python${{ matrix.python-version }} -m pip install --upgrade pip 41 | python${{ matrix.python-version }} -m pip install --no-deps .[server,test] 42 | - name: Test modules 43 | run: python${{ matrix.python-version }} -m pytest --cov=crystal_toolkit --cov-report=xml tests 44 | - name: Test example apps 45 | env: 46 | PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }} 47 | run: python${{ matrix.python-version }} -m pytest --cov=crystal_toolkit --cov-report=xml --color=yes --webdriver Chrome --headless crystal_toolkit/apps/examples/tests/ 48 | - uses: codecov/codecov-action@v1 49 | if: matrix.python-version == 3.10 50 | with: 51 | token: ${{ secrets.CODECOV_TOKEN }} 52 | file: ./coverage.xml 53 | -------------------------------------------------------------------------------- /.github/workflows/pytest-docs.yml: -------------------------------------------------------------------------------- 1 | name: Build Docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - "v*" 9 | pull_request: 10 | branches: 11 | - main 12 | release: 13 | types: [published] 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | matrix: 20 | python-version: ["3.10"] 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | with: 25 | fetch-depth: 0 26 | - name: Set up Python ${{ matrix.python-version }} 27 | uses: actions/setup-python@v4 28 | with: 29 | python-version: ${{ matrix.python-version }} 30 | cache: 'pip' 31 | cache-dependency-path: '**/pyproject.toml' 32 | - name: Install webdriver 33 | run: sudo apt-get update && sudo apt-get install chromium-chromedriver 34 | - name: Install dependencies 35 | run: | 36 | python${{ matrix.python-version }} -m pip install --upgrade pip packaging wheel cython setuptools 37 | python${{ matrix.python-version }} -m pip install `grep numpy== requirements/ubuntu-latest_py${{ matrix.python-version }}_extras.txt` 38 | python${{ matrix.python-version }} -m pip install -r requirements/ubuntu-latest_py${{ matrix.python-version }}_extras.txt 39 | python${{ matrix.python-version }} -m pip install --upgrade pip 40 | python${{ matrix.python-version }} -m pip install --no-deps . 41 | - name: Build new docs 42 | run: | 43 | cd docs_rst 44 | make html 45 | - name: Detect changes on release 46 | if: startsWith(github.head_ref, 'releases/') 47 | id: changes 48 | shell: bash 49 | run: | 50 | echo "count=$(git diff-index HEAD | wc -l | xargs)" >> $GITHUB_OUTPUT 51 | echo "files=$(git ls-files --exclude-standard --others | wc -l | xargs)" >> $GITHUB_OUTPUT 52 | - name: Commit new docs 53 | if: steps.changes.outputs.count > 0 || steps.changes.outputs.files > 0 54 | run: | 55 | git config user.name github-actions 56 | git config user.email github-actions@github.com 57 | git add -A 58 | git commit -m "Automated doc build" 59 | git push 60 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | deploy: 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | python-version: ["3.11"] 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | token: ${{ secrets.PAT }} 22 | 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v5 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | cache: "pip" 28 | cache-dependency-path: '**/pyproject.toml' 29 | 30 | - name: Install dependencies 31 | run: | 32 | python${{ matrix.python-version }} -m pip install --upgrade pip packaging wheel build cython setuptools 33 | python${{ matrix.python-version }} -m pip install `grep numpy== requirements/ubuntu-latest_py${{ matrix.python-version }}_extras.txt` 34 | python${{ matrix.python-version }} -m pip install -r requirements/ubuntu-latest_py${{ matrix.python-version }}_extras.txt 35 | python${{ matrix.python-version }} -m pip install --upgrade pip 36 | python${{ matrix.python-version }} -m pip install --no-deps .[server] 37 | 38 | - name: Build package 39 | run: python${{ matrix.python-version }} -m build 40 | 41 | - name: Publish package 42 | uses: pypa/gh-action-pypi-publish@release/v1 43 | with: 44 | user: __token__ 45 | password: ${{ secrets.PYPI_API_TOKEN }} 46 | -------------------------------------------------------------------------------- /.github/workflows/url-check.yml: -------------------------------------------------------------------------------- 1 | name: Check URLs 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | lychee-link-check: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Check out repo 14 | uses: actions/checkout@v3 15 | 16 | - name: Check for broken links 17 | uses: lycheeverse/lychee-action@v1 18 | with: 19 | # --exclude-loopback ensures we don't check localhost URLs 20 | args: --exclude-loopback './**/*.md' './**/*.rst' 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | __pycache__/ 5 | 6 | # IntelliJ project settings 7 | .idea 8 | 9 | # auto-generated documentation 10 | docs_rst/_build 11 | 12 | build/* 13 | *.egg-info 14 | dist/* 15 | .vscode 16 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | ci: 2 | autoupdate_schedule: quarterly 3 | 4 | default_stages: [pre-commit] 5 | 6 | default_install_hook_types: [pre-commit, commit-msg] 7 | 8 | # ignore generated docs and dependency lock files, the directory 9 | # jupyterlab-extension/ and all SVG, JS and CSS files 10 | exclude: ^(docs/.+|.*lock.*|jupyterlab-extension/.+|.*\.(svg|js|css))|_version.py$ 11 | 12 | repos: 13 | - repo: https://github.com/astral-sh/ruff-pre-commit 14 | rev: v0.5.0 15 | hooks: 16 | - id: ruff 17 | args: [--fix, --ignore, D] 18 | - id: ruff-format 19 | 20 | # - repo: https://github.com/pre-commit/mirrors-mypy 21 | # rev: v1.3.0 22 | # hooks: 23 | # - id: mypy 24 | 25 | - repo: https://github.com/pre-commit/pre-commit-hooks 26 | rev: v4.6.0 27 | hooks: 28 | - id: check-case-conflict 29 | - id: check-symlinks 30 | - id: check-yaml 31 | - id: end-of-file-fixer 32 | - id: mixed-line-ending 33 | - id: trailing-whitespace 34 | 35 | - repo: https://github.com/codespell-project/codespell 36 | rev: v2.3.0 37 | hooks: 38 | - id: codespell 39 | stages: [pre-commit, commit-msg] 40 | args: [--ignore-words-list, "nd,te,ois,dscribe", --check-filenames] 41 | 42 | - repo: https://github.com/kynan/nbstripout 43 | rev: 0.7.1 44 | hooks: 45 | - id: nbstripout 46 | args: [--drop-empty-cells, --keep-output] 47 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | title: Crystal Toolkit - A Web App Framework to Improve Usability and Accessibility of Materials Science Research Algorithms 3 | message: If you use this software, please cite it as below. 4 | authors: 5 | - family-names: Horton 6 | given-names: Matthew 7 | affiliation: Lawrence Berkeley National Laboratory 8 | orcid: 0000-0001-7777-8871 9 | - family-names: Shen 10 | given-names: Jimmy-Xuan 11 | affiliation: UC Berkeley, LBL 12 | orcid: 0000-0002-2743-7531 13 | - family-names: Burns 14 | given-names: Jordan 15 | - family-names: Cohen 16 | given-names: Orion 17 | affiliation: UC Berkeley, Lawrence Berkeley National Laboratory 18 | - family-names: Chabbey 19 | given-names: François 20 | - family-names: Ganose 21 | given-names: Alex 22 | affiliation: Lawrence Berkeley National Laboratory 23 | orcid: 0000-0002-4486-3321 24 | - family-names: Guha 25 | given-names: Rishabh 26 | - family-names: Huck 27 | given-names: Patrick 28 | affiliation: Lawrence Berkeley National Laboratory 29 | - family-names: Li 30 | given-names: Hamming Howard 31 | - family-names: McDermott 32 | given-names: Matthew 33 | affiliation: Lawrence Berkeley National Laboratory, University of California Berkeley 34 | - family-names: Montoya 35 | given-names: Joseph 36 | affiliation: Toyota Research Institute 37 | orcid: 0000-0001-5760-2860 38 | - family-names: Moore 39 | given-names: Guy 40 | affiliation: Lawrence Berkeley National Laboratory, University of California Berkeley 41 | - family-names: Munro 42 | given-names: Jason 43 | affiliation: Lawrence Berkeley National Laboratory 44 | - family-names: O'Donnell 45 | given-names: Cody 46 | - family-names: Ophus 47 | given-names: Colin 48 | - family-names: Petretto 49 | given-names: Guido 50 | affiliation: Université catholique de Louvain 51 | - family-names: Riebesell 52 | given-names: Janosh 53 | affiliation: University of Cambridge, Lawrence Berkeley National Laboratory 54 | orcid: 0000-0001-5233-3462 55 | - family-names: Wetizner 56 | given-names: Steven 57 | - family-names: Wander 58 | given-names: Brook 59 | - family-names: Winston 60 | given-names: Donny 61 | affiliation: Consulting at donnywinston.com 62 | orcid: 0000-0002-8424-0604 63 | - family-names: Yang 64 | given-names: Ruoxi 65 | affiliation: Lawrence Berkeley National Laboratory 66 | orcid: 0000-0001-8225-5856 67 | - family-names: Zeltmann 68 | given-names: Steven 69 | - family-names: Jain 70 | given-names: Anubhav 71 | affiliation: Lawrence Berkeley National Laboratory 72 | orcid: 0000-0001-5893-9967 73 | - family-names: Persson 74 | given-names: Kristin A. 75 | affiliation: Lawrence Berkeley National Laboratory 76 | orcid: 0000-0003-2495-5509 77 | license: MIT 78 | license-url: https://github.com/materialsproject/crystaltoolkit/blob/main/LICENSE 79 | repository-code: https://github.com/materialsproject/crystaltoolkit 80 | type: software 81 | url: https://docs.crystaltoolkit.org 82 | arxiv: https://arxiv.org/abs/2302.06147 83 | doi: 10.48550/arXiv.2302.06147 84 | version: 2023.02.01 # replace with whatever version you use 85 | date-released: 2023-02-13 86 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | LABEL maintainer="mkhorton@lbl.gov" 3 | 4 | RUN apt-get update && apt-get install vim gfortran povray -y 5 | 6 | WORKDIR /home/build 7 | 8 | # install critic2 9 | RUN git clone https://github.com/aoterodelaroza/critic2.git && \ 10 | cd critic2 && git checkout 84da382 && autoreconf && ./configure && \ 11 | make && make install 12 | 13 | # install enumlib 14 | ENV F90 gfortran 15 | RUN git clone --recursive https://github.com/msg-byu/enumlib.git && \ 16 | cd enumlib && git checkout 165c917 && cd symlib/src/ && make && \ 17 | cd ../../src && make enum.x && make makestr.x && \ 18 | cp enum.x makestr.x /usr/local/bin 19 | 20 | WORKDIR /home/app 21 | 22 | RUN pip install --upgrade --no-cache-dir pip && \ 23 | pip install -r requirements/ubuntu-latest_py3.9_extras.txt 24 | 25 | # whether to embed in materialsproject.org or not 26 | ENV CRYSTAL_TOOLKIT_MP_EMBED_MODE=False 27 | 28 | ENV CRYSTAL_TOOLKIT_NUM_WORKERS=16 29 | 30 | # for Crossref API, used for DOI lookups 31 | ENV CROSSREF_MAILTO=YOUR_EMAIL_HERE 32 | 33 | # this can be obtained from materialsproject.org 34 | ENV PMG_MAPI_KEY=YOUR_MP_API_KEY_HERE 35 | 36 | # whether to run the server in debug mode or not 37 | ENV CRYSTAL_TOOLKIT_DEBUG_MODE=False 38 | 39 | ADD . /home/app 40 | 41 | EXPOSE 8000 42 | CMD gunicorn --workers=$CRYSTAL_TOOLKIT_NUM_WORKERS --timeout=300 --bind=0.0.0.0 crystal_toolkit.apps.main:server 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Crystal Toolkit Copyright (c) 2017, The Regents of the University of 2 | California, through Lawrence Berkeley National Laboratory (subject 3 | to receipt of any required approvals from the U.S. Dept. of Energy). 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 10 | (1) Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | (2) Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the following 15 | disclaimer in the documentation and/or other materials provided with 16 | the distribution. 17 | 18 | (3) Neither the name of the University of California, Lawrence 19 | Berkeley National Laboratory, U.S. Dept. of Energy nor the names of 20 | its contributors may be used to endorse or promote products derived 21 | from this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 | POSSIBILITY OF SUCH DAMAGE. 35 | 36 | You are under no obligation whatsoever to provide any bug fixes, 37 | patches, or upgrades to the features, functionality or performance 38 | of the source code ("Enhancements") to anyone; however, if you 39 | choose to make your Enhancements available either publicly, or 40 | directly to Lawrence Berkeley National Laboratory or its 41 | contributors, without imposing a separate written license agreement 42 | for such Enhancements, then you hereby grant the following license: 43 | a non-exclusive, royalty-free perpetual license to install, use, 44 | modify, prepare derivative works, incorporate into other computer 45 | software, distribute, and sublicense such enhancements or derivative 46 | works thereof, in binary and source code form. 47 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | We are a small, academic project without a formal security process. 6 | 7 | If you find a security vulnerability, please contact and CC . 8 | 9 | PGP keys can be made available on request. 10 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of 4 | fostering an open and welcoming community, we pledge to respect all people who 5 | contribute through reporting issues, posting feature requests, updating 6 | documentation, submitting pull requests or patches, and other activities. 7 | 8 | We are committed to making participation in this project a harassment-free 9 | experience for everyone, regardless of level of experience, gender, gender 10 | identity and expression, sexual orientation, disability, personal appearance, 11 | body size, race, ethnicity, age, religion, or nationality. 12 | 13 | Examples of unacceptable behavior by participants include: 14 | 15 | * The use of sexualized language or imagery 16 | * Personal attacks 17 | * Trolling or insulting/derogatory comments 18 | * Public or private harassment 19 | * Publishing other's private information, such as physical or electronic 20 | addresses, without explicit permission 21 | * Other unethical or unprofessional conduct 22 | 23 | Project maintainers have the right and responsibility to remove, edit, or 24 | reject comments, commits, code, wiki edits, issues, and other contributions 25 | that are not aligned to this Code of Conduct, or to ban temporarily or 26 | permanently any contributor for other behaviors that they deem inappropriate, 27 | threatening, offensive, or harmful. 28 | 29 | By adopting this Code of Conduct, project maintainers commit themselves to 30 | fairly and consistently applying these principles to every aspect of managing 31 | this project. Project maintainers who do not follow or enforce the Code of 32 | Conduct may be permanently removed from the project team. 33 | 34 | This Code of Conduct applies both within project spaces and in public spaces 35 | when an individual is representing the project or its community. 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 38 | reported by contacting a project maintainer at conduct@materialsproject.org. All 39 | complaints will be reviewed and investigated and will result in a response that 40 | is deemed necessary and appropriate to the circumstances. Maintainers are 41 | obligated to maintain confidentiality with regard to the reporter of an 42 | incident to the extent possible by law and institutional policy. 43 | 44 | This Code of Conduct is adapted from the [Contributor Covenant][covenant], 45 | version 1.3.0, available at 46 | 47 | [covenant]: https://contributor-covenant.org 48 | -------------------------------------------------------------------------------- /crystal_toolkit/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from importlib.metadata import PackageNotFoundError, version 4 | from pathlib import Path 5 | 6 | from monty.json import MSONable 7 | 8 | import crystal_toolkit.helpers.layouts as ctl 9 | from crystal_toolkit.core.jupyter import patch_msonable 10 | from crystal_toolkit.core.plugin import CrystalToolkitPlugin 11 | from crystal_toolkit.renderables import ( 12 | Lattice, 13 | Molecule, 14 | MoleculeGraph, 15 | PhaseDiagram, 16 | Site, 17 | Structure, 18 | StructureGraph, 19 | VolumetricData, 20 | ) 21 | 22 | patch_msonable() 23 | 24 | MODULE_PATH = Path(__file__).parents[0] 25 | 26 | try: 27 | __version__ = version("crystal_toolkit") 28 | except PackageNotFoundError: # pragma: no cover 29 | # package is not installed 30 | pass 31 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/__init__.py -------------------------------------------------------------------------------- /crystal_toolkit/apps/app_metadata.yaml: -------------------------------------------------------------------------------- 1 | CatalysisApp: 2 | author: Open Catalyst Project 3 | category: Explore and Search 4 | credits: 5 | - Binary data visualization app contributed by Brook Wander. 6 | description: 'Search catalysis data from the Open Catalyst 2020 (OC20) Dataset.' 7 | docs_url: https://next-gen-docs.materialsproject.org/apps/catalysis-explorer 8 | dois: [10.1021/acscatal.0c04525] 9 | external_links: 10 | - href: https://opencatalystproject.org 11 | label: Open Catalyst Project 12 | icon: icon-fontastic-catalysis 13 | login_required: true 14 | name: Catalysis Explorer 15 | url: catalysis 16 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/crystaltoolkit.css: -------------------------------------------------------------------------------- 1 | body, html, .body { 2 | background: #f3f3f3 !important; 3 | } 4 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/doi_cache.json: -------------------------------------------------------------------------------- 1 | {"10.26434/chemrxiv.11294480.v1": "D. Waroquiers, J. George, M. Horton, S. Schenk, K. Persson, G.-M. Rignanese, X. Gonze, and G. Hautier, \u201cChemEnv\u202f: A Fast and Robust Coordination Environment Identification Tool,\u201d Dec. 2019.\n", "10.3389/fmats.2017.00034": "N. E. R. Zimmermann, M. K. Horton, A. Jain, and M. Haranczyk, \u201cAssessing Local Structure Motifs Using Order Parameters for Motif Recognition, Interstitial Identification, and Diffusion Path Characterization,\u201d Frontiers in Materials, vol. 4, Nov. 2017.\n"} 2 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/favicon.ico -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/favicon.png -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-brands-400.eot -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-brands-400.woff -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-regular-400.eot -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-regular-400.woff -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-solid-900.eot -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-solid-900.woff -------------------------------------------------------------------------------- /crystal_toolkit/apps/assets/fonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/assets/fonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /crystal_toolkit/apps/constants.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from collections import defaultdict 4 | 5 | from monty.serialization import loadfn 6 | from pydash import get, set_ 7 | 8 | from crystal_toolkit.settings import SETTINGS 9 | 10 | APP_METADATA = loadfn(SETTINGS.APP_METADATA) 11 | 12 | # list of URLs available in the website 13 | _BASE_URL = "https://materialsproject.org/" 14 | _apps_sitemap = [] 15 | 16 | # Construct a nested dictionary showing the relationship between apps 17 | # based on their urls, used for About page etc. 18 | APP_TREE = {} 19 | for app_class_name, metadata in APP_METADATA.items(): 20 | if metadata["url"] and not metadata["url"].startswith("http"): 21 | _apps_sitemap.append(_BASE_URL + metadata["url"]) 22 | path = metadata["url"].replace("/", ".") 23 | if not get(APP_TREE, path): 24 | set_(APP_TREE, path, {"NAME": app_class_name}) 25 | else: 26 | get(APP_TREE, path)["NAME"] = app_class_name 27 | 28 | # This is currently hard-coded 29 | _MP_APP_CATEGORY_ORDER = [ 30 | "Explore and Search", 31 | "Analysis Tools", 32 | "Characterization", 33 | "Reference Data", 34 | ] 35 | 36 | MP_APPS_BY_CATEGORY = defaultdict(list) 37 | 38 | MP_APPS_BY_CATEGORY = { 39 | category: MP_APPS_BY_CATEGORY[category] for category in _MP_APP_CATEGORY_ORDER 40 | } 41 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/BaFe2As2_fs.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/examples/BaFe2As2_fs.json.gz -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/examples/__init__.py -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/bandstructure.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import os 4 | 5 | import dash 6 | 7 | # dos and bs data from local jsons 8 | from monty.serialization import loadfn 9 | 10 | import crystal_toolkit.components as ctc 11 | from crystal_toolkit.helpers.layouts import H1, Container 12 | from crystal_toolkit.settings import SETTINGS 13 | 14 | # assets folder set for visual styles only 15 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 16 | 17 | # If callbacks created dynamically they cannot be statically checked at app startup. 18 | # For this simple example this IS a problem and, 19 | # nested layout this will need to be enabled -- consult Dash documentation 20 | # for more information. 21 | # app.config["suppress_callback_exceptions"] = True 22 | 23 | path = os.path.dirname(os.path.realpath(__file__)) 24 | bandstructure_symm_line = loadfn(f"{path}/GaN_bs.json") 25 | density_of_states = loadfn(f"{path}/GaN_dos.json") 26 | 27 | # create the Crystal Toolkit component 28 | bsdos_component = ctc.BandstructureAndDosComponent( 29 | bandstructure_symm_line=bandstructure_symm_line, 30 | density_of_states=density_of_states, 31 | id="bs_dos", 32 | ) 33 | 34 | # example layout to demonstrate capabilities of component 35 | layout = Container( 36 | [H1("Band Structure and Density of States Example"), bsdos_component.layout()] 37 | ) 38 | 39 | # wrap your app.layout with crystal_toolkit_layout() 40 | # to ensure all necessary components are loaded into layout 41 | ctc.register_crystal_toolkit(app, layout=layout) 42 | 43 | 44 | # run this app with "python path/to/this/file.py" 45 | # in production, deploy behind gunicorn or similar 46 | # see Dash docs for more info 47 | if __name__ == "__main__": 48 | app.run(debug=True, port=8050) 49 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/basic_hello_structure.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | from dash import html 5 | from pymatgen.core import Lattice, Structure 6 | 7 | import crystal_toolkit.components as ctc 8 | from crystal_toolkit.settings import SETTINGS 9 | 10 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 11 | 12 | structure = Structure(Lattice.cubic(4.2), ["Na", "K"], [[0, 0, 0], [0.5, 0.5, 0.5]]) 13 | 14 | # create the Crystal Toolkit component 15 | structure_component = ctc.StructureMoleculeComponent(structure, id="hello_structure") 16 | 17 | # add the component's layout to our app's layout 18 | layout = html.Div([structure_component.layout()]) 19 | 20 | # as explained in "preamble" section in documentation 21 | ctc.register_crystal_toolkit(app=app, layout=layout) 22 | if __name__ == "__main__": 23 | app.run(debug=True, port=8050) 24 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/basic_hello_structure_interactive.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | from dash import html 5 | 6 | # standard Dash imports for callbacks (interactivity) 7 | from dash.dependencies import Input, Output 8 | from pymatgen.core import Lattice, Structure 9 | 10 | import crystal_toolkit.components as ctc 11 | 12 | # don't run callbacks on page load 13 | app = dash.Dash(prevent_initial_callbacks=True) 14 | 15 | # now we give a list of structures to pick from 16 | structures = [ 17 | Structure(Lattice.hexagonal(5, 3), ["Na", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]), 18 | Structure(Lattice.cubic(5), ["K", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]), 19 | ] 20 | 21 | # we show the first structure by default 22 | structure_component = ctc.StructureMoleculeComponent( 23 | structures[0], id="hello_structure" 24 | ) 25 | 26 | # and we create a button for user interaction 27 | my_button = html.Button("Swap Structure", id="change_structure_button") 28 | 29 | # now we have two entries in our app layout, 30 | # the structure component's layout and the button 31 | layout = html.Div([structure_component.layout(), my_button]) 32 | 33 | ctc.register_crystal_toolkit(app=app, layout=layout) 34 | 35 | 36 | # for the interactivity, we use a standard Dash callback 37 | @app.callback( 38 | Output(structure_component.id(), "data"), 39 | Input("change_structure_button", "n_clicks"), 40 | ) 41 | def update_structure(n_clicks): 42 | """Toggle between hexagonal and cubic structures on button click.""" 43 | return structures[n_clicks % 2] 44 | 45 | 46 | if __name__ == "__main__": 47 | app.run(debug=True, port=8050) 48 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/basic_hello_world.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | from dash import html 5 | 6 | from crystal_toolkit.settings import SETTINGS 7 | 8 | # create Dash app as normal 9 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 10 | 11 | # create your layout 12 | app.layout = html.Span(["Hello scientist!"]) 13 | 14 | # run this app with "python path/to/this/file.py" 15 | # in production, deploy behind gunicorn or similar 16 | # see Dash docs for more info 17 | if __name__ == "__main__": 18 | app.run(debug=True, port=8050) 19 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/chgcar.py: -------------------------------------------------------------------------------- 1 | # %% 2 | from __future__ import annotations 3 | 4 | import dash 5 | from dash import html 6 | from dash_mp_components import CrystalToolkitScene 7 | from pymatgen.io.vasp import Chgcar 8 | 9 | import crystal_toolkit.components as ctc 10 | from crystal_toolkit.settings import SETTINGS 11 | 12 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 13 | 14 | chgcar = Chgcar.from_file("../../../tests/test_files/chgcar.vasp") 15 | scene = chgcar.get_scene(isolvl=0.0001) 16 | 17 | layout = html.Div( 18 | [CrystalToolkitScene(data=scene.to_json())], 19 | style={"width": "100px", "height": "100px"}, 20 | ) 21 | # %% 22 | # as explained in "preamble" section in documentation 23 | ctc.register_crystal_toolkit(app=app, layout=layout) 24 | 25 | if __name__ == "__main__": 26 | app.run(debug=True, port=8050) 27 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/diffraction.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | from pymatgen.core import Lattice, Structure 5 | 6 | import crystal_toolkit.components as ctc 7 | from crystal_toolkit.helpers.layouts import H1, H2, Container 8 | from crystal_toolkit.settings import SETTINGS 9 | 10 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 11 | 12 | structure = Structure(Lattice.cubic(4.2), ["Na", "K"], [[0, 0, 0], [0.5, 0.5, 0.5]]) 13 | 14 | xrd_component = ctc.XRayDiffractionComponent(initial_structure=structure) 15 | 16 | # example layout to demonstrate capabilities of component 17 | layout = Container( 18 | [ 19 | H1("XRDComponent Example"), 20 | H2("Generated from Structure object", style={"fontSize": "1rem"}), 21 | xrd_component.layout(), 22 | ] 23 | ) 24 | 25 | # as explained in "preamble" section in documentation 26 | ctc.register_crystal_toolkit(app=app, layout=layout) 27 | 28 | # run this app with "python path/to/this/file.py" 29 | # in production, deploy behind gunicorn or similar 30 | # see Dash docs for more info 31 | if __name__ == "__main__": 32 | app.run(debug=True, port=8050) 33 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/diffraction_dynamic.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | from dash.dependencies import Input, Output 5 | from pymatgen.core import Lattice, Structure 6 | 7 | import crystal_toolkit.components as ctc 8 | from crystal_toolkit.helpers.layouts import H1, Button, Container 9 | from crystal_toolkit.settings import SETTINGS 10 | 11 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 12 | 13 | xrd_component = ctc.XRayDiffractionComponent(id="xrd-diffraction") 14 | 15 | # example layout to demonstrate capabilities of component 16 | page_title = H1("XRDComponent Example (Structure Added After Loading)") 17 | load_btn = Button("Load XRD", id="load-xrd-button") 18 | layout = Container([page_title, xrd_component.layout(), load_btn]) 19 | 20 | # as explained in "preamble" section in documentation 21 | ctc.register_crystal_toolkit(app=app, layout=layout) 22 | 23 | 24 | @app.callback(Output(xrd_component.id(), "data"), Input(load_btn, "n_clicks")) 25 | def load_structure(n_clicks: int) -> Structure: 26 | """Load a cubic structure on button click.""" 27 | return Structure(Lattice.cubic(4.2), ["Na", "K"], [[0, 0, 0], [0.5, 0.5, 0.5]]) 28 | 29 | 30 | # run this app with "python path/to/this/file.py" 31 | # in production, deploy behind gunicorn or similar 32 | # see Dash docs for more info 33 | if __name__ == "__main__": 34 | app.run(debug=True, port=8050) 35 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/diffraction_empty.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | 5 | import crystal_toolkit.components as ctc 6 | from crystal_toolkit.helpers.layouts import H1, Container 7 | from crystal_toolkit.settings import SETTINGS 8 | 9 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 10 | 11 | xrd_component = ctc.XRayDiffractionComponent() 12 | 13 | # example layout to demonstrate capabilities of component 14 | layout = Container( 15 | [H1("XRDComponent Example (Empty, No Structure Defined)"), xrd_component.layout()] 16 | ) 17 | 18 | # as explained in "preamble" section in documentation 19 | ctc.register_crystal_toolkit(app=app, layout=layout) 20 | 21 | # run this app with "python path/to/this/file.py" 22 | # in production, deploy behind gunicorn or similar 23 | # see Dash docs for more info 24 | if __name__ == "__main__": 25 | app.run(debug=True, port=8050) 26 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/diffraction_tem.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | 5 | # create our crystal structure using pymatgen 6 | from pymatgen.core import Lattice, Structure 7 | 8 | import crystal_toolkit.components as ctc 9 | from crystal_toolkit.helpers.layouts import H1, H3, Container 10 | from crystal_toolkit.settings import SETTINGS 11 | 12 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 13 | 14 | 15 | structure = Structure( 16 | Lattice.cubic(5.44), 17 | ["Si"] * 8, 18 | [ 19 | [0.25, 0.75, 0.25], 20 | [0.0, 0.0, 0.5], 21 | [0.25, 0.25, 0.75], 22 | [0.0, 0.5, 0.0], 23 | [0.75, 0.75, 0.75], 24 | [0.5, 0.0, 0.0], 25 | [0.75, 0.25, 0.25], 26 | [0.5, 0.5, 0.5], 27 | ], 28 | ) 29 | 30 | tem_component = ctc.TEMDiffractionComponent(initial_structure=structure) 31 | 32 | # example layout to demonstrate capabilities of component 33 | layout = Container( 34 | [ 35 | H1("TEMDiffractionComponent Example"), 36 | H3("Generated from Structure object"), 37 | tem_component.layout(), 38 | ] 39 | ) 40 | 41 | # as explained in "preamble" section in documentation 42 | ctc.register_crystal_toolkit(app=app, layout=layout) 43 | 44 | # run this app with "python path/to/this/file.py" 45 | # in production, deploy behind gunicorn or similar 46 | # see Dash docs for more info 47 | if __name__ == "__main__": 48 | app.run(debug=True, port=8050) 49 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/fermi_surface.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import os 4 | 5 | import dash 6 | from monty.serialization import loadfn 7 | 8 | import crystal_toolkit.components as ctc 9 | from crystal_toolkit.helpers.layouts import H1, Container 10 | from crystal_toolkit.settings import SETTINGS 11 | 12 | # assets folder set for visual styles only 13 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 14 | 15 | # If callbacks created dynamically they cannot be statically checked at app startup. 16 | # For this simple example this IS a problem and, 17 | # nested layout this will need to be enabled -- consult Dash documentation 18 | # for more information. 19 | # app.config["suppress_callback_exceptions"] = True 20 | 21 | path = os.path.dirname(os.path.realpath(__file__)) 22 | fermi_surface = loadfn(f"{path}/BaFe2As2_fs.json.gz") 23 | 24 | # create the Crystal Toolkit component 25 | fs_component = ctc.FermiSurfaceComponent(fermi_surface, id="fermi_surface") 26 | 27 | # example layout to demonstrate capabilities of component 28 | layout = Container([H1("Fermi Surface Example"), fs_component.layout()]) 29 | 30 | # wrap your app.layout with crystal_toolkit_layout() 31 | # to ensure all necessary components are loaded into layout 32 | ctc.register_crystal_toolkit(app, layout=layout) 33 | 34 | # run this app with "python path/to/this/file.py" 35 | # in production, deploy behind gunicorn or similar 36 | # see Dash docs for more info 37 | if __name__ == "__main__": 38 | app.run(debug=True, port=8050) 39 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/kwarg_inputs.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import random 4 | 5 | import dash 6 | from dash import Input, Output, dcc, html 7 | from dash.exceptions import PreventUpdate 8 | 9 | import crystal_toolkit.components as ctc 10 | import crystal_toolkit.helpers.layouts as ctl 11 | from crystal_toolkit.settings import SETTINGS 12 | 13 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 14 | 15 | your_component = ctc.MPComponent(id="example") 16 | 17 | bool_input = your_component.get_bool_input( 18 | kwarg_label="bool_example", 19 | default=False, 20 | label="Example Boolean Input", 21 | help_str="This can explain to the user what this boolean input controls.", 22 | ) 23 | 24 | matrix_input = your_component.get_numerical_input( 25 | kwarg_label="matrix_example", 26 | default=[[1, 0, 0], [0, 1, 0], [0, 0, 1]], 27 | shape=(3, 3), 28 | label="Example Matrix Input", 29 | help_str="This can explain to the user what this slider input controls.", 30 | ) 31 | 32 | slider_input = your_component.get_slider_input( 33 | kwarg_label="slider_example", 34 | default=2.0, 35 | label="Example Slider Input", 36 | help_str="This can explain to the user what this slider input controls.", 37 | ) 38 | 39 | # create your layout 40 | layout = ctl.Section( 41 | [ 42 | ctl.H1("Example of input controls"), 43 | dcc.Markdown( 44 | "These examples are intended for people developing their own `MPComponent`." 45 | ), 46 | ctl.H2("Boolean input"), 47 | bool_input, 48 | ctl.H2("Matrix input"), 49 | matrix_input, 50 | ctl.H2("Slider input"), 51 | slider_input, 52 | ctl.H2("Dynamic inputs"), 53 | ctl.Button("Generate inputs", id="generate-inputs"), 54 | html.Div(id="dynamic-inputs"), 55 | ctl.H1("Output"), 56 | html.Span(id="output"), 57 | ] 58 | ) 59 | 60 | 61 | @app.callback( 62 | Output("output", "children"), Input(your_component.get_all_kwargs_id(), "value") 63 | ) 64 | def show_outputs(*args): 65 | """Reconstruct the kwargs from the state of the component and display them as string.""" 66 | kwargs = your_component.reconstruct_kwargs_from_state() 67 | 68 | return str(kwargs) 69 | 70 | 71 | @app.callback( 72 | Output("dynamic-inputs", "children"), Input("generate-inputs", "n_clicks") 73 | ) 74 | def add_inputs(n_clicks): 75 | """Add a slider input with random initial value to the layout.""" 76 | if not n_clicks: 77 | raise PreventUpdate 78 | 79 | element = random.choice(["Li", "Na", "K"]) 80 | return your_component.get_slider_input( 81 | kwarg_label=f"slider_{element}", 82 | default=random.uniform(0, 1), 83 | label=f"{element} Slider Input", 84 | help_str="This can explain to the user what this slider input controls.", 85 | ) 86 | 87 | 88 | # tell Crystal Toolkit about the app and layout we want to display 89 | ctc.register_crystal_toolkit(app=app, layout=layout, cache=None) 90 | 91 | # run this app with "python path/to/this/file.py" 92 | # in production, deploy behind gunicorn or similar 93 | # see Dash docs for more info 94 | if __name__ == "__main__": 95 | app.run(debug=True, port=8050) 96 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/matbench_dielectric.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/examples/matbench_dielectric.json.gz -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/matbench_dielectric_datatable_xrd.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import dash 6 | import plotly.io as pio 7 | from dash import dash_table, html 8 | from dash.dependencies import Input, Output 9 | 10 | import crystal_toolkit.components as ctc 11 | import crystal_toolkit.helpers.layouts as ctl 12 | from crystal_toolkit.apps.examples.utils import ( 13 | load_and_store_matbench_dataset, 14 | matbench_dielectric_desc, 15 | ) 16 | from crystal_toolkit.settings import SETTINGS 17 | 18 | if TYPE_CHECKING: 19 | from pymatgen.core import Structure 20 | 21 | pio.templates.default = "plotly_white" 22 | 23 | 24 | __author__ = "Janosh Riebesell" 25 | __date__ = "2022-07-21" 26 | __email__ = "janosh@lbl.gov" 27 | 28 | """ 29 | Run this app with: 30 | python crystal_toolkit/apps/examples/matbench_dielectric_datatable_xrd.py 31 | """ 32 | 33 | df_diel = load_and_store_matbench_dataset("matbench_dielectric") 34 | 35 | datatable_diel = dash_table.DataTable( 36 | data=df_diel.drop(columns="structure").round(2).to_dict("records"), 37 | id="datatable-diel", 38 | page_size=50, 39 | ) 40 | 41 | 42 | structure_component = ctc.StructureMoleculeComponent(id="structure") 43 | xrd_component = ctc.XRayDiffractionComponent(id="xrd") 44 | 45 | structure_xrd_stacked = html.Div( 46 | [structure_component.layout(), xrd_component.layout()], 47 | style=dict(display="grid", gap="2em", alignContent="start"), 48 | ) 49 | page_title = ctl.H1( 50 | "Matbench Dielectric Dataset", style=dict(textAlign="center", marginTop="1em") 51 | ) 52 | description = html.P( 53 | "Click a table cell to view its structure and XRD plot.", 54 | style=dict(textAlign="center"), 55 | ) 56 | 57 | app = dash.Dash(prevent_initial_callbacks=True, assets_folder=SETTINGS.ASSETS_PATH) 58 | main_div = html.Div( 59 | [datatable_diel, structure_xrd_stacked], 60 | style=dict(margin="2em", display="flex", gap="2em", justifyContent="center"), 61 | ) 62 | app.layout = html.Div([page_title, description, main_div, matbench_dielectric_desc]) 63 | 64 | ctc.register_crystal_toolkit(app=app, layout=app.layout) 65 | 66 | 67 | @app.callback( 68 | Output(structure_component.id(), "data"), 69 | # currently broken due to internal callback in XRayDiffractionComponent 70 | # Output(xrd_component.id(), "data"), 71 | Input(datatable_diel, "active_cell"), 72 | ) 73 | def update_structure(active_cell: dict[str, int | str]) -> Structure: 74 | """Update StructureMoleculeComponent with pymatgen structure when user clicks on new scatter 75 | point. 76 | """ 77 | row_idx = active_cell["row"] 78 | return df_diel.structure[row_idx] 79 | 80 | 81 | if __name__ == "__main__": 82 | app.run(debug=True, port=8050) 83 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/mpcontribs/adsorbate_choices.txt: -------------------------------------------------------------------------------- 1 | *C 2 | *C*C 3 | *CCH 4 | *CCH2 5 | *CCH2OH 6 | *CCH3 7 | *CCHO 8 | *CCHOH 9 | *CCO 10 | *CH 11 | *CH*CH 12 | *CH*COH 13 | *CH2 14 | *CH2*O 15 | *CH2CH2OH 16 | *CH2CH3 17 | *CH2OH 18 | *CH3 19 | *CH4 20 | *CHCH2 21 | *CHCH2OH 22 | *CHCHO 23 | *CHCHOH 24 | *CHCO 25 | *CHO 26 | *CHO*CHO 27 | *CHOCH2OH 28 | *CHOCHOH 29 | *CHOH 30 | *CHOHCH2 31 | *CHOHCH2OH 32 | *CHOHCH3 33 | *CHOHCHOH 34 | *CN 35 | *COCH2O 36 | *COCH2OH 37 | *COCH3 38 | *COCHO 39 | *COH 40 | *COHCH2OH 41 | *COHCH3 42 | *COHCHO 43 | *COHCHOH 44 | *COHCOH 45 | *H 46 | *N 47 | *N*NH 48 | *N*NO 49 | *N2 50 | *NH 51 | *NH2 52 | *NH2N(CH3)2 53 | *NH3 54 | *NHNH 55 | *NO 56 | *NO2 57 | *NO2NO2 58 | *NO3 59 | *NONH 60 | *O 61 | *OCH2CH3 62 | *OCH2CHOH 63 | *OCH3 64 | *OCHCH3 65 | *OH 66 | *OH2 67 | *OHCH2CH3 68 | *OHCH3 69 | *OHNH2 70 | *OHNNCH3 71 | *ONH 72 | *ONN(CH3)2 73 | *ONNH2 74 | *ONOH 75 | CH2*CO 76 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/mpcontribs/catalysis_columns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title":"Catalyst ID", 4 | "selector": "identifier", 5 | "formatType":"LINK", 6 | "formatOptions" : { 7 | "baseUrl": "/catalysis/", 8 | "preserveQuery": true 9 | }, 10 | "minWidth": "140px" 11 | }, 12 | { 13 | "title":"MPContribs ID", 14 | "selector": "id", 15 | "formatType":"LINK", 16 | "formatOptions": { 17 | "baseUrl": "https://contribs.materialsproject.org/contributions/", 18 | "target": "_blank" 19 | }, 20 | "minWidth": "130px", 21 | "omit": true 22 | }, 23 | { 24 | "title":"Formula", 25 | "selector": "formula", 26 | "formatType":"FORMULA", 27 | "minWidth": "150px" 28 | }, 29 | { 30 | "title":"Bulk Material ID", 31 | "selector": "data.mpid", 32 | "formatType":"LINK", 33 | "formatOptions" : { 34 | "baseUrl": "/materials/" 35 | }, 36 | "minWidth": "130px" 37 | }, 38 | { 39 | "title":"Bulk Formula", 40 | "selector": "data.bulkFormula", 41 | "formatType":"FORMULA" 42 | }, 43 | { 44 | "title":"Adsorbate Smiles", 45 | "selector": "data.adsorbateSmiles" 46 | }, 47 | { 48 | "title":"Adsorbate IUPAC Formula", 49 | "selector": "data.adsorbateIUPACFormula" 50 | }, 51 | { 52 | "title":"Adsorption Energy", 53 | "selector": "data.adsorptionEnergy.value", 54 | "formatType":"FIXED_DECIMAL", 55 | "formatOptions": { 56 | "decimals": 3 57 | }, 58 | "right": true 59 | }, 60 | { 61 | "title":"h", 62 | "selector": "data.h.value", 63 | "right": true 64 | }, 65 | { 66 | "title":"k", 67 | "selector": "data.k.value", 68 | "right": true 69 | }, 70 | { 71 | "title":"l", 72 | "selector": "data.l.value", 73 | "right": true 74 | }, 75 | { 76 | "title":"Surface Shift", 77 | "selector": "data.surfaceShift.value", 78 | "formatType":"FIXED_DECIMAL", 79 | "formatOptions": { 80 | "decimals": 3 81 | }, 82 | "right": true 83 | } 84 | ] 85 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/mpcontribs/catalysis_filter_groups.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Composition", 4 | "filters": [ 5 | { 6 | "name": "Bulk Formula", 7 | "params": ["data__bulkFormula__exact"], 8 | "type": "MATERIALS_INPUT", 9 | "isSearchBarField": true, 10 | "props": { 11 | "type": "formula", 12 | "periodicTableMode": "none", 13 | "errorMessage": "Please enter a valid bulk formula (e.g. AlCu4).", 14 | "helpItems": [ 15 | { "label": "Bulk Formula Examples" }, 16 | { "label": null, "examples": ["Ti2Pd3", "FeSi"] } 17 | ] 18 | } 19 | } 20 | ] 21 | }, 22 | { 23 | "name": "Adsorbate", 24 | "filters": [ 25 | { 26 | "name": "Adsorbate SMILES", 27 | "params": ["data__adsorbateSmiles__exact"], 28 | "type": "TEXT_INPUT" 29 | }, 30 | { 31 | "name": "Adsorbate IUPAC Formula", 32 | "params": ["data__adsorbateIUPACFormula__exact"], 33 | "type": "TEXT_INPUT" 34 | } 35 | ] 36 | }, 37 | { 38 | "name": "Surface", 39 | "filters": [ 40 | { 41 | "name": "Bulk Material ID", 42 | "params": ["data__mpid__exact"], 43 | "type": "TEXT_INPUT" 44 | }, 45 | { 46 | "name": "Formula", 47 | "params": ["formula__exact"], 48 | "type": "MATERIALS_INPUT", 49 | "props": { 50 | "type": "formula", 51 | "periodicTableMode": "none", 52 | "errorMessage": "Please enter a valid chemical formula (e.g. Al60H2O).", 53 | "helpItems": [ 54 | { "label": "Formula Examples" }, 55 | { "label": null, "examples": ["Cr18H2CS36O", "Tc48CN"] } 56 | ] 57 | } 58 | }, 59 | { 60 | "name": "Miller index, h", 61 | "params": ["data__h__value__gte", "data__h__value__lte"], 62 | "type": "SLIDER", 63 | "props": { "domain": [0, 2], "step": 1 } 64 | }, 65 | { 66 | "name": "Miller index, k", 67 | "params": ["data__k__value__gte", "data__k__value__lte"], 68 | "type": "SLIDER", 69 | "props": { "domain": [-2, 2], "step": 1 } 70 | }, 71 | { 72 | "name": "Miller index, l", 73 | "params": ["data__l__value__gte", "data__l__value__lte"], 74 | "type": "SLIDER", 75 | "props": { "domain": [-2, 2], "step": 1 } 76 | }, 77 | { 78 | "name": "Surface Shift", 79 | "params": ["data__surfaceShift__value__gte", "data__surfaceShift__value__lte"], 80 | "units": "Å", 81 | "type": "SLIDER", 82 | "props": { "domain": [0, 1], "step": 0.01 } 83 | } 84 | ] 85 | }, 86 | { 87 | "name": "Properties", 88 | "filters": [ 89 | { 90 | "name": "Adsorption Energy", 91 | "params": ["data__adsorptionEnergy__value__gte", "data__adsorptionEnergy__value__lte"], 92 | "units": "eV", 93 | "type": "SLIDER", 94 | "props": { "domain": [-10, 10], "step": 1 } 95 | } 96 | ] 97 | } 98 | ] 99 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/phase_diagram.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | from dash import dcc, html 5 | from pymatgen.analysis.phase_diagram import PhaseDiagram 6 | from pymatgen.ext.matproj import MPRester 7 | 8 | import crystal_toolkit.components as ctc 9 | from crystal_toolkit.settings import SETTINGS 10 | 11 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 12 | 13 | # If callbacks created dynamically they cannot be statically checked at app startup. 14 | # For this simple example this is not a problem, but if creating a complicated, 15 | # nested layout this will need to be enabled -- consult Dash documentation 16 | # for more information. 17 | app.config["suppress_callback_exceptions"] = True 18 | 19 | # tell Crystal Toolkit about the app 20 | ctc.register_app(app) 21 | 22 | # first, retrieve entries from Materials Project 23 | with MPRester() as mpr: 24 | # li_entries = mpr.get_entries_in_chemsys("Li") 25 | # li_o_entries = mpr.get_entries_in_chemsys("Li-O") 26 | li_co_o_entries = mpr.get_entries_in_chemsys("Li-O-Co") 27 | # li_co_o_fe_entries = mpr.get_entries_in_chemsys("Li-O-Co-Fe") 28 | 29 | # and then create the phase diagrams 30 | # li_phase_diagram = PhaseDiagram(li_entries) 31 | # li_o_phase_diagram = PhaseDiagram(li_o_entries) 32 | li_co_o_phase_diagram = PhaseDiagram(li_co_o_entries) 33 | # li_co_o_fe_phase_diagram = PhaseDiagram(li_co_o_fe_entries) 34 | 35 | # and the corresponding Crystal Toolkit components 36 | # we're creating four components here to demonstrate 37 | # visualizing 1-D, 2-D, 3-D and 4-D phase diagrams 38 | # li_phase_diagram_component = ctc.PhaseDiagramComponent(li_phase_diagram) 39 | # li_o_phase_diagram_component = ctc.PhaseDiagramComponent(li_o_phase_diagram) 40 | li_co_o_phase_diagram_component = ctc.PhaseDiagramComponent(li_co_o_phase_diagram) 41 | # li_co_o_fe_phase_diagram_component = ctc.PhaseDiagramComponent(li_co_o_fe_phase_diagram) 42 | 43 | 44 | # example layout to demonstrate capabilities of component 45 | layout = html.Div( 46 | [ 47 | html.H1("PhaseDiagramComponent Example"), 48 | html.H2("Standard Layout (1 Element)"), 49 | html.H2("Standard Layout (2 Elements)"), 50 | html.H2("Standard Layout (3 Elements)"), 51 | li_co_o_phase_diagram_component.layout(), 52 | html.H2("Standard Layout (4 Elements)"), 53 | html.H2("Technical Details"), 54 | dcc.Markdown(str(li_co_o_phase_diagram_component)), 55 | ] 56 | ) 57 | 58 | # wrap your app.layout with crystal_toolkit_layout() 59 | # to ensure all necessary components are loaded into layout 60 | app.layout = ctc.crystal_toolkit_layout(layout) 61 | 62 | 63 | # run this app with "python path/to/this/file.py" 64 | # in production, deploy behind gunicorn or similar 65 | # see Dash docs for more info 66 | if __name__ == "__main__": 67 | app.run(debug=True, port=8050) 68 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/phonon.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import os 4 | 5 | import dash 6 | 7 | # for loading DOS and BS data from json files 8 | from monty.serialization import loadfn 9 | 10 | from crystal_toolkit.components import register_crystal_toolkit 11 | from crystal_toolkit.components.phonon import PhononBandstructureAndDosComponent 12 | from crystal_toolkit.helpers.layouts import H1, Container 13 | from crystal_toolkit.settings import SETTINGS 14 | 15 | # create Dash app as normal, assets folder set for visual styles only 16 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 17 | 18 | # If callbacks created dynamically they cannot be statically checked at app startup. 19 | # For this simple example this IS a problem and, 20 | # nested layout this will need to be enabled -- consult Dash documentation 21 | # for more information. 22 | # app.config["suppress_callback_exceptions"] = True 23 | 24 | path = os.path.dirname(os.path.realpath(__file__)) 25 | bandstructure_symm_line = loadfn(f"{path}/BaTiO3_ph_bs.json") 26 | density_of_states = loadfn(f"{path}/BaTiO3_ph_dos.json") 27 | 28 | # create the Crystal Toolkit component 29 | ph_bs_dos_component = PhononBandstructureAndDosComponent( 30 | bandstructure_symm_line=bandstructure_symm_line, 31 | density_of_states=density_of_states, 32 | id="ph_bs_dos", 33 | ) 34 | 35 | # example layout to demonstrate capabilities of component 36 | page_title = H1("Phonon Band Structure and Density of States Example") 37 | layout = Container([page_title, ph_bs_dos_component.layout()]) 38 | 39 | # wrap your app.layout with crystal_toolkit_layout() 40 | # to ensure all necessary components are loaded into layout 41 | register_crystal_toolkit(app, layout=layout) 42 | 43 | 44 | # run this app with "python path/to/this/file.py" 45 | # in production, deploy behind gunicorn or similar 46 | # see Dash docs for more info 47 | if __name__ == "__main__": 48 | app.run(debug=True, port=8050) 49 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/pourbaix.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | from dash import html 5 | from pymatgen.ext.matproj import MPRester 6 | 7 | import crystal_toolkit.components as ctc 8 | from crystal_toolkit.settings import SETTINGS 9 | 10 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 11 | 12 | # If callbacks created dynamically they cannot be statically checked at app startup. 13 | # For this simple example this is not a problem, but if creating a complicated, 14 | # nested layout this will need to be enabled -- consult Dash documentation 15 | # for more information. 16 | app.config["suppress_callback_exceptions"] = True 17 | 18 | # first, retrieve entries from Materials Project 19 | with MPRester() as mpr: 20 | pourbaix_entries = mpr.get_pourbaix_entries("Fe-Co") 21 | 22 | pourbaix_component = ctc.PourbaixDiagramComponent(default_data=pourbaix_entries) 23 | 24 | # example layout to demonstrate capabilities of component 25 | layout = html.Div( 26 | [ 27 | html.H1("PourbaixDiagramComponent Example"), 28 | html.Button("Get Pourbaix Diagram", id="get-pourbaix"), 29 | pourbaix_component.layout(), 30 | html.Div(id="pourbaix-output"), 31 | ], 32 | style=dict(maxWidth="90vw", margin="2em auto"), 33 | ) 34 | 35 | ctc.register_crystal_toolkit(app=app, layout=layout) 36 | 37 | # run this app with "python path/to/this/file.py" 38 | # in production, deploy behind gunicorn or similar 39 | # see Dash docs for more info 40 | if __name__ == "__main__": 41 | app.run(debug=True, port=8050) 42 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/structure.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | from dash import html 5 | from pymatgen.core import Lattice, Structure 6 | 7 | import crystal_toolkit.components as ctc 8 | from crystal_toolkit.settings import SETTINGS 9 | 10 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 11 | 12 | # create the Structure object 13 | structure = Structure( 14 | Lattice.cubic(4.2), 15 | ["Na", "K"], 16 | [[0, 0, 0], [0.5, 0.5, 0.5]], 17 | site_properties={"magmom": [-2, 2]}, 18 | ) 19 | 20 | # create the Crystal Toolkit component 21 | structure_component = ctc.StructureMoleculeComponent(structure, id="my_structure") 22 | 23 | # example layout to demonstrate capabilities of component 24 | layout = html.Div( 25 | [ 26 | html.H1("StructureMoleculeComponent Example"), 27 | html.H2("Standard Layout"), 28 | structure_component.layout(), 29 | html.H2("Optional Title Layout"), 30 | structure_component.title_layout(), 31 | ], 32 | style=dict( 33 | margin="2em auto", display="grid", placeContent="center", placeItems="center" 34 | ), 35 | ) 36 | 37 | # tell crystal toolkit about your app and layout 38 | ctc.register_crystal_toolkit(app, layout=layout) 39 | 40 | # run this app with "python path/to/this/file.py" 41 | # in production, deploy behind gunicorn or similar 42 | # see Dash docs for more info 43 | if __name__ == "__main__": 44 | app.run(debug=True, port=8050) 45 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/structure_magnetic.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | from dash import html 5 | from pymatgen.core import Lattice, Structure 6 | 7 | import crystal_toolkit.components as ctc 8 | from crystal_toolkit.settings import SETTINGS 9 | 10 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 11 | 12 | # create the Structure object 13 | structure = Structure( 14 | Lattice.cubic(3.0), 15 | ["Ni", "Ti"], 16 | [[0, 0, 0], [0.5, 0.5, 0.5]], 17 | site_properties={"magmom": [[-2.0, 1.0, 0.0], [1.0, 1.0, -1.0]]}, 18 | # site_properties={"magmom": [3.0, -2.0]}, 19 | ) 20 | 21 | # create the Crystal Toolkit component 22 | structure_component = ctc.StructureMoleculeComponent(structure, id="struct") 23 | 24 | # example layout to demonstrate capabilities of component 25 | layout = html.Div( 26 | [ 27 | html.H1("StructureMoleculeComponent Example"), 28 | html.H2("Standard Layout"), 29 | structure_component.layout(size="400px"), 30 | html.H2("Optional Additional Layouts"), 31 | html.H3("Screenshot Layout"), 32 | structure_component.screenshot_layout(), 33 | html.H3("Options Layout"), 34 | structure_component.options_layout(), 35 | html.H3("Title Layout"), 36 | structure_component.title_layout(), 37 | html.H3("Legend Layout"), 38 | structure_component.legend_layout(), 39 | ] 40 | ) 41 | 42 | # tell crystal toolkit about your app and layout 43 | ctc.register_crystal_toolkit(app, layout=layout) 44 | 45 | # run this app with "python path/to/this/file.py" 46 | # in production, deploy behind gunicorn or similar 47 | # see Dash docs for more info 48 | if __name__ == "__main__": 49 | app.run(debug=True, port=8050) 50 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/examples/tests/__init__.py -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/tests/readme.md: -------------------------------------------------------------------------------- 1 | # End-to-end Testing 2 | 3 | The tests for this code are constructed as small example apps. Running a test might involve simply verifying the app starts 4 | correctly, checking console log output does not have errors, simulating user interaction, and taking screenshots of the 5 | app state to ensure that the app looks as expected. 6 | 7 | Ideally, each individual component should have at least one example app. The example apps are also used to demonstrate 8 | correct usage of these components. 9 | 10 | ## Dependencies 11 | 12 | The tests in this folder need the dependencies specified in `tests/requirements.txt`, in particular `dash[testing]` and `selenium`. 13 | 14 | ## Troubleshooting 15 | 16 | If you're seeing errors like 17 | 18 | ```sh 19 | ERROR dash.testing.browser:browser.py:433 <<>> 20 | ``` 21 | 22 | or 23 | 24 | ```sh 25 | E selenium.common.exceptions.WebDriverException: Message: unknown error: cannot find Chrome binary 26 | ``` 27 | 28 | try manually installing `chromedriver` and/or `google-chrome`. On macOS, this can be done with `brew`: 29 | 30 | ```sh 31 | brew install --cask chromedriver 32 | brew install --cask google-chrome 33 | ``` 34 | 35 | macOS may complain that it cannot verify the security of these executables in which case you can manually override and give permission in 'System Preferences > Security & Privacy'. 36 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/tests/test_bandstructure.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import time 4 | from typing import TYPE_CHECKING 5 | 6 | from crystal_toolkit.apps.examples.bandstructure import app 7 | 8 | if TYPE_CHECKING: 9 | from crystal_toolkit.apps.examples.tests.typing import DashDuo 10 | 11 | 12 | def test_bs(dash_duo: DashDuo) -> None: 13 | dash_duo.start_server(app) 14 | dash_duo.clear_storage() 15 | 16 | time.sleep(5) 17 | dash_duo.percy_snapshot("example_bsdos_on_load") 18 | 19 | # # test choosing elemental projection 20 | # el = dash_duo.select_dcc_dropdown( 21 | # '{"component_id":"CTbs_dos","hint":"literal","idx":"False","kwarg_label":"dos-select"}', 22 | # index=1, 23 | # ) 24 | # 25 | # time.sleep(3) 26 | # dash_duo.percy_snapshot("example_bsdos_projection_index_1") 27 | # 28 | # # test selecting total orbital projection 29 | # el = dash_duo.select_dcc_dropdown("#CTbs_dos_dos-select", index=2) 30 | # 31 | # time.sleep(3) 32 | # dash_duo.percy_snapshot("example_bsdos_projection_index_2") 33 | 34 | logs = dash_duo.get_logs() 35 | assert not logs, f"Unexpected browser {logs=}" 36 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/tests/test_basic.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import time 4 | from typing import TYPE_CHECKING 5 | 6 | from crystal_toolkit.apps.examples.basic_hello_structure import ( 7 | app as hello_structure_app, 8 | ) 9 | from crystal_toolkit.apps.examples.basic_hello_structure_interactive import ( 10 | app as hello_structure_interactive_app, 11 | ) 12 | from crystal_toolkit.apps.examples.basic_hello_world import app as hello_world_app 13 | 14 | if TYPE_CHECKING: 15 | from crystal_toolkit.apps.examples.tests.typing import DashDuo 16 | 17 | 18 | def test_hello_scientist(dash_duo: DashDuo): 19 | dash_duo.start_server(hello_world_app) 20 | dash_duo.clear_storage() 21 | 22 | dash_duo.percy_snapshot("hello_scientist") 23 | 24 | logs = dash_duo.get_logs() 25 | assert not logs, f"Unexpected browser {logs=}" 26 | 27 | 28 | def test_hello_structure(dash_duo: DashDuo) -> None: 29 | dash_duo.start_server(hello_structure_app) 30 | dash_duo.clear_storage() 31 | 32 | time.sleep(1) 33 | dash_duo.percy_snapshot("hello_structure") 34 | 35 | logs = dash_duo.get_logs() 36 | assert not logs, f"Unexpected browser {logs=}" 37 | 38 | 39 | def test_hello_structure_interactive(dash_duo: DashDuo) -> None: 40 | dash_duo.start_server(hello_structure_interactive_app) 41 | dash_duo.clear_storage() 42 | 43 | dash_duo.percy_snapshot("hello_structure_interactive_on_load") 44 | 45 | dash_duo.multiple_click("#change_structure_button", 1) 46 | 47 | dash_duo.percy_snapshot("hello_structure_interactive_on_click") 48 | 49 | logs = dash_duo.get_logs() 50 | assert not logs, f"Unexpected browser {logs=}" 51 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/tests/test_diffraction.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from time import sleep 4 | from typing import TYPE_CHECKING 5 | 6 | from selenium.webdriver.common.keys import Keys 7 | 8 | from crystal_toolkit.apps.examples.diffraction import app 9 | 10 | if TYPE_CHECKING: 11 | from crystal_toolkit.apps.examples.tests.typing import DashDuo 12 | 13 | 14 | def test_diffraction(dash_duo: DashDuo) -> None: 15 | dash_duo.start_server(app) 16 | dash_duo.clear_storage() 17 | 18 | # make sure the XRD component was mounted and is a node with class 'dash-graph' 19 | node = dash_duo.find_element("#CTXRayDiffractionComponent_xrd-plot") 20 | assert "dash-graph" in node.get_attribute("class") 21 | 22 | sleep(1) 23 | # select 'Shape Factor' and 'Peak Profile' inputs and increment their values 24 | # to ensure they throw no errors 25 | input_nodes = dash_duo.find_elements("input[type=number]") 26 | input_nodes[0].send_keys(Keys.ARROW_UP) 27 | sleep(1) 28 | input_nodes[1].send_keys(Keys.ARROW_UP) 29 | sleep(1) 30 | # focus the other input since component only updates on blur 31 | input_nodes[0].send_keys(Keys.ARROW_UP) 32 | 33 | logs = dash_duo.get_logs() 34 | assert not logs, f"Unexpected browser {logs=}" 35 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/tests/test_fermi_surface.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from crystal_toolkit.apps.examples.tests.typing import DashDuo 7 | 8 | 9 | def test_diffraction(dash_duo: DashDuo) -> None: 10 | from crystal_toolkit.apps.examples.fermi_surface import app 11 | 12 | dash_duo.start_server(app) 13 | dash_duo.clear_storage() 14 | 15 | # make sure the FS component was mounted and is a node with class 'dash-graph' 16 | node = dash_duo.find_element("#CTfermi_surface_fermi-surface-graph") 17 | assert "dash-graph" in node.get_attribute("class") 18 | 19 | logs = dash_duo.get_logs() 20 | assert not logs, f"Unexpected browser {logs=}" 21 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/tests/test_structure.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from time import sleep 4 | from typing import TYPE_CHECKING 5 | 6 | from crystal_toolkit.apps.examples.structure import app 7 | 8 | if TYPE_CHECKING: 9 | from crystal_toolkit.apps.examples.tests.typing import DashDuo 10 | 11 | 12 | def test_structure(dash_duo: DashDuo) -> None: 13 | dash_duo.start_server(app) 14 | dash_duo.clear_storage() 15 | 16 | dash_duo.percy_snapshot("example_structure_on_load") 17 | sleep(1) 18 | 19 | # click the settings button (second button in the button-bar) to show the settings panel 20 | # and test the settings options. 21 | dash_duo.find_element(".mpc-button-bar .button[data-for*=settings]").click() 22 | 23 | # make sure changing unit cell works 24 | for idx in range(3): 25 | dash_duo.select_dcc_dropdown("#CTmy_structure_unit-cell-choice", index=idx) 26 | dash_duo.percy_snapshot(f"example_structure_unit-cell_index_{idx}") 27 | 28 | # test changing radius 29 | dash_duo.select_dcc_dropdown("#CTmy_structure_radius_strategy", index=0) 30 | dash_duo.percy_snapshot("example_structure_radius_index_0") 31 | sleep(1) 32 | 33 | # test changing radius again 34 | dash_duo.select_dcc_dropdown("#CTmy_structure_radius_strategy", index=2) 35 | dash_duo.percy_snapshot("example_structure_primitive_radius_index_2") 36 | sleep(1) 37 | 38 | logs = dash_duo.get_logs() 39 | assert not logs, f"Unexpected browser {logs=}" 40 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/tests/typing.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Protocol, Union 4 | 5 | import dash 6 | 7 | ElemOrSelector = Union[str, dash.development.base_component.Component] 8 | 9 | 10 | class DashDuo(Protocol): 11 | """The dash_duo pytest fixture lives in dash.testing.plugin.dash_duo. 12 | 13 | See https://dash.plotly.com/testing#browser-apis 14 | and https://github.com/plotly/dash/issues/2170 15 | """ 16 | 17 | # driver = ... # selenium.webdriver.remote.WebDriver 18 | 19 | def start_server(self, start_server) -> None: ... 20 | 21 | def find_element( 22 | self, selector: str 23 | ) -> dash.development.base_component.Component: ... 24 | 25 | def wait_for_text_to_equal( 26 | self, selector: str, text: str, timeout: int | None = None 27 | ) -> None: ... 28 | 29 | def get_logs(self) -> list[str]: ... 30 | 31 | def clear_storage(self) -> None: ... 32 | 33 | def percy_snapshot(self, name: str, wait_for_callbacks: bool = False) -> None: ... 34 | 35 | def multiple_click(self, selector: str, clicks: int) -> None: ... 36 | 37 | def wait_for_element(self, selector: str, timeout: int | None = None) -> None: ... 38 | 39 | def take_snapshot(self, name: str) -> None: ... 40 | 41 | def wait_for_page(self, url: str | None = None, timeout: int = 10) -> None: ... 42 | 43 | def find_elements( 44 | self, selector: str 45 | ) -> list[dash.development.base_component.Component]: ... 46 | 47 | def select_dcc_dropdown( 48 | self, 49 | elem_or_selector: ElemOrSelector, 50 | value: str | None = None, 51 | index: int | None = None, 52 | ) -> None: 53 | # https://github.com/plotly/dash/blob/04217e8/dash/testing/browser.py#L409 54 | ... 55 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/transformations.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | from dash import html 5 | from dash.dependencies import Input, Output 6 | from dash_mp_components import JsonView 7 | from pymatgen.core import Lattice, Structure 8 | from pymatgen.ext.matproj import MPRester 9 | 10 | import crystal_toolkit.components as ctc 11 | from crystal_toolkit.settings import SETTINGS 12 | 13 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 14 | 15 | # create the Structure object 16 | structure = Structure(Lattice.cubic(4.2), ["Na", "K"], [[0, 0, 0], [0.5, 0.5, 0.5]]) 17 | 18 | 19 | # create an input structure as an example 20 | structure_component = ctc.StructureMoleculeComponent( 21 | MPRester().get_structure_by_material_id("mp-804"), id="structure_in" 22 | ) 23 | # and a way to view the transformed structure 24 | structure_component_transformed = ctc.StructureMoleculeComponent( 25 | MPRester().get_structure_by_material_id("mp-804"), id="structure_out" 26 | ) 27 | 28 | # and the transformation component itself 29 | transformation_component = ctc.AllTransformationsComponent( 30 | input_structure_component=structure_component, 31 | ) 32 | 33 | # example layout to demonstrate capabilities of component 34 | layout = html.Div( 35 | [ 36 | html.H1("TransformationComponent Example"), 37 | html.H2("Standard Layout"), 38 | transformation_component.layout(), 39 | html.H3("Example Input Structure"), 40 | structure_component.layout(size="500px"), 41 | html.H3("Example Transformed Structure"), 42 | structure_component_transformed.layout(size="500px"), 43 | html.H3("JSON View of Transformations"), 44 | JsonView(id="json"), 45 | ] 46 | ) 47 | 48 | # tell crystal toolkit about your app and layout 49 | ctc.register_crystal_toolkit(app, layout=layout) 50 | 51 | # this is here for to see the JSON representation of 52 | # the transformations when running the example app, 53 | # it is not necessary for running the component 54 | app.clientside_callback( 55 | """ 56 | function (...args) { 57 | return {"transformations": args} 58 | } 59 | """, 60 | Output("json", "src"), 61 | [ 62 | Input(trafo.id(), "data") 63 | for trafo in transformation_component.transformations.values() 64 | ], 65 | ) 66 | 67 | 68 | @app.callback( 69 | Output(structure_component_transformed.id(), "data"), 70 | Input(transformation_component.id(), "data"), 71 | ) 72 | def update_structure(struct): 73 | return struct 74 | 75 | 76 | # run this app with "python path/to/this/file.py" 77 | # in production, deploy behind gunicorn or similar 78 | # see Dash docs for more info 79 | if __name__ == "__main__": 80 | app.run(debug=True, port=8050) 81 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/transformations_minimal.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import dash 4 | from dash import dcc, html 5 | from dash.dependencies import Input, Output 6 | from dash_mp_components import JsonView 7 | from pymatgen.core import Lattice, Structure 8 | from pymatgen.ext.matproj import MPRester 9 | 10 | import crystal_toolkit.components as ctc 11 | from crystal_toolkit.settings import SETTINGS 12 | 13 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 14 | 15 | # create the Structure object 16 | structure = Structure(Lattice.cubic(4.2), ["Na", "K"], [[0, 0, 0], [0.5, 0.5, 0.5]]) 17 | 18 | 19 | # create an input structure as an example 20 | structure = MPRester().get_structure_by_material_id("mp-804") 21 | structure_in = dcc.Store(id="structure_in", data=structure.as_dict()) 22 | # patch, this should be a JSON component ... 23 | structure_in.id = lambda: "structure_in" 24 | 25 | # and the transformation component itself 26 | transformation_component = ctc.AllTransformationsComponent( 27 | transformations=[ 28 | "AutoOxiStateDecorationTransformationComponent", 29 | "SupercellTransformationComponent", 30 | # "SlabTransformationComponent", 31 | # "SubstitutionTransformationComponent", 32 | "CubicSupercellTransformationComponent", 33 | # "GrainBoundaryTransformationComponent" 34 | ], 35 | input_structure=structure_in, 36 | ) 37 | 38 | # example layout to demonstrate capabilities of component 39 | layout = html.Div( 40 | [ 41 | html.H1("TransformationComponent Example"), 42 | html.H2("Standard Layout"), 43 | transformation_component.layout(), 44 | html.H3("Example Input Structure"), 45 | JsonView(src=structure.as_dict()), 46 | html.H3("Example Transformed Structure"), 47 | JsonView(src={}, id="structure_out"), 48 | ] 49 | ) 50 | 51 | # tell crystal toolkit about your app and layout 52 | ctc.register_crystal_toolkit(app, layout=layout) 53 | 54 | 55 | @app.callback( 56 | Output("structure_out", "data"), Input(transformation_component.id(), "data") 57 | ) 58 | def update_structure(struct): 59 | return struct 60 | 61 | 62 | # run this app with "python path/to/this/file.py" 63 | # in production, deploy behind gunicorn or similar 64 | # see Dash docs for more info 65 | if __name__ == "__main__": 66 | app.run(debug=True, port=8050) 67 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import os 4 | from typing import TYPE_CHECKING 5 | 6 | from dash import dcc 7 | from pymatgen.symmetry.analyzer import SpacegroupAnalyzer 8 | from tqdm import tqdm 9 | 10 | if TYPE_CHECKING: 11 | import pandas as pd 12 | 13 | 14 | def load_and_store_matbench_dataset(dataset_name: str) -> pd.DataFrame: 15 | """Load, process and save Matbench datasets to disk to avoid having to re-process on subsequent 16 | app runs. 17 | """ 18 | data_path = os.path.join(os.path.dirname(__file__), f"{dataset_name}.json.gz") 19 | 20 | if os.path.isfile(data_path): 21 | import pandas as pd 22 | 23 | df = pd.read_json(data_path) 24 | else: 25 | try: 26 | from matminer.datasets import load_dataset 27 | 28 | df = load_dataset(dataset_name) 29 | 30 | if "structure" in df: 31 | df[["spg_symbol", "spg_num"]] = [ 32 | struct.get_space_group_info() 33 | for struct in tqdm(df.structure, desc="Getting space groups") 34 | ] 35 | 36 | df["crystal_sys"] = [ 37 | SpacegroupAnalyzer(x).get_crystal_system() for x in df.structure 38 | ] 39 | 40 | df["volume"] = [x.volume for x in df.structure] 41 | df["formula"] = [x.formula for x in df.structure] 42 | 43 | df.to_json(data_path, default_handler=lambda x: x.as_dict()) 44 | except ImportError: 45 | print( 46 | "matminer is not installed but needed to download a dataset. Run " 47 | "`pip install matminer`" 48 | ) 49 | 50 | return df 51 | 52 | 53 | matbench_dielectric_desc = dcc.Markdown( 54 | """ 55 | ## About the [`matbench_dielectric` dataset][mp_mb_diel] 56 | 57 | Intended use: Machine learning task to predict refractive index from structure. 58 | All data from Materials Project. Removed entries having a formation energy (or energy 59 | above the convex hull) more than 150meV and those having refractive indices less than 60 | 1 and those containing noble gases. Retrieved April 2, 2019. 61 | 62 | - Input: Pymatgen Structure of the material 63 | - Target variable: refractive index n (unitless) 64 | - Entries: 636 65 | 66 | See [MatBench website](https://matbench.materialsproject.org) for details. 67 | 68 | [mp_mb_diel]: https://ml.materialsproject.org/projects/matbench_dielectric 69 | """, 70 | style=dict(margin="3em auto", maxWidth="50em"), 71 | ) 72 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/examples/write_structure_screenshot_to_file.py: -------------------------------------------------------------------------------- 1 | # This example is used to write structures to images in an automated manner. 2 | # It is a very specific script! Not intended for general use. 3 | from __future__ import annotations 4 | 5 | import urllib 6 | from pathlib import Path 7 | from time import sleep 8 | 9 | import dash 10 | from dash import dcc, html 11 | from dash.dependencies import Input, Output, State 12 | from pymatgen.ext.matproj import MPRester 13 | from pymatgen.symmetry.analyzer import SpacegroupAnalyzer 14 | 15 | import crystal_toolkit.components as ctc 16 | from crystal_toolkit.settings import SETTINGS 17 | 18 | SCREENSHOT_PATH = Path.home() / "screenshots" 19 | 20 | app = dash.Dash(assets_folder=SETTINGS.ASSETS_PATH) 21 | server = app.server 22 | 23 | structure_component = ctc.StructureMoleculeComponent( 24 | show_compass=False, 25 | bonded_sites_outside_unit_cell=True, 26 | scene_settings={"zoomToFit2D": True}, 27 | ) 28 | 29 | layout = html.Div( 30 | [structure_component.layout(), dcc.Location(id="url"), html.Div(id="dummy-output")] 31 | ) 32 | 33 | 34 | def get_structure_for_mpid(mpid): 35 | from pymatgen.ext.matproj import MPRester 36 | 37 | with MPRester() as mpr: 38 | structure = mpr.get_structure_by_material_id(mpid) 39 | 40 | return SpacegroupAnalyzer(structure).get_conventional_standard_structure() 41 | 42 | 43 | @app.callback( 44 | Output(structure_component.id("scene"), "imageRequest"), 45 | Input(structure_component.id("graph"), "data"), 46 | ) 47 | def trigger_image_request(data): 48 | sleep(1) 49 | return {"filetype": "png"} 50 | 51 | 52 | @app.callback(Output(structure_component.id(), "data"), Input("url", "pathname")) 53 | def trigger_new_data(url): 54 | mp_id = url[1:] 55 | with MPRester() as mpr: 56 | structure = mpr.get_structure_by_material_id(mp_id) 57 | 58 | return SpacegroupAnalyzer(structure).get_conventional_standard_structure() 59 | 60 | 61 | @app.callback( 62 | Output("dummy-output", "children"), 63 | Input(structure_component.id("scene"), "imageDataTimestamp"), 64 | State("url", "pathname"), 65 | State(structure_component.id("scene"), "imageData"), 66 | ) 67 | def save_image(image_data_timestamp, url, image_data): 68 | if image_data: 69 | # print(image_data.strip("data:image/png;base64,")[-1:-100]) 70 | # image_bytes = b64decode(image_data.strip("data:image/png;base64,").encode('ascii')) 71 | response = urllib.request.urlopen(image_data) 72 | with open(SCREENSHOT_PATH / f"{url[1:]}.png", "wb") as file: 73 | file.write(response.file.read()) 74 | 75 | 76 | ctc.register_crystal_toolkit(app=app, layout=layout) 77 | if __name__ == "__main__": 78 | app.run(debug=True, port=8050) 79 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/help.yaml: -------------------------------------------------------------------------------- 1 | CatalysisApp: 2 | catapp-add-data: 3 | help: Click on a point in the figure to view additional information. 4 | label: Additional Data 5 | link: null 6 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/apps/tests/__init__.py -------------------------------------------------------------------------------- /crystal_toolkit/apps/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from playwright.sync_api import Page 3 | 4 | 5 | @pytest.fixture(autouse=True) 6 | def _assert_no_console_errors(page: Page): 7 | logs = [] 8 | page.on("console", lambda msg: logs.append(msg)) 9 | 10 | page.goto("http://127.0.0.1:8050") 11 | 12 | yield 13 | 14 | errors = [msg.text for msg in logs if msg.type == "error"] 15 | assert len(errors) == 0, f"Unexpected browser {errors=}" 16 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/tests/test_main.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import time 4 | from typing import TYPE_CHECKING 5 | 6 | if TYPE_CHECKING: 7 | from crystal_toolkit.apps.examples.tests.typing import DashDuo 8 | 9 | 10 | def test_main_app_startup(dash_duo: DashDuo): 11 | from crystal_toolkit.apps.main import app 12 | 13 | dash_duo.start_server(app) 14 | # dash_duo.clear_storage() 15 | 16 | dash_duo.wait_for_element("#StructureMoleculeComponent_title", timeout=4) 17 | time.sleep(10) 18 | 19 | dash_duo.percy_snapshot("main_app_startup-layout") 20 | dash_duo.take_snapshot("main_app_startup-layout") 21 | 22 | logs = dash_duo.get_logs() 23 | assert not logs, f"Unexpected browser {logs=}" 24 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/tests/test_pourbaix.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from playwright.sync_api import Page 4 | 5 | 6 | def test_pourbaix(page: Page): 7 | from crystal_toolkit.apps.examples.pourbaix import app 8 | 9 | thread = threading.Thread(target=app.run) 10 | thread.start() 11 | 12 | # select 1st structure 13 | page.locator(".react-select__input-container").click() 14 | page.get_by_text("Fe₃H (mp-1184287-GGA)", exact=True).click() 15 | 16 | # click toggle switches 17 | page.locator("div.mpc-switch").nth(0).click() # click on "Filter Solids" 18 | page.locator("div.mpc-switch").nth(1).click() # click on "Show Heatmap" 19 | 20 | # select 2nd structure 21 | page.locator(".react-select__input-container").click() 22 | page.get_by_text("CoH (mp-1206874-GGA)", exact=True).click() 23 | -------------------------------------------------------------------------------- /crystal_toolkit/apps/tests/test_structure.py: -------------------------------------------------------------------------------- 1 | import re 2 | import threading 3 | 4 | from playwright.sync_api import Page, expect 5 | 6 | 7 | def test_structure(page: Page): 8 | from crystal_toolkit.apps.examples.structure import app 9 | 10 | thread = threading.Thread(target=app.run) 11 | thread.start() 12 | 13 | expect(page).to_have_title("Crystal Toolkit") 14 | h1_text = page.text_content("h1") 15 | assert h1_text == "StructureMoleculeComponent Example" 16 | 17 | # repeatedly drag the canvas to test rotating the structure 18 | canvas = page.locator("canvas") 19 | canvas.drag_to(target=canvas, source_position={"x": 100, "y": 20}) 20 | canvas.drag_to(target=canvas, source_position={"x": 0, "y": 70}) 21 | 22 | # test enter and exit "Full screen" 23 | full_screen_button = page.query_selector('button[data-for^="expand-"]') 24 | assert full_screen_button.is_visible() 25 | page.locator("button").filter(has_text="Full screen").click() 26 | page.locator("button").filter(has_text="Exit full screen").click() 27 | 28 | # Check if "Show settings" button exists and is visible 29 | settings_button = page.query_selector('button[data-for^="settings-"]') 30 | assert settings_button.is_visible() 31 | 32 | # test "export structure as image" button 33 | image_button = page.query_selector('div[data-for^="image-"] button') 34 | image_button.click() 35 | with page.expect_download() as download: 36 | page.get_by_text("Screenshot (PNG)").click() 37 | assert download.value.url.startswith("blob:http://") 38 | 39 | # test "export structure as file" button 40 | position_button = page.query_selector("div[data-for^='export-'] button") 41 | position_button.click() 42 | with page.expect_download() as download: 43 | page.get_by_text("CIF (Symmetrized)").click() 44 | 45 | assert re.match("", 55 | str(download.value), 56 | ) 57 | -------------------------------------------------------------------------------- /crystal_toolkit/components/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from crystal_toolkit.components.bandstructure import ( 4 | BandstructureAndDosComponent, 5 | BandstructureAndDosPanelComponent, 6 | ) 7 | from crystal_toolkit.components.diffraction import XRayDiffractionComponent 8 | from crystal_toolkit.components.diffraction_tem import TEMDiffractionComponent 9 | from crystal_toolkit.components.fermi_surface import FermiSurfaceComponent 10 | from crystal_toolkit.components.localenv import LocalEnvironmentPanel 11 | from crystal_toolkit.components.phase_diagram import ( 12 | PhaseDiagramComponent, 13 | PhaseDiagramPanelComponent, 14 | ) 15 | from crystal_toolkit.components.phonon import ( 16 | PhononBandstructureAndDosComponent, 17 | PhononBandstructureAndDosPanelComponent, 18 | ) 19 | from crystal_toolkit.components.pourbaix import PourbaixDiagramComponent 20 | from crystal_toolkit.components.search import SearchComponent 21 | from crystal_toolkit.components.structure import StructureMoleculeComponent 22 | 23 | # from crystal_toolkit.components.submit_snl import SubmitSNLPanel 24 | from crystal_toolkit.components.symmetry import SymmetryPanel 25 | from crystal_toolkit.components.transformations.autooxistatedecoration import ( 26 | AutoOxiStateDecorationTransformationComponent, 27 | ) 28 | from crystal_toolkit.components.transformations.core import AllTransformationsComponent 29 | 30 | # from crystal_toolkit.components.transformations.cubic import ( 31 | # CubicSupercellTransformationComponent, 32 | # ) 33 | from crystal_toolkit.components.transformations.grainboundary import ( 34 | GrainBoundaryTransformationComponent, 35 | ) 36 | 37 | # from crystal_toolkit.components.transformations.rattle import ( 38 | # MonteCarloRattleTransformationComponent, 39 | # ) 40 | from crystal_toolkit.components.transformations.slab import SlabTransformationComponent 41 | from crystal_toolkit.components.transformations.substitution import ( 42 | SubstitutionTransformationComponent, 43 | ) 44 | from crystal_toolkit.components.transformations.supercell import ( 45 | SupercellTransformationComponent, 46 | ) 47 | from crystal_toolkit.components.upload import StructureMoleculeUploadComponent 48 | 49 | # from crystal_toolkit.components.xas import XASComponent 50 | # from crystal_toolkit.components.xas import XASPanelComponent 51 | from crystal_toolkit.core.mpcomponent import MPComponent 52 | 53 | register_app = MPComponent.register_app 54 | register_cache = MPComponent.register_cache 55 | register_crystal_toolkit = MPComponent.register_crystal_toolkit 56 | crystal_toolkit_layout = MPComponent.crystal_toolkit_layout 57 | -------------------------------------------------------------------------------- /crystal_toolkit/components/robocrys.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from dash import html 4 | from dash.dependencies import Input, Output 5 | from robocrys import StructureCondenser, StructureDescriber 6 | from robocrys import __version__ as robocrys_version 7 | 8 | from crystal_toolkit.core.panelcomponent import PanelComponent 9 | from crystal_toolkit.helpers.layouts import Loading, MessageBody, MessageContainer 10 | 11 | 12 | class RobocrysComponent(PanelComponent): 13 | @property 14 | def title(self) -> str: 15 | return "Description" 16 | 17 | @property 18 | def description(self) -> str: 19 | return ( 20 | "Your friendly robocrystallographer tries to describe a structure much " 21 | "like a human crystallographer would." 22 | ) 23 | 24 | def contents_layout(self) -> html.Div: 25 | return Loading(id=self.id("robocrys")) 26 | 27 | def generate_callbacks(self, app, cache) -> None: 28 | super().generate_callbacks(app, cache) 29 | 30 | @app.callback(Output(self.id("robocrys"), "children"), Input(self.id(), "data")) 31 | @cache.memoize() 32 | def run_robocrys_analysis(new_store_contents): 33 | struct = self.from_data(new_store_contents) 34 | 35 | try: 36 | condenser = StructureCondenser() 37 | describer = StructureDescriber(fmt="unicode") 38 | 39 | condensed_structure = condenser.condense_structure(struct) 40 | 41 | description = describer.describe(condensed_structure) 42 | 43 | except Exception as exc: 44 | description = str(exc) 45 | 46 | repo_link = html.A( 47 | f"🤖 robocrys v{robocrys_version}", 48 | href="https://github.com/hackingmaterials/robocrystallographer", 49 | style={"white-space": "nowrap"}, 50 | ) 51 | return MessageContainer( 52 | MessageBody([f"{description} - ", repo_link]), kind="dark" 53 | ) 54 | -------------------------------------------------------------------------------- /crystal_toolkit/components/transformations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/components/transformations/__init__.py -------------------------------------------------------------------------------- /crystal_toolkit/components/transformations/autooxistatedecoration.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from pymatgen.transformations.standard_transformations import ( 4 | AutoOxiStateDecorationTransformation, 5 | ) 6 | 7 | from crystal_toolkit.components.transformations.core import TransformationComponent 8 | 9 | 10 | class AutoOxiStateDecorationTransformationComponent(TransformationComponent): 11 | @property 12 | def title(self) -> str: 13 | return "Detect likely oxidation states" 14 | 15 | @property 16 | def description(self) -> str: 17 | return """Annotate the crystal structure with likely oxidation states 18 | using a bond valence approach. This transformation can fail if it cannot find 19 | a satisfactory combination of oxidation states, and might be slow for large 20 | structures. 21 | """ 22 | 23 | @property 24 | def transformation(self): 25 | return AutoOxiStateDecorationTransformation 26 | 27 | def options_layouts(self, state=None, structure=None): 28 | state = state or { 29 | "symm_tol": 0.1, 30 | "max_radius": 4, 31 | "max_permutations": 10000, 32 | "distance_scale_factor": 1.015, 33 | } 34 | 35 | symm_tol = self.get_numerical_input( 36 | label="Symmetry tolerance", 37 | kwarg_label="symm_tol", 38 | state=state, 39 | help_str="""Symmetry tolerance used to determine which sites are 40 | symmetrically equivalent. Set to 0 to turn off symmetry.""", 41 | shape=(), 42 | ) 43 | 44 | max_radius = self.get_numerical_input( 45 | label="Maximum radius /Å", 46 | kwarg_label="max_radius", 47 | state=state, 48 | help_str="""Maximum radius in Ångstroms used to find nearest neighbors.""", 49 | shape=(), 50 | ) 51 | 52 | max_permutations = self.get_numerical_input( 53 | label="Maximum number of permutations", 54 | kwarg_label="max_permutations", 55 | state=state, 56 | help_str="""Maximum number of permutations of oxidation states to test.""", 57 | shape=(), 58 | ) 59 | 60 | distance_scale_factor = self.get_numerical_input( 61 | label="Distance scale factor", 62 | kwarg_label="distance_scale_factor", 63 | state=state, 64 | help_str="""A scale factor to be applied. This is 65 | useful for scaling distances, esp in the case of 66 | calculation-relaxed structures, which may tend to under (GGA) or 67 | over bind (LDA). The default of 1.015 works for GGA. For 68 | experimental structure, set this to 1.""", 69 | shape=(), 70 | ) 71 | 72 | return symm_tol, max_radius, max_permutations, distance_scale_factor 73 | -------------------------------------------------------------------------------- /crystal_toolkit/components/transformations/cubic.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from pymatgen.transformations.advanced_transformations import ( 4 | CubicSupercellTransformation, 5 | ) 6 | 7 | from crystal_toolkit.components.transformations.core import TransformationComponent 8 | 9 | 10 | class CubicSupercellTransformationComponent(TransformationComponent): 11 | @property 12 | def title(self) -> str: 13 | return "Make nearly cubic supercell" 14 | 15 | @property 16 | def description(self) -> str: 17 | return """A transformation that aims to generate a nearly cubic supercell structure 18 | from a structure. 19 | 20 | The algorithm solves for a transformation matrix that makes the supercell 21 | cubic. The matrix must have integer entries, so entries are rounded in such 22 | a way that forces the matrix to be nonsingular. From the supercell 23 | resulting from this transformation matrix, vector projections are used to 24 | determine the side length of the largest cube that can fit inside the 25 | supercell. The algorithm will iteratively increase the size of the supercell 26 | until the largest inscribed cube's side length is at least the minimum length 27 | and the number of atoms in the supercell falls in the range specified. 28 | """ 29 | 30 | @property 31 | def transformation(self): 32 | return CubicSupercellTransformation 33 | 34 | def options_layouts(self, state=None, structure=None): 35 | state = state or { 36 | "max_atoms": 100, 37 | "min_atoms": len(structure) if structure else 50, 38 | "min_length": 10, 39 | "force_diagonal": False, 40 | } 41 | 42 | max_atoms = self.get_numerical_input( 43 | label="Maximum number of atoms", 44 | kwarg_label="max_atoms", 45 | state=state, 46 | help_str="""Maximum number of atoms allowed in the supercell.""", 47 | shape=(), 48 | ) 49 | 50 | min_atoms = self.get_numerical_input( 51 | label="Minimum number of atoms", 52 | kwarg_label="min_atoms", 53 | state=state, 54 | help_str="""Minimum number of atoms allowed in the supercell.""", 55 | shape=(), 56 | ) 57 | 58 | min_length = self.get_numerical_input( 59 | label="Minimum length /Å", 60 | kwarg_label="min_length", 61 | state=state, 62 | help_str="""Minimum length of the smallest supercell lattice vector.""", 63 | shape=(), 64 | ) 65 | 66 | force_diagonal = self.get_bool_input( 67 | label="Force diagonal", 68 | kwarg_label="force_diagonal", 69 | state=state, 70 | help_str="""If enabled, return a transformation with a diagonal transformation matrix.""", 71 | ) 72 | 73 | return max_atoms, min_atoms, min_length, force_diagonal 74 | -------------------------------------------------------------------------------- /crystal_toolkit/components/transformations/rattle.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from pymatgen.transformations.advanced_transformations import ( 4 | MonteCarloRattleTransformation, 5 | ) 6 | 7 | from crystal_toolkit.components.transformations.core import TransformationComponent 8 | 9 | 10 | class MonteCarloRattleTransformationComponent(TransformationComponent): 11 | @property 12 | def title(self) -> str: 13 | return "Rattle a supercell" 14 | 15 | @property 16 | def description(self) -> str: 17 | return """Uses a Monte Carlo rattle procedure to randomly perturb the sites in a 18 | structure using the [hiPhive](https://hiphive.materialsmodeling.org) code. 19 | 20 | Rattling atom \\` i \\` is carried out as a Monte Carlo move that is accepted with 21 | a probability determined from the minimum interatomic distance 22 | \\` d\\_{ij} \\`. If \\` \\\\min(d\\_{ij}) \\` is smaller than \\` d\\_{min} \\` 23 | the move is only accepted with a low probability. 24 | 25 | This process is repeated for each atom a number of times meaning 26 | the magnitude of the final displacements is not *directly* 27 | connected to the rattle amplitude. 28 | """ 29 | 30 | @property 31 | def transformation(self): 32 | return MonteCarloRattleTransformation 33 | 34 | def options_layouts(self, state=None, structure=None): 35 | state = state or { 36 | "rattle_std": 0.2, 37 | "min_distance": 0.1, 38 | "seed": None, 39 | } 40 | 41 | rattle_std = self.get_numerical_input( 42 | label="Rattle amplitude", 43 | kwarg_label="rattle_std", 44 | state=state, 45 | help_str="""Rattle amplitude (standard deviation in normal distribution). 46 | Note: this value is not *directly* connected to the 47 | final average displacement for the structures""", 48 | shape=(), 49 | ) 50 | 51 | min_distance = self.get_numerical_input( 52 | label="Minimum distance /Å", 53 | kwarg_label="min_distance", 54 | state=state, 55 | help_str="""Interatomic distance used for computing the probability 56 | for each rattle move.""", 57 | shape=(), 58 | ) 59 | 60 | seed = self.get_numerical_input( 61 | label="Random seed", 62 | kwarg_label="seed", 63 | state=state, 64 | help_str="""Seed for setting up NumPy random state from which random numbers 65 | are generated. If not set, a random seed will be generated 66 | (default). This option allows the output of this transformation 67 | to be deterministic.""", 68 | shape=(), 69 | is_int=True, 70 | ) 71 | 72 | return rattle_std, min_distance, seed 73 | -------------------------------------------------------------------------------- /crystal_toolkit/components/transformations/substitution.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from pymatgen.transformations.standard_transformations import SubstitutionTransformation 4 | 5 | from crystal_toolkit.components.transformations.core import TransformationComponent 6 | 7 | 8 | class SubstitutionTransformationComponent(TransformationComponent): 9 | @property 10 | def title(self) -> str: 11 | return "Substitute one species for another" 12 | 13 | @property 14 | def description(self) -> str: 15 | return """Replace one species in your structure (\"Previous Species\") 16 | with another species (\"New Species\"). The new species can be specified as an 17 | element (for example, O), as an element with an oxidation state (for example, O2-) 18 | or as a composition (for example, {"Au":0.5, "Cu":0.5} for a 50/50 mixture of gold 19 | and copper). Please consult the pymatgen documentation for more information. 20 | """ 21 | 22 | @property 23 | def transformation(self): 24 | return SubstitutionTransformation 25 | 26 | def options_layouts(self, state=None, structure=None): 27 | if structure and structure.is_ordered: 28 | species_mapping = {el: el for el in map(str, structure.types_of_specie)} 29 | else: 30 | species_mapping = {} 31 | 32 | state = state or {"species_map": species_mapping} 33 | 34 | species_mapping = self.get_dict_input( 35 | label="Species Mapping", 36 | kwarg_label="species_map", 37 | state=state, 38 | help_str="A mapping from an original species (element or element with oxidation state, e.g. O or O2-) " 39 | "to a new species (element, element with oxidation state, or a composition, e.g. O or O2- or " 40 | '{"Au": 0.5, "Cu": 0.5}). In pymatgen, these are Element, Species and Composition classes ' 41 | "respectively.", 42 | key_name="Original Species", 43 | value_name="New Species", 44 | ) 45 | 46 | return [species_mapping] 47 | 48 | def generate_callbacks(self, app, cache) -> None: 49 | super().generate_callbacks(app, cache) 50 | # 51 | # @app.callback( 52 | # Output(self.id("transformation_args_kwargs"), "data"), 53 | # Input(self.id("species_mapping"), "data"), 54 | # ) 55 | # def update_transformation_kwargs(rows): 56 | # def get_el_occu(string): 57 | # try: 58 | # el_occu = literal_eval(string) 59 | # except ValueError: 60 | # el_occu = string 61 | # return el_occu 62 | # 63 | # species_map = { 64 | # get_el_occu(row["prev"]): get_el_occu(row["new"]) 65 | # for row in rows 66 | # if (row["prev"] and row["new"]) 67 | # } 68 | # 69 | # print(species_map) 70 | # 71 | # return {"args": [species_map], "kwargs": {}} 72 | -------------------------------------------------------------------------------- /crystal_toolkit/components/transformations/supercell.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from dash import html 4 | from dash_mp_components import CrystalToolkitScene 5 | from pymatgen.transformations.standard_transformations import SupercellTransformation 6 | 7 | from crystal_toolkit.components.transformations.core import TransformationComponent 8 | from crystal_toolkit.core.scene import Scene 9 | 10 | 11 | class SupercellTransformationComponent(TransformationComponent): 12 | @property 13 | def title(self) -> str: 14 | return "Make a supercell" 15 | 16 | @property 17 | def description(self) -> str: 18 | return """Create a supercell by providing a scaling matrix that transforms 19 | input lattice vectors a, b and c into transformed lattice vectors a', b' and c'. 20 | 21 | 22 | For example, to create a supercell with lattice vectors a'=2a, b'=2b, c'=2c enter a 23 | scaling matrix [[2, 0, 0], [0, 2, 0], [0, 0, 2]] or to create a supercell with 24 | lattice vectors a' = 2a+b, b' = 3b and c' = c enter a scaling matrix 25 | [[2, 1, 0], [0, 3, 0], [0, 0, 1]]. All elements of the scaling matrix must be 26 | integers.""" 27 | 28 | @property 29 | def transformation(self): 30 | return SupercellTransformation 31 | 32 | def options_layouts(self, state=None, structure=None): 33 | state = state or {"scaling_matrix": ((1, 0, 0), (0, 1, 0), (0, 0, 1))} 34 | 35 | return self.get_numerical_input( 36 | label="Scaling matrix", 37 | kwarg_label="scaling_matrix", 38 | state=state, 39 | help_str="""Scaling matrix that transforms 40 | input lattice vectors a, b and c into transformed lattice vectors a', b' and c'.""", 41 | shape=(3, 3), 42 | ) 43 | 44 | def get_preview_layout(self, struct_in, struct_out): 45 | if struct_in.lattice == struct_out.lattice: 46 | return html.Div() 47 | 48 | lattice_in = struct_in.lattice.get_scene() 49 | lattice_out = struct_out.lattice.get_scene(color="red") 50 | 51 | scene = Scene("lattices", contents=[lattice_in, lattice_out]) 52 | 53 | return html.Div( 54 | [CrystalToolkitScene(data=scene.to_json())], 55 | style={"width": "100px", "height": "100px"}, 56 | ) 57 | -------------------------------------------------------------------------------- /crystal_toolkit/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/core/__init__.py -------------------------------------------------------------------------------- /crystal_toolkit/core/panelcomponent.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from dash import html 4 | from dash.dependencies import Input, Output, State 5 | from dash.exceptions import PreventUpdate 6 | 7 | from crystal_toolkit.core.mpcomponent import MPComponent 8 | from crystal_toolkit.helpers.layouts import Reveal 9 | 10 | 11 | class PanelComponent(MPComponent): 12 | """A component intended to do wrap another component or set of components inside a panel. The 13 | key benefit is that the inner contents of the panel are not loaded until the panel is opened, so 14 | can reduce the number of callbacks run until a user initiates interaction. 15 | 16 | To use, implement the "contents_layout" method, and add any new callbacks necessary to fill it. 17 | """ 18 | 19 | @property 20 | def title(self) -> str: 21 | return "Untitled Panel" 22 | 23 | @property 24 | def description(self) -> str | None: 25 | return None 26 | 27 | def panel_layout(self, open_by_default=False): 28 | message = html.Div(id=self.id("message")) 29 | 30 | description = html.Div( 31 | self.description, 32 | id=self.id("description"), 33 | className="mpc-panel-description", 34 | ) 35 | 36 | initial_contents = html.Div(id=self.id("contents")) 37 | 38 | return Reveal( 39 | title=self.title, 40 | children=[message, description, html.Br(), initial_contents], 41 | id=self.id("panel"), 42 | summary_id=self.id("panel_summary"), 43 | open=open_by_default, 44 | ) 45 | 46 | def contents_layout(self) -> html.Div: 47 | raise NotImplementedError 48 | 49 | def generate_callbacks(self, app, cache) -> None: 50 | @app.callback( 51 | Output(self.id("contents"), "children"), 52 | Input(self.id("panel_summary"), "n_clicks"), 53 | State(self.id("contents"), "children"), 54 | ) 55 | def load_panel(panel_n_clicks, current_contents): 56 | if current_contents or panel_n_clicks is None: 57 | raise PreventUpdate 58 | 59 | return html.Div(self.contents_layout(), id=self.id("inner_contents")) 60 | -------------------------------------------------------------------------------- /crystal_toolkit/defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "scene": { 3 | "cylinders": { 4 | "color": "#000000", 5 | "radius": 0.15, 6 | "light": true, 7 | "opacity": 1.0 8 | }, 9 | "lines": { 10 | "color": "#000000", 11 | "linewidth": 3.0, 12 | "opacity": 1.0 13 | }, 14 | "surface": { 15 | "color": "#6495ed", 16 | "edge_width": 0.2, 17 | "light": true, 18 | "opacity": 0.5 19 | }, 20 | "spheres": { 21 | "color": "#000000", 22 | "radius": 0.5, 23 | "light": true, 24 | "opacity": 1.0 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crystal_toolkit/defaults.py: -------------------------------------------------------------------------------- 1 | """Populate the default values from the JSON file.""" 2 | 3 | from __future__ import annotations 4 | 5 | import json 6 | import os as _os 7 | from collections import defaultdict 8 | from typing import Any 9 | 10 | _DEFAULTS: dict[str, Any] = defaultdict() 11 | default_js = _os.path.join( 12 | _os.path.join(_os.path.dirname(_os.path.abspath(__file__))), "./", "defaults.json" 13 | ) 14 | 15 | with open(default_js) as handle: 16 | _DEFAULTS.update(json.loads(handle.read())) 17 | -------------------------------------------------------------------------------- /crystal_toolkit/helpers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/helpers/__init__.py -------------------------------------------------------------------------------- /crystal_toolkit/helpers/pretty_labels.py: -------------------------------------------------------------------------------- 1 | # strip latex math wrapping for labels 2 | # (since MathJax isn't yet supported in hover labels, see https://github.com/plotly/plotly.js/issues/559) 3 | # TODO: add this to string utils in pymatgen 4 | from __future__ import annotations 5 | 6 | pretty_labels = { 7 | "$": "", 8 | "\\mid": "|", 9 | "\\Gamma": "Γ", 10 | "\\Sigma": "Σ", 11 | "GAMMA": "Γ", 12 | "_1": "₁", 13 | "_2": "₂", 14 | "_3": "₃", 15 | "_4": "₄", 16 | "_{1}": "₁", 17 | "_{2}": "₂", 18 | "_{3}": "₃", 19 | "_{4}": "₄", 20 | "^{*}": "*", 21 | } 22 | -------------------------------------------------------------------------------- /crystal_toolkit/renderables/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from crystal_toolkit.renderables.lattice import Lattice 4 | from crystal_toolkit.renderables.molecule import Molecule 5 | from crystal_toolkit.renderables.moleculegraph import MoleculeGraph 6 | from crystal_toolkit.renderables.phasediagram import PhaseDiagram 7 | from crystal_toolkit.renderables.site import Site 8 | from crystal_toolkit.renderables.structure import Structure 9 | from crystal_toolkit.renderables.structuregraph import StructureGraph 10 | from crystal_toolkit.renderables.volumetric import VolumetricData 11 | -------------------------------------------------------------------------------- /crystal_toolkit/renderables/molecule.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from collections import defaultdict 4 | 5 | from pymatgen.core import Molecule 6 | 7 | from crystal_toolkit.core.legend import Legend 8 | from crystal_toolkit.core.scene import Scene 9 | 10 | 11 | def get_scene_from_molecule(self, origin=None, legend: Legend | None = None): 12 | """Create CTK objects for the lattice and sties 13 | Args: 14 | self: Structure object 15 | origin: x,y,z fractional coordinates of the origin 16 | legend: Legend for the sites. 17 | 18 | Returns: 19 | CTK scene object to be rendered 20 | """ 21 | origin = origin if origin else (0, 0, 0) 22 | 23 | legend = legend or Legend(self) 24 | 25 | primitives: dict[str, list] = defaultdict(list) 26 | 27 | for site in self: 28 | site_scene = site.get_scene(origin=origin, legend=legend) 29 | 30 | for scene in site_scene.contents: 31 | primitives[scene.name] += scene.contents 32 | 33 | return Scene( 34 | name=self.composition.reduced_formula, 35 | contents=[Scene(name=key, contents=val) for key, val in primitives.items()], 36 | origin=origin, 37 | ) 38 | 39 | 40 | Molecule.get_scene = get_scene_from_molecule 41 | -------------------------------------------------------------------------------- /crystal_toolkit/renderables/moleculegraph.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from collections import defaultdict 4 | 5 | from pymatgen.analysis.graphs import MoleculeGraph 6 | from pymatgen.analysis.local_env import OpenBabelNN 7 | 8 | from crystal_toolkit.core.legend import Legend 9 | from crystal_toolkit.core.scene import Scene 10 | 11 | # TODO: fix Sam's bug (reorder) 12 | 13 | 14 | def get_molecule_graph_scene( 15 | self, 16 | origin=None, 17 | explicitly_calculate_polyhedra_hull=False, 18 | legend=None, 19 | draw_polyhedra=False, 20 | show_atom_idx=True, 21 | show_atom_coord=True, 22 | show_bond_order=True, 23 | show_bond_length=False, 24 | visualize_bond_orders=False, 25 | ) -> Scene: 26 | """Create a Molecule Graph scene. 27 | 28 | Args: 29 | show_atom_idx: Defaults to True, shows the site index of each atom in the molecule 30 | show_atom_coord: Defaults to True, shows the 3D coordinates of each atom in the molecule 31 | show_bond_order: Defaults to True, shows the calculated bond order in the chosen local 32 | environment strategy 33 | show_bond_length: Defaults to False, shows the calculated length between two connected atoms 34 | visualize_bpnd_orders: Defaults False, will show the 'integral' number of bonds calculated 35 | from the OpenBabelNN strategy in the Molecule Graph 36 | 37 | Returns: 38 | A Molecule Graph scene. 39 | """ 40 | if visualize_bond_orders: 41 | vis_mol_graph = MoleculeGraph.with_local_env_strategy( 42 | self.molecule, OpenBabelNN() 43 | ) 44 | else: 45 | vis_mol_graph = self 46 | legend = legend or Legend(self.molecule) 47 | 48 | primitives: dict[str, list] = defaultdict(list) 49 | 50 | for idx, site in enumerate(self.molecule): 51 | connected_sites = vis_mol_graph.get_connected_sites(idx) 52 | 53 | site_scene = site.get_scene( 54 | site_idx=idx, 55 | connected_sites=connected_sites, 56 | origin=origin, 57 | explicitly_calculate_polyhedra_hull=explicitly_calculate_polyhedra_hull, 58 | legend=legend, 59 | show_atom_idx=show_atom_idx, 60 | show_atom_coord=show_atom_coord, 61 | show_bond_order=show_bond_order, 62 | show_bond_length=show_bond_length, 63 | visualize_bond_orders=visualize_bond_orders, 64 | draw_polyhedra=draw_polyhedra, 65 | ) 66 | for scene in site_scene.contents: 67 | primitives[scene.name] += scene.contents 68 | 69 | return Scene( 70 | name=self.molecule.composition.reduced_formula, 71 | contents=[Scene(name=key, contents=val) for key, val in primitives.items()], 72 | origin=origin if origin else (0, 0, 0), 73 | ) 74 | 75 | 76 | MoleculeGraph.get_scene = get_molecule_graph_scene 77 | -------------------------------------------------------------------------------- /crystal_toolkit/renderables/phasediagram.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from pymatgen.analysis.phase_diagram import PDPlotter, PhaseDiagram 4 | 5 | 6 | def get_plot( 7 | self, 8 | show_unstable=0.2, 9 | label_stable=True, 10 | label_unstable=True, 11 | ordering=None, 12 | energy_colormap=None, 13 | process_attributes=False, 14 | label_uncertainties=False, 15 | ): 16 | """Plot a PhaseDiagram. 17 | 18 | :param show_unstable: Whether unstable (above the hull) phases will be 19 | plotted. If a number > 0 is entered, all phases with 20 | e_hull < show_unstable (eV/atom) will be shown. 21 | :param label_stable: Whether to label stable compounds. 22 | :param label_unstable: Whether to label unstable compounds. 23 | :param ordering: Ordering of vertices (matplotlib backend only). 24 | :param energy_colormap: Colormap for coloring energy (matplotlib backend only). 25 | :param process_attributes: Whether to process the attributes (matplotlib 26 | backend only). 27 | :param plt: Existing plt object if plotting multiple phase diagrams ( 28 | matplotlib backend only). 29 | :param label_uncertainties: Whether to add error bars to the hull (plotly 30 | backend only). For binaries, this also shades the hull with the 31 | uncertainty window 32 | """ 33 | plotter = PDPlotter(self, backend="plotly", show_unstable=show_unstable) 34 | 35 | return plotter.get_plot( 36 | label_stable=label_stable, 37 | label_unstable=label_unstable, 38 | ordering=ordering, 39 | energy_colormap=energy_colormap, 40 | process_attributes=process_attributes, 41 | label_uncertainties=label_uncertainties, 42 | ) 43 | 44 | 45 | PhaseDiagram.get_plot = get_plot 46 | -------------------------------------------------------------------------------- /crystal_toolkit/renderables/trajectory.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/crystal_toolkit/renderables/trajectory.py -------------------------------------------------------------------------------- /docs/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: 7fb58f2e59309da3d5bf0e68e0b06635 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/.nojekyll -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | docs.crystaltoolkit.org 2 | -------------------------------------------------------------------------------- /docs/_images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_images/logo.png -------------------------------------------------------------------------------- /docs/_images/structuremoleculecomponent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_images/structuremoleculecomponent.png -------------------------------------------------------------------------------- /docs/_images/structuremoleculecomponent_callbacks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_images/structuremoleculecomponent_callbacks.png -------------------------------------------------------------------------------- /docs/_sources/components.rst.txt: -------------------------------------------------------------------------------- 1 | ================= 2 | Component Library 3 | ================= 4 | 5 | .. toctree:: 6 | :hidden: 7 | 8 | components/structuremoleculecomponent 9 | components/dash_components 10 | -------------------------------------------------------------------------------- /docs/_sources/components/dash_components.rst.txt: -------------------------------------------------------------------------------- 1 | Dash Components 2 | --------------- 3 | 4 | Several custom Dash components are distributed with Crystal Toolkit to enable 5 | the functionality of Crystal Toolkit apps. 6 | 7 | These can be used and imported as any other Plotly Dash component. 8 | 9 | Simple3DScene 10 | ~~~~~~~~~~~~~ 11 | 12 | The intent of this component is to provide easy three-dimensional rendering of 13 | "scenes" containing geometric primitives, such as cylinders or spheres. 14 | 15 | Above all, this component is designed for *simple* use. It is not designed to 16 | compete with full scene graph implementations such as VTK or Three.js. If you 17 | want advanced usage, you should use these very powerful and well-documented 18 | libraries directly. Simple3DScene does use Three.js behind the scenes to power 19 | its functionality. 20 | 21 | Link to documentation for creating ``Scene`` objects inside Python. 22 | 23 | Link to ``Simple3DScene`` Dash component to render resulting ``Scene`` object. 24 | -------------------------------------------------------------------------------- /docs/_sources/components/structuremoleculecomponent.rst.txt: -------------------------------------------------------------------------------- 1 | Structures and Molecules 2 | ------------------------ 3 | 4 | This component can render the ``pymatgen`` objects ``Structure``, 5 | ``Molecule``, ``StructureGraph`` and ``MoleculeGraph``. See its 6 | documentation `here. <../source/crystal_toolkit.components.structure>`_ 7 | 8 | Screenshot 9 | ~~~~~~~~~~ 10 | 11 | .. image:: ../images/structuremoleculecomponent.png 12 | :align: center 13 | :alt: Example of StructureMoleculeComponent 14 | 15 | Example Usage 16 | ~~~~~~~~~~~~~ 17 | 18 | .. literalinclude:: ../../crystal_toolkit/apps/examples/structure.py 19 | 20 | Callback Graph 21 | ~~~~~~~~~~~~~~ 22 | 23 | .. image:: ../images/structuremoleculecomponent_callbacks.png 24 | :align: center 25 | :alt: Example of StructureMoleculeComponent 26 | -------------------------------------------------------------------------------- /docs/_sources/first_component.rst.txt: -------------------------------------------------------------------------------- 1 | ==================== 2 | Your First Component 3 | ==================== 4 | 5 | This page is intended for **developers of Crystal Toolkit** who want to add 6 | a new ``MPComponent`` to support interactive viewing of an ``MSONable`` object, 7 | such as crystal structures, phase diagrams, etc. 8 | 9 | .. Important:: 10 | Crystal Toolkit is built on top of `Dash by Plotly `_. 11 | Dash is a framework to build rich, interactive web apps purely from Python with 12 | no JavaScript knowledge required. 13 | If you're not familiar with the Dash framework, please read their documentation 14 | and try their example app first. 15 | 16 | The basic steps are to: 17 | 18 | 1. Sub-class `MPComponent `_. Recognize 19 | that the component comes with a ``dcc.Store`` which contains the ``MSON`` 20 | representation of whatever the component is intended to render. 21 | 22 | 2. Implement its master ``layout()`` method to return the "default" layout 23 | for your component. You may also add additional ``..._layout()`` 24 | methods for optional layouts; for example, the ``StructureMoleculeComponent`` 25 | has ``legend_layout()`` to return the legend for the structure or molecule 26 | being displayed. 27 | 28 | The ``_sub_layouts`` method, which returns a dictionary with values corresponding 29 | to different parts of your component, is available for book-keeping if your 30 | component is complex. 31 | 32 | 4. For interactivity, implement the ``generate_callbacks(app, cache)`` method. 33 | Inside this method you can define callbacks to be associated with the component. 34 | *At minimum,* make sure that if the component's main ``dcc.Store`` is updated 35 | with a new object (for example, a new crystal structure is set for 36 | ``StructureMoleculeComponent``) that the state of the component is also updated 37 | appropriately. 38 | 39 | Try to keep the total number of callbacks to a minimum, and 40 | the size of the data stores small wherever possible, to improve performance of 41 | your component. Using multiple-output callbacks, and judicious use of 42 | ``raise PreventUpdate`` and ``return no_update`` can help with this, especially 43 | if checking for the initial callback firing on page load. 44 | 45 | If you have a long-running callback, or one that *may* be long-running, make 46 | sure to wrap it in a ``dcc.Loading`` component to improve the user experience. 47 | 48 | At this point, the component should be working. It needs a simple **example app** 49 | to be added to ``crystal_toolkit.apps.examples`` and a corresponding **test** that 50 | the example app runs, and finally a short documentation page in ``docs_rst``. Please 51 | copy from the existing examples as necessary. 52 | -------------------------------------------------------------------------------- /docs/_sources/helpers.rst.txt: -------------------------------------------------------------------------------- 1 | ======= 2 | Helpers 3 | ======= 4 | 5 | The ``helpers`` submodule in Crystal Toolkit contains a few utilities 6 | that are useful for making your app. 7 | 8 | Inputs 9 | ------ 10 | 11 | The `inputs `_ submodule contains various 12 | controls for inputting floating point numbers, matrices, boolean values, etc. with labels 13 | attached. 14 | 15 | Layouts 16 | ------- 17 | 18 | The Crystal Toolkit app makes heavy use of the 19 | `Bulma CSS Framework `_ for styling. The 20 | `layouts `_ submodule contains 21 | a few wrappers for ``html.Div`` with these styles pre-applied, such as 22 | ``Columns``, ``Box``, ``Footer``, etc. 23 | 24 | Renderers 25 | --------- 26 | 27 | Three-dimensional scenes created using the 28 | `Scene `_ class can be rendered 29 | by the ``Simple3DScene`` Dash component, but also other tools including 30 | pythreejs (for Jupypter integration), POV-Ray (for high-quality rendering) and 31 | asymptote (for LaTeX integration). 32 | -------------------------------------------------------------------------------- /docs/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. toctree:: 2 | :hidden: 3 | 4 | introduction 5 | Try The App! 6 | first_web_app 7 | first_component 8 | components 9 | mp_app 10 | helpers 11 | jupyter 12 | API Docs 13 | 14 | .. include:: introduction.rst 15 | -------------------------------------------------------------------------------- /docs/_sources/jupyter.rst.txt: -------------------------------------------------------------------------------- 1 | =================== 2 | Jupyter Integration 3 | =================== 4 | 5 | Crystal Toolkit offers integration with JupyterLab to 6 | allow easy viewing of crystal structures and other Materials Project 7 | data interactively. 8 | 9 | Installation 10 | ------------ 11 | 12 | There are two steps to using Crystal Toolkit inside Jupyter: 13 | 14 | 1. Make sure Jupyter Lab is installed and run using ``jupyter lab``, version 3.x. 15 | Crystal Toolkit is not supported in the older Jupyter notebooks or older versions 16 | of Jupyter Lab. 17 | 18 | 2. Ensure Crystal Toolkit is installed as normal, ``pip install crystal-toolkit --upgrade`` 19 | 20 | 3. Restart Jupyter Lab completely. You be asked to perform a "build," click OK and it's normal 21 | for this to take a minute. After this it's ready to use! 22 | 23 | The extension may still work on Jupyter Lab 2.x by additionally running: 24 | 25 | ``jupyter labextension install crystaltoolkit-extension`` 26 | 27 | However 2.x is no longer supported, and this command does not need to be run with Jupyter Lab 3.x 28 | 29 | Usage 30 | ----- 31 | 32 | To use, simply ``import crystal_toolkit`` and use ``pymatgen`` as normal for crystal structures 33 | to be shown using Crystal Toolkit. 34 | -------------------------------------------------------------------------------- /docs/_sources/mp_app.rst.txt: -------------------------------------------------------------------------------- 1 | ======================= 2 | A Materials Project App 3 | ======================= 4 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.bandstructure.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.bandstructure module 2 | ================================================ 3 | 4 | .. automodule:: crystal_toolkit.components.bandstructure 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.diffraction.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.diffraction module 2 | ============================================== 3 | 4 | .. automodule:: crystal_toolkit.components.diffraction 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.localenv.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.localenv module 2 | =========================================== 3 | 4 | .. automodule:: crystal_toolkit.components.localenv 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.phase_diagram.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.phase\_diagram module 2 | ================================================= 3 | 4 | .. automodule:: crystal_toolkit.components.phase_diagram 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.pourbaix.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.pourbaix module 2 | =========================================== 3 | 4 | .. automodule:: crystal_toolkit.components.pourbaix 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.robocrys.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.robocrys module 2 | =========================================== 3 | 4 | .. automodule:: crystal_toolkit.components.robocrys 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components package 2 | =================================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | crystal_toolkit.components.transformations 11 | 12 | Submodules 13 | ---------- 14 | 15 | .. toctree:: 16 | :maxdepth: 4 17 | 18 | crystal_toolkit.components.bandstructure 19 | crystal_toolkit.components.diffraction 20 | crystal_toolkit.components.localenv 21 | crystal_toolkit.components.phase_diagram 22 | crystal_toolkit.components.pourbaix 23 | crystal_toolkit.components.robocrys 24 | crystal_toolkit.components.search 25 | crystal_toolkit.components.structure 26 | crystal_toolkit.components.submit_snl 27 | crystal_toolkit.components.symmetry 28 | crystal_toolkit.components.upload 29 | crystal_toolkit.components.xas 30 | 31 | Module contents 32 | --------------- 33 | 34 | .. automodule:: crystal_toolkit.components 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.search.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.search module 2 | ========================================= 3 | 4 | .. automodule:: crystal_toolkit.components.search 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.structure.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.structure module 2 | ============================================ 3 | 4 | .. automodule:: crystal_toolkit.components.structure 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.submit_snl.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.submit\_snl module 2 | ============================================== 3 | 4 | .. automodule:: crystal_toolkit.components.submit_snl 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.symmetry.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.symmetry module 2 | =========================================== 3 | 4 | .. automodule:: crystal_toolkit.components.symmetry 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.transformations.autooxistatedecoration.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.transformations.autooxistatedecoration module 2 | ========================================================================= 3 | 4 | .. automodule:: crystal_toolkit.components.transformations.autooxistatedecoration 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.transformations.core.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.transformations.core module 2 | ======================================================= 3 | 4 | .. automodule:: crystal_toolkit.components.transformations.core 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.transformations.cubic.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.transformations.cubic module 2 | ======================================================== 3 | 4 | .. automodule:: crystal_toolkit.components.transformations.cubic 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.transformations.grainboundary.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.transformations.grainboundary module 2 | ================================================================ 3 | 4 | .. automodule:: crystal_toolkit.components.transformations.grainboundary 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.transformations.rattle.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.transformations.rattle module 2 | ========================================================= 3 | 4 | .. automodule:: crystal_toolkit.components.transformations.rattle 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.transformations.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.transformations package 2 | =================================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | crystal_toolkit.components.transformations.autooxistatedecoration 11 | crystal_toolkit.components.transformations.core 12 | crystal_toolkit.components.transformations.cubic 13 | crystal_toolkit.components.transformations.grainboundary 14 | crystal_toolkit.components.transformations.rattle 15 | crystal_toolkit.components.transformations.slab 16 | crystal_toolkit.components.transformations.substitution 17 | crystal_toolkit.components.transformations.supercell 18 | 19 | Module contents 20 | --------------- 21 | 22 | .. automodule:: crystal_toolkit.components.transformations 23 | :members: 24 | :undoc-members: 25 | :show-inheritance: 26 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.transformations.slab.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.transformations.slab module 2 | ======================================================= 3 | 4 | .. automodule:: crystal_toolkit.components.transformations.slab 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.transformations.substitution.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.transformations.substitution module 2 | =============================================================== 3 | 4 | .. automodule:: crystal_toolkit.components.transformations.substitution 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.transformations.supercell.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.transformations.supercell module 2 | ============================================================ 3 | 4 | .. automodule:: crystal_toolkit.components.transformations.supercell 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.upload.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.upload module 2 | ========================================= 3 | 4 | .. automodule:: crystal_toolkit.components.upload 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.components.xas.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.components.xas module 2 | ====================================== 3 | 4 | .. automodule:: crystal_toolkit.components.xas 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.core.legend.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.core.legend module 2 | =================================== 3 | 4 | .. automodule:: crystal_toolkit.core.legend 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.core.mpcomponent.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.core.mpcomponent module 2 | ======================================== 3 | 4 | .. automodule:: crystal_toolkit.core.mpcomponent 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.core.panelcomponent.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.core.panelcomponent module 2 | =========================================== 3 | 4 | .. automodule:: crystal_toolkit.core.panelcomponent 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.core.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.core package 2 | ============================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | crystal_toolkit.core.tests 11 | 12 | Submodules 13 | ---------- 14 | 15 | .. toctree:: 16 | :maxdepth: 4 17 | 18 | crystal_toolkit.core.legend 19 | crystal_toolkit.core.mpcomponent 20 | crystal_toolkit.core.panelcomponent 21 | crystal_toolkit.core.scene 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: crystal_toolkit.core 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.core.scene.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.core.scene module 2 | ================================== 3 | 4 | .. automodule:: crystal_toolkit.core.scene 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.core.tests.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.core.tests package 2 | =================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | crystal_toolkit.core.tests.test_legend 11 | 12 | Module contents 13 | --------------- 14 | 15 | .. automodule:: crystal_toolkit.core.tests 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.core.tests.test_legend.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.core.tests.test\_legend module 2 | =============================================== 3 | 4 | .. automodule:: crystal_toolkit.core.tests.test_legend 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.helpers.asymptote_renderer.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.helpers.asymptote\_renderer module 2 | =================================================== 3 | 4 | .. automodule:: crystal_toolkit.helpers.asymptote_renderer 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.helpers.layouts.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.helpers.layouts module 2 | ======================================= 3 | 4 | .. automodule:: crystal_toolkit.helpers.layouts 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.helpers.povray_renderer.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.helpers.povray\_renderer module 2 | ================================================ 3 | 4 | .. automodule:: crystal_toolkit.helpers.povray_renderer 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.helpers.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.helpers package 2 | ================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | crystal_toolkit.helpers.asymptote_renderer 11 | crystal_toolkit.helpers.layouts 12 | crystal_toolkit.helpers.povray_renderer 13 | crystal_toolkit.helpers.utils 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: crystal_toolkit.helpers 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.helpers.utils.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.helpers.utils module 2 | ===================================== 3 | 4 | .. automodule:: crystal_toolkit.helpers.utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.renderables.lattice.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.renderables.lattice module 2 | =========================================== 3 | 4 | .. automodule:: crystal_toolkit.renderables.lattice 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.renderables.molecule.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.renderables.molecule module 2 | ============================================ 3 | 4 | .. automodule:: crystal_toolkit.renderables.molecule 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.renderables.moleculegraph.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.renderables.moleculegraph module 2 | ================================================= 3 | 4 | .. automodule:: crystal_toolkit.renderables.moleculegraph 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.renderables.phasediagram.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.renderables.phasediagram module 2 | ================================================ 3 | 4 | .. automodule:: crystal_toolkit.renderables.phasediagram 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.renderables.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.renderables package 2 | ==================================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | crystal_toolkit.renderables.lattice 11 | crystal_toolkit.renderables.molecule 12 | crystal_toolkit.renderables.moleculegraph 13 | crystal_toolkit.renderables.phasediagram 14 | crystal_toolkit.renderables.site 15 | crystal_toolkit.renderables.structure 16 | crystal_toolkit.renderables.structuregraph 17 | crystal_toolkit.renderables.trajectory 18 | crystal_toolkit.renderables.volumetric 19 | 20 | Module contents 21 | --------------- 22 | 23 | .. automodule:: crystal_toolkit.renderables 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.renderables.site.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.renderables.site module 2 | ======================================== 3 | 4 | .. automodule:: crystal_toolkit.renderables.site 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.renderables.structure.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.renderables.structure module 2 | ============================================= 3 | 4 | .. automodule:: crystal_toolkit.renderables.structure 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.renderables.structuregraph.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.renderables.structuregraph module 2 | ================================================== 3 | 4 | .. automodule:: crystal_toolkit.renderables.structuregraph 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.renderables.trajectory.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.renderables.trajectory module 2 | ============================================== 3 | 4 | .. automodule:: crystal_toolkit.renderables.trajectory 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.renderables.volumetric.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.renderables.volumetric module 2 | ============================================== 3 | 4 | .. automodule:: crystal_toolkit.renderables.volumetric 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit package 2 | ======================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | crystal_toolkit.components 11 | crystal_toolkit.core 12 | crystal_toolkit.helpers 13 | crystal_toolkit.renderables 14 | 15 | Submodules 16 | ---------- 17 | 18 | .. toctree:: 19 | :maxdepth: 4 20 | 21 | crystal_toolkit.settings 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: crystal_toolkit 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/_sources/source/crystal_toolkit.settings.rst.txt: -------------------------------------------------------------------------------- 1 | crystal\_toolkit.settings module 2 | ================================ 3 | 4 | .. automodule:: crystal_toolkit.settings 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/_sources/source/modules.rst.txt: -------------------------------------------------------------------------------- 1 | crystal_toolkit 2 | =============== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | crystal_toolkit 8 | -------------------------------------------------------------------------------- /docs/_sources/troubleshooting.rst.txt: -------------------------------------------------------------------------------- 1 | =============== 2 | Troubleshooting 3 | =============== 4 | 5 | This page is intended to help developers of Crystal Toolkit. 6 | -------------------------------------------------------------------------------- /docs/_static/css/fonts/Roboto-Slab-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/Roboto-Slab-Bold.woff -------------------------------------------------------------------------------- /docs/_static/css/fonts/Roboto-Slab-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/Roboto-Slab-Bold.woff2 -------------------------------------------------------------------------------- /docs/_static/css/fonts/Roboto-Slab-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/Roboto-Slab-Regular.woff -------------------------------------------------------------------------------- /docs/_static/css/fonts/Roboto-Slab-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/Roboto-Slab-Regular.woff2 -------------------------------------------------------------------------------- /docs/_static/css/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/_static/css/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/_static/css/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/_static/css/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /docs/_static/css/fonts/lato-bold-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/lato-bold-italic.woff -------------------------------------------------------------------------------- /docs/_static/css/fonts/lato-bold-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/lato-bold-italic.woff2 -------------------------------------------------------------------------------- /docs/_static/css/fonts/lato-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/lato-bold.woff -------------------------------------------------------------------------------- /docs/_static/css/fonts/lato-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/lato-bold.woff2 -------------------------------------------------------------------------------- /docs/_static/css/fonts/lato-normal-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/lato-normal-italic.woff -------------------------------------------------------------------------------- /docs/_static/css/fonts/lato-normal-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/lato-normal-italic.woff2 -------------------------------------------------------------------------------- /docs/_static/css/fonts/lato-normal.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/lato-normal.woff -------------------------------------------------------------------------------- /docs/_static/css/fonts/lato-normal.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/css/fonts/lato-normal.woff2 -------------------------------------------------------------------------------- /docs/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | var DOCUMENTATION_OPTIONS = { 2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), 3 | VERSION: '', 4 | LANGUAGE: 'en', 5 | COLLAPSE_INDEX: false, 6 | BUILDER: 'html', 7 | FILE_SUFFIX: '.html', 8 | LINK_SUFFIX: '.html', 9 | HAS_SOURCE: true, 10 | SOURCELINK_SUFFIX: '.txt', 11 | NAVIGATION_WITH_KEYS: false, 12 | SHOW_SEARCH_SUMMARY: true, 13 | ENABLE_SEARCH_SHORTCUTS: true, 14 | }; -------------------------------------------------------------------------------- /docs/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/file.png -------------------------------------------------------------------------------- /docs/_static/js/badge_only.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}}); -------------------------------------------------------------------------------- /docs/_static/js/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); -------------------------------------------------------------------------------- /docs/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/minus.png -------------------------------------------------------------------------------- /docs/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/_static/plus.png -------------------------------------------------------------------------------- /docs/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs/objects.inv -------------------------------------------------------------------------------- /docs_rst/CNAME: -------------------------------------------------------------------------------- 1 | docs.crystaltoolkit.org 2 | -------------------------------------------------------------------------------- /docs_rst/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = . 8 | BUILDDIR = _build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @rm -rf ../docs/ 20 | @rm -rf source/ 21 | @sphinx-apidoc -e -f -o source/ ../crystal_toolkit ../crystal_toolkit/apps 22 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 23 | @cp -r "$(BUILDDIR)/html/." ../docs/ 24 | @cp CNAME ../docs/ 25 | -------------------------------------------------------------------------------- /docs_rst/_static/css/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs_rst/_static/css/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs_rst/_static/css/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs_rst/_static/css/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs_rst/_static/css/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs_rst/_static/css/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs_rst/_static/css/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs_rst/_static/css/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /docs_rst/_static/js/badge_only.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}}); -------------------------------------------------------------------------------- /docs_rst/_static/js/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); -------------------------------------------------------------------------------- /docs_rst/components.rst: -------------------------------------------------------------------------------- 1 | ================= 2 | Component Library 3 | ================= 4 | 5 | .. toctree:: 6 | :hidden: 7 | 8 | components/bulma_layouts 9 | components/structuremoleculecomponent 10 | components/dash_components 11 | -------------------------------------------------------------------------------- /docs_rst/components/bulma_layouts.rst: -------------------------------------------------------------------------------- 1 | Bulma Layouts 2 | ------------- 3 | 4 | `Bulma `_ is a popular CSS-only web framework which can make it easier to build responsive web interfaces. 5 | This is an alternative to other frameworks, such as Bootstrap, which require additional JavaScript to be loaded. 6 | 7 | Crystal Toolkit provides wrappers around the in-built Dash HTML components with Bulma CSS styles pre-applied. 8 | 9 | To use:: 10 | 11 | from crystal_toolkit import ctl 12 | 13 | # a simple two-column layout 14 | my_layout = ctl.Columns([ 15 | ctl.Column([]), 16 | ctl.Column([]) 17 | ]) 18 | 19 | Most Bulma styles are supported and fully type-hinted in Python. It is recommended to keep the Bulma docs open when 20 | using these components to make it easier to understand how to achieve specific layouts! 21 | -------------------------------------------------------------------------------- /docs_rst/components/dash_components.rst: -------------------------------------------------------------------------------- 1 | Dash Components 2 | --------------- 3 | 4 | Several custom Dash components are distributed with Crystal Toolkit to enable 5 | the functionality of Crystal Toolkit apps. 6 | 7 | These can be used and imported as any other Plotly Dash component. 8 | 9 | Simple3DScene 10 | ~~~~~~~~~~~~~ 11 | 12 | The intent of this component is to provide easy three-dimensional rendering of 13 | "scenes" containing geometric primitives, such as cylinders or spheres. 14 | 15 | Above all, this component is designed for *simple* use. It is not designed to 16 | compete with full scene graph implementations such as VTK or Three.js. If you 17 | want advanced usage, you should use these very powerful and well-documented 18 | libraries directly. Simple3DScene does use Three.js behind the scenes to power 19 | its functionality. 20 | 21 | Link to documentation for creating ``Scene`` objects inside Python. 22 | 23 | Link to ``Simple3DScene`` Dash component to render resulting ``Scene`` object. 24 | -------------------------------------------------------------------------------- /docs_rst/components/structuremoleculecomponent.rst: -------------------------------------------------------------------------------- 1 | Structures and Molecules 2 | ------------------------ 3 | 4 | This component can render the ``pymatgen`` objects ``Structure``, 5 | ``Molecule``, ``StructureGraph`` and ``MoleculeGraph``. See its 6 | documentation `here. <../source/crystal_toolkit.components.structure>`_ 7 | 8 | Screenshot 9 | ~~~~~~~~~~ 10 | 11 | .. image:: ../images/structuremoleculecomponent.png 12 | :align: center 13 | :alt: Example of StructureMoleculeComponent 14 | 15 | Example Usage 16 | ~~~~~~~~~~~~~ 17 | 18 | .. literalinclude:: ../../crystal_toolkit/apps/examples/structure.py 19 | 20 | Callback Graph 21 | ~~~~~~~~~~~~~~ 22 | 23 | .. image:: ../images/structuremoleculecomponent_callbacks.png 24 | :align: center 25 | :alt: Example of StructureMoleculeComponent 26 | -------------------------------------------------------------------------------- /docs_rst/first_component.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Your First Component 3 | ==================== 4 | 5 | This page is intended for **developers of Crystal Toolkit** who want to add 6 | a new ``MPComponent`` to support interactive viewing of an ``MSONable`` object, 7 | such as crystal structures, phase diagrams, etc. 8 | 9 | .. Important:: 10 | Crystal Toolkit is built on top of `Dash by Plotly `_. 11 | Dash is a framework to build rich, interactive web apps purely from Python with 12 | no JavaScript knowledge required. 13 | If you're not familiar with the Dash framework, please read their documentation 14 | and try their example app first. 15 | 16 | The basic steps are to: 17 | 18 | 1. Sub-class `MPComponent `_. Recognize 19 | that the component comes with a ``dcc.Store`` which contains the ``MSON`` 20 | representation of whatever the component is intended to render. 21 | 22 | 2. Implement its master ``layout()`` method to return the "default" layout 23 | for your component. You may also add additional ``..._layout()`` 24 | methods for optional layouts; for example, the ``StructureMoleculeComponent`` 25 | has ``legend_layout()`` to return the legend for the structure or molecule 26 | being displayed. 27 | 28 | The ``_sub_layouts`` method, which returns a dictionary with values corresponding 29 | to different parts of your component, is available for book-keeping if your 30 | component is complex. 31 | 32 | 4. For interactivity, implement the ``generate_callbacks(app, cache)`` method. 33 | Inside this method you can define callbacks to be associated with the component. 34 | *At minimum,* make sure that if the component's main ``dcc.Store`` is updated 35 | with a new object (for example, a new crystal structure is set for 36 | ``StructureMoleculeComponent``) that the state of the component is also updated 37 | appropriately. 38 | 39 | Try to keep the total number of callbacks to a minimum, and 40 | the size of the data stores small wherever possible, to improve performance of 41 | your component. Using multiple-output callbacks, and judicious use of 42 | ``raise PreventUpdate`` and ``return no_update`` can help with this, especially 43 | if checking for the initial callback firing on page load. 44 | 45 | If you have a long-running callback, or one that *may* be long-running, make 46 | sure to wrap it in a ``dcc.Loading`` component to improve the user experience. 47 | 48 | At this point, the component should be working. It needs a simple **example app** 49 | to be added to ``crystal_toolkit.apps.examples`` and a corresponding **test** that 50 | the example app runs, and finally a short documentation page in ``docs_rst``. Please 51 | copy from the existing examples as necessary. 52 | -------------------------------------------------------------------------------- /docs_rst/helpers.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Helpers 3 | ======= 4 | 5 | The ``helpers`` submodule in Crystal Toolkit contains a few utilities 6 | that are useful for making your app. 7 | 8 | Inputs 9 | ------ 10 | 11 | The `inputs `_ submodule contains various 12 | controls for inputting floating point numbers, matrices, boolean values, etc. with labels 13 | attached. 14 | 15 | Layouts 16 | ------- 17 | 18 | The Crystal Toolkit app makes heavy use of the 19 | `Bulma CSS Framework `_ for styling. The 20 | `layouts `_ submodule contains 21 | a few wrappers for ``html.Div`` with these styles pre-applied, such as 22 | ``Columns``, ``Box``, ``Footer``, etc. 23 | 24 | Renderers 25 | --------- 26 | 27 | Three-dimensional scenes created using the 28 | `Scene `_ class can be rendered 29 | by the ``Simple3DScene`` Dash component, but also other tools including 30 | pythreejs (for Jupypter integration), POV-Ray (for high-quality rendering) and 31 | asymptote (for LaTeX integration). 32 | -------------------------------------------------------------------------------- /docs_rst/images/jupyter-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs_rst/images/jupyter-demo.gif -------------------------------------------------------------------------------- /docs_rst/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs_rst/images/logo.png -------------------------------------------------------------------------------- /docs_rst/images/structuremoleculecomponent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs_rst/images/structuremoleculecomponent.png -------------------------------------------------------------------------------- /docs_rst/images/structuremoleculecomponent_callbacks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/docs_rst/images/structuremoleculecomponent_callbacks.png -------------------------------------------------------------------------------- /docs_rst/index.rst: -------------------------------------------------------------------------------- 1 | .. toctree:: 2 | :hidden: 3 | 4 | introduction 5 | Try The App! 6 | first_web_app 7 | first_component 8 | components 9 | mp_app 10 | helpers 11 | jupyter 12 | modernization 13 | API Docs 14 | 15 | .. include:: introduction.rst 16 | -------------------------------------------------------------------------------- /docs_rst/jupyter.rst: -------------------------------------------------------------------------------- 1 | =================== 2 | Jupyter Integration 3 | =================== 4 | 5 | Crystal Toolkit offers integration with Jupyter to 6 | allow easy viewing of crystal structures and other Materials Project 7 | data interactively. 8 | 9 | Usage 10 | ----- 11 | 12 | To use, simply ``import crystal_toolkit`` and use ``pymatgen`` as normal for crystal structures 13 | to be shown using Crystal Toolkit. 14 | 15 | Caveats 16 | ------- 17 | 18 | Crystal Toolkit now uses Dash's in-built `Jupyter integration `_. 19 | Previous versions of Crystal Toolkit used a customer Jupyter extension, but this extension was limited in scope, 20 | difficult to maintain, and restricted usage to specific versions of Jupyter (Jupyter Lab 2+). The new solution 21 | runs a Dash server behind-the-scenes. 22 | 23 | Issues might be encountered when running behind a proxy. To fix, try:: 24 | 25 | from dash import jupyter_dash 26 | 27 | jupyter_dash.infer_jupyter_proxy_config() 28 | 29 | Alternatively, consult the Dash documentation or forums for help. The default port is 8884, but can be modified 30 | by setting the ``CT_JUPYTER_EMBED_PORT`` environment variable. 31 | -------------------------------------------------------------------------------- /docs_rst/modernization.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Modernization 3 | ============= 4 | 5 | Crystal Toolkit has been able to work with both Dash 1.x and Dash 2. However, 6 | several design choices were made before Dash 2 was developed that can now be 7 | replaced with first-party solutions now provided by Dash 2. 8 | 9 | The minimum version required is now Dash 2.11. 10 | 11 | Wherever possible, changes will be made gradually and in a backwards-compatible way. 12 | However, please pay attention to deprecation warnings! 13 | 14 | The overall goal is to defer to first-party solutions wherever possible, with the 15 | hope of making the Crystal Toolkit codebase leaner and simpler. 16 | 17 | Plugin 18 | ------ 19 | 20 | Previously, a `ctc.register_crystal_toolkit()` line was required in every Crystal Toolkit 21 | app. Dash now supports plugins, so the new solution is:: 22 | 23 | from crystal_toolkit import CrystalToolkitPlugin 24 | 25 | my_layout = ... # your initial app layout 26 | 27 | # provide other arguments to Dash constructor as required 28 | dash = Dash(..., plugins=[CrystalToolkitPlugin(layout=my_layout)]) 29 | 30 | Jupyter 31 | ------- 32 | 33 | Previously, Crystal Toolkit supplied its own Jupyter Lab extension. While this is still 34 | installed by default to render ``Scene`` objects, most end users will now use a Dash-based 35 | Jupyter renderer. This will allow for display of Crystal Toolkit components in Jupyter 36 | exactly as in its Dash app counterpart. 37 | 38 | Pagination 39 | ---------- 40 | 41 | Crystal Toolkit as developed before first-party support for multipage apps was developed. As 42 | such, there are some limitations for very large Crystal Toolkit apps, which result in a lot of 43 | ``dcc.Store`` elements being added to a layout. This design choice can now be reconsidered. 44 | This improvement is pending. 45 | 46 | 47 | All-in-One Components and Pattern-Matched Callbacks 48 | --------------------------------------------------- 49 | 50 | Crystal Toolkit as developed before pattern-matched callbacks were available, and before 51 | the "all-in-one" component pattern was established. Many components can now be simplified 52 | to use these features. This improvement is pending. 53 | -------------------------------------------------------------------------------- /docs_rst/troubleshooting.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Troubleshooting 3 | =============== 4 | 5 | This page is intended to help developers of Crystal Toolkit. 6 | -------------------------------------------------------------------------------- /jupyterlab-extension/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | coverage 4 | **/*.d.ts 5 | tests 6 | -------------------------------------------------------------------------------- /jupyterlab-extension/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'eslint:recommended', 4 | 'plugin:@typescript-eslint/eslint-recommended', 5 | 'plugin:@typescript-eslint/recommended', 6 | 'plugin:prettier/recommended' 7 | ], 8 | parser: '@typescript-eslint/parser', 9 | parserOptions: { 10 | project: 'tsconfig.json', 11 | sourceType: 'module' 12 | }, 13 | plugins: ['@typescript-eslint'], 14 | rules: { 15 | '@typescript-eslint/interface-name-prefix': [ 16 | 'error', 17 | { prefixWithI: 'always' } 18 | ], 19 | '@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }], 20 | '@typescript-eslint/no-explicit-any': 'off', 21 | '@typescript-eslint/no-namespace': 'off', 22 | '@typescript-eslint/no-use-before-define': 'off', 23 | '@typescript-eslint/quotes': [ 24 | 'error', 25 | 'single', 26 | { avoidEscape: true, allowTemplateLiterals: false } 27 | ], 28 | curly: ['error', 'all'], 29 | eqeqeq: 'error', 30 | 'prefer-arrow-callback': 'error' 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /jupyterlab-extension/.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: master 6 | pull_request: 7 | branches: '*' 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v3 15 | - name: Install node 16 | uses: actions/setup-node@v3 17 | with: 18 | node-version: '10.x' 19 | - name: Install Python 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: '3.7' 23 | architecture: 'x64' 24 | - name: Install dependencies 25 | run: python -m pip install jupyterlab 26 | - name: Build the extension 27 | run: | 28 | jlpm 29 | jlpm run eslint:check 30 | python -m pip install . 31 | 32 | jupyter labextension list 2>&1 | grep -ie "crystaltoolkit-extension.*OK" 33 | python -m jupyterlab.browser_check 34 | -------------------------------------------------------------------------------- /jupyterlab-extension/.gitignore: -------------------------------------------------------------------------------- 1 | *.bundle.* 2 | lib/ 3 | node_modules/ 4 | *.egg-info/ 5 | .ipynb_checkpoints 6 | *.tsbuildinfo 7 | crystaltoolkit-extension/labextension 8 | 9 | # Created by https://www.gitignore.io/api/python 10 | # Edit at https://www.gitignore.io/?templates=python 11 | 12 | ### Python ### 13 | # Byte-compiled / optimized / DLL files 14 | __pycache__/ 15 | *.py[cod] 16 | *$py.class 17 | 18 | # C extensions 19 | *.so 20 | 21 | # Distribution / packaging 22 | .Python 23 | build/ 24 | develop-eggs/ 25 | dist/ 26 | downloads/ 27 | eggs/ 28 | .eggs/ 29 | lib/ 30 | lib64/ 31 | parts/ 32 | sdist/ 33 | var/ 34 | wheels/ 35 | pip-wheel-metadata/ 36 | share/python-wheels/ 37 | .installed.cfg 38 | *.egg 39 | MANIFEST 40 | 41 | # PyInstaller 42 | # Usually these files are written by a python script from a template 43 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 44 | *.manifest 45 | *.spec 46 | 47 | # Installer logs 48 | pip-log.txt 49 | pip-delete-this-directory.txt 50 | 51 | # Unit test / coverage reports 52 | htmlcov/ 53 | .tox/ 54 | .nox/ 55 | .coverage 56 | .coverage.* 57 | .cache 58 | nosetests.xml 59 | coverage.xml 60 | *.cover 61 | .hypothesis/ 62 | .pytest_cache/ 63 | 64 | # Translations 65 | *.mo 66 | *.pot 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # pyenv 78 | .python-version 79 | 80 | # celery beat schedule file 81 | celerybeat-schedule 82 | 83 | # SageMath parsed files 84 | *.sage.py 85 | 86 | # Spyder project settings 87 | .spyderproject 88 | .spyproject 89 | 90 | # Rope project settings 91 | .ropeproject 92 | 93 | # Mr Developer 94 | .mr.developer.cfg 95 | .project 96 | .pydevproject 97 | 98 | # mkdocs documentation 99 | /site 100 | 101 | # mypy 102 | .mypy_cache/ 103 | .dmypy.json 104 | dmypy.json 105 | 106 | # Pyre type checker 107 | .pyre/ 108 | 109 | # End of https://www.gitignore.io/api/python 110 | 111 | # OSX files 112 | .DS_Store 113 | -------------------------------------------------------------------------------- /jupyterlab-extension/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | **/node_modules 3 | **/lib 4 | **/package.json 5 | -------------------------------------------------------------------------------- /jupyterlab-extension/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /jupyterlab-extension/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Matthew Horton All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /jupyterlab-extension/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.md 3 | include pyproject.toml 4 | include jupyter-config/crystaltoolkit-extension.json 5 | 6 | include package.json 7 | include install.json 8 | include ts*.json 9 | 10 | graft crystaltoolkit-extension/labextension 11 | 12 | # Javascript files 13 | graft src 14 | graft style 15 | prune **/node_modules 16 | prune lib 17 | 18 | # Patterns to exclude from any directory 19 | global-exclude *~ 20 | global-exclude *.pyc 21 | global-exclude *.pyo 22 | global-exclude .git 23 | global-exclude .ipynb_checkpoints 24 | -------------------------------------------------------------------------------- /jupyterlab-extension/README.md: -------------------------------------------------------------------------------- 1 | # crystaltoolkit-extension 2 | 3 | ![Github Actions Status](https://github.com/materialsproject/crystaltoolkit/workflows/release/badge.svg) 4 | 5 | A JupyterLab extension for rendering Crystal Toolkit Scene JSON files. 6 | 7 | ## Requirements 8 | 9 | * JupyterLab >= 3.0 10 | 11 | ## Install 12 | 13 | ```bash 14 | pip install crystaltoolkit-extension 15 | ``` 16 | 17 | ## Contributing 18 | 19 | ### Development install 20 | 21 | Note: You will need NodeJS to build the extension package. 22 | 23 | The `jlpm` command is JupyterLab's pinned version of 24 | [yarn](https://yarnpkg.com/) that is installed with JupyterLab. You may use 25 | `yarn` or `npm` in lieu of `jlpm` below. 26 | 27 | ```bash 28 | # Clone the repo to your local environment 29 | # Change directory to the crystaltoolkit-extension directory 30 | # Install package in development mode 31 | pip install -e . 32 | # Link your development version of the extension with JupyterLab 33 | jupyter labextension develop . --overwrite 34 | # Rebuild extension Typescript source after making changes 35 | jlpm run build 36 | ``` 37 | 38 | You can watch the source directory and run JupyterLab at the same time in different terminals to watch for changes in the extension's source and automatically rebuild the extension. 39 | 40 | ```bash 41 | # Watch the source directory in one terminal, automatically rebuilding when needed 42 | jlpm run watch 43 | # Run JupyterLab in another terminal 44 | jupyter lab 45 | ``` 46 | 47 | With the watch command running, every saved change will immediately be built locally and available in your running JupyterLab. Refresh JupyterLab to load the change in your browser (you may need to wait several seconds for the extension to be rebuilt). 48 | 49 | By default, the `jlpm run build` command generates the source maps for this extension to make it easier to debug using the browser dev tools. To also generate source maps for the JupyterLab core extensions, you can run the following command: 50 | 51 | ```bash 52 | jupyter lab build --minimize=False 53 | ``` 54 | 55 | ### Uninstall 56 | 57 | ```bash 58 | pip uninstall crystaltoolkit-extension 59 | ``` 60 | -------------------------------------------------------------------------------- /jupyterlab-extension/crystaltoolkit-extension/__init__.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os.path as osp 3 | 4 | from ._version import __version__ 5 | 6 | HERE = osp.abspath(osp.dirname(__file__)) 7 | 8 | with open(osp.join(HERE, "labextension", "package.json")) as fid: 9 | data = json.load(fid) 10 | 11 | 12 | def _jupyter_labextension_paths(): 13 | return [{"src": "labextension", "dest": data["name"]}] 14 | -------------------------------------------------------------------------------- /jupyterlab-extension/crystaltoolkit-extension/_version.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | 5 | def _fetch_version(): 6 | HERE = os.path.abspath(os.path.dirname(__file__)) 7 | 8 | for folder, _, _ in os.walk(HERE): 9 | try: 10 | with open(os.path.join(folder, "package.json")) as file: 11 | return json.load(file)["version"] 12 | except FileNotFoundError: 13 | pass 14 | 15 | raise FileNotFoundError(f"Could not find package.json under dir {HERE}") 16 | 17 | 18 | __version__ = _fetch_version() 19 | __all__ = ["__version__"] 20 | -------------------------------------------------------------------------------- /jupyterlab-extension/install.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageManager": "python", 3 | "packageName": "crystaltoolkit-extension", 4 | "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package crystaltoolkit-extension" 5 | } 6 | -------------------------------------------------------------------------------- /jupyterlab-extension/lib/index.d.ts: -------------------------------------------------------------------------------- 1 | import { IRenderMime } from '@jupyterlab/rendermime-interfaces'; 2 | import { Widget } from '@lumino/widgets'; 3 | /** 4 | * A widget for rendering Crystal Toolkit Scene JSON 5 | */ 6 | export declare class SceneRenderer extends Widget implements IRenderMime.IRenderer { 7 | private sceneContainer; 8 | private model; 9 | private scene; 10 | /** 11 | * Construct a new output widget 12 | */ 13 | constructor(options: IRenderMime.IRendererOptions); 14 | /** 15 | * Render Crystal Toolkit Scene JSON into this widget's node. 16 | */ 17 | renderModel(model: IRenderMime.IMimeModel): Promise; 18 | dispose(): void; 19 | } 20 | /** 21 | * A mime renderer factory for Crystal Toolkit Scene JSON data. 22 | */ 23 | export declare const rendererFactory: IRenderMime.IRendererFactory; 24 | /** 25 | * Extension definition. 26 | */ 27 | declare const extension: IRenderMime.IExtension; 28 | export default extension; 29 | -------------------------------------------------------------------------------- /jupyterlab-extension/lib/index.js: -------------------------------------------------------------------------------- 1 | import { Widget } from '@lumino/widgets'; 2 | import { Scene } from '@materialsproject/mp-react-components'; 3 | /** 4 | * The default mime type for the extension. 5 | */ 6 | const MIME_TYPE = 'application/vnd.mp.ctk+json'; 7 | /** 8 | * The class name added to the extension. 9 | */ 10 | const CLASS_NAME = 'mimerenderer-mp_ctk_json'; 11 | /** 12 | * A widget for rendering Crystal Toolkit Scene JSON 13 | */ 14 | export class SceneRenderer extends Widget { 15 | /** 16 | * Construct a new output widget 17 | */ 18 | constructor(options) { 19 | super(); 20 | this.addClass(CLASS_NAME); 21 | this.sceneContainer = document.createElement('div'); 22 | this.sceneContainer.setAttribute('style', 'height: 400px; width: 400px'); 23 | this.node.appendChild(this.sceneContainer); 24 | } 25 | /** 26 | * Render Crystal Toolkit Scene JSON into this widget's node. 27 | */ 28 | renderModel(model) { 29 | // Save reference to model 30 | this.model = model; 31 | console.log("Running dev version 2!"); 32 | // wait for the next event loop 33 | setTimeout(() => { 34 | this.scene = new Scene(model, // sceneJSON 35 | this.sceneContainer, // domElement 36 | {}, // settings 37 | 50, // size 38 | 10, // padding 39 | (objects) => { 40 | null; 41 | }, () => { 42 | /* we do not need to dispatch camera changes */ 43 | }, null); 44 | this.scene.addToScene(this.model.data[MIME_TYPE]); 45 | this.scene.resizeRendererToDisplaySize(); 46 | }, 0); 47 | return Promise.resolve(); 48 | } 49 | dispose() { 50 | this.scene.onDestroy(); 51 | } 52 | } 53 | /** 54 | * A mime renderer factory for Crystal Toolkit Scene JSON data. 55 | */ 56 | export const rendererFactory = { 57 | safe: true, 58 | mimeTypes: [MIME_TYPE], 59 | createRenderer: (options) => new SceneRenderer(options), 60 | }; 61 | /** 62 | * Extension definition. 63 | */ 64 | const extension = { 65 | id: 'crystaltoolkit-extension:plugin', 66 | rendererFactory, 67 | rank: 0, 68 | dataType: 'json', 69 | fileTypes: [ 70 | { 71 | name: 'ctk_json', 72 | displayName: 'Crystal Toolkit Scene JSON', 73 | fileFormat: 'json', 74 | mimeTypes: [MIME_TYPE], 75 | extensions: ['.ctk.json'], 76 | }, 77 | ], 78 | documentWidgetFactoryOptions: { 79 | name: 'SceneViewer', 80 | primaryFileType: 'ctk_json', 81 | fileTypes: ['ctk_json'], 82 | defaultFor: ['ctk_json'], 83 | }, 84 | }; 85 | export default extension; 86 | -------------------------------------------------------------------------------- /jupyterlab-extension/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "crystaltoolkit-extension", 3 | "version": "0.6.0", 4 | "description": "A JupyterLab extension for rendering Crystal Toolkit Scene JSON files.", 5 | "author": "Matthew Horton ", 6 | "main": "lib/index.js", 7 | "types": "lib/index.d.ts", 8 | "style": "style/index.css", 9 | "keywords": [ 10 | "jupyter", 11 | "jupyterlab", 12 | "jupyterlab-extension" 13 | ], 14 | "files": [ 15 | "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", 16 | "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}", 17 | "style/index.js" 18 | ], 19 | "jupyterlab": { 20 | "mimeExtension": true, 21 | "outputDir": "crystaltoolkit-extension/labextension" 22 | }, 23 | "scripts": { 24 | "build": "jlpm run build:lib && jlpm run build:labextension:dev", 25 | "build:labextension": "jupyter labextension build .", 26 | "build:labextension:dev": "jupyter labextension build --development True .", 27 | "build:lib": "tsc", 28 | "build:prod": "jlpm run build:lib && jlpm run build:labextension", 29 | "clean": "jlpm run clean:lib", 30 | "clean:all": "jlpm run clean:lib && jlpm run clean:labextension", 31 | "clean:labextension": "rimraf crystaltoolkit-extension/labextension", 32 | "clean:lib": "rimraf lib tsconfig.tsbuildinfo", 33 | "eslint": "eslint . --ext .ts,.tsx --fix", 34 | "eslint:check": "eslint . --ext .ts,.tsx", 35 | "extension:disable": "jupyter labextension disable crystaltoolkit-extension", 36 | "extension:enable": "jupyter labextension enable crystaltoolkit-extension", 37 | "extension:install": "jupyter labextension install crystaltoolkit-extension", 38 | "extension:uninstall": "jupyter labextension uninstall crystaltoolkit-extension", 39 | "install:extension": "jupyter labextension develop --overwrite .", 40 | "prepare": "jlpm run clean && jlpm run build:prod", 41 | "watch": "run-p watch:src watch:labextension", 42 | "watch:labextension": "jupyter labextension watch .", 43 | "watch:src": "tsc -w" 44 | }, 45 | "dependencies": { 46 | "@jupyterlab/rendermime-interfaces": "^3.0.0", 47 | "@lumino/widgets": "^1.16.1", 48 | "@materialsproject/mp-react-components": "^0.1.9" 49 | }, 50 | "devDependencies": { 51 | "@jupyterlab/builder": "^3.0.0-rc.13", 52 | "@typescript-eslint/eslint-plugin": "^2.27.0", 53 | "@typescript-eslint/parser": "^2.27.0", 54 | "eslint": "^7.5.0", 55 | "eslint-config-prettier": "^6.10.1", 56 | "eslint-plugin-prettier": "^3.1.2", 57 | "npm-run-all": "^4.1.5", 58 | "prettier": "^1.19.0", 59 | "rimraf": "^3.0.2", 60 | "typescript": "~4.1.3", 61 | "css-loader": "^6.5.1", 62 | "style-loader": "^3.3.1" 63 | }, 64 | "styleModule": "style/index.js" 65 | } 66 | -------------------------------------------------------------------------------- /jupyterlab-extension/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["jupyter_packaging~=0.7.9", "jupyterlab>=3.0.0rc13,==3.*", "setuptools>=40.8.0", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | -------------------------------------------------------------------------------- /jupyterlab-extension/setup.py: -------------------------------------------------------------------------------- 1 | """crystaltoolkit-extension setup.""" 2 | import json 3 | import os 4 | 5 | import setuptools 6 | from jupyter_packaging import ( 7 | combine_commands, 8 | create_cmdclass, 9 | ensure_targets, 10 | install_npm, 11 | skip_if_exists, 12 | ) 13 | 14 | HERE = os.path.abspath(os.path.dirname(__file__)) 15 | 16 | # The name of the project 17 | name = "crystaltoolkit-extension" 18 | 19 | # Get our version 20 | with open(os.path.join(HERE, "package.json")) as file: 21 | version = json.load(file)["version"] 22 | 23 | lab_path = os.path.join(HERE, name, "labextension") 24 | 25 | # Representative files that should exist after a successful build 26 | jstargets = [ 27 | os.path.join(lab_path, "package.json"), 28 | ] 29 | 30 | package_data_spec = {name: ["*"]} 31 | 32 | labext_name = "crystaltoolkit-extension" 33 | 34 | data_files_spec = [ 35 | ("share/jupyter/labextensions/%s" % labext_name, lab_path, "**"), 36 | ("share/jupyter/labextensions/%s" % labext_name, HERE, "install.json"), 37 | ] 38 | 39 | cmdclass = create_cmdclass( 40 | "jsdeps", package_data_spec=package_data_spec, data_files_spec=data_files_spec 41 | ) 42 | 43 | js_command = combine_commands( 44 | install_npm(HERE, build_cmd="build:prod", npm=["jlpm"]), 45 | ensure_targets(jstargets), 46 | ) 47 | 48 | is_repo = os.path.exists(os.path.join(HERE, ".git")) 49 | if is_repo: 50 | cmdclass["jsdeps"] = js_command 51 | else: 52 | cmdclass["jsdeps"] = skip_if_exists(jstargets, js_command) 53 | 54 | with open("README.md") as readme: 55 | long_description = readme.read() 56 | 57 | setup_args = dict( 58 | name=name, 59 | version=version, 60 | url="https://github.com/materialsproject/crystaltoolkit", 61 | author="Matthew Horton ", 62 | description="A JupyterLab extension for rendering Crystal Toolkit Scene JSON files.", 63 | long_description=long_description, 64 | long_description_content_type="text/markdown", 65 | cmdclass=cmdclass, 66 | packages=setuptools.find_packages(), 67 | install_requires=["jupyterlab>=3.0.0rc13,==3.*"], 68 | zip_safe=False, 69 | include_package_data=True, 70 | python_requires=">=3.6", 71 | license="BSD-3-Clause", 72 | platforms="Linux, Mac OS X, Windows", 73 | keywords=["Jupyter", "JupyterLab", "JupyterLab3"], 74 | classifiers=[ 75 | "License :: OSI Approved :: BSD License", 76 | "Programming Language :: Python", 77 | "Programming Language :: Python :: 3", 78 | "Programming Language :: Python :: 3.6", 79 | "Programming Language :: Python :: 3.7", 80 | "Programming Language :: Python :: 3.8", 81 | "Framework :: Jupyter", 82 | ], 83 | ) 84 | 85 | 86 | if __name__ == "__main__": 87 | setuptools.setup(**setup_args) 88 | -------------------------------------------------------------------------------- /jupyterlab-extension/src/index.ts: -------------------------------------------------------------------------------- 1 | import { IRenderMime } from '@jupyterlab/rendermime-interfaces'; 2 | import { Widget } from '@lumino/widgets'; 3 | import { Scene } from '@materialsproject/mp-react-components'; 4 | 5 | /** 6 | * The default mime type for the extension. 7 | */ 8 | const MIME_TYPE = 'application/vnd.mp.ctk+json'; 9 | 10 | /** 11 | * The class name added to the extension. 12 | */ 13 | const CLASS_NAME = 'mimerenderer-mp_ctk_json'; 14 | 15 | /** 16 | * A widget for rendering Crystal Toolkit Scene JSON 17 | */ 18 | export class SceneRenderer extends Widget implements IRenderMime.IRenderer { 19 | private sceneContainer: HTMLDivElement; 20 | private model!: IRenderMime.IMimeModel; 21 | private scene: Scene; 22 | /** 23 | * Construct a new output widget 24 | */ 25 | constructor(options: IRenderMime.IRendererOptions) { 26 | super(); 27 | this.addClass(CLASS_NAME); 28 | this.sceneContainer = document.createElement('div') as HTMLDivElement; 29 | this.sceneContainer.setAttribute('style', 'height: 400px; width: 400px'); 30 | this.node.appendChild(this.sceneContainer); 31 | } 32 | /** 33 | * Render Crystal Toolkit Scene JSON into this widget's node. 34 | */ 35 | renderModel(model: IRenderMime.IMimeModel): Promise { 36 | // Save reference to model 37 | this.model = model; 38 | 39 | // wait for the next event loop 40 | setTimeout(() => { 41 | this.scene = new Scene( 42 | model, // sceneJSON 43 | this.sceneContainer, // domElement 44 | {}, // settings 45 | 50, // size 46 | 10, // padding 47 | (objects) => { // clickCallback 48 | null 49 | }, 50 | () => { // cameraState 51 | /* we do not need to dispatch camera changes */ 52 | }, null); 53 | this.scene.addToScene(this.model.data[MIME_TYPE]); 54 | this.scene.resizeRendererToDisplaySize(); 55 | }, 0); 56 | 57 | return Promise.resolve(); 58 | } 59 | 60 | dispose() { 61 | this.scene.onDestroy(); 62 | } 63 | } 64 | 65 | /** 66 | * A mime renderer factory for Crystal Toolkit Scene JSON data. 67 | */ 68 | export const rendererFactory: IRenderMime.IRendererFactory = { 69 | safe: true, 70 | mimeTypes: [MIME_TYPE], 71 | createRenderer: (options) => new SceneRenderer(options), 72 | }; 73 | 74 | /** 75 | * Extension definition. 76 | */ 77 | const extension: IRenderMime.IExtension = { 78 | id: 'crystaltoolkit-extension:plugin', 79 | rendererFactory, 80 | rank: 0, 81 | dataType: 'json', 82 | fileTypes: [ 83 | { 84 | name: 'ctk_json', 85 | displayName: 'Crystal Toolkit Scene JSON', 86 | fileFormat: 'json', 87 | mimeTypes: [MIME_TYPE], 88 | extensions: ['.ctk.json'], 89 | }, 90 | ], 91 | documentWidgetFactoryOptions: { 92 | name: 'SceneViewer', 93 | primaryFileType: 'ctk_json', 94 | fileTypes: ['ctk_json'], 95 | defaultFor: ['ctk_json'], 96 | }, 97 | }; 98 | 99 | export default extension; 100 | -------------------------------------------------------------------------------- /jupyterlab-extension/src/types.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/jupyterlab-extension/src/types.d.ts -------------------------------------------------------------------------------- /jupyterlab-extension/style/base.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/jupyterlab-extension/style/base.css -------------------------------------------------------------------------------- /jupyterlab-extension/style/index.css: -------------------------------------------------------------------------------- 1 | @import url('base.css'); 2 | -------------------------------------------------------------------------------- /jupyterlab-extension/style/index.js: -------------------------------------------------------------------------------- 1 | import './base.css'; 2 | -------------------------------------------------------------------------------- /jupyterlab-extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "composite": true, 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "incremental": true, 8 | "jsx": "react", 9 | "module": "esnext", 10 | "moduleResolution": "node", 11 | "noEmitOnError": true, 12 | "noImplicitAny": false, 13 | "noUnusedLocals": true, 14 | "outDir": "lib", 15 | "preserveWatchOutput": true, 16 | "resolveJsonModule": true, 17 | "rootDir": "src", 18 | "sourceMap": false, 19 | "strict": true, 20 | "target": "es2017", 21 | "types": [] 22 | }, 23 | "include": ["src/*"] 24 | } 25 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/tests/__init__.py -------------------------------------------------------------------------------- /tests/asy_test/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/tests/asy_test/core/__init__.py -------------------------------------------------------------------------------- /tests/asy_test/core/test_jupyter.py: -------------------------------------------------------------------------------- 1 | import plotly.express as px 2 | from monty.json import MSONable 3 | 4 | from crystal_toolkit.core.jupyter import patch_msonable 5 | from crystal_toolkit.core.scene import Scene 6 | 7 | 8 | def test_patch_msonable(): 9 | patch_msonable() 10 | 11 | class GetSceneClass(MSONable): 12 | def get_scene(self): 13 | return Scene(name="test_scene") 14 | 15 | class GetPlotClass(MSONable): 16 | def get_plot(self): 17 | """Dummy plotly object""" 18 | return px.scatter(x=[1, 2, 3], y=[1, 2, 3]) 19 | 20 | class AsDictClass(MSONable): 21 | def __init__(self, a: int) -> None: 22 | self.a = a 23 | 24 | # The output of _ipython_display_ is None 25 | # However, the logic for the creating the different output 26 | # dictionaries should be executed so the following tests 27 | # are still valuable. 28 | as_dict_class = AsDictClass(1) 29 | assert as_dict_class._ipython_display_() is None 30 | 31 | get_scene_class = GetSceneClass() 32 | assert get_scene_class._ipython_display_() is None 33 | 34 | get_plot_class = GetPlotClass() 35 | assert get_plot_class._ipython_display_() is None 36 | -------------------------------------------------------------------------------- /tests/asy_test/multi/AlN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/tests/asy_test/multi/AlN.png -------------------------------------------------------------------------------- /tests/asy_test/multi/GaN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/tests/asy_test/multi/GaN.png -------------------------------------------------------------------------------- /tests/asy_test/multi/InN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/materialsproject/crystaltoolkit/649d21789fa2e06ef799975dfa5f8844ed2800f6/tests/asy_test/multi/InN.png -------------------------------------------------------------------------------- /tests/asy_test/multi/Makefile: -------------------------------------------------------------------------------- 1 | SRCS = $(wildcard *.asy) 2 | PROGS = $(patsubst %.asy,%,$(SRCS)) 3 | all: $(PROGS) 4 | %: %.asy 5 | asy -render 5 -f png $< 6 | -------------------------------------------------------------------------------- /tests/asy_test/single/Makefile: -------------------------------------------------------------------------------- 1 | all: interact 2 | 3 | interact: 4 | asy -V GaN.asy 5 | 6 | offscreen: 7 | asy --offscreen GaN.asy 8 | -------------------------------------------------------------------------------- /tests/asy_test/test_asymptote.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from crystal_toolkit.helpers.asymptote_renderer import ( 4 | ASY_OBJS, 5 | _read_color, 6 | _read_properties, 7 | ) 8 | 9 | 10 | def test_read_properties(standard_scenes): 11 | def _set_and_read_properties(scene): 12 | # make sure the _meta["asy"] attribute is set 13 | scene._meta = scene._meta or {} 14 | scene._meta["asy"] = scene._meta.get("asy", {}) 15 | 16 | scene.prop0 = "scene" 17 | scene._meta["prop0"] = "meta" 18 | user_setting = {scene.type: {"prop0": "user"}} 19 | p0 = _read_properties(scene, property="prop0", user_settings=user_setting) 20 | assert p0 == "user" 21 | 22 | scene.prop1 = "scene" 23 | scene._meta["asy"]["prop1"] = "meta" 24 | p1 = _read_properties(scene, property="prop1") 25 | assert p1 == "meta" 26 | 27 | for val in standard_scenes.values(): 28 | _set_and_read_properties(val) 29 | # Default color is used 30 | assert _read_color(val) is not None 31 | 32 | 33 | def test_asymptote_renderer(standard_scenes): 34 | for key in ["lines", "spheres", "cylinders", "surface"]: 35 | asy_obj = ASY_OBJS[key].from_ctk(standard_scenes[key]) 36 | assert "draw" in str(asy_obj).lower() 37 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | # conftest file for pytest 2 | from __future__ import annotations 3 | 4 | from pathlib import Path 5 | 6 | import pytest 7 | 8 | from crystal_toolkit.core.scene import Cylinders, Lines, Spheres, Surface 9 | 10 | 11 | @pytest.fixture(scope="session") 12 | def test_files(): 13 | """The path to the test_files directory.""" 14 | return Path(__file__).parent / "test_files" 15 | 16 | 17 | @pytest.fixture(scope="session") 18 | def standard_scenes(): 19 | """Dictionary of standard scenes for testing purposes.""" 20 | return { 21 | "spheres": Spheres( 22 | positions=[[0, 0, 0], [1, 1, 1]], 23 | color=None, 24 | radius=0.3, 25 | ), 26 | "cylinders": Cylinders( 27 | positionPairs=[[[0, 0, 0], [1, 1, 1]]], radius=0.3, color=None 28 | ), 29 | "lines": Lines( 30 | positions=[[0, 0, 0], [1, 1, 1]], 31 | color=None, 32 | ), 33 | "surface": Surface( 34 | positions=[[0, 0, 0], [1, 1, 1], [2, 2, 2]], 35 | color=None, 36 | ), 37 | } 38 | -------------------------------------------------------------------------------- /tests/requirements.txt: -------------------------------------------------------------------------------- 1 | # Packages needed to run the tests. 2 | # Switch into a virtual environment 3 | # pip install -r requirements.txt 4 | 5 | chromedriver-binary 6 | dash[testing]>=0.31.0 # be sure to install dash with additional dependencies for testing 7 | dash-core-components 8 | dash-html-components 9 | dash-renderer 10 | ipdb 11 | percy 12 | selenium==4.2 # pin needed due to DashComposite AttributeError: 'WebDriver' object has no attribute 'find_element_by_css_selector' (see https://stackoverflow.com/a/72754667) 13 | flake8 14 | pylint 15 | -------------------------------------------------------------------------------- /tests/test_structure.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pymatgen.core import Lattice, Molecule, Structure 3 | 4 | from crystal_toolkit.components.structure import StructureMoleculeComponent 5 | 6 | NaK = Structure(Lattice.cubic(4.2), ["Na", "K"], [[0, 0, 0], [0.5, 0.5, 0.5]]) 7 | 8 | water = Molecule(["O", "H", "H"], [[0, 0, 0], [0.7, 0.7, 0], [-0.7, 0.7, 0]]) 9 | 10 | 11 | @pytest.mark.parametrize( 12 | ("structure", "expected"), 13 | [ 14 | (NaK, "StructureMoleculeComponent(formula='K1 Na1', atoms=2)"), 15 | (water, "StructureMoleculeComponent(formula='H2 O1', atoms=3)"), 16 | ], 17 | ) 18 | def test_repr_with_struct_or_mol(structure, expected): 19 | component = StructureMoleculeComponent(structure) 20 | assert repr(component) == expected 21 | assert str(component) == expected 22 | 23 | 24 | def test_repr_without_structure(): 25 | component = StructureMoleculeComponent() 26 | expected = "StructureMoleculeComponent(formula=None, atoms=None)" 27 | assert repr(component) == expected 28 | assert str(component) == expected 29 | -------------------------------------------------------------------------------- /tests/test_volumetric.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pymatgen.io.vasp import Chgcar 3 | 4 | 5 | def test_volumetric(test_files): 6 | chgcar = Chgcar.from_file(test_files / "chgcar.vasp") 7 | max_val = chgcar.data["total"].max() 8 | 9 | scene = chgcar.get_scene(isolvl=10, normalization=None) 10 | assert scene is not None 11 | 12 | # out of range 13 | with pytest.raises(ValueError, match="Isosurface level is not within data range"): 14 | scene = chgcar.get_scene(isolvl=max_val * 2, normalization=None) 15 | 16 | # cannot be computed 17 | with pytest.raises(RuntimeError): 18 | scene = chgcar.get_scene(isolvl=max_val / 2, normalization=None) 19 | 20 | # vesta units 21 | scene = chgcar.get_scene(isolvl=0.001, normalization="vesta") 22 | --------------------------------------------------------------------------------