Repository: chalk-diagrams/chalk Branch: master Commit: 6899b958f11e Files: 117 Total size: 413.2 KB Directory structure: gitextract_pp7itskp/ ├── .github/ │ └── workflows/ │ ├── checks.yml │ ├── mkdocs-publish-ghpages.yml │ └── selfassign.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── chalk/ │ ├── __init__.py │ ├── align.py │ ├── arrow.py │ ├── backend/ │ │ ├── __init__.py │ │ ├── cairo.py │ │ ├── svg.py │ │ └── tikz.py │ ├── combinators.py │ ├── core.py │ ├── envelope.py │ ├── model.py │ ├── monoid.py │ ├── py.typed │ ├── shapes/ │ │ ├── __init__.py │ │ ├── arc.py │ │ ├── arrowheads.py │ │ ├── image.py │ │ ├── latex.py │ │ ├── path.py │ │ ├── segment.py │ │ ├── shape.py │ │ └── text.py │ ├── style.py │ ├── subdiagram.py │ ├── trace.py │ ├── trail.py │ ├── transform.py │ ├── types.py │ ├── utils.py │ └── visitor.py ├── doc/ │ └── crop-images.sh ├── docs/ │ ├── about/ │ │ ├── index.md │ │ └── license.md │ ├── api/ │ │ ├── alignment.py │ │ ├── combinators.py │ │ ├── internals.md │ │ ├── names.py │ │ ├── rendering.py │ │ ├── shapes.py │ │ ├── style.py │ │ ├── trails.py │ │ ├── transformations.py │ │ └── utils.md │ ├── assets/ │ │ ├── css-js/ │ │ │ ├── as-fastapi/ │ │ │ │ ├── chat.js │ │ │ │ ├── custom.css │ │ │ │ ├── custom.js │ │ │ │ ├── termynal.css │ │ │ │ └── termynal.js │ │ │ ├── general/ │ │ │ │ ├── css/ │ │ │ │ │ ├── progressbar.css │ │ │ │ │ └── social-color-stryle.css │ │ │ │ └── js/ │ │ │ │ ├── highlight-config.js │ │ │ │ ├── material-extra/ │ │ │ │ │ ├── extra-uml.js │ │ │ │ │ ├── material-extra-theme.js │ │ │ │ │ └── uml.js │ │ │ │ └── tables.js │ │ │ ├── mkdocs-tooltips/ │ │ │ │ └── css/ │ │ │ │ └── custom.css │ │ │ ├── pymdownx-extras/ │ │ │ │ ├── css/ │ │ │ │ │ └── extra.css │ │ │ │ └── js/ │ │ │ │ └── extra-uml.js │ │ │ └── termynal/ │ │ │ ├── css/ │ │ │ │ ├── custom.css │ │ │ │ └── termynal.css │ │ │ ├── js/ │ │ │ │ ├── custom.js │ │ │ │ └── termynal.js │ │ │ └── readme.md │ │ └── snippets/ │ │ ├── macros/ │ │ │ └── .gitkeep │ │ └── notifications/ │ │ └── videos/ │ │ └── disclaimer.md │ ├── examples/ │ │ ├── hanoi.py │ │ ├── koch.py │ │ ├── lenet.py │ │ ├── squares.py │ │ └── tensor.py │ ├── index.md │ ├── overrides/ │ │ └── main.html │ └── quickstart/ │ └── .gitkeep ├── examples/ │ ├── arrows.py │ ├── bigben.py │ ├── comparison.tex │ ├── escher_square_limit.py │ ├── hanoi.py │ ├── hex_variation.py │ ├── hilbert.py │ ├── intro.py │ ├── isometric.py │ ├── koch.py │ ├── latex.py │ ├── lattice.py │ ├── lenet.py │ ├── logo.py │ ├── normalized.py │ ├── output/ │ │ ├── index.html │ │ ├── path.tex │ │ └── path.tex.tex │ ├── path.py │ ├── rectangle_parade.py │ ├── squares.py │ ├── subdiagrams.py │ ├── tensor.py │ ├── tests/ │ │ └── index.tpl.html │ ├── tournament-network.py │ └── tree.py ├── mkdocs.yml ├── pyproject.toml ├── requirements/ │ ├── dev.txt │ └── docs.txt ├── requirements.txt ├── setup.cfg ├── setup.py └── tests/ ├── test_envelope.py └── test_reverse_trail.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/checks.yml ================================================ name: checks.yml on: [push, pull_request] jobs: build: runs-on: ubuntu-latest strategy: matrix: python-version: ["3.12", "3.10"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | sudo apt update && sudo apt upgrade -y sudo apt-get install libcairo2-dev pdf2svg texlive texlive-science texlive-latex-recommended texlive-latex-extra python -m pip install --upgrade pip pip install -U pip wheel make install.dev install.base install.e install.docs - name: Format with [[ isort ]] run: | # stop the build if there are errors raised by isort make isort - name: Format with [[ black ]] run: | # stop the build if there are errors raised by black make black - name: Lint with [[ flake8 ]] run: | # stop the build if there are Python syntax errors or undefined names make flake - name: Docstring linting -- type check against function/method signature with [[ darglint ]] run: | # stop the build if docstring type-mismatch detected make darglint - name: Doctest coverage check with [[ interrogate ]] run: | # stop the build if doctest threshold does not meet make interrogate - name: Type check with [[ mypy ]] run: | # stop the build if there are type errors make type - name: Unit test with [[ pytest ]] run: | # stop the build if there are type errors make test - name: Make sure examples run run: | make images - name: Make sure docs run run: | make docsapi ================================================ FILE: .github/workflows/mkdocs-publish-ghpages.yml ================================================ name: "MkDocs Publish Docs on GitHub Pages CI" on: # Manually trigger workflow workflow_dispatch: inputs: branch: description: Build MkDocs from Branch (Optional) required: false # Trigger when a push happens # to select branches. push: branches: - master env: PYTHON_VERSION: "3.8" USER_SPECIFIED_BRANCH: ${{ github.event.inputs.branch }} REPO_OWNER: ${{ github.repository_owner }} # https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v2 - name: Set up Python runtime uses: actions/setup-python@v2 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install Python dependencies for MkDocs run: | echo "REPO_OWNER: ${{ env.REPO_OWNER }}" ls pip install -r requirements/docs.txt - name: Install all other dependencies run: | pip install -r requirements.txt - name: Deploy documentation env: FONTAWESOME_KIT: ${{ secrets.FONTAWESOME_KIT }} run: | # Check if user-provided branch exists # then switch to that branch. if [[ -z $(git branch --list "${{ env.USER_SPECIFIED_BRANCH }}") ]]; \ then (\ echo "Switching to branch: ${{ env.USER_SPECIFIED_BRANCH }}" && \ git checkout ${{ env.USER_SPECIFIED_BRANCH }} \ ); else USER_SPECIFIED_BRANCH=${GITHUB_REF##*/} ; fi && \ echo "Current Git Branch: ${USER_SPECIFIED_BRANCH}" # Install chalk from current branch python -m pip install "." # Begin Deploying MkDocs mkdocs gh-deploy --force mkdocs --version ================================================ FILE: .github/workflows/selfassign.yml ================================================ # Allow users to automatically tag themselves to issues # # Usage: # - a github user (a member of the repo) needs to comment # with "#self-assign" on an issue to be assigned to them. #------------------------------------------------------------ name: Self-assign on: issue_comment: types: created jobs: one: runs-on: ubuntu-latest if: >- (github.event.comment.body == '#take' || github.event.comment.body == '#self-assign') steps: - run: | echo "Assigning issue ${{ github.event.issue.number }} to ${{ github.event.comment.user.login }}" curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ -d '{"assignees": ["${{ github.event.comment.user.login }}"]}' \ https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/assignees echo "Done 🔥 " ================================================ FILE: .gitignore ================================================ # User Defined .vscode # Temporary files *.swp # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python .archives/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ ================================================ FILE: CHANGELOG.md ================================================ ## `v0.2.2` – 2024-06-14 Added: - Isometric example (#130) - Associative reduce (#129) - Subdiagram (#116) - Property-based testing (#111) Changed: - Rewrite of core (#132) - Bug fixes and typos (#110, #127, #128) ## `v0.2.1` — 2022-09-07 Added: - Traces and envelopes - TikZ backend - Arrows and connections - More examples (e.g, Big Ben) - Gallery of examples - Documentation Changed: - Use `planar` library for geometry - Major code refactoring ## `v0.1.2` — 2022-05-20 Other changes: - Add license (MIT license) - Remove dependency on `streamlit` ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2022 Dan Oneață and Alexander Rush Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: MANIFEST.in ================================================ include README.md include chalk/py.typed # marker file for PEP 561 include CHANGELOG.md include changelog.md include LICENSE include LICENSE.txt include CITATION.cff include *.cff # citation info include MANIFEST.in include pyproject.toml include setup.py include setup.cfg include requirements.txt recursive-include requirements *.txt recursive-exclude examples * recursive-exclude tests * recursive-exclude docs * recursive-exclude site * recursive-exclude apps * recursive-exclude .archives * exclude .flake8 exclude .gitignore exclude .pre-commit-config.yaml exclude mkdocs.yml exclude Makefile ================================================ FILE: Makefile ================================================ # maintenance .PHONY: isort flake black test type interrogate darglint \ clean cleanall style docs check # installation .PHONY: install installplus install.e install.all install.base install.dev install.docs # uninstallation .PHONY: uninstall uninstallplus uninstall.e uninstall.all \ uninstall.base uninstall.dev uninstall.docs # documentation .PHONY: pregendocs.doc pregendocs.examples pregendocs.local pregendocs.remote \ gendocs \ postgendocs.doc postgendocs.local postgendocs.remote gendocsall.local # generate examples .PHONY: intro squares hanoi escher_square lattice lenet logo \ hilbert koch tensor latex hex_variation images \ tree serve ####------------------------------------------------------------#### # libname is either same as PACKAGE_NAME or # as on PYPI (replace - with _) LIBNAME := chalk_diagrams PACKAGE_NAME := chalk TESTPYPI_DOWNLOAD_URL := "https://test.pypi.org/simple/" PYPIPINSTALL := "python -m pip install -U --index-url" PIPINSTALL_PYPITEST := "$(PYPIPINSTALL) $(TESTPYPI_DOWNLOAD_URL)" PKG_INFO := "import pkginfo; dev = pkginfo.Develop('.'); print((dev.$${FIELD}))" # This is where you store the eggfile # and other generated archives ARCHIVES_DIR := ".archives" # Folder path for tests TESTS_DIR := "tests" # Interrogate will flag the test as FAILED if # % success threshold is under the following value INTERROGATE_FAIL_UNDER := 0 # ideally this should be 100 # Specify paths of various dependency files REQ_FOLDER := "requirements" # location: requirements.txt REQ_FILE := "requirements.txt" # location: requirements/dev.txt DEV_REQ_FILE := "dev.txt" # location: requirements/docs.txt DOCS_REQ_FILE := "docs.txt" ####------------------------------------------------------------#### ### Code maintenance ## Run isort isort: @ echo "✨ Applying import sorter: isort ... ⏳" # The settings are maintained in setup.cfg file. isort $(PACKAGE_NAME) setup.py \ tests \ ## Run black black: @ echo "✨ Applying formatter: black ... ⏳" black --target-version py38 --line-length 79 $(PACKAGE_NAME) setup.py \ tests \ ## Run flake8 flake: @ echo "✨ Applying formatter: flake8 ... ⏳" flake8 --show-source $(PACKAGE_NAME) setup.py \ tests \ ## Run pytest test: @ echo "✨ Run tests: pytest ... ⏳" @if [ -d "$(TESTS_DIR)" ]; then pytest $(TESTS_DIR); else echo "\n\t🔥 No tests configured yet. Skipping tests.\n"; fi ## Run mypy type: @ echo "✨ Applying type checker: mypy ... ⏳" mypy --strict --ignore-missing-imports --no-warn-unused-ignores $(PACKAGE_NAME) \ tests \ ## Run darglint darglint: @ echo "✨ Applying docstring type checker: darglint ... ⏳" # The settings are maintained in setup.cfg file. darglint -v 2 $(PACKAGE_NAME) --ignore-properties ## Run interrogate interrogate: @ echo "✨ Applying doctest checker: interrogate ... ⏳" $(eval INTERROGATE_CONFIG := -vv --ignore-nested-functions --ignore-semiprivate --ignore-private --ignore-magic --ignore-module --ignore-init-method --fail-under $(INTERROGATE_FAIL_UNDER)) $(eval INTERROGATE_COMMAND := interrogate $(INTERROGATE_CONFIG)) # Check tests folder @if [ -d "$(TESTS_DIR)" ]; then $(INTERROGATE_COMMAND) $(TESTS_DIR); else echo "\n\t🔥 No tests configured yet. Skipping tests.\n"; fi # Check package folder @$(INTERROGATE_COMMAND) $(PACKAGE_NAME) ## Cleanup # # Instruction: # # make clean : if only cleaning artifacts created after running, # code, tests, etc. # make cleanall : if cleaning all artifacts (including the ones # generated after creating dist and wheels). # # Note: archives created (dist and wheels) are stored in # $(ARCHIVES_DIR). This is defined at the top of this Makefile. #-------------------------------------------------------------------- clean: @ echo "🪣 Cleaning repository ... ⏳" rm -rf \ .ipynb_checkpoints **/.ipynb_checkpoints \ .pytest_cache **/.pytest_cache \ **/__pycache__ **/**/__pycache__ cleanall: clean @ echo "🪣 Cleaning dist/archive files ... ⏳" rm -rf build/* dist/* $(PACKAGE_NAME).egg-info/* $(ARCHIVES_DIR)/* ## Style Checks and Unit Tests style: clean isort black flake clean docs: clean darglint interrogate clean check: style docs type test clean ####------------------------------------------------------------#### ### Code Installation ## Install for development (from local repository) # # Instruction: Contributors will need to run... # # - "make installplus": if installing for the first time or want to # update to the latest dev-requirements or # other extra dependencies. # - "make install.e" : if only installing the local source (after # making some changes) to the source code. #-------------------------------------------------------------------- # .PHONY: install.e install.e: clean @echo "📀🟢🔵 Installing $(PACKAGE_NAME) from local source ... ⏳" python -m pip install -Ue .[tikz,latex,png,svg] # .PHONY: install install: clean install.base install.e @echo "📀🟢🟡🔵 Installing $(PACKAGE_NAME) and base-dependencies from PyPI ... ⏳" # .PHONY: installplus installplus: install.all install.e @echo "📀🟢🟡🔵🟠 Installing $(PACKAGE_NAME) and all-dependencies from PyPI ... ⏳" # .PHONY: install.all install.all: clean install.base install.dev install.docs @echo "📀🟢🟡 Installing $(PACKAGE_NAME)'s all-dependencies from PyPI ... ⏳" # .PHONY: install.base install.base: @echo "📀🟢🟡 Installing from: $(DEV_REQ_FILE) ... ⏳" if [ -f $(REQ_FILE) ]; then python -m pip install -U -r $(REQ_FILE); fi # .PHONY: install.dev install.dev: @echo "📀🟢🟡 Installing from: $(DEV_REQ_FILE) ... ⏳" if [ -f $(REQ_FOLDER)/$(DEV_REQ_FILE) ]; then python -m pip install -U -r $(REQ_FOLDER)/$(DEV_REQ_FILE); fi # .PHONY: install.docs install.docs: @echo "📀🟢🟡 Installing from: $(DOCS_REQ_FILE) ... ⏳" @if [ -f $(REQ_FOLDER)/$(DOCS_REQ_FILE) ]; then python -m pip install -U -r $(REQ_FOLDER)/$(DOCS_REQ_FILE); fi ## Uninstall from dev-environment # .PHONY: uninstall.e uninstall.e: clean @echo "📀🟢🔵 Uninstalling $(PACKAGE_NAME)' local editable version ... ⏳" @# https://stackoverflow.com/questions/48826015/uninstall-a-package-installed-with-pip-install rm -rf "$(LIBNAME).egg-info" # .PHONY: uninstall uninstall: clean uninstall.base uninstall.e @echo "📀🔴🟡🔵 Uninstalling $(PACKAGE_NAME) and base-dependencies from PyPI ... ⏳" # .PHONY: uninstallplus uninstallplus: uninstall.all uninstall.e @echo "📀🔴🟡🔵🟠 Uninstalling $(PACKAGE_NAME) and all-dependencies from PyPI ... ⏳" # .PHONY: uninstall.all uninstall.all: clean uninstall.base uninstall.dev uninstall.docs clean @echo "📀🔴🟡 Uninstalling $(PACKAGE_NAME)'s all-dependencies from PyPI ... ⏳" # .PHONY: uninstall.base uninstall.base: @echo "📀🔴🟡 Uninstalling from: $(DEV_REQ_FILE) ... ⏳" if [ -f $(REQ_FILE) ]; then python -m pip uninstall -r $(REQ_FILE); fi # .PHONY: uninstall.dev uninstall.dev: @echo "📀🔴🟡 Uninstalling from: $(DEV_REQ_FILE) ... ⏳" if [ -f $(REQ_FOLDER)/$(DEV_REQ_FILE) ]; then python -m pip uninstall -r $(REQ_FOLDER)/$(DEV_REQ_FILE); fi # .PHONY: uninstall.docs uninstall.docs: @echo "📀🔴🟡 Uninstalling from: $(DEV_REQ_FILE) ... ⏳" @if [ -f $(REQ_FOLDER)/$(DOCS_REQ_FILE) ]; then python -m pip uninstall -r $(REQ_FOLDER)/$(DOCS_REQ_FILE); fi ## Install from test.pypi.org # # Instruction: # # 🔥 This is useful if you want to test the latest released package # from the TestPyPI, before you push the release to PyPI. #-------------------------------------------------------------------- pipinstalltest: @echo "💿 Installing $(PACKAGE_NAME) from TestPyPI ($(TESTPYPI_DOWNLOAD_URL)) ... ⏳" # Example Usage: # 👉 To run a command like: # > python -m pip install -U --index-url https://test.pypi.org/simple/ $(PACKAGE_NAME)==$(VERSION) # 👉 Run the following command: # > make pipinstalltest VERSION="0.1.0" # 👉 Specifying VERSION="#.#.#" installs a specific version. # If no version is specified, the latest version is installed from TestPyPI. @if [ $(VERSION) ]; then $(PIPINSTALL_PYPITEST) $(PACKAGE_NAME)==$(VERSION); else $(PIPINSTALL_PYPITEST) $(PACKAGE_NAME); fi; ## Gendocs # .PHONY: gendocs gendocs: @echo "🔥 Generate documentation with MkDocs ... ⏳" # generate documentation mkdocs serve --dirtyreload ## Postgendocs # .PHONY: postgendocs.doc postgendocs.doc: #echo "Cleanup docs... ⏳" rm -rf docs/doc # .PHONY: postgendocs.local postgendocs.local: postgendocs.doc # .PHONY: postgendocs.remote postgendocs.remote: postgendocs.doc # .PHONY: gendocsall.local gendocsall.local: pregendocs.local gendocs postgendocs.local # .PHONY: gendocsall.remote # gendocsall.remote: pregendocs.remote gendocs postgendocs.remote # @ # Use mkdocs-publish-ghpages.yml action instead of this make command ####------------------------------------------------------------#### ### Generate Output for Examples intro: python examples/intro.py squares: python examples/squares.py hanoi: python examples/hanoi.py escher_square: python examples/escher_square_limit.py lattice: python examples/lattice.py lenet: python examples/lenet.py logo: python examples/logo.py hilbert: python examples/hilbert.py koch: python examples/koch.py tensor: python examples/tensor.py latex: python examples/latex.py hex_variation: python examples/hex_variation.py tree: python examples/tree.py tournament: python examples/tournament-network.py parade: python examples/rectangle_parade.py arrows: python examples/arrows.py path: python examples/path.py images: squares hanoi intro hilbert koch tensor hex_variation tree tournament parade arrows path lenet escher_square logo @echo "🎁 Generate all examples ... ⏳" serve: python -m http.server 8080 -d examples/output/ docsapi: python docs/api/*.py ================================================ FILE: README.md ================================================

![]() squares.py |
![]() logo.py |
![]() escher_square_limit.py |
![]() hilbert.py |
![]() koch.py |
![]() hex-variation.py |
![]() lenet.py |
![]() tensor.py |
![]() hanoi.py |
![]() tree.py |
![]() lattice.py |
================================================
FILE: docs/api/names.py
================================================
# + tags=["hide_inp"]
from colour import Color
from chalk.core import BaseDiagram
from chalk import *
def help(f):
import pydoc
from IPython.display import HTML
return HTML(pydoc.HTMLDoc().docroutine(f))
set_svg_height(100)
# -
# Chalk supports basic methods for complex connected layouts and diagrams.
# Individual elements can be assigned names, and then be referenced in their subdiagram locations.
# As we will see, names are particularly useful for connecting different parts of the diagram with arrows.
# Our implementation follows the API of the Haskell [diagrams](https://diagrams.github.io/doc/manual.html#named-subdiagrams) library,
# but named nodes are also common in TikZ.
#
# ### Diagram.named
# + tags=["hide_inp"]
help(BaseDiagram.named)
# -
diagram = circle(0.5).named("x") | square(1)
diagram
# ### Diagram.get_subdiagram
# + tags=["hide_inp"]
help(BaseDiagram.get_subdiagram)
# -
# A `Subdiagram` is a `Diagram` paired with its enclosing context (a `Transformation` for the moment; but `Style` should also be added at some point).
# It has the following methods:
# - `get_envelope`, which returns the corresponding `Envelope`
# - `get_trace`, which returns the corresponding `Trace`
# - `get_location`, which returns the local origin of the `Subdiagram`
# - `boundary_from`, which return the furthest point on the boundary of the `Subdiagram`, starting from the local origin of the `Subdigram` and going in the direction of a given vector.
#
diagram = circle(0.5).named("x") | square(1)
sub = diagram.get_subdiagram("x")
diagram + circle(0.2).translate_by(sub.get_location())
# ### Diagram.with_names
# + tags=["hide_inp"]
help(BaseDiagram.with_names)
# -
root = circle(1).named("root")
leaves = hcat([circle(1).named(c) for c in "abcde"], sep=0.5).center()
def connect(subs, nodes):
root, leaf = subs
pp = tuple(root.boundary_from(unit_y))
pc = tuple(leaf.boundary_from(-unit_y))
return nodes + make_path([pp, pc])
nodes = root / vstrut(2) / leaves
for c in "abcde":
nodes = nodes.with_names(["root", c], connect)
nodes
# ### Diagram.qualify
# + tags=["hide_inp"]
help(BaseDiagram.qualify)
# -
red = Color("red")
def attach(subs, dia):
sub1, sub2 = subs
p1 = tuple(sub1.get_location())
p2 = tuple(sub2.get_location())
return dia + make_path([p1, p2]).line_color(red)
def squares():
s = square(1)
return (
(s.named("NW") | s.named("NE")) /
(s.named("SW") | s.named("SE")))
dia = hcat([squares().qualify(str(i)) for i in range(5)], sep=0.5)
pairs = [
(("0", "NE"), ("2", "SW")),
(("1", "SE"), ("4", "NE")),
(("3", "NW"), ("3", "SE")),
(("0", "SE"), ("1", "NW")),
]
dia
for pair in pairs:
dia = dia.with_names(pair, attach)
dia
# ### Diagram.show_labels
# + tags=["hide_inp"]
help(BaseDiagram.show_labels)
# -
dia.show_labels(font_size=0.2)
# ### Diagram.connect
# + tags=["hide_inp"]
help(BaseDiagram.connect)
# -
diagram = circle(0.5).named("x") | hstrut(1) | square(1).named("y")
diagram.connect("x", "y")
# ### Diagram.connect_outside
# + tags=["hide_inp"]
help(BaseDiagram.connect_outside)
# -
diagram = circle(0.5).named("x") | hstrut(1) | square(1).named("y")
diagram.connect_outside("x", "y")
================================================
FILE: docs/api/rendering.py
================================================
# + tags=["hide"]
import math
from chalk.core import BaseDiagram
from chalk import *
def help(f):
import pydoc
from IPython.display import HTML
return HTML(pydoc.HTMLDoc().docroutine(f))
# -
# Chalk supports three back-ends (Cairo, SVG, TikZ),
# which allow the created `Diagram`s to be rendered as PNG, SVG, PDF files, respectively.
# The three corresponding methods for rendering are: `render`, `render_svg`, `render_pdf`;
# these are documented below.
#
# ### Diagram.render
# + tags=["hide_inp"]
help(BaseDiagram.render)
# -
circle(1).render("circle.png")
from IPython.display import Image
Image("circle.png")
# ### Diagram.render_svg
# + tags=["hide_inp"]
help(BaseDiagram.render_svg)
# -
# ### Diagram.render_pdf
# + tags=["hide_inp"]
help(BaseDiagram.render_pdf)
# -
# ### ``Diagram``s in IPython notebooks
# When a ``Diagram`` is used in an IPython notebook, it is automatically displayed as an SVG.
# To adjust the height of the generated image, one can use the `set_svg_height` function:
# + tags=["hide_inp"]
help(set_svg_height)
# -
# This function is particularly useful for showing tall drawings:
set_svg_height(500)
vcat([circle(1) for _ in range(5)])
================================================
FILE: docs/api/shapes.py
================================================
# + tags=["hide"]
from chalk.core import BaseDiagram
from chalk import *
def help(f):
import pydoc
from IPython.display import HTML
return HTML(pydoc.HTMLDoc().docroutine(f))
# -
# Elementary diagrams can be created using shapes: polygons, circle-like shapes, text and paths.
# ## Polygons
# ### Triangle
# + tags=["hide_inp"]
help(triangle)
# -
triangle(1)
# ### Square and rectangle
# + tags=["hide_inp"]
help(square)
# -
square(1)
# + tags=["hide_inp"]
help(rectangle)
# -
rectangle(3, 1, 0.0)
# ### Regular polygon
# + tags=["hide_inp"]
help(regular_polygon)
# -
hcat(
[
regular_polygon(5, 1),
regular_polygon(6, 1),
regular_polygon(7, 1),
],
sep=0.5,
)
# ## Circle-like shapes
# ### Circle
# + tags=["hide_inp"]
help(circle)
# -
circle(1)
# ### Arc
# Arcs can be specified either using angles (see ``arc``) or points (see ``arc_between``).
# + tags=["hide_inp"]
help(arc)
# -
quarter = 90
arc(1, 0, quarter)
arc(1, 0, quarter) + arc(1, 2 * quarter, 3 * quarter)
# + tags=["hide_inp"]
help(arc_between)
# -
arc_between((0, 0), (1, 0), 1)
# ## Text
# + tags=["hide_inp"]
help(text)
# -
# Note that unlike other shapes, ``text`` has an empty envelope, so we need to explicitly specify it in order to get a non-empty rendering.
text("hello", 1).with_envelope(rectangle(2.5, 1))
# ## Paths
# + tags=["hide_inp"]
help(make_path)
# -
make_path([(0, 0), (0, 1), (1, 1), (1, 2)])
================================================
FILE: docs/api/style.py
================================================
# + tags=["hide_inp"]
from chalk.core import BaseDiagram
from chalk import *
def help(f):
import pydoc
from IPython.display import HTML
return HTML(pydoc.HTMLDoc().docroutine(f))
# -
# Diagrams can be styled using standard vector graphic style
# primitives. Colors use the Python [colour](https://github.com/vaab/colour) library.
from colour import Color
blue = Color("blue")
orange = Color("orange")
# ### Diagram.fill_color
# + tags=["hide_inp"]
help(BaseDiagram.fill_color)
# -
#
triangle(1).fill_color(blue)
# ### Diagram.fill_opacity
# + tags=["hide_inp"]
help(BaseDiagram.fill_opacity)
# -
#
triangle(1).fill_color(blue).fill_opacity(0.2)
# ### Diagram.line_color
# + tags=["hide_inp"]
help(BaseDiagram.line_color)
# -
#
triangle(1).line_color(blue)
# ### Diagram.line_width
# + tags=["hide_inp"]
help(BaseDiagram.line_width)
# -
#
triangle(1).line_width(0.05)
# ### Diagram.dashing
# + tags=["hide_inp"]
help(BaseDiagram.dashing)
# -
#
triangle(1).dashing([0.2, 0.1], 0)
# ### Advanced Example
# Example: Outer styles override inner styles
(triangle(1).fill_color(orange) | square(2)).fill_color(blue)
================================================
FILE: docs/api/trails.py
================================================
# + tags=["hide_inp"]
import math
from chalk import *
from planar import Vec2Array
def help(f):
import pydoc
from IPython.display import HTML
return HTML(pydoc.HTMLDoc().docroutine(f))
# -
# Chalk also includes a ``Trail`` primitive which allows for creating new ``Diagram``s and more complex shapes.
# ``Trail``s are specified by position-invariant offsets and can be rendered as ``Path``s.
# See the [Koch](../examples/koch/) example for a use case.
# ### Constructors
# ``Trail``s are a sequence of vectors and can be constructed using the ``from_offsets`` method:
trail = Trail.from_offsets([V2(1, 0), V2(1, 1), V2(0, 1)])
# ### Converting to ``Diagram``
# In order to render, `Trail`s have to be turned into ``Diagram``s, which can be achieved using the `stroke` method.
# + tags=["hide_inp"]
help(Trail.stroke)
# -
trail.stroke()
# ### Transformations
# `Trail`s can be transformed using the usual geometric transformations, which are also applied to the ``Diagram`` object.
# For example, ``Trail``s can be rotated:
# + tags=["hide_inp"]
help(Trail.rotate_by)
# -
trail2 = trail.rotate_by(0.2)
trail2.stroke()
# However, since `Trail`s are translation invariant, applying the `translate` method leaves the `Trail` instance unchanged.
# ### Composition
# ``Trail``s form a monoid with addition given by list concatenation and identity given by the empty list.
# Intuitively, adding two ``Trails`` appends the two sequences of offsets.
# + tags=["hide_inp"]
help(Trail.__add__)
# -
(trail + trail2).stroke()
================================================
FILE: docs/api/transformations.py
================================================
# + tags=["hide_inp"]
from chalk.core import BaseDiagram
from chalk import *
def help(f):
import pydoc
from IPython.display import HTML
return HTML(pydoc.HTMLDoc().docroutine(f))
# -
# Any Diagram (or other object in Chalk) can be transformed by affine transformation.
# These produce a new diagram in the standard manner.
# ### scale
# + tags=["hide_inp"]
help(BaseDiagram.scale)
# -
#
triangle(1) | triangle(1).scale(2)
# Transformations apply to the whole diagram.
(triangle(1) | triangle(1)).scale(2)
# ### translate
# + tags=["hide_inp"]
help(BaseDiagram.translate)
# -
#
triangle(1).translate(1, 1).show_envelope().show_origin()
#
triangle(1) + triangle(1).translate(1, 1)
# ### shear_x
# + tags=["hide_inp"]
help(BaseDiagram.shear_x)
# -
#
square(1).shear_x(0.25).show_envelope()
#
square(1) | square(1).shear_x(0.25)
# ### rotate
# + tags=["hide_inp"]
help(BaseDiagram.rotate)
# -
#
triangle(1) | triangle(1).rotate(90)
# ### rotate_by
# + tags=["hide_inp"]
help(BaseDiagram.rotate_by)
# -
#
triangle(1) | triangle(1).rotate_by(0.2)
================================================
FILE: docs/api/utils.md
================================================
---
title: chalk.utils
---
# **`{{ title }}`**
👍
::: {{ title }}
================================================
FILE: docs/assets/css-js/as-fastapi/chat.js
================================================
((window.gitter = {}).chat = {}).options = {
room: 'tiangolo/fastapi'
};
================================================
FILE: docs/assets/css-js/as-fastapi/custom.css
================================================
/* source: https: //github.com/tiangolo/fastapi/blob/1876ebc77949a9a254909ec61ea0c09365169ec2/docs/en/docs/css/custom.css */
.termynal-comment {
color: #4a968f;
font-style: italic;
display: block;
}
.termy [data-termynal] {
white-space: pre-wrap;
}
a.external-link::after {
/* \00A0 is a non-breaking space
to make the mark be on the same line as the link
*/
content: "\00A0[↪]";
}
a.internal-link::after {
/* \00A0 is a non-breaking space
to make the mark be on the same line as the link
*/
content: "\00A0↪";
}
.shadow {
box-shadow: 5px 5px 10px #999;
}
/* Give space to lower icons so Gitter chat doesn't get on top of them */
.md-footer-meta {
padding-bottom: 2em;
}
.user-list {
display: flex;
flex-wrap: wrap;
margin-bottom: 2rem;
}
.user-list-center {
justify-content: space-evenly;
}
.user {
margin: 1em;
min-width: 7em;
}
.user .avatar-wrapper {
width: 80px;
height: 80px;
margin: 10px auto;
overflow: hidden;
border-radius: 50%;
position: relative;
}
.user .avatar-wrapper img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.user .title {
text-align: center;
}
.user .count {
font-size: 80%;
text-align: center;
}
a.announce-link:link,
a.announce-link:visited {
color: #fff;
}
a.announce-link:hover {
color: var(--md-accent-fg-color);
}
.announce-wrapper {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
align-items: center;
}
.announce-wrapper div.item {
display: none;
}
.announce-wrapper .sponsor-badge {
display: block;
position: absolute;
top: -5px;
right: 0;
font-size: 0.5rem;
color: #999;
background-color: #666;
border-radius: 10px;
padding: 0 10px;
z-index: 10;
}
.announce-wrapper .sponsor-image {
display: block;
border-radius: 20px;
}
.announce-wrapper>div {
min-height: 40px;
display: flex;
align-items: center;
}
.twitter {
color: #00acee;
}
================================================
FILE: docs/assets/css-js/as-fastapi/custom.js
================================================
// source: https://github.com/tiangolo/fastapi/blob/1876ebc77949a9a254909ec61ea0c09365169ec2/docs/en/docs/js/custom.js
const div = document.querySelector('.github-topic-projects')
async function getDataBatch(page) {
const response = await fetch(`https://api.github.com/search/repositories?q=topic:fastapi&per_page=100&page=${page}`, { headers: { Accept: 'application/vnd.github.mercy-preview+json' } })
const data = await response.json()
return data
}
async function getData() {
let page = 1
let data = []
let dataBatch = await getDataBatch(page)
data = data.concat(dataBatch.items)
const totalCount = dataBatch.total_count
while (data.length < totalCount) {
page += 1
dataBatch = await getDataBatch(page)
data = data.concat(dataBatch.items)
}
return data
}
function setupTermynal() {
document.querySelectorAll(".use-termynal").forEach(node => {
node.style.display = "block";
new Termynal(node, {
lineDelay: 500
});
});
const progressLiteralStart = "---> 100%";
const promptLiteralStart = "$ ";
const customPromptLiteralStart = "# ";
const termynalActivateClass = "termy";
let termynals = [];
function createTermynals() {
document
.querySelectorAll(`.${termynalActivateClass} .highlight`)
.forEach(node => {
const text = node.textContent;
const lines = text.split("\n");
const useLines = [];
let buffer = [];
function saveBuffer() {
if (buffer.length) {
let isBlankSpace = true;
buffer.forEach(line => {
if (line) {
isBlankSpace = false;
}
});
dataValue = {};
if (isBlankSpace) {
dataValue["delay"] = 0;
}
if (buffer[buffer.length - 1] === "") {
// A last single text extraction.
let text = ""
for (let j = 0; j < parent.childNodes.length; j++) {
const subEl = parent.childNodes[j]
if (subEl.tagName.toLowerCase() === "code") {
for (let k = 0; k < subEl.childNodes.length; k++) {
const child = subEl.childNodes[k]
const whitespace = /^\s*$/
if (child.nodeName === "#text" && !(whitespace.test(child.nodeValue))) {
text = child.nodeValue
break
}
}
}
}
return text
}
// We use this to determine if we want the dark or light theme.
// This is specific for our MkDocs Material environment.
// You should load your configs based on your own environment's needs.
const defaultConfig = {
startOnLoad: false,
theme: "default",
flowchart: {
htmlLabels: false
},
er: {
useMaxWidth: false
},
sequence: {
useMaxWidth: false,
noteFontWeight: "14px",
actorFontSize: "14px",
messageFontSize: "16px"
}
}
mermaid.mermaidAPI.globalReset()
// Non Material themes should just use "default"
let scheme = null
try {
scheme = document.querySelector("[data-md-color-scheme]").getAttribute("data-md-color-scheme")
} catch (err) {
scheme = "default"
}
const config = (typeof mermaidConfig === "undefined") ?
defaultConfig :
mermaidConfig[scheme] || (mermaidConfig.default || defaultConfig)
mermaid.initialize(config)
// Find all of our Mermaid sources and render them.
const blocks = document.querySelectorAll(`pre.${className}, mermaid-div`)
const surrogate = document.querySelector("html")
for (let i = 0; i < blocks.length; i++) {
const block = blocks[i]
const parentEl = (block.tagName.toLowerCase() === "mermaid-div") ?
block.shadowRoot.querySelector(`pre.${className}`) :
block
// Create a temporary element with the typeset and size we desire.
// Insert it at the end of our parent to render the SVG.
const temp = document.createElement("div")
temp.style.visibility = "hidden"
temp.style.display = "display"
temp.style.padding = "0"
temp.style.margin = "0"
temp.style.lineHeight = "initial"
temp.style.fontSize = "16px"
surrogate.appendChild(temp)
try {
mermaid.mermaidAPI.render(
`_mermaid_${i}`,
getFromCode(parentEl),
content => {
const el = document.createElement("div")
el.className = className
el.innerHTML = content
// Insert the render where we want it and remove the original text source.
// Mermaid will clean up the temporary element.
const shadow = document.createElement("mermaid-div")
shadow.shadowRoot.appendChild(el)
block.parentNode.insertBefore(shadow, block)
parentEl.style.display = "none"
shadow.shadowRoot.appendChild(parentEl)
if (parentEl !== block) {
block.parentNode.removeChild(block)
}
},
temp
)
} catch (err) { } // eslint-disable-line no-empty
if (surrogate.contains(temp)) {
surrogate.removeChild(temp)
}
}
}
================================================
FILE: docs/assets/css-js/general/js/tables.js
================================================
document$.subscribe(function () {
var tables = document.querySelectorAll("article table")
tables.forEach(function (table) {
new Tablesort(table)
})
})
================================================
FILE: docs/assets/css-js/mkdocs-tooltips/css/custom.css
================================================
.tooltip {
cursor:default;
}
.icons {
margin: 0 auto !important;
}
.icons.position {
width: 240px; /* 3 * (10 + 60 + 10) */
}
.icons.color {
width: 325px; /* 4 * (10 + 60 + 10) + 5 (?) */
}
@media only screen and (max-width: 400px) {
.icons.color {
width: 165px; /* 2 * (10 + 60 + 10) + 5 (?) */
}
}
.icons span {
line-height: 60px;
display: inline-block;
cursor: default;
font-size: 60px;
margin: 10px;
padding: 0px;
width: 60px;
height: 60px;
text-align: center;
vertical-align: middle;
}
.md-button {
text-align: center;
margin: 10px;
}
.disabled {
cursor: not-allowed;
pointer-events: none;
}
================================================
FILE: docs/assets/css-js/pymdownx-extras/css/extra.css
================================================
@charset "UTF-8";
:root>* {
--md-code-link-bg-color: hsla(0, 0%, 96%, 1);
--md-code-link-accent-bg-color: var(--md-code-link-bg-color);
--md-default-bg-color--trans: rgb(100%, 100%, 100%, 0);
--md-code-special-bg-color: #e8e8e8;
--md-code-alternate-bg-color: var(--md-code-bg-color);
--md-code-hl-punctuation-color: var(--md-code-fg-color);
--md-code-hl-namespace-color: var(--md-code-fg-color);
--md-code-hl-entity-color: var(--md-code-hl-keyword-color);
--md-code-hl-tag-color: var(--md-code-hl-keyword-color);
--md-code-hl-builtin-color: var(--md-code-hl-constant-color);
--md-code-hl-class-color: var(--md-code-hl-function-color);
--md-typeset-a-color: #00bcd4;
--md-progress-stripe: var(--md-default-bg-color--lighter);
--md-progress-100: #00e676;
--md-progress-80: #00e676;
--md-progress-60: #fbc02d;
--md-progress-40: #ff9100;
--md-progress-20: #ff5252;
--md-progress-0: #ff1744;
--md-typeset-kbd-color: #ebebeb;
--md-typeset-kbd-border-color: #b8b8b8;
--md-typeset-kbd-accent-color: hsla(0, 100%, 100%, 1);
--md-default-bg-color--dark: #2b2e3b;
--md-default-bg-color--darker: #252732;
--md-default-bg-color--darkest: #1e2029;
--md-default-bg-color--ultra-dark: #111217
}
:root>[data-md-color-scheme=slate] {
--md-code-link-bg-color: hsla(232, 15%, 15%, 1);
--md-code-link-accent-bg-color: var(--md-code-link-bg-color);
--md-code-special-bg-color: #2b2d3b;
--md-default-bg-color--trans: hsla(232, 15%, 15%, 0);
--md-typeset-kbd-color: var(--md-default-fg-color--lightest);
--md-typeset-kbd-border-color: #1a1c24;
--md-typeset-kbd-accent-color: var(--md-default-fg-color--lighter)
}
:root>[data-md-color-scheme=dracula] {
--md-default-fg-color: rgba(248, 248, 242, 0.87);
--md-default-fg-color--light: rgba(248, 248, 242, 0.54);
--md-default-fg-color--lighter: rgba(248, 248, 242, 0.16);
--md-default-fg-color--lightest: rgba(248, 248, 242, 0.07);
--md-default-bg-color: var(--md-default-bg-color--darkest);
--md-default-bg-color--light: rgba(50, 52, 67, 0.7);
--md-default-bg-color--lighter: rgba(50, 52, 67, 0.3);
--md-default-bg-color--lightest: rgba(50, 52, 67, 0.12);
--md-default-bg-color--trans: rgba(50, 52, 67, 0);
--md-text-color: var(--md-default-fg-color);
--md-typeset-color: var(--md-default-fg-color);
--md-admonition-fg-color: var(--md-default-fg-color);
--md-code-fg-color: hsl(60deg, 30%, 96%);
--md-code-bg-color: hsl(231deg, 15%, 18%);
--md-code-inline-bg-color: #323443;
--md-code-hl-operator-color: hsl(326deg, 100%, 74%);
--md-code-hl-punctuation-color: hsl(60deg, 30%, 96%);
--md-code-hl-string-color: hsl(65deg, 92%, 76%);
--md-code-hl-special-color: hsl(265deg, 89%, 78%);
--md-code-hl-number-color: hsl(265deg, 89%, 78%);
--md-code-hl-keyword-color: hsl(326deg, 100%, 74%);
--md-code-hl-name-color: hsl(60deg, 30%, 96%);
--md-code-hl-constant-color: hsl(265deg, 89%, 78%);
--md-code-hl-function-color: hsl(135deg, 94%, 65%);
--md-code-hl-comment-color: hsl(225deg, 27%, 51%);
--md-code-hl-variable-color: hsl(31deg, 100%, 71%);
--md-code-hl-generic-color: hsl(225deg, 27%, 51%);
--md-code-hl-color: hsl(231deg, 25%, 25%);
--md-code-hl-entity-color: hsl(135deg, 94%, 65%);
--md-code-hl-tag-color: hsl(326deg, 100%, 74%);
--md-code-hl-namespace-color: hsl(60deg, 30%, 96%);
--md-code-hl-builtin-color: hsl(191deg, 97%, 77%);
--md-code-hl-class-color: hsl(191deg, 97%, 77%);
--md-code-special-bg-color: #1c1e26;
--md-code-alternate-bg-color: #3d3e49;
--md-code-link-bg-color: #364653;
--md-typeset-a-color: hsl(191deg, 97%, 77%);
--md-typeset-mark-color: #6e7252;
--md-typeset-del-color: #734568;
--md-typeset-ins-color: #36724e;
--md-progress-stripe: var(--md-default-bg-color--lightest);
--md-progress-100: hsl(135deg, 94%, 65%);
--md-progress-80: hsl(135deg, 92%, 79%);
--md-progress-60: hsl(65deg, 92%, 76%);
--md-progress-40: hsl(31deg, 100%, 71%);
--md-progress-20: hsl(326deg, 100%, 74%);
--md-progress-0: hsl(0deg, 100%, 67%);
--md-typeset-kbd-color: var(--md-default-fg-color--lightest);
--md-typeset-kbd-border-color: var(--md-default-bg-color--ultra-dark);
--md-typeset-kbd-accent-color: var(--md-default-fg-color--lighter)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=red],
[data-md-color-scheme=dracula][data-md-color-primary=red] {
--md-primary-code-bg-color: #47303a;
--md-primary-fg-color: hsla(0deg, 100%, 67%, 1);
--md-primary-fg-color--transparent: hsla(0deg, 100%, 67%, 0.1);
--md-primary-fg-color--light: hsla(0deg, 100%, 72%, 1);
--md-primary-fg-color--dark: hsla(0deg, 100%, 62%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=pink],
[data-md-color-scheme=dracula][data-md-color-primary=pink] {
--md-primary-code-bg-color: #47354b;
--md-primary-fg-color: hsla(326deg, 100%, 74%, 1);
--md-primary-fg-color--transparent: hsla(326deg, 100%, 74%, 0.1);
--md-primary-fg-color--light: hsla(326deg, 100%, 79%, 1);
--md-primary-fg-color--dark: hsla(326deg, 100%, 69%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=purple],
[data-md-color-scheme=dracula][data-md-color-primary=purple] {
--md-primary-code-bg-color: #3e3952;
--md-primary-fg-color: hsla(265deg, 89%, 78%, 1);
--md-primary-fg-color--transparent: hsla(265deg, 89%, 78%, 0.1);
--md-primary-fg-color--light: hsla(265deg, 89%, 83%, 1);
--md-primary-fg-color--dark: hsla(265deg, 89%, 73%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=deep-purple],
[data-md-color-scheme=dracula][data-md-color-primary=deep-purple] {
--md-primary-code-bg-color: #3e3952;
--md-primary-fg-color: hsla(265deg, 89%, 78%, 1);
--md-primary-fg-color--transparent: hsla(265deg, 89%, 78%, 0.1);
--md-primary-fg-color--light: hsla(265deg, 89%, 83%, 1);
--md-primary-fg-color--dark: hsla(265deg, 89%, 73%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=blue],
[data-md-color-scheme=dracula][data-md-color-primary=blue] {
--md-primary-code-bg-color: #303446;
--md-primary-fg-color: hsla(225deg, 27%, 51%, 1);
--md-primary-fg-color--transparent: hsla(225deg, 27%, 51%, 0.1);
--md-primary-fg-color--light: hsla(225deg, 27%, 56%, 1);
--md-primary-fg-color--dark: hsla(225deg, 27%, 46%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=indigo],
[data-md-color-scheme=dracula][data-md-color-primary=indigo] {
--md-primary-code-bg-color: #303446;
--md-primary-fg-color: hsla(225deg, 27%, 51%, 1);
--md-primary-fg-color--transparent: hsla(225deg, 27%, 51%, 0.1);
--md-primary-fg-color--light: hsla(225deg, 27%, 56%, 1);
--md-primary-fg-color--dark: hsla(225deg, 27%, 46%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=light-blue],
[data-md-color-scheme=dracula][data-md-color-primary=light-blue] {
--md-primary-code-bg-color: #303446;
--md-primary-fg-color: hsla(225deg, 27%, 51%, 1);
--md-primary-fg-color--transparent: hsla(225deg, 27%, 51%, 0.1);
--md-primary-fg-color--light: hsla(225deg, 27%, 56%, 1);
--md-primary-fg-color--dark: hsla(225deg, 27%, 46%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=cyan],
[data-md-color-scheme=dracula][data-md-color-primary=cyan] {
--md-primary-code-bg-color: #364653;
--md-primary-fg-color: hsla(191deg, 97%, 77%, 1);
--md-primary-fg-color--transparent: hsla(191deg, 97%, 77%, 0.1);
--md-primary-fg-color--light: hsla(191deg, 97%, 82%, 1);
--md-primary-fg-color--dark: hsla(191deg, 97%, 72%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=teal],
[data-md-color-scheme=dracula][data-md-color-primary=teal] {
--md-primary-code-bg-color: #364653;
--md-primary-fg-color: hsla(191deg, 97%, 77%, 1);
--md-primary-fg-color--transparent: hsla(191deg, 97%, 77%, 0.1);
--md-primary-fg-color--light: hsla(191deg, 97%, 82%, 1);
--md-primary-fg-color--dark: hsla(191deg, 97%, 72%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=green],
[data-md-color-scheme=dracula][data-md-color-primary=green] {
--md-primary-code-bg-color: #2d4840;
--md-primary-fg-color: hsla(135deg, 94%, 65%, 1);
--md-primary-fg-color--transparent: hsla(135deg, 94%, 65%, 0.1);
--md-primary-fg-color--light: hsla(135deg, 94%, 70%, 1);
--md-primary-fg-color--dark: hsla(135deg, 94%, 60%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=light-green],
[data-md-color-scheme=dracula][data-md-color-primary=light-green] {
--md-primary-code-bg-color: #2d4840;
--md-primary-fg-color: hsla(135deg, 94%, 65%, 1);
--md-primary-fg-color--transparent: hsla(135deg, 94%, 65%, 0.1);
--md-primary-fg-color--light: hsla(135deg, 94%, 70%, 1);
--md-primary-fg-color--dark: hsla(135deg, 94%, 60%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=lime],
[data-md-color-scheme=dracula][data-md-color-primary=lime] {
--md-primary-code-bg-color: #2d4840;
--md-primary-fg-color: hsla(135deg, 94%, 65%, 1);
--md-primary-fg-color--transparent: hsla(135deg, 94%, 65%, 0.1);
--md-primary-fg-color--light: hsla(135deg, 94%, 70%, 1);
--md-primary-fg-color--dark: hsla(135deg, 94%, 60%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=yellow],
[data-md-color-scheme=dracula][data-md-color-primary=yellow] {
--md-primary-code-bg-color: #454842;
--md-primary-fg-color: hsla(65deg, 92%, 76%, 1);
--md-primary-fg-color--transparent: hsla(65deg, 92%, 76%, 0.1);
--md-primary-fg-color--light: hsla(65deg, 92%, 81%, 1);
--md-primary-fg-color--dark: hsla(65deg, 92%, 71%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=amber],
[data-md-color-scheme=dracula][data-md-color-primary=amber] {
--md-primary-code-bg-color: #454842;
--md-primary-fg-color: hsla(65deg, 92%, 76%, 1);
--md-primary-fg-color--transparent: hsla(65deg, 92%, 76%, 0.1);
--md-primary-fg-color--light: hsla(65deg, 92%, 81%, 1);
--md-primary-fg-color--dark: hsla(65deg, 92%, 71%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=orange],
[data-md-color-scheme=dracula][data-md-color-primary=orange] {
--md-primary-code-bg-color: #473e3d;
--md-primary-fg-color: hsla(31deg, 100%, 71%, 1);
--md-primary-fg-color--transparent: hsla(31deg, 100%, 71%, 0.1);
--md-primary-fg-color--light: hsla(31deg, 100%, 76%, 1);
--md-primary-fg-color--dark: hsla(31deg, 100%, 66%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=deep-orange],
[data-md-color-scheme=dracula][data-md-color-primary=deep-orange] {
--md-primary-code-bg-color: #473e3d;
--md-primary-fg-color: hsla(31deg, 100%, 71%, 1);
--md-primary-fg-color--transparent: hsla(31deg, 100%, 71%, 0.1);
--md-primary-fg-color--light: hsla(31deg, 100%, 76%, 1);
--md-primary-fg-color--dark: hsla(31deg, 100%, 66%, 1);
--md-primary-bg-color: var(--md-default-bg-color);
--md-primary-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=red],
[data-md-color-scheme=dracula][data-md-color-accent=red] {
--md-code-link-accent-bg-color: #472c36;
--md-accent-fg-color: hsla(0deg, 100%, 62%, 1);
--md-accent-fg-color--transparent: hsla(0deg, 100%, 62%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=pink],
[data-md-color-scheme=dracula][data-md-color-accent=pink] {
--md-code-link-accent-bg-color: #473149;
--md-accent-fg-color: hsla(326deg, 100%, 69%, 1);
--md-accent-fg-color--transparent: hsla(326deg, 100%, 69%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=purple],
[data-md-color-scheme=dracula][data-md-color-accent=purple] {
--md-code-link-accent-bg-color: #3c3652;
--md-accent-fg-color: hsla(265deg, 89%, 73%, 1);
--md-accent-fg-color--transparent: hsla(265deg, 89%, 73%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=deep-purple],
[data-md-color-scheme=dracula][data-md-color-accent=deep-purple] {
--md-code-link-accent-bg-color: #3c3652;
--md-accent-fg-color: hsla(265deg, 89%, 73%, 1);
--md-accent-fg-color--transparent: hsla(265deg, 89%, 73%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=blue],
[data-md-color-scheme=dracula][data-md-color-accent=blue] {
--md-code-link-accent-bg-color: #2e3243;
--md-accent-fg-color: hsla(225deg, 27%, 46%, 1);
--md-accent-fg-color--transparent: hsla(225deg, 27%, 46%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=indigo],
[data-md-color-scheme=dracula][data-md-color-accent=indigo] {
--md-code-link-accent-bg-color: #2e3243;
--md-accent-fg-color: hsla(225deg, 27%, 46%, 1);
--md-accent-fg-color--transparent: hsla(225deg, 27%, 46%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=light-blue],
[data-md-color-scheme=dracula][data-md-color-accent=light-blue] {
--md-code-link-accent-bg-color: #2e3243;
--md-accent-fg-color: hsla(225deg, 27%, 46%, 1);
--md-accent-fg-color--transparent: hsla(225deg, 27%, 46%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=cyan],
[data-md-color-scheme=dracula][data-md-color-accent=cyan] {
--md-code-link-accent-bg-color: #324553;
--md-accent-fg-color: hsla(191deg, 97%, 72%, 1);
--md-accent-fg-color--transparent: hsla(191deg, 97%, 72%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=teal],
[data-md-color-scheme=dracula][data-md-color-accent=teal] {
--md-code-link-accent-bg-color: #324553;
--md-accent-fg-color: hsla(191deg, 97%, 72%, 1);
--md-accent-fg-color--transparent: hsla(191deg, 97%, 72%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=green],
[data-md-color-scheme=dracula][data-md-color-accent=green] {
--md-code-link-accent-bg-color: #2a483d;
--md-accent-fg-color: hsla(135deg, 94%, 60%, 1);
--md-accent-fg-color--transparent: hsla(135deg, 94%, 60%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=light-green],
[data-md-color-scheme=dracula][data-md-color-accent=light-green] {
--md-code-link-accent-bg-color: #2a483d;
--md-accent-fg-color: hsla(135deg, 94%, 60%, 1);
--md-accent-fg-color--transparent: hsla(135deg, 94%, 60%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=lime],
[data-md-color-scheme=dracula][data-md-color-accent=lime] {
--md-code-link-accent-bg-color: #2a483d;
--md-accent-fg-color: hsla(135deg, 94%, 60%, 1);
--md-accent-fg-color--transparent: hsla(135deg, 94%, 60%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=yellow],
[data-md-color-scheme=dracula][data-md-color-accent=yellow] {
--md-code-link-accent-bg-color: #45483e;
--md-accent-fg-color: hsla(65deg, 92%, 71%, 1);
--md-accent-fg-color--transparent: hsla(65deg, 92%, 71%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=amber],
[data-md-color-scheme=dracula][data-md-color-accent=amber] {
--md-code-link-accent-bg-color: #45483e;
--md-accent-fg-color: hsla(65deg, 92%, 71%, 1);
--md-accent-fg-color--transparent: hsla(65deg, 92%, 71%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=orange],
[data-md-color-scheme=dracula][data-md-color-accent=orange] {
--md-code-link-accent-bg-color: #473d39;
--md-accent-fg-color: hsla(31deg, 100%, 66%, 1);
--md-accent-fg-color--transparent: hsla(31deg, 100%, 66%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] :not([data-md-color-scheme])[data-md-color-primary=deep-orange],
[data-md-color-scheme=dracula][data-md-color-accent=deep-orange] {
--md-code-link-accent-bg-color: #473d39;
--md-accent-fg-color: hsla(31deg, 100%, 66%, 1);
--md-accent-fg-color--transparent: hsla(31deg, 100%, 66%, 0.1);
--md-accent-bg-color: var(--md-default-bg-color);
--md-accent-bg-color--light: var(--md-default-bg-color--light)
}
:root {
--md-heart: #ff5252;
--md-heart-big: #ff1744
}
:root [data-md-color-scheme=dracula] {
--md-heart: hsl(326deg, 100%, 74%);
--md-heart-big: hsl(0deg, 100%, 67%)
}
.md-typeset a.source-link {
position: relative;
top: -.6rem;
float: right;
color: var(--md-default-fg-color--lighter);
transition: color 125ms
}
.md-typeset a.source-link:hover {
color: var(--md-accent-fg-color)
}
.md-typeset a.source-link .twemoji {
height: 1.2rem
}
.md-typeset a.source-link .twemoji svg {
width: 1.2rem;
height: 1.2rem
}
.md-typeset div.highlight.md-max-height pre>code {
max-height: 15rem
}
.twemoji.heart-throb svg,
.twemoji.heart-throb-hover svg {
position: relative;
color: var(--md-heart);
-webkit-animation: pulse 1.5s ease infinite;
animation: pulse 1.5s ease infinite
}
@-webkit-keyframes pulse {
0% {
transform: scale(1)
}
40% {
color: var(--md-heart-big);
transform: scale(1.3)
}
50% {
transform: scale(1.2)
}
60% {
color: var(--md-heart-big);
transform: scale(1.3)
}
100% {
transform: scale(1)
}
}
@keyframes pulse {
0% {
transform: scale(1)
}
40% {
color: var(--md-heart-big);
transform: scale(1.3)
}
50% {
transform: scale(1.2)
}
60% {
color: var(--md-heart-big);
transform: scale(1.3)
}
100% {
transform: scale(1)
}
}
footer.sponsorship {
text-align: center
}
footer.sponsorship hr {
display: inline-block;
width: 1.6rem;
margin: 0 .7rem;
vertical-align: middle;
border-bottom: 2px solid var(--md-default-fg-color--lighter)
}
footer.sponsorship:hover hr {
border-color: var(--md-accent-fg-color)
}
footer.sponsorship:not(:hover) .twemoji.heart-throb-hover svg {
color: var(--md-default-fg-color--lighter) !important
}
body:not([data-md-prefers-color-scheme=true])[data-md-color-scheme=dracula] .md-icon .light-mode,
body:not([data-md-prefers-color-scheme=true])[data-md-color-scheme=dracula] .md-icon .system-mode,
body:not([data-md-prefers-color-scheme=true])[data-md-color-scheme=dracula] .md-icon .unknown-mode {
display: none
}
body:not([data-md-prefers-color-scheme=true])[data-md-color-scheme=default] .md-icon .dark-mode,
body:not([data-md-prefers-color-scheme=true])[data-md-color-scheme=default] .md-icon .system-mode,
body:not([data-md-prefers-color-scheme=true])[data-md-color-scheme=default] .md-icon .unknown-mode {
display: none
}
body:not([data-md-prefers-color-scheme=true]):not([data-md-color-scheme=default]):not([data-md-color-scheme=dracula]) .md-icon .dark-mode,
body:not([data-md-prefers-color-scheme=true]):not([data-md-color-scheme=default]):not([data-md-color-scheme=dracula]) .md-icon .light-mode,
body:not([data-md-prefers-color-scheme=true]):not([data-md-color-scheme=default]):not([data-md-color-scheme=dracula]) .md-icon .system-mode {
display: none
}
body[data-md-prefers-color-scheme=true] .md-icon .dark-mode,
body[data-md-prefers-color-scheme=true] .md-icon .light-mode,
body[data-md-prefers-color-scheme=true] .md-icon .unknown-mode {
display: none
}
.md-header-nav__scheme {
z-index: 0
}
[data-md-toggle=search]:checked~.md-header .md-header-nav__scheme {
display: none
}
:root>* {
--md-admonition-bg-color: transparent;
--md-admonition-icon--settings: url('data:image/svg+xml;charset=utf-8,');
--md-admonition-bg-color--settings: rgba(170, 0, 255, 0.1);
--md-admonition-icon-color--settings: #aa00ff;
--md-admonition-icon--new: url('data:image/svg+xml;charset=utf-8,');
--md-admonition-bg-color--new: rgba(255, 214, 0, 0.1);
--md-admonition-icon-color--new: #ffd600;
--md-admonition-bg-color--note: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--note: hsl(51deg, 94%, 73%);
--md-admonition-bg-color--abstract: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--abstract: hsl(191deg, 97%, 77%);
--md-admonition-bg-color--info: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--info: hsl(190deg, 94%, 87%);
--md-admonition-bg-color--tip: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--tip: hsl(161deg, 97%, 77%);
--md-admonition-bg-color--success: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--success: hsl(135deg, 94%, 65%);
--md-admonition-bg-color--question: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--question: hsl(135deg, 92%, 79%);
--md-admonition-bg-color--warning: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--warning: hsl(31deg, 100%, 71%);
--md-admonition-bg-color--failure: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--failure: hsl(0deg, 100%, 59%);
--md-admonition-bg-color--danger: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--danger: hsl(0deg, 100%, 67%);
--md-admonition-bg-color--bug: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--bug: hsl(325deg, 100%, 64%);
--md-admonition-bg-color--example: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--example: hsl(265deg, 89%, 78%);
--md-admonition-bg-color--quote: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--quote: hsl(225deg, 8%, 51%)
}
:root>[data-md-color-scheme=dracula] {
--md-admonition-icon-color: $drac-dark-yellow
}
:root>[data-md-color-scheme=dracula] {
--md-admonition-bg-color--settings: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--settings: hsl(326deg, 100%, 74%)
}
:root>[data-md-color-scheme=dracula] {
--md-admonition-bg-color--new: var(--md-default-bg-color--ultra-dark);
--md-admonition-icon-color--new: hsl(65deg, 92%, 76%)
}
[data-md-color-scheme=dracula] .md-typeset .admonition,
[data-md-color-scheme=dracula] .md-typeset details {
border-color: var(--md-admonition-icon-color--note);
box-shadow: 0 .2rem .5rem hsla(0deg, 0%, 0%, .3), 0 0 .05rem hsla(0deg, 0%, 0%, .2)
}
[data-md-color-scheme=dracula] .md-typeset .admonition>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details>summary {
background-color: var(--md-admonition-bg-color--note);
border-color: var(--md-admonition-icon-color--note);
border-left: .2rem solid
}
[data-md-color-scheme=dracula] .md-typeset .admonition>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details>summary::before {
background-color: var(--md-admonition-icon-color--note)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.note,
[data-md-color-scheme=dracula] .md-typeset details.note {
border-color: var(--md-admonition-icon-color--note)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.note>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.note>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.note>summary {
background-color: var(--md-admonition-bg-color--note);
border-color: var(--md-admonition-icon-color--note)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.note>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.note>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.note>summary::before {
background-color: var(--md-admonition-icon-color--note)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.abstract,
[data-md-color-scheme=dracula] .md-typeset .admonition.summary,
[data-md-color-scheme=dracula] .md-typeset .admonition.tldr,
[data-md-color-scheme=dracula] .md-typeset details.abstract,
[data-md-color-scheme=dracula] .md-typeset details.summary,
[data-md-color-scheme=dracula] .md-typeset details.tldr {
border-color: var(--md-admonition-icon-color--abstract)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.abstract>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.summary>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.tldr>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.abstract>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.abstract>summary,
[data-md-color-scheme=dracula] .md-typeset details.summary>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.summary>summary,
[data-md-color-scheme=dracula] .md-typeset details.tldr>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.tldr>summary {
background-color: var(--md-admonition-bg-color--abstract);
border-color: var(--md-admonition-icon-color--abstract)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.abstract>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.summary>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.tldr>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.abstract>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.abstract>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.summary>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.summary>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.tldr>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.tldr>summary::before {
background-color: var(--md-admonition-icon-color--abstract)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.info,
[data-md-color-scheme=dracula] .md-typeset .admonition.todo,
[data-md-color-scheme=dracula] .md-typeset details.info,
[data-md-color-scheme=dracula] .md-typeset details.todo {
border-color: var(--md-admonition-icon-color--info)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.info>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.todo>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.info>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.info>summary,
[data-md-color-scheme=dracula] .md-typeset details.todo>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.todo>summary {
background-color: var(--md-admonition-bg-color--info);
border-color: var(--md-admonition-icon-color--info)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.info>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.todo>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.info>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.info>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.todo>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.todo>summary::before {
background-color: var(--md-admonition-icon-color--info)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.hint,
[data-md-color-scheme=dracula] .md-typeset .admonition.important,
[data-md-color-scheme=dracula] .md-typeset .admonition.tip,
[data-md-color-scheme=dracula] .md-typeset details.hint,
[data-md-color-scheme=dracula] .md-typeset details.important,
[data-md-color-scheme=dracula] .md-typeset details.tip {
border-color: var(--md-admonition-icon-color--tip)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.hint>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.important>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.tip>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.hint>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.hint>summary,
[data-md-color-scheme=dracula] .md-typeset details.important>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.important>summary,
[data-md-color-scheme=dracula] .md-typeset details.tip>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.tip>summary {
background-color: var(--md-admonition-bg-color--tip);
border-color: var(--md-admonition-icon-color--tip)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.hint>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.important>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.tip>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.hint>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.hint>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.important>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.important>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.tip>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.tip>summary::before {
background-color: var(--md-admonition-icon-color--tip)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.check,
[data-md-color-scheme=dracula] .md-typeset .admonition.done,
[data-md-color-scheme=dracula] .md-typeset .admonition.success,
[data-md-color-scheme=dracula] .md-typeset details.check,
[data-md-color-scheme=dracula] .md-typeset details.done,
[data-md-color-scheme=dracula] .md-typeset details.success {
border-color: var(--md-admonition-icon-color--success)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.check>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.done>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.success>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.check>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.check>summary,
[data-md-color-scheme=dracula] .md-typeset details.done>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.done>summary,
[data-md-color-scheme=dracula] .md-typeset details.success>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.success>summary {
background-color: var(--md-admonition-bg-color--success);
border-color: var(--md-admonition-icon-color--success)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.check>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.done>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.success>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.check>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.check>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.done>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.done>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.success>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.success>summary::before {
background-color: var(--md-admonition-icon-color--success)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.faq,
[data-md-color-scheme=dracula] .md-typeset .admonition.help,
[data-md-color-scheme=dracula] .md-typeset .admonition.question,
[data-md-color-scheme=dracula] .md-typeset details.faq,
[data-md-color-scheme=dracula] .md-typeset details.help,
[data-md-color-scheme=dracula] .md-typeset details.question {
border-color: var(--md-admonition-icon-color--question)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.faq>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.help>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.question>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.faq>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.faq>summary,
[data-md-color-scheme=dracula] .md-typeset details.help>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.help>summary,
[data-md-color-scheme=dracula] .md-typeset details.question>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.question>summary {
background-color: var(--md-admonition-bg-color--question);
border-color: var(--md-admonition-icon-color--question)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.faq>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.help>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.question>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.faq>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.faq>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.help>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.help>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.question>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.question>summary::before {
background-color: var(--md-admonition-icon-color--question)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.attention,
[data-md-color-scheme=dracula] .md-typeset .admonition.caution,
[data-md-color-scheme=dracula] .md-typeset .admonition.warning,
[data-md-color-scheme=dracula] .md-typeset details.attention,
[data-md-color-scheme=dracula] .md-typeset details.caution,
[data-md-color-scheme=dracula] .md-typeset details.warning {
border-color: var(--md-admonition-icon-color--warning)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.attention>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.caution>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.warning>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.attention>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.attention>summary,
[data-md-color-scheme=dracula] .md-typeset details.caution>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.caution>summary,
[data-md-color-scheme=dracula] .md-typeset details.warning>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.warning>summary {
background-color: var(--md-admonition-bg-color--warning);
border-color: var(--md-admonition-icon-color--warning)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.attention>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.caution>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.warning>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.attention>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.attention>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.caution>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.caution>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.warning>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.warning>summary::before {
background-color: var(--md-admonition-icon-color--warning)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.fail,
[data-md-color-scheme=dracula] .md-typeset .admonition.failure,
[data-md-color-scheme=dracula] .md-typeset .admonition.missing,
[data-md-color-scheme=dracula] .md-typeset details.fail,
[data-md-color-scheme=dracula] .md-typeset details.failure,
[data-md-color-scheme=dracula] .md-typeset details.missing {
border-color: var(--md-admonition-icon-color--failure)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.fail>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.failure>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.missing>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.fail>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.fail>summary,
[data-md-color-scheme=dracula] .md-typeset details.failure>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.failure>summary,
[data-md-color-scheme=dracula] .md-typeset details.missing>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.missing>summary {
background-color: var(--md-admonition-bg-color--failure);
border-color: var(--md-admonition-icon-color--failure)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.fail>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.failure>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.missing>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.fail>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.fail>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.failure>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.failure>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.missing>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.missing>summary::before {
background-color: var(--md-admonition-icon-color--failure)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.danger,
[data-md-color-scheme=dracula] .md-typeset .admonition.error,
[data-md-color-scheme=dracula] .md-typeset details.danger,
[data-md-color-scheme=dracula] .md-typeset details.error {
border-color: var(--md-admonition-icon-color--danger)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.danger>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.error>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.danger>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.danger>summary,
[data-md-color-scheme=dracula] .md-typeset details.error>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.error>summary {
background-color: var(--md-admonition-bg-color--danger);
border-color: var(--md-admonition-icon-color--danger)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.danger>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.error>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.danger>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.danger>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.error>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.error>summary::before {
background-color: var(--md-admonition-icon-color--danger)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.bug,
[data-md-color-scheme=dracula] .md-typeset details.bug {
border-color: var(--md-admonition-icon-color--bug)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.bug>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.bug>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.bug>summary {
background-color: var(--md-admonition-bg-color--bug);
border-color: var(--md-admonition-icon-color--bug)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.bug>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.bug>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.bug>summary::before {
background-color: var(--md-admonition-icon-color--bug)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.example,
[data-md-color-scheme=dracula] .md-typeset details.example {
border-color: var(--md-admonition-icon-color--example)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.example>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.example>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.example>summary {
background-color: var(--md-admonition-bg-color--example);
border-color: var(--md-admonition-icon-color--example)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.example>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.example>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.example>summary::before {
background-color: var(--md-admonition-icon-color--example)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.cite,
[data-md-color-scheme=dracula] .md-typeset .admonition.quote,
[data-md-color-scheme=dracula] .md-typeset details.cite,
[data-md-color-scheme=dracula] .md-typeset details.quote {
border-color: var(--md-admonition-icon-color--quote)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.cite>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset .admonition.quote>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.cite>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.cite>summary,
[data-md-color-scheme=dracula] .md-typeset details.quote>.admonition-title,
[data-md-color-scheme=dracula] .md-typeset details.quote>summary {
background-color: var(--md-admonition-bg-color--quote);
border-color: var(--md-admonition-icon-color--quote)
}
[data-md-color-scheme=dracula] .md-typeset .admonition.cite>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset .admonition.quote>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.cite>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.cite>summary::before,
[data-md-color-scheme=dracula] .md-typeset details.quote>.admonition-title::before,
[data-md-color-scheme=dracula] .md-typeset details.quote>summary::before {
background-color: var(--md-admonition-icon-color--quote)
}
.md-typeset .admonition.config,
.md-typeset .admonition.settings,
.md-typeset details.config,
.md-typeset details.settings {
border-color: var(--md-admonition-icon-color--settings)
}
.md-typeset .admonition.config>.admonition-title,
.md-typeset .admonition.settings>.admonition-title,
.md-typeset details.config>.admonition-title,
.md-typeset details.config>summary,
.md-typeset details.settings>.admonition-title,
.md-typeset details.settings>summary {
background-color: var(--md-admonition-bg-color--settings);
border-color: var(--md-admonition-icon-color--settings)
}
.md-typeset .admonition.config>.admonition-title::before,
.md-typeset .admonition.settings>.admonition-title::before,
.md-typeset details.config>.admonition-title::before,
.md-typeset details.config>summary::before,
.md-typeset details.settings>.admonition-title::before,
.md-typeset details.settings>summary::before {
width: 1rem;
height: 1rem;
background-color: var(--md-admonition-icon-color--settings);
background-size: 1rem;
-webkit-mask-image: var(--md-admonition-icon--settings);
mask-image: var(--md-admonition-icon--settings);
content: " "
}
.md-typeset .admonition.new,
.md-typeset details.new {
border-color: var(--md-admonition-icon-color--new)
}
.md-typeset .admonition.new>.admonition-title,
.md-typeset details.new>.admonition-title,
.md-typeset details.new>summary {
background-color: var(--md-admonition-bg-color--new);
border-color: var(--md-admonition-icon-color--new)
}
.md-typeset .admonition.new>.admonition-title::before,
.md-typeset details.new>.admonition-title::before,
.md-typeset details.new>summary::before {
width: 1rem;
height: 1rem;
background-color: var(--md-admonition-icon-color--new);
background-size: 1rem;
-webkit-mask-image: var(--md-admonition-icon--new);
mask-image: var(--md-admonition-icon--new);
content: " "
}
mjx-container[display=true] {
font-size: 120% !important
}
mjx-container:not([display]) {
font-size: 100% !important
}
[data-md-color-scheme=dracula] .CtxtMenu_InfoContent pre,
[data-md-color-scheme=dracula] .CtxtMenu_InfoSignature input,
[data-md-color-scheme=slate] .CtxtMenu_InfoContent pre,
[data-md-color-scheme=slate] .CtxtMenu_InfoSignature input {
color: #000
}
[data-md-color-scheme=dracula] .CtxtMenu_Info,
[data-md-color-scheme=dracula] .CtxtMenu_Menu,
[data-md-color-scheme=slate] .CtxtMenu_Info,
[data-md-color-scheme=slate] .CtxtMenu_Menu {
box-shadow: 0 10px 20px rgba(0, 0, 0, .5)
}
.md-typeset .arithmatex {
overflow-x: auto !important;
overflow-y: hidden !important
}
.katex-display .katex-html {
display: flex !important;
flex-direction: row;
flex-wrap: nowrap;
align-items: baseline;
justify-content: space-between
}
.katex-display .katex-html .base {
display: inline !important
}
.katex-display .katex-html .tag {
position: relative !important;
display: inline !important;
margin-left: var(--margin-small)
}
.md-typeset del.critic,
.md-typeset ins.critic,
.md-typeset mark.critic {
padding: 0 .25em;
color: unset;
box-shadow: none
}
.md-typeset .critic.break {
margin: 0
}
.md-typeset details {
overflow: hidden
}
.md-typeset details>summary:focus {
outline-style: none
}
.highlight .kc {
color: var(--md-code-hl-constant-color)
}
.highlight .nc,
.highlight .ne {
color: var(--md-code-hl-class-color)
}
.highlight .mb {
color: var(--md-code-hl-number-color)
}
.highlight .bp,
.highlight .nb {
color: var(--md-code-hl-builtin-color)
}
.highlight .nn {
color: var(--md-code-hl-namespace-color)
}
.highlight .na,
.highlight .nd,
.highlight .ni {
color: var(--md-code-hl-entity-color)
}
.highlight .nl,
.highlight .nt {
color: var(--md-code-hl-tag-color)
}
.md-typeset :not(pre)>code {
margin: 0;
padding: 0 .2941176471em;
color: var(--md-code-fg-color);
background-color: var(--md-code-inline-bg-color);
border-radius: .1rem;
box-shadow: none
}
.md-typeset a>code {
color: inherit !important;
background-color: var(--md-code-link-bg-color) !important;
transition: color 125ms;
transition: background-color 125ms
}
.md-typeset a>code * {
color: var(--md-typeset-a-color) !important
}
.md-typeset a>code:hover {
background-color: var(--md-code-link-accent-bg-color) !important
}
.md-typeset a>code:hover * {
color: var(--md-accent-fg-color) !important
}
.md-typeset pre>code {
outline: 0
}
.md-typeset td code {
word-break: normal
}
.md-typeset .highlight {
-moz-tab-size: 8;
-o-tab-size: 8;
tab-size: 8
}
.md-typeset .highlight [data-linenos].special::before {
background-color: var(--md-code-special-bg-color)
}
.md-typeset .highlighttable .linenodiv .special {
margin-right: -.5882352941em;
margin-left: -1.1764705882em;
padding-right: .5882352941em;
padding-left: 1.1764705882em;
background-color: var(--md-code-special-bg-color)
}
.md-typeset .highlight span.filename {
position: relative;
display: block;
margin-top: 1em;
padding: .5em 1.1764705882em .5em 2.9411764706em;
font-weight: 700;
font-size: .68rem;
background-color: var(--md-default-bg-color--ultra-dark);
border-top-left-radius: .1rem;
border-top-right-radius: .1rem
}
.md-typeset .highlight span.filename+pre {
margin-top: 0
}
.md-typeset .highlight span.filename+pre code {
border-top-left-radius: 0;
border-top-right-radius: 0
}
.md-typeset .highlight span.filename::before {
position: absolute;
left: .8823529412em;
width: 1.4705882353em;
height: 1.4705882353em;
background-color: var(--md-default-fg-color);
-webkit-mask-image: url('data:image/svg+xml;charset=utf-8,');
mask-image: url('data:image/svg+xml;charset=utf-8,');
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: contain;
mask-size: contain;
content: ""
}
.md-typeset .keys .key-power::before {
padding-right: .4em;
content: "⏻"
}
.md-typeset .keys .key-fingerprint::before {
padding-right: .4em;
content: "☝"
}
:root>* {
--magiclink-email-icon: url('data:image/svg+xml;charset=utf-8,');
--magiclink-github-icon: url('data:image/svg+xml;charset=utf-8,');
--magiclink-bitbucket-icon: url('data:image/svg+xml;charset=utf-8,');
--magiclink-gitlab-icon: url('data:image/svg+xml;charset=utf-8,');
--magiclink-commit-icon: url('data:image/svg+xml;charset=utf-8,');
--magiclink-compare-icon: url('data:image/svg+xml;charset=utf-8,');
--magiclink-pull-icon: url('data:image/svg+xml;charset=utf-8,');
--magiclink-issue-icon: url('data:image/svg+xml;charset=utf-8,');
--magiclink-discussion-icon: url('data:image/svg+xml;charset=utf-8,')
}
.md-typeset a[href^="mailto:"]:not(.magiclink-ignore)::before {
-webkit-mask-image: var(--magiclink-email-icon);
mask-image: var(--magiclink-email-icon)
}
.md-typeset .magiclink-commit:not(.magiclink-ignore),
.md-typeset .magiclink-compare:not(.magiclink-ignore),
.md-typeset .magiclink-discussion:not(.magiclink-ignore),
.md-typeset .magiclink-issue:not(.magiclink-ignore),
.md-typeset .magiclink-pull:not(.magiclink-ignore),
.md-typeset .magiclink-repository:not(.magiclink-ignore),
.md-typeset a[href^="mailto:"]:not(.magiclink-ignore) {
position: relative;
padding-left: 1.375em
}
.md-typeset .magiclink-commit:not(.magiclink-ignore)::before,
.md-typeset .magiclink-compare:not(.magiclink-ignore)::before,
.md-typeset .magiclink-discussion:not(.magiclink-ignore)::before,
.md-typeset .magiclink-issue:not(.magiclink-ignore)::before,
.md-typeset .magiclink-pull:not(.magiclink-ignore)::before,
.md-typeset .magiclink-repository:not(.magiclink-ignore)::before,
.md-typeset a[href^="mailto:"]:not(.magiclink-ignore)::before {
position: absolute;
top: 0;
left: 0;
display: block;
box-sizing: border-box;
width: 1.25em;
height: 1.25em;
background-color: var(--md-typeset-a-color);
background-size: 1.25em;
transition: background-color 125ms;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: contain;
mask-size: contain;
content: ""
}
.md-typeset .magiclink-commit:not(.magiclink-ignore):hover::before,
.md-typeset .magiclink-compare:not(.magiclink-ignore):hover::before,
.md-typeset .magiclink-discussion:not(.magiclink-ignore):hover::before,
.md-typeset .magiclink-issue:not(.magiclink-ignore):hover::before,
.md-typeset .magiclink-pull:not(.magiclink-ignore):hover::before,
.md-typeset .magiclink-repository:not(.magiclink-ignore):hover::before,
.md-typeset a[href^="mailto:"]:not(.magiclink-ignore):hover::before {
background-color: var(--md-accent-fg-color)
}
.md-typeset .magiclink-commit:not(.magiclink-ignore)::before {
-webkit-mask-image: var(--magiclink-commit-icon);
mask-image: var(--magiclink-commit-icon)
}
.md-typeset .magiclink-compare:not(.magiclink-ignore)::before {
-webkit-mask-image: var(--magiclink-compare-icon);
mask-image: var(--magiclink-compare-icon)
}
.md-typeset .magiclink-pull:not(.magiclink-ignore)::before {
-webkit-mask-image: var(--magiclink-pull-icon);
mask-image: var(--magiclink-pull-icon)
}
.md-typeset .magiclink-issue:not(.magiclink-ignore)::before {
-webkit-mask-image: var(--magiclink-issue-icon);
mask-image: var(--magiclink-issue-icon)
}
.md-typeset .magiclink-discussion:not(.magiclink-ignore)::before {
-webkit-mask-image: var(--magiclink-discussion-icon);
mask-image: var(--magiclink-discussion-icon)
}
.md-typeset .magiclink-repository.magiclink-github:not(.magiclink-ignore)::before {
-webkit-mask-image: var(--magiclink-github-icon);
mask-image: var(--magiclink-github-icon)
}
.md-typeset .magiclink-repository.magiclink-gitlab:not(.magiclink-ignore)::before {
-webkit-mask-image: var(--magiclink-gitlab-icon);
mask-image: var(--magiclink-gitlab-icon)
}
.md-typeset .magiclink-repository.magiclink-bitbucket:not(.magiclink-ignore)::before {
-webkit-mask-image: var(--magiclink-bitbucket-icon);
mask-image: var(--magiclink-bitbucket-icon)
}
.md-typeset mark:not(.critic) {
padding: 0 .25em;
box-shadow: none
}
.md-typeset .progress-label {
position: absolute;
width: 100%;
margin: 0;
color: var(--md-text-color);
font-weight: 700;
line-height: 1.4rem;
white-space: nowrap;
text-align: center;
text-shadow: -.0625em -.0625em .375em var(--md-default-bg-color--light), .0625em -.0625em .375em var(--md-default-bg-color--light), -.0625em .0625em .375em var(--md-default-bg-color--light), .0625em .0625em .375em var(--md-default-bg-color--light)
}
.md-typeset .progress-bar {
float: left;
height: 1.2rem;
background-color: #2979ff
}
.md-typeset .candystripe-animate .progress-bar {
-webkit-animation: animate-stripes 3s linear infinite;
animation: animate-stripes 3s linear infinite
}
.md-typeset .progress {
position: relative;
display: block;
width: 100%;
height: 1.2rem;
margin: .5rem 0;
background-color: var(--md-default-fg-color--lightest)
}
.md-typeset .progress.thin {
height: .4rem;
margin-top: .9rem
}
.md-typeset .progress.thin .progress-label {
margin-top: -.4rem
}
.md-typeset .progress.thin .progress-bar {
height: .4rem
}
.md-typeset .progress.candystripe .progress-bar {
background-image: linear-gradient(135deg, var(--md-progress-stripe) 27%, transparent 27%, transparent 52%, var(--md-progress-stripe) 52%, var(--md-progress-stripe) 77%, transparent 77%, transparent);
background-size: 2rem 2rem
}
.md-typeset .progress-100plus .progress-bar {
background-color: var(--md-progress-100)
}
.md-typeset .progress-80plus .progress-bar {
background-color: var(--md-progress-80)
}
.md-typeset .progress-60plus .progress-bar {
background-color: var(--md-progress-60)
}
.md-typeset .progress-40plus .progress-bar {
background-color: var(--md-progress-40)
}
.md-typeset .progress-20plus .progress-bar {
background-color: var(--md-progress-20)
}
.md-typeset .progress-0plus .progress-bar {
background-color: var(--md-progress-0)
}
@-webkit-keyframes animate-stripes {
0% {
background-position: 0 0
}
100% {
background-position: 6rem 0
}
}
@keyframes animate-stripes {
0% {
background-position: 0 0
}
100% {
background-position: 6rem 0
}
}
[data-md-color-scheme=dracula] .md-typeset .tabbed-set>.tabbed-labels {
box-shadow: 0 -.05rem var(--md-default-fg-color--lighter) inset
}
.md-typeset .tabbed-alternate.tabbed-set .tabbed-control {
width: 2rem
}
.md-typeset .tabbed-alternate.tabbed-set .tabbed-control[hidden] {
width: 1.2rem;
opacity: 0
}
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block {
padding: 0 .6rem;
overflow: hidden
}
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block>.codehilite:only-child,
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block>.codehilitetable:only-child,
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block>.highlight:only-child,
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block>.highlighttable:only-child,
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block>pre:only-child {
margin-right: -1.2rem;
margin-left: -1.2rem;
padding-right: .6rem;
padding-left: .6rem
}
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block>.codehilite:only-child span.filename,
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block>.codehilitetable:only-child span.filename,
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block>.highlight:only-child span.filename,
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block>.highlighttable:only-child span.filename,
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block>pre:only-child span.filename {
margin-top: 0
}
.md-typeset .tabbed-alternate.tabbed-set>.tabbed-content>.tabbed-block>mermaid-div:only-child {
margin-right: -1.2rem;
margin-left: -1.2rem;
padding-right: .6rem;
padding-left: .6rem
}
[data-md-color-scheme=dracula] .md-typeset table:not([class]) {
box-shadow: 0 .2rem .5rem hsla(0deg, 0%, 0%, .3), 0 0 .05rem hsla(0deg, 0%, 0%, .2)
}
[data-md-color-scheme=dracula] .md-typeset table:not([class]) tr:hover {
background-color: rgba(0, 0, 0, .08)
}
[data-md-color-scheme=dracula] .md-typeset table:not([class]) th {
color: var(--md-text-color);
background-color: var(--md-default-bg-color--ultra-dark);
border-bottom: .05rem solid var(--md-primary-fg-color)
}
[data-md-color-scheme=dracula] .md-typeset table:not([class]) td {
border-top: .05rem solid var(--md-default-fg-color--lighter)
}
[data-md-color-scheme=dracula] .md-typeset .task-list-control .task-list-indicator::before {
background-color: var(--md-default-fg-color--lighter)
}
[data-md-color-scheme=dracula] .md-typeset .task-list-control [type=checkbox]:checked+.task-list-indicator::before {
background-color: hsl(135deg, 94%, 65%)
}
.md-typeset .headerlink {
width: 1em;
height: 1em;
vertical-align: middle;
background-color: var(--md-default-fg-color--lighter);
background-size: 1em;
-webkit-mask-size: 1em;
mask-size: 1em;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
visibility: visible;
-webkit-mask-image: url('data:image/svg+xml;charset=utf-8,');
mask-image: url('data:image/svg+xml;charset=utf-8,')
}
.md-typeset .headerlink:hover,
.md-typeset [id]:target .headerlink {
background-color: var(--md-accent-fg-color)
}
diagram-div {
overflow: auto
}
html {
background-color: transparent
}
[data-md-component=announce] .twemoji {
color: var(--md-primary-fg-color)
}
[data-md-color-scheme=dracula] {
--md-text-color: var(--md-default-fg-color);
background-color: var(--md-default-bg-color);
--md-footer-bg-color: transparent;
--md-footer-bg-color--dark: var(--md-default-bg-color--darkest);
--md-header-fg-color: var(--md-text-color);
--md-header-bg-color: var(--md-default-bg-color--darkest)
}
[data-md-color-scheme=dracula] .md-header {
color: var(--md-text-color);
background-color: var(--md-header-bg-color);
border-bottom: .05rem solid var(--md-primary-fg-color)
}
[data-md-color-scheme=dracula] .md-header[data-md-state=shadow] {
box-shadow: 0 0 .2rem rgba(0, 0, 0, .15), 0 0 .2rem .4rem rgba(0, 0, 0, .2)
}
[data-md-color-scheme=dracula] .md-top {
background-color: var(--md-default-bg-color--dark)
}
[data-md-color-scheme=dracula] .md-top:hover {
background-color: var(--md-primary-fg-color)
}
[data-md-color-scheme=dracula] .md-tabs {
color: var(--md-text-color);
background-color: var(--md-primary-fg-color--transparent)
}
[data-md-color-scheme=dracula] .md-tabs__link--active {
color: var(--md-primary-fg-color)
}
[data-md-color-scheme=dracula] .md-tabs__link:hover {
color: var(--md-accent-fg-color)
}
[data-md-color-scheme=dracula] .md-hero {
color: var(--md-text-color);
background-color: var(--md-primary-fg-color--transparent)
}
[data-md-color-scheme=dracula] .md-nav__source {
color: var(--md-text-color)
}
[data-md-color-scheme=dracula] .md-nav__link[data-md-state=blur] {
color: var(--md-default-fg-color--light)
}
[data-md-color-scheme=dracula] .md-nav__item .md-nav__link--active {
color: var(--md-primary-fg-color)
}
[data-md-color-scheme=dracula] .md-nav__link:focus,
[data-md-color-scheme=dracula] .md-nav__link:hover {
color: var(--md-accent-fg-color)
}
[data-md-color-scheme=dracula] .md-search__input {
color: var(--md-text-color);
background-color: var(--md-accent-bg-color--light)
}
[data-md-color-scheme=dracula] .md-search__input:hover {
background-color: var(--md-default-bg-color)
}
[data-md-color-scheme=dracula] .md-search__input~.md-search__icon {
color: var(--md-text-color)
}
[data-md-color-scheme=dracula] .md-search__input::-moz-placeholder {
color: var(--md-default-fg-color--light)
}
[data-md-color-scheme=dracula] .md-search__input:-ms-input-placeholder {
color: var(--md-default-fg-color--light)
}
[data-md-color-scheme=dracula] .md-search__input::placeholder {
color: var(--md-default-fg-color--light)
}
[data-md-color-scheme=dracula] .md-overlay,
[data-md-color-scheme=dracula] .md-search__overlay {
background-color: var(--md-default-bg-color--light)
}
[data-md-color-scheme=dracula] .md-footer-nav__direction {
color: var(--md-primary-fg-color)
}
[data-md-color-scheme=dracula] .md-footer-meta {
border-top: .05rem solid var(--md-primary-fg-color)
}
[data-md-color-scheme=dracula] [data-md-component=announce] {
background-color: var(--md-default-bg-color--ultra-dark)
}
.md-typeset h5 {
color: var(--md-text-color);
text-transform: none
}
.md-search__scrollwrap,
.md-sidebar__scrollwrap,
.md-typeset div.arithmatex,
.md-typeset div.mermaid,
.md-typeset mermaid-div,
.md-typeset pre.arithmatex,
.md-typeset pre>code,
.md-typeset__scrollwrap {
scrollbar-color: var(--md-default-fg-color--lighter) transparent;
scrollbar-width: thin
}
.md-search__scrollwrap::-webkit-scrollbar,
.md-sidebar__scrollwrap::-webkit-scrollbar,
.md-typeset div.arithmatex::-webkit-scrollbar,
.md-typeset div.mermaid::-webkit-scrollbar,
.md-typeset mermaid-div::-webkit-scrollbar,
.md-typeset pre.arithmatex::-webkit-scrollbar,
.md-typeset pre>code::-webkit-scrollbar,
.md-typeset__scrollwrap::-webkit-scrollbar {
width: .2rem;
height: .2rem
}
.md-search__scrollwrap::-webkit-scrollbar-corner,
.md-sidebar__scrollwrap::-webkit-scrollbar-corner,
.md-typeset div.arithmatex::-webkit-scrollbar-corner,
.md-typeset div.mermaid::-webkit-scrollbar-corner,
.md-typeset mermaid-div::-webkit-scrollbar-corner,
.md-typeset pre.arithmatex::-webkit-scrollbar-corner,
.md-typeset pre>code::-webkit-scrollbar-corner,
.md-typeset__scrollwrap::-webkit-scrollbar-corner {
background-color: transparent
}
.md-search__scrollwrap::-webkit-scrollbar-thumb,
.md-sidebar__scrollwrap::-webkit-scrollbar-thumb,
.md-typeset div.arithmatex::-webkit-scrollbar-thumb,
.md-typeset div.mermaid::-webkit-scrollbar-thumb,
.md-typeset mermaid-div::-webkit-scrollbar-thumb,
.md-typeset pre.arithmatex::-webkit-scrollbar-thumb,
.md-typeset pre>code::-webkit-scrollbar-thumb,
.md-typeset__scrollwrap::-webkit-scrollbar-thumb {
background-color: var(--md-default-fg-color--lighter)
}
.md-search__scrollwrap::-webkit-scrollbar-thumb:hover,
.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover,
.md-typeset div.arithmatex::-webkit-scrollbar-thumb:hover,
.md-typeset div.mermaid::-webkit-scrollbar-thumb:hover,
.md-typeset mermaid-div::-webkit-scrollbar-thumb:hover,
.md-typeset pre.arithmatex::-webkit-scrollbar-thumb:hover,
.md-typeset pre>code::-webkit-scrollbar-thumb:hover,
.md-typeset__scrollwrap::-webkit-scrollbar-thumb:hover {
background-color: var(--md-accent-fg-color)
}
.md-search__scrollwrap:hover,
.md-sidebar__scrollwrap:hover,
.md-typeset div.arithmatex:hover,
.md-typeset div.mermaid:hover,
.md-typeset mermaid-div:hover,
.md-typeset pre.arithmatex:hover,
.md-typeset pre>code:hover,
.md-typeset__scrollwrap:hover {
scrollbar-color: var(--md-accent-fg-color) transparent
}
@media screen and (max-width:59.9375em) {
.md-header-nav__scheme {
padding-right: 0
}
label[for=__search] {
padding-left: 0
}
[data-md-color-scheme=dracula] .md-nav__source {
color: var(--md-text-color);
background-color: var(--md-primary-fg-color--transparent)
}
[data-md-color-scheme=dracula] .md-nav .md-nav__title {
color: var(--md-text-color);
background-color: var(--md-header-bg-color);
border-bottom: .05rem solid var(--md-primary-fg-color)
}
}
@media screen and (max-width:44.9375em) {
[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels {
padding-left: 0
}
.md-content__inner>.tabbed-set .tabbed-labels {
max-width: 100%;
margin: 0;
-webkit-padding-start: 0;
padding-inline-start: 0;
scroll-padding-inline-start: 0
}
.md-content__inner>.tabbed-set .tabbed-labels::after {
-webkit-padding-end: 0;
padding-inline-end: 0;
content: none
}
.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev {
-webkit-margin-start: 0;
margin-inline-start: 0;
-webkit-padding-start: 0;
padding-inline-start: 0
}
.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next {
-webkit-margin-end: 0;
margin-inline-end: 0;
-webkit-padding-end: 0;
padding-inline-end: 0
}
}
@media screen and (max-width:76.1875em) {
[data-md-color-scheme=dracula] .md-nav--primary .md-nav__item--active>.md-nav__link:not(:hover) {
color: var(--md-primary-fg-color)
}
[data-md-color-scheme=dracula] .md-nav--primary .md-nav__title {
color: var(--md-text-color);
background-color: var(--md-header-bg-color);
border-bottom: .05rem solid var(--md-primary-fg-color)
}
}
/*# sourceMappingURL=extra-e384f43f0f.css.map */
/*# sourceMappingURL=extra-4ca32c29f0.css.map */
/*# source: https://github.com/facelessuser/pymdown-extensions/blob/main/docs/theme/assets/pymdownx-extras/extra-4ca32c29f0.css */
/*# css unpacked using: http://cssunpacker.com/ */
================================================
FILE: docs/assets/css-js/pymdownx-extras/js/extra-uml.js
================================================
function _typeof(e) { return (_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e })(e) } !function () { "use strict"; function e(t) { return (e = Object.setPrototypeOf ? Object.getPrototypeOf : function (e) { return e.__proto__ || Object.getPrototypeOf(e) })(t) } function t(e, n) { return (t = Object.setPrototypeOf || function (e, t) { return e.__proto__ = t, e })(e, n) } function n() { if ("undefined" == typeof Reflect || !Reflect.construct) return !1; if (Reflect.construct.sham) return !1; if ("function" == typeof Proxy) return !0; try { return Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], (function () { }))), !0 } catch (e) { return !1 } } function o(e, r, i) { return (o = n() ? Reflect.construct : function (e, n, o) { var r = [null]; r.push.apply(r, n); var i = new (Function.bind.apply(e, r)); return o && t(i, o.prototype), i }).apply(null, arguments) } function r(n) { var i = "function" == typeof Map ? new Map : void 0; return (r = function (n) { if (null === n || (r = n, -1 === Function.toString.call(r).indexOf("[native code]"))) return n; var r; if ("function" != typeof n) throw new TypeError("Super expression must either be null or a function"); if (void 0 !== i) { if (i.has(n)) return i.get(n); i.set(n, a) } function a() { return o(n, arguments, e(this).constructor) } return a.prototype = Object.create(n.prototype, { constructor: { value: a, enumerable: !1, writable: !0, configurable: !0 } }), t(a, n) })(n) } function i(e, t) { if (t && ("object" === _typeof(t) || "function" == typeof t)) return t; if (void 0 !== t) throw new TypeError("Derived constructors may only return object or undefined"); return function (e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e }(e) } var a, c, u = function (o) { var a = function (o) { !function (e, n) { if ("function" != typeof n && null !== n) throw new TypeError("Super expression must either be null or a function"); e.prototype = Object.create(n && n.prototype, { constructor: { value: e, writable: !0, configurable: !0 } }), n && t(e, n) }(u, o); var r, a, c = (r = u, a = n(), function () { var t, n = e(r); if (a) { var o = e(this).constructor; t = Reflect.construct(n, arguments, o) } else t = n.apply(this, arguments); return i(this, t) }); function u() { var e; !function (e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") }(this, u); var t = (e = c.call(this)).attachShadow({ mode: "open" }), n = document.createElement("style"); return n.textContent = "\n :host {\n display: block;\n line-height: initial;\n font-size: 16px;\n }\n div.mermaid {\n margin: 0;\n overflow: visible;\n }", t.appendChild(n), e } return u }(r(HTMLElement)); void 0 === customElements.get("mermaid-div") && customElements.define("mermaid-div", a); var c = { startOnLoad: !1, theme: "default", flowchart: { htmlLabels: !1 }, er: { useMaxWidth: !1 }, sequence: { useMaxWidth: !1, noteFontWeight: "14px", actorFontSize: "14px", messageFontSize: "16px" } }; mermaid.mermaidAPI.globalReset(); var u = null; try { u = document.querySelector("[data-md-color-scheme]").getAttribute("data-md-color-scheme") } catch (e) { u = "default" } var l = "undefined" == typeof mermaidConfig ? c : mermaidConfig[u] || mermaidConfig.default || c; mermaid.initialize(l); for (var d = document.querySelectorAll("pre.".concat(o, ", mermaid-div")), f = document.querySelector("html"), s = function (e) { var t = d[e], n = "mermaid-div" === t.tagName.toLowerCase() ? t.shadowRoot.querySelector("pre.".concat(o)) : t, r = document.createElement("div"); r.style.visibility = "hidden", r.style.display = "display", r.style.padding = "0", r.style.margin = "0", r.style.lineHeight = "initial", r.style.fontSize = "16px", f.appendChild(r); try { mermaid.mermaidAPI.render("_mermaid_".concat(e), function (e) { for (var t = "", n = 0; n < e.childNodes.length; n++) { var o = e.childNodes[n]; if ("code" === o.tagName.toLowerCase()) for (var r = 0; r < o.childNodes.length; r++) { var i = o.childNodes[r]; if ("#text" === i.nodeName && !/^\s*$/.test(i.nodeValue)) { t = i.nodeValue; break } } } return t }(n), (function (e) { var r = document.createElement("div"); r.className = o, r.innerHTML = e; var i = document.createElement("mermaid-div"); i.shadowRoot.appendChild(r), t.parentNode.insertBefore(i, t), n.style.display = "none", i.shadowRoot.appendChild(n), n !== t && t.parentNode.removeChild(t) }), r) } catch (e) { } f.contains(r) && f.removeChild(r) }, m = 0; m < d.length; m++)s(m) }; c = new MutationObserver((function (e) { e.forEach((function (e) { if ("attributes" === e.type) { var t = e.target.getAttribute("data-md-color-scheme"); t || (t = "default"), localStorage.setItem("data-md-color-scheme", t), "undefined" != typeof mermaid && u("mermaid") } })) })), a = function () { c.observe(document.querySelector("body"), { attributeFilter: ["data-md-color-scheme"] }), "undefined" != typeof mermaid && u("mermaid") }, document.addEventListener("DOMContentLoaded", a), document.addEventListener("DOMContentSwitch", a) }();
//# sourceMappingURL=extra-uml-fcd33c93.js.map
//# source: https://github.com/facelessuser/pymdown-extensions/blob/main/docs/theme/assets/pymdownx-extras/extra-uml-fcd33c93.js
================================================
FILE: docs/assets/css-js/termynal/css/custom.css
================================================
.termynal-comment {
color: #4a968f;
font-style: italic;
display: block;
}
.termy [data-termynal] {
white-space: pre-wrap;
}
a.external-link::after {
/* \00A0 is a non-breaking space
to make the mark be on the same line as the link
*/
content: "\00A0[↪]";
}
a.internal-link::after {
/* \00A0 is a non-breaking space
to make the mark be on the same line as the link
*/
content: "\00A0↪";
}
.shadow {
box-shadow: 5px 5px 10px #999;
}
================================================
FILE: docs/assets/css-js/termynal/css/termynal.css
================================================
/**
* termynal.js
*
* @author Ines Montani
* @version 0.0.1
* @license MIT
*/
:root {
--color-bg: #252a33;
--color-text: #eee;
--color-text-subtle: #a2a2a2;
}
[data-termynal] {
width: 750px;
max-width: 100%;
background: var(--color-bg);
color: var(--color-text);
/* font-size: 18px; */
font-size: 15px;
/* font-family: 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace; */
font-family: 'Roboto Mono', 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace;
border-radius: 4px;
padding: 75px 45px 35px;
position: relative;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
[data-termynal]:before {
content: '';
position: absolute;
top: 15px;
left: 15px;
display: inline-block;
width: 15px;
height: 15px;
border-radius: 50%;
/* A little hack to display the window buttons in one pseudo element. */
background: #d9515d;
-webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
}
[data-termynal]:after {
content: 'bash';
position: absolute;
color: var(--color-text-subtle);
top: 5px;
left: 0;
width: 100%;
text-align: center;
}
a[data-terminal-control] {
text-align: right;
display: block;
color: #aebbff;
}
[data-ty] {
display: block;
line-height: 2;
}
[data-ty]:before {
/* Set up defaults and ensure empty lines are displayed. */
content: '';
display: inline-block;
vertical-align: middle;
}
[data-ty="input"]:before,
[data-ty-prompt]:before {
margin-right: 0.75em;
color: var(--color-text-subtle);
}
[data-ty="input"]:before {
content: '$';
}
[data-ty][data-ty-prompt]:before {
content: attr(data-ty-prompt);
}
[data-ty-cursor]:after {
content: attr(data-ty-cursor);
font-family: monospace;
margin-left: 0.5em;
-webkit-animation: blink 1s infinite;
animation: blink 1s infinite;
}
/* Cursor animation */
@-webkit-keyframes blink {
50% {
opacity: 0;
}
}
@keyframes blink {
50% {
opacity: 0;
}
}
================================================
FILE: docs/assets/css-js/termynal/js/custom.js
================================================
function setupTermynal() {
document.querySelectorAll(".use-termynal").forEach(node => {
node.style.display = "block";
new Termynal(node, {
lineDelay: 500
});
});
const progressLiteralStart = "---> 100%";
const promptLiteralStart = "$ ";
const customPromptLiteralStart = "# ";
const termynalActivateClass = "termy";
let termynals = [];
function createTermynals() {
document
.querySelectorAll(`.${termynalActivateClass} .highlight`)
.forEach(node => {
const text = node.textContent;
const lines = text.split("\n");
const useLines = [];
let buffer = [];
function saveBuffer() {
if (buffer.length) {
let isBlankSpace = true;
buffer.forEach(line => {
if (line) {
isBlankSpace = false;
}
});
dataValue = {};
if (isBlankSpace) {
dataValue["delay"] = 0;
}
if (buffer[buffer.length - 1] === "") {
// A last single
won't have effect
// so put an additional one
buffer.push("");
}
const bufferValue = buffer.join("
");
dataValue["value"] = bufferValue;
useLines.push(dataValue);
buffer = [];
}
}
for (let line of lines) {
if (line === progressLiteralStart) {
saveBuffer();
useLines.push({
type: "progress"
});
} else if (line.startsWith(promptLiteralStart)) {
saveBuffer();
const value = line.replace(promptLiteralStart, "").trimEnd();
useLines.push({
type: "input",
value: value
});
} else if (line.startsWith("// ")) {
saveBuffer();
const value = "💬 " + line.replace("// ", "").trimEnd();
useLines.push({
value: value,
class: "termynal-comment",
delay: 0
});
} else if (line.startsWith(customPromptLiteralStart)) {
saveBuffer();
const promptStart = line.indexOf(promptLiteralStart);
if (promptStart === -1) {
console.error("Custom prompt found but no end delimiter", line)
}
const prompt = line.slice(0, promptStart).replace(customPromptLiteralStart, "")
let value = line.slice(promptStart + promptLiteralStart.length);
useLines.push({
type: "input",
value: value,
prompt: prompt
});
} else {
buffer.push(line);
}
}
saveBuffer();
const div = document.createElement("div");
node.replaceWith(div);
const termynal = new Termynal(div, {
lineData: useLines,
noInit: true,
lineDelay: 500
});
termynals.push(termynal);
});
}
function loadVisibleTermynals() {
termynals = termynals.filter(termynal => {
if (termynal.container.getBoundingClientRect().top - innerHeight <= 0) {
termynal.init();
return false;
}
return true;
});
}
window.addEventListener("scroll", loadVisibleTermynals);
createTermynals();
loadVisibleTermynals();
}
async function main() {
setupTermynal()
}
main()
================================================
FILE: docs/assets/css-js/termynal/js/termynal.js
================================================
/**
* termynal.js
* A lightweight, modern and extensible animated terminal window, using
* async/await.
*
* @author Ines Montani
* @version 0.0.1
* @license MIT
*/
'use strict';
/** Generate a terminal widget. */
class Termynal {
/**
* Construct the widget's settings.
* @param {(string|Node)=} container - Query selector or container element.
* @param {Object=} options - Custom settings.
* @param {string} options.prefix - Prefix to use for data attributes.
* @param {number} options.startDelay - Delay before animation, in ms.
* @param {number} options.typeDelay - Delay between each typed character, in ms.
* @param {number} options.lineDelay - Delay between each line, in ms.
* @param {number} options.progressLength - Number of characters displayed as progress bar.
* @param {string} options.progressChar – Character to use for progress bar, defaults to █.
* @param {number} options.progressPercent - Max percent of progress.
* @param {string} options.cursor – Character to use for cursor, defaults to ▋.
* @param {Object[]} lineData - Dynamically loaded line data objects.
* @param {boolean} options.noInit - Don't initialise the animation.
*/
constructor(container = '#termynal', options = {}) {
this.container = (typeof container === 'string') ? document.querySelector(container) : container;
this.pfx = `data-${options.prefix || 'ty'}`;
this.originalStartDelay = this.startDelay = options.startDelay
|| parseFloat(this.container.getAttribute(`${this.pfx}-startDelay`)) || 600;
this.originalTypeDelay = this.typeDelay = options.typeDelay
|| parseFloat(this.container.getAttribute(`${this.pfx}-typeDelay`)) || 90;
this.originalLineDelay = this.lineDelay = options.lineDelay
|| parseFloat(this.container.getAttribute(`${this.pfx}-lineDelay`)) || 1500;
this.progressLength = options.progressLength
|| parseFloat(this.container.getAttribute(`${this.pfx}-progressLength`)) || 40;
this.progressChar = options.progressChar
|| this.container.getAttribute(`${this.pfx}-progressChar`) || '█';
this.progressPercent = options.progressPercent
|| parseFloat(this.container.getAttribute(`${this.pfx}-progressPercent`)) || 100;
this.cursor = options.cursor
|| this.container.getAttribute(`${this.pfx}-cursor`) || '▋';
this.lineData = this.lineDataToElements(options.lineData || []);
this.loadLines()
if (!options.noInit) this.init()
}
loadLines() {
// Load all the lines and create the container so that the size is fixed
// Otherwise it would be changing and the user viewport would be constantly
// moving as she/he scrolls
const finish = this.generateFinish()
finish.style.visibility = 'hidden'
this.container.appendChild(finish)
// Appends dynamically loaded lines to existing line elements.
this.lines = [...this.container.querySelectorAll(`[${this.pfx}]`)].concat(this.lineData);
for (let line of this.lines) {
line.style.visibility = 'hidden'
this.container.appendChild(line)
}
const restart = this.generateRestart()
restart.style.visibility = 'hidden'
this.container.appendChild(restart)
this.container.setAttribute('data-termynal', '');
}
/**
* Initialise the widget, get lines, clear container and start animation.
*/
init() {
/**
* Calculates width and height of Termynal container.
* If container is empty and lines are dynamically loaded, defaults to browser `auto` or CSS.
*/
const containerStyle = getComputedStyle(this.container);
this.container.style.width = containerStyle.width !== '0px' ?
containerStyle.width : undefined;
this.container.style.minHeight = containerStyle.height !== '0px' ?
containerStyle.height : undefined;
this.container.setAttribute('data-termynal', '');
this.container.innerHTML = '';
for (let line of this.lines) {
line.style.visibility = 'visible'
}
this.start();
}
/**
* Start the animation and rener the lines depending on their data attributes.
*/
async start() {
this.addFinish()
await this._wait(this.startDelay);
for (let line of this.lines) {
const type = line.getAttribute(this.pfx);
const delay = line.getAttribute(`${this.pfx}-delay`) || this.lineDelay;
if (type == 'input') {
line.setAttribute(`${this.pfx}-cursor`, this.cursor);
await this.type(line);
await this._wait(delay);
}
else if (type == 'progress') {
await this.progress(line);
await this._wait(delay);
}
else {
this.container.appendChild(line);
await this._wait(delay);
}
line.removeAttribute(`${this.pfx}-cursor`);
}
this.addRestart()
this.finishElement.style.visibility = 'hidden'
this.lineDelay = this.originalLineDelay
this.typeDelay = this.originalTypeDelay
this.startDelay = this.originalStartDelay
}
generateRestart() {
const restart = document.createElement('a')
restart.onclick = (e) => {
e.preventDefault()
this.container.innerHTML = ''
this.init()
}
restart.href = '#'
restart.setAttribute('data-terminal-control', '')
restart.innerHTML = "restart ↻"
return restart
}
generateFinish() {
const finish = document.createElement('a')
finish.onclick = (e) => {
e.preventDefault()
this.lineDelay = 0
this.typeDelay = 0
this.startDelay = 0
}
finish.href = '#'
finish.setAttribute('data-terminal-control', '')
finish.innerHTML = "fast →"
this.finishElement = finish
return finish
}
addRestart() {
const restart = this.generateRestart()
this.container.appendChild(restart)
}
addFinish() {
const finish = this.generateFinish()
this.container.appendChild(finish)
}
/**
* Animate a typed line.
* @param {Node} line - The line element to render.
*/
async type(line) {
const chars = [...line.textContent];
line.textContent = '';
this.container.appendChild(line);
for (let char of chars) {
const delay = line.getAttribute(`${this.pfx}-typeDelay`) || this.typeDelay;
await this._wait(delay);
line.textContent += char;
}
}
/**
* Animate a progress bar.
* @param {Node} line - The line element to render.
*/
async progress(line) {
const progressLength = line.getAttribute(`${this.pfx}-progressLength`)
|| this.progressLength;
const progressChar = line.getAttribute(`${this.pfx}-progressChar`)
|| this.progressChar;
const chars = progressChar.repeat(progressLength);
const progressPercent = line.getAttribute(`${this.pfx}-progressPercent`)
|| this.progressPercent;
line.textContent = '';
this.container.appendChild(line);
for (let i = 1; i < chars.length + 1; i++) {
await this._wait(this.typeDelay);
const percent = Math.round(i / chars.length * 100);
line.textContent = `${chars.slice(0, i)} ${percent}%`;
if (percent > progressPercent) {
break;
}
}
}
/**
* Helper function for animation delays, called with `await`.
* @param {number} time - Timeout, in ms.
*/
_wait(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
/**
* Converts line data objects into line elements.
*
* @param {Object[]} lineData - Dynamically loaded lines.
* @param {Object} line - Line data object.
* @returns {Element[]} - Array of line elements.
*/
lineDataToElements(lineData) {
return lineData.map(line => {
let div = document.createElement('div');
div.innerHTML = `${line.value || ''}`;
return div.firstElementChild;
});
}
/**
* Helper function for generating attributes string.
*
* @param {Object} line - Line data object.
* @returns {string} - String of attributes.
*/
_attributes(line) {
let attrs = '';
for (let prop in line) {
// Custom add class
if (prop === 'class') {
attrs += ` class=${line[prop]} `
continue
}
if (prop === 'type') {
attrs += `${this.pfx}="${line[prop]}" `
} else if (prop !== 'value') {
attrs += `${this.pfx}-${prop}="${line[prop]}" `
}
}
return attrs;
}
}
/**
* HTML API: If current script has container(s) specified, initialise Termynal.
*/
if (document.currentScript.hasAttribute('data-termynal-container')) {
const containers = document.currentScript.getAttribute('data-termynal-container');
containers.split('|')
.forEach(container => new Termynal(container))
}
================================================
FILE: docs/assets/css-js/termynal/readme.md
================================================
# **Termynal**: Terminal Animation
Just copy and paste the `terminal` folder in a `docs/assests`
folder and then add the following snippet to your `mkdocs.yml`.
```yaml
# for terminal animation
extra_css:
- assets/termynal/css/termynal.css
- assets/termynal/css/custom.css
extra_javascript:
- assets/termynal/js/termynal.js
- assets/termynal/js/custom.js
``
================================================
FILE: docs/assets/snippets/macros/.gitkeep
================================================
================================================
FILE: docs/assets/snippets/notifications/videos/disclaimer.md
================================================
!!! warning "Disclaimer"
This library is currently under rapid initial development. Breaking changes may happen frequently.
================================================
FILE: docs/examples/hanoi.py
================================================
# Based on the following example from Diagrams
# https://archives.haskell.org/projects.haskell.org/diagrams/gallery/Hanoi.html
from PIL import Image as PILImage
from typing import Dict, List, Tuple
from colour import Color # type: ignore
from chalk import Diagram, rectangle, concat, hcat, vcat
Disk = int
Stack = List[Disk] # disks on one peg
Hanoi = List[Stack] # disks on all three pegs
Move = Tuple[int, int]
colors: List[Color] = [
Color("#9FB4CC"),
Color("#CCCC9F"),
Color("#DB4105"),
]
black = Color("black")
def draw_disk(n: Disk) -> Diagram:
return (
rectangle(n + 2, 1)
.fill_color(colors[n])
.line_color(colors[n])
.line_width(0.05)
)
draw_disk(0)
def draw_stack(s: Stack) -> Diagram:
disks = vcat(map(draw_disk, s))
post = rectangle(0.8, 6).fill_color(black)
return post.align_b() + disks.align_b()
draw_stack([0, 1])
def draw_hanoi(state: Hanoi) -> Diagram:
hsep = 7
return concat(
draw_stack(stack).translate(7 * i, 0) for i, stack in enumerate(state)
)
draw_hanoi([[0], [1, 2], []])
def solve_hanoi(num_disks: int) -> List[Move]:
def solve_hanoi_1(num_disks, *, source, spare, target):
if num_disks <= 0:
return []
else:
return (
solve_hanoi_1(num_disks - 1, source=source, spare=target, target=spare)
+ [(source, target)]
+ solve_hanoi_1(num_disks - 1, source=spare, spare=source, target=target)
)
return solve_hanoi_1(num_disks, source=0, spare=1, target=2)
def do_move(move: Move, state: Hanoi) -> Hanoi:
def remove_disk(src, state):
disk, *src_new = state[src]
state_new = state[:src] + [src_new] + state[src + 1 :]
return disk, state_new
def add_disk(tgt, disk, state):
tgt_new = [disk] + state[tgt]
state_new = state[:tgt] + [tgt_new] + state[tgt + 1 :]
return state_new
src, tgt = move
disk, state1 = remove_disk(src, state)
state2 = add_disk(tgt, disk, state1)
return state2
def state_sequence(num_disks: int) -> List[Hanoi]:
state: Hanoi = [list(range(num_disks)), [], []]
states: List[Hanoi] = [state]
for move in solve_hanoi(num_disks):
state = do_move(move, state)
states.append(state)
return states
def draw_state_sequence(seq: List[Hanoi]) -> Diagram:
return concat(draw_hanoi(state).translate(0, 7.5 * i) for i, state in enumerate(seq))
diagram = draw_state_sequence(state_sequence(3))
path = "examples/output/hanoi.svg"
diagram.render_svg(path, height=700)
path = "examples/output/hanoi.png"
diagram.render(path, height=700)
PILImage.open(path)
================================================
FILE: docs/examples/koch.py
================================================
# Based on the following example from Diagrams
# https://archives.haskell.org/projects.haskell.org/diagrams/gallery/Koch.html
from PIL import Image as PILImage
from chalk import *
from chalk.transform import *
import chalk
unit_x = Trail.hrule(1)
def koch(n):
if n == 0:
return unit_x.scale_x(5)
else:
return (
koch(n - 1).scale(1 / 3)
+ koch(n - 1).scale(1 / 3).rotate_by(+1 / 6)
+ koch(n - 1).scale(1 / 3).rotate_by(-1 / 6)
+ koch(n - 1).scale(1 / 3)
)
d = vcat(koch(i).stroke().line_width(0.01) for i in range(1, 5))
# Render
height = 512
d.render_svg("examples/output/koch.svg", height)
d.render("examples/output/koch.png", height)
PILImage.open("examples/output/koch.png")
================================================
FILE: docs/examples/lenet.py
================================================
from PIL import Image as PILImage
from chalk import *
from colour import Color
from chalk import BoundingBox
# Colors
papaya = Color("#ff9700")
blue = Color("#005FDB")
black = Color("#000000")
white = Color("#ffffff")
grey = Color("#bbbbbb")
# Some general functions
def label(te):
"Create text."
return text(te, 2).fill_color(black).line_width(0)
def cover(d, a, b):
"Draw a bounding_box around a subdiagram"
b1 = d.get_subdiagram_envelope(a)
b2 = d.get_subdiagram_envelope(b)
new_bb = b1 + b2
return rectangle(new_bb.width, new_bb.height) \
.translate(new_bb.center.x, new_bb.center.y)
def tile(d, m, n, name = ""):
"Tile a digram with names"
return hcat(vcat(d.named((name, j, i)) for j in range(n)) for i in range(m)).center_xy()
def connect_all(d, a, b):
"Connect all corners of two diagrams"
for x_border in [-unit_x, unit_x]:
for y_border in [-unit_y, unit_y]:
p = x_border + y_border
d = d.connect_perim(a, b, p, p, ArrowOpts(head_arrow=empty()))
return d
# NN drawing
def cell():
return rectangle(1, 1).line_width(0.01)
def matrix(n, r, c):
return tile(cell(), c, r, n)
def back(r, n):
"Backing stack"
return concat((r.translate(-i/2, -i/2).fill_opacity((n - i + n /2) / n)
for i in range(n-1, -1, -1)))
lw = 0.05
def stack(n, size, l, top, bot):
"Feature map stack"
m = matrix(n, size, size).fill_color(Color("#dddddd"))
r = rectangle(size, size).fill_color(grey).line_width(lw)
return (label(top) / (back(r, l) + m) / label(bot)).center_xy()
stack("a", 32, 0, "", "")
def network(n, size, top, bot):
"Draw a network layer"
return (label(top) / rectangle(2, size).fill_color(grey).line_width(lw).named(n) / label(bot)).center_xy()
# The number 7
draw = make_path([(-10, -10), (10, -10 ), (-10, 10)]).line_width(0.09).line_color(blue).fill_opacity(0)
# Draw the main diagram.
h = hstrut(6.5)
d = ((stack("a", 32, 0, "", "") + draw) | (label("conv") / h) |
stack("b", 28, 6, "", "C1") | (label("pool") / h) |
stack("c", 14, 6, "", "S2") | (label("conv") / h) |
stack("d", 10, 16, "", "C3") | (label("pool") / h) | hstrut(-0.5) |
stack("e", 5, 16, "", "S4") | (label("dense") / h) |
network("dense1", 12, "", "") | (label("dense") / (h)) |
network("dense2", 8.4, "", "") | (label("dense") / h) |
network("dense3", 1, "", ""))
d = d.scale_uniform_to_x(5)
# Draw the orange boxes
boxes = [(("a", 2, 2), ("a", 6, 6)),
(("b", 2, 2), ("b", 2, 2)),
(("b", 20, 2), ("b", 23, 5)),
(("c", 10, 2), ("c", 11, 3)),
(("c", 4, 6), ("c", 8, 10)),
(("d", 4, 6), ("d", 4, 6)),
(("d", 6, 4), ("d", 9, 7)),
(("e", 3, 2), ("e", 4, 3))]
d += concat([cover(d, *b).fill_color(papaya).fill_opacity(0.3).named(("box", i))
for i, b in enumerate(boxes)])
connect = [(("box", i), ("box", i + 1)) for i in range(0, 6, 2)]
for b in connect:
d = connect_all(d, *b)
set_svg_height(300)
d
================================================
FILE: docs/examples/squares.py
================================================
from PIL import Image as PILImage
import math
import random
from itertools import product
from colour import Color
from chalk import square, concat, empty
random.seed(0)
def make_square():
colors = [
Color("#ff9700"), # papaya
Color("#005FDB"), # blue
]
# generate uniformly a value in [-max_angle, max_angle]
max_angle = math.pi / 24.0
θ = 2 * max_angle * random.random() - max_angle
# pick a random color
i = random.random() > 0.75
color = colors[i]
return square(0.75).line_color(color).rotate_rad(-θ)
make_square()
def make_group(num_squares=4):
return concat(make_square() for _ in range(num_squares))
make_group()
disps = range(4)
diagram = concat(make_group().translate(x, y) for x, y in product(disps, disps))
diagram = diagram.line_width(0.02)
diagram
================================================
FILE: docs/examples/tensor.py
================================================
from PIL import Image as PILImage
from chalk import *
from colour import Color
h = hstrut(2.5)
papaya = Color("#ff9700")
white = Color("white")
black = Color("black")
def draw_cube():
# Assemble cube
face_m = rectangle(1, 1).align_tl()
face_t = rectangle(1, 0.5).shear_x(-1).align_bl()
face_r = rectangle(0.5, 1).shear_y(-1).align_tr()
cube = (face_t + face_m).align_tr() + face_r
# Replace envelope with front face.
return cube.align_bl().with_envelope(face_m.align_bl())
def draw_tensor(depth, rows, columns):
"Draw a tensor"
cube = draw_cube()
# Fix this ...
hyp = (unit_y * 0.5).shear_x(-1)
# Build a matrix.
front = cat([hcat([cube for i in range(columns)])
for j in reversed(range(rows))], -unit_y).align_t()
# Build depth
return concat(front.translate(-k * hyp.x, -k * hyp.y)
for k in reversed(range(depth)))
draw_tensor(2, 3, 4)
def t(d, r, c):
return draw_tensor(d, r, c).fill_color(white)
def label(te, s=1.5):
return (text(te, s).fill_color(black).line_color(white).center_xy())
# Create a diagram.
d, r, c = 3, 4, 5
base = t(d, r, c).line_color(papaya)
m = hcat([t(1, r, c), t(d, 1, c), label("→"), (base + t(1, r, c)), (base + t(d, 1, c) ), label("="), t(d, r, c)], sep=2.5).line_width(0.02)
m
================================================
FILE: docs/index.md
================================================
---
hide:
- navigation
- toc
---
--8<-- "README.md"
================================================
FILE: docs/overrides/main.html
================================================
{% extends "base.html" %}
{% block content %}
{{ super() }}
{% endblock content %}
================================================
FILE: docs/quickstart/.gitkeep
================================================
================================================
FILE: examples/arrows.py
================================================
from chalk import *
from chalk.trail import Trail
from colour import Color
from PIL import Image as PILImage
grey = Color("grey")
blue = Color("blue")
orange = Color("orange")
octagon = regular_polygon(8, 1.5).rotate_by(1 / 16).line_color(grey).line_width(0.5).show_origin()
dias = octagon.named("first") | hstrut(3) | octagon.named("second")
ex1 = dias.connect(
"first",
"second",
ArrowOpts(trail=Trail.from_offsets([unit_x, 0.25 * unit_y, unit_x, 0.25 * unit_y]))
)
ex1
ex1 = dias.connect(
"first",
"second",
ArrowOpts(
head_style=Style.empty().fill_color(grey),
arc_height=0.5,
shaft_style=Style.empty().line_color(blue),
),
)
ex1 = ex1.connect(
"second",
"first",
ArrowOpts(
head_style=Style.empty().fill_color(grey),
arc_height=0.5,
shaft_style=Style.empty().line_color(blue),
),
)
ex12 = ex1.connect_perim(
"first",
"second",
unit_x.rotate_by(15 / 16),
unit_x.rotate_by(9 / 16),
ArrowOpts(head_pad=0.1),
)
ex3 = arrow_v(unit_y)
d = ex12 + ex3
d
output_path = "examples/output/arrows.svg"
d.render_svg(output_path, height=200)
output_path = "examples/output/arrows.png"
d.render(output_path, height=200)
PILImage.open(output_path)
output_path = "examples/output/arrows.pdf"
d.render_pdf(output_path, height=200)
================================================
FILE: examples/bigben.py
================================================
# # Big Ben
# *A literate notebook by [Sasha Rush](http://www.rush-nlp.com)*
# [Big Ben](https://en.wikipedia.org/wiki/Big_Ben) is the most iconic clock face in the world.
#
# In this notebook, we are going to replicate the design of the clockface from first principles using the
# Chalk library. This project was done for fun without any knowledge of clockmaking or even the right
# terminology. It is meant mainly as an introduction programmatic 2D diagramming.
# Here is what it will look like when we are done.
#
# ## Preliminary: Roman Numerals
from chalk import *
from colour import Color
# The whole diagram a simple color pallet of gold black and a bit of grey.
gold = Color("#E7D49C")
white = Color("#CCCCCC")
black = Color("black")
grey = Color("#444444")
# To begin, we will introduce some of the concepts of the Chalk library
# by mimicking the shape of the roman numeral I, V, and X.
# 
# Chalk uses basic shapes to build up compositional diagrams. For instance here
# is a filled rectangle.
column = rectangle(1, 4).fill_color(black)
column
# Each diagram has style properties and an "envelope" that describes
# its boundaries. Envelopes are a bit complex, they roughly are the
# the bounding box of the diagram.
column.show_envelope()
# Next lets make a diamond with an inlay. To do this we use `+` to put a
# grey box on a black box.
diamond = rectangle(1, 1).fill_color(black) + rectangle(0.5, 0.5).fill_color(grey)
diamond
# The benefit of the envelope representation is that it behaves more
# intuitively under affine transformations like rotation.
diamond = diamond.rotate_by(1 / 8)
diamond.show_envelope()
# We can easily combine diagrams. To see what a combination will look
# like we can use the `show_beside` method. You give it a vector along
# which to combine.
column.show_beside(diamond, -unit_y)
# We can also update the envelope of diagrams before combination.
# For instance here we substitute a small envelope for overlap.
column = column.with_envelope(rectangle(1, 2.5))
column.show_beside(diamond, -unit_y)
# When stacking on top we can use the shortcut `/`. The function `center_xy` resets
# the center to the middle of the envelope.
i = ((column / diamond).beside(diamond, -unit_y)).center_xy()
i = i + rectangle(0.01, 4).line_color(grey)
i.show_envelope()
# We can also put diagrams next to each other using the `|` notation.
ii = i | i
ii
# We can similar create diagrams for the other roman numerals.
# The `align` functions also re-center diagrams.
v = rectangle(1.5, 1).fill_color(black).align_bl() + i.align_b()
v
# Changing the center allows us to use `+` which joins diagrams together at the origin.
v = (v.align_br() + i.align_b()).center_xy()
v
# Creating X is a bit harder. We use two transformations to help us out.
# Using `translate` helps us nudge diagrams away from the origin.
ddiamond = (diamond | diamond).translate(-0.5, 0)
ddiamond.show_origin()
# Using `shear` lets us create a center line with a diagonal slash.
mid = (
rectangle(2, 0.5).fill_color(black) + rectangle(1.5, 0.1).fill_color(grey)
).shear_x(-0.2)
mid
# We can then combine these complex diagrams together.
column = column
x = ((column / ddiamond) + mid).beside(ddiamond, -unit_y).center_xy()
x
# Compositionality is fun. We can take these shapes and make numbers from 1-12.
numbers = [
x | i | i,
i,
i | i,
i | i | i,
i | v,
v,
v | i,
v | i | i,
v | i | i | i,
i | x,
x,
x | i,
]
# We can draw the main clock-face by moving each number to the edge, and then rotating it
# to its location. The `concat` combinator glues each of these together at the origin.
part0 = concat(
[
n.center_xy().scale(0.05).translate_by(-unit_y).rotate_by(-i / 12)
for i, n in enumerate(numbers)
]
)
set_svg_height(300)
part0.show_origin()
# ## Inner Pattern
# 
# This inner pattern is a bit more complex. We are going to need more than just
# simple shapes to draw it.
# To start, let us make a function for rotational symmetry.
def rot_cycle(d: Diagram, times: int) -> Diagram:
"Rotate diagram around a circle."
return concat(d.rotate_by(i / times) for i in range(times))
# To try it out, we make the inner pattern by making a circle and
# rotating it around 12 times.
set_svg_height(200)
width = -4.4
inner_circle = rot_cycle(circle(1.1).translate(0, width), 12).rotate_by(
(1 / 12) / 2
) + circle(3).fill_color(black)
inner_circle
# Now we want to trace a trail that looks like the inner patttern.
# There is no magic here, just a little geometry to guess the shapes.
# Vectors `unit_y` and `unit_x` are geometric helpers.
u45 = unit_x.rotate(-45)
u60 = unit_x.rotate(60)
diffy = abs(u45.y / u60.y)
diffx = diffy * abs(u60.x / u45.x)
# A `Trail` is a sequence of vectors drawn in order.
# Once you are done drawing one you can use `stroke` to
# make it a diagram. We start at the top left and draw
# downward.
fudge = 0.73
y = (
Trail.from_offsets(
[
u45,
diffy * u60,
-diffy * u60,
-fudge * u60,
fudge * u60,
diffx * u45,
diffx * unit_y,
]
)
.stroke()
.align_br()
)
y.show_origin()
# To draw the curve we use `arc_between` which
# connects two points with a specified radius.
curve = 0.5
under_arc = arc_between(-unit_x, 2 * -unit_y, curve).align_tr()
under_arc.show_origin()
# We then combine them to the right scale.
pattern = (y.scale(3) / under_arc).align_r()
pattern.show_origin()
# And then use reflection to double the pattern.
pattern = (pattern + pattern.reflect_x()).align_b()
pattern
# We can then rotate this to create the whole pattern. We set the
# fudge factor above to make the pattern connect.
set_svg_height(300)
part1 = inner_circle + rot_cycle(pattern.translate(0, width - 1), 12)
part1 = part1.line_color(gold).line_width(0.2)
part1
# Looks pretty close to the original!
# 
# ## Outer Bands
# 
# With the functions we have so far it is not so hard to do the rest of the main
# clock-face. The maink point worth noting is that we can build each part without
# needing to know the sizes of the others. This makes it easy to debug and update.
# The first band is two circles with a black dots. Nothing new.
set_svg_height(200)
band1 = (circle(1.1).line_width(0.1) + circle(1)).line_width(0.2) + rot_cycle(
diamond.scale(0.05).translate(1.05, 0), 12
)
band1
# Band two has thin dividing lines and the hour markers from part 0.
# In order to fit in the numbers we write a function that lets us scale to a given circle.
def fit_in(b: Diagram, s: Diagram, frame=0.1) -> Diagram:
# Find the inner radius
m = min([x for x in b.get_trace()(origin, unit_x) if x > 0])
# Scale the inner diagram to that size
return b + s.scale_uniform_to_x(2 * m - frame)
# We use this to put the numbers in a circle.
band2 = fit_in(circle(1.4), part0, 0.1) + circle(1)
band2
# We then draw thin lines in this region.
def thin_line(h):
return rectangle(h, 0.001).fill_color(black).center_xy().line_width(0.01)
lines = thin_line(0.4)
band2 = band2 + rot_cycle(lines.translate(1.2, 0), 48)
band2
# Band 3 has a little jewel cross. We can draw this with shapes.
diamond = rectangle(1, 1).rotate_by(1 / 8).fill_color(black).line_color(black)
s = (
(diamond | rectangle(2, 1).with_envelope(rectangle(1, 1)) | diamond)
.fill_color(black)
.line_color(black)
.center_xy()
)
s = s.scale_y(0.5) + s.rotate_by(0.25).scale_y(0.75).scale_x(0.25)
jewel = s.rotate_by(0.25)
jewel
# Draw the outlines
a = 1.8
c = 1.7
b = 1.6
band3 = (
circle(2.0).line_width(0.7)
+ (circle(a) + circle(b)).line_width(0.3)
+ circle(1.4).line_width(0.4)
)
band3
# Add the thin lines and rounded rect tracks
track = rectangle(0.33, 0.001, 0.1).fill_color(black).center_xy().line_width(0.01)
band3 = (
band3
+ rot_cycle(track.line_width(0.3).translate(c, 0), 60)
+ rot_cycle(thin_line(0.6).translate(c, 0).rotate_by(1 / 48), 48)
)
band3
# Add the jewel.
band3 = band3 + rot_cycle(
jewel.center_xy().scale_uniform_to_x((a - b) * 2).translate(0, c), 12
)
band3
# And voila.
part2 = fit_in(band3, fit_in(band2, band1))
set_svg_height(300)
part2
# Looks pretty close to the original!
# 
# ## Frame
# !
# The whole clock is surrounded by a thick gold frame with some ornamentation. We start with the outer box.
set_svg_height(200)
r = rectangle(1, 1).fill_color(black).line_color(gold).line_width(0.6)
r
# Next we do each of the outer corners by themselves. We first make a sloping triangle shape using trails and arc_between.
corner = (
Trail.hrule(1).stroke().align_l()
+ Trail.vrule(1).reflect_y().stroke()
+ arc_between((0, -1), (1, 0), -0.2)
).line_width(0.2)
corner
# Internally there is a little golden decoration. To make this we use the `juxtapose` function
# which moves a diagram to be next to another along an angle.
decal = rectangle(2, 2).with_envelope(rectangle(0, 0)).fill_color(gold)
c = circle(1).fill_color(black)
decal = concat(
[
decal.juxtapose(c, unit_y),
decal.juxtapose(c, -unit_y),
decal.juxtapose(c, unit_x),
decal.juxtapose(c, -unit_x),
decal,
]
)
decal.show_origin()
# We then add a black circle behind it to emphasize details.
decal = decal.line_color(gold).line_width(0.2)
decal = circle(2).fill_color(black) + decal
decal
# To add the other shapes with we `arc` which draws part of a circle.
disp = 20 # degrees
marc = arc(2 / 2, 0, 180 - disp)
decal = concat(
[
decal,
decal.juxtapose(marc, unit_x.rotate(90 + disp)),
decal.juxtapose(marc.rotate(-(90 + disp)), unit_x.rotate(-disp)),
]
).line_width(0.2)
decal
# We scale the decoration to fit in the corner we created.
fudge = 0.515
corner = corner.align_bl() + decal.scale_uniform_to_x(fudge).align_bl()
corner = corner.align_tr().translate(-0.4, 0.4).line_color(gold)
corner.show_origin()
# The corners are rotationally symmetric.
corner4 = rot_cycle(corner, 4)
corner4
# Putting it together gives the outer frame.
set_svg_height(300)
inner = (
circle(1)
.line_width(0.3)
.line_color(gold)
.fill_color(black)
.scale_uniform_to_x(1 - 0.04)
)
part3 = fit_in(r, corner4, 0.05) + inner
part3
# !
# ## Clock Hands
# 
# To make the clock hands we just trace a path. We `make_path` and give
# it a list of coordinates. We then reflect since it is symmetric.
set_svg_height(200)
hand = (
make_path([(2, -0.5), (1, -0), (0.4, 20), (0, 21), (0, -1.5), (0.5, -1), (2, -0.5)], closed=True)
.fill_color(black)
.line_color(grey)
)
hand = (hand + hand.reflect_x()).translate(0, -4).line_width(0.1)
hand.show_origin()
hand2 = make_path(
[
(1, 0),
(1, 7),
(2, 7),
(2.5, 8),
(2, 8.5),
(1, 9.5),
(0.3, 11),
(0, 12),
(0, 0),
(1, 0),
],
closed=True
).fill_color(black)
hand2 = (hand2 + hand2.reflect_x()).translate(0, -3).line_width(0.1).line_color(grey)
hand2.show_origin()
# We then overlay them as in the picture at the right scales.
set_svg_height(300)
part4 = hand2.scale_uniform_to_y(0.5).rotate_by(0.07) + hand.scale_uniform_to_y(1.0)
part4
# ## All Together
# Our final picture overlays each of the three parts using our fitting functions.
# Each part was done separately, but they all click together to make the final image.
final = (
part3
+ fit_in(inner, (fit_in(part2, part1)), 0.0)
+ part4.scale_x(0.8).scale(0.55).rotate_by(0.10)
)
final
final.render_svg("chalk_bigben.svg", height=300)
#
================================================
FILE: examples/comparison.tex
================================================
\documentclass{article}%
\usepackage[T1]{fontenc}%
\usepackage[utf8]{inputenc}%
\usepackage{lmodern}%
\usepackage{fullpage}%
\usepackage{textcomp}%
\usepackage{lastpage}%
\usepackage{graphicx}%
%
%
%
\begin{document}%
\section{Intro}
\includegraphics[width=100pt]{examples/output/intro-01.png}
\includegraphics[width=100pt]{examples/output/intro-01.pdf}
\includegraphics[width=100pt]{examples/output/intro-02.png}
\includegraphics[width=100pt]{examples/output/intro-02.pdf}
\includegraphics[width=100pt]{examples/output/intro-03.png}
\includegraphics[width=100pt]{examples/output/intro-03.pdf}
\includegraphics[width=100pt]{examples/output/intro-04.png}
\includegraphics[width=100pt]{examples/output/intro-04.pdf}
\pagebreak
\section{LeNet}
\includegraphics[width=\textwidth]{examples/output/lenet.png}
\includegraphics[width=\textwidth]{examples/output/lenet.pdf}
\pagebreak
\section{Squares}
\includegraphics[width=\textwidth]{examples/output/squares.png}
\includegraphics[width=\textwidth]{examples/output/squares.pdf}
\pagebreak
\section{Tensor}
\includegraphics[width=\textwidth]{examples/output/tensor.png}
\includegraphics[width=\textwidth]{examples/output/tensor.pdf}
\pagebreak
\section{Logo}
\includegraphics[width=\textwidth]{examples/output/logo.png}
\includegraphics[width=\textwidth]{examples/output/logo.pdf}
\pagebreak
\section{Hanoi}
\includegraphics[width=0.6\textwidth]{examples/output/hanoi.png}
\includegraphics[width=0.6\textwidth]{examples/output/hanoi.pdf}
\pagebreak
\section{Escher}
\includegraphics[width=\textwidth]{examples/output/escher-square-limit.png}
\includegraphics[width=\textwidth]{examples/output/escher-square-limit.pdf}
\pagebreak
\section{Hex}
\includegraphics[width=\textwidth]{examples/output/hex-variation.png}
\includegraphics[width=\textwidth]{examples/output/hex-variation.pdf}
\pagebreak
\end{document}
================================================
FILE: examples/escher_square_limit.py
================================================
# This example is based on a corresponding example from Lisp by Frank Buss:
# https://frank-buss.de/lisp/functional.html
# A more general implementation is provided by Jeremy Gibbons using diagrams in Haskell:
# https://archives.haskell.org/projects.haskell.org/diagrams/gallery/SquareLimit.html
import math
from toolz import take, iterate # type: ignore
from chalk import concat, make_path, square, strut
# fmt: off
markings = {
"p": [
[(4, 4), (6, 0)],
[(0, 3), (3, 4), (0, 8), (0, 3)],
[(4, 5), (7, 6), (4, 10), (4, 5)],
[(11, 0), (10, 4), (8, 8), (4, 13), (0, 16)],
[(11, 0), (14, 2), (16, 2)],
[(10, 4), (13, 5), (16, 4)],
[(9, 6), (12, 7), (16, 6)],
[(8, 8), (12, 9), (16, 8)],
[(8, 12), (16, 10)],
[(0, 16), (6, 15), (8, 16), (12, 12), (16, 12)],
[(10, 16), (12, 14), (16, 13)],
[(12, 16), (13, 15), (16, 14)],
[(14, 16), (16, 15)],
],
"q": [
[(2, 0), (4, 5), (4, 7)],
[(4, 0), (6, 5), (6, 7)],
[(6, 0), (8, 5), (8, 8)],
[(8, 0), (10, 6), (10, 9)],
[(10, 0), (14, 11)],
[(12, 0), (13, 4), (16, 8), (15, 10), (16, 16), (12, 10), (6, 7), (4, 7), (0, 8)],
[(13, 0), (16, 6)],
[(14, 0), (16, 4)],
[(15, 0), (16, 2)],
[(0, 10), (7, 11)],
[(9, 12), (10, 10), (12, 12), (9, 12)],
[(8, 15), (9, 13), (11, 15), (8, 15)],
[(0, 12), (3, 13), (7, 15), (8, 16)],
[(2, 16), (3, 13)],
[(4, 16), (5, 14)],
[(6, 16), (7, 15)],
],
"r": [
[(0, 12), (1, 14)],
[(0, 8), (2, 12)],
[(0, 4), (5, 10)],
[(0, 0), (8, 8)],
[(1, 1), (4, 0)],
[(2, 2), (8, 0)],
[(3, 3), (8, 2), (12, 0)],
[(5, 5), (12, 3), (16, 0)],
[(0, 16), (2, 12), (8, 8), (14, 6), (16, 4)],
[(6, 16), (11, 10), (16, 6)],
[(11, 16), (12, 12), (16, 8)],
[(12, 12), (16, 16)],
[(13, 13), (16, 10)],
[(14, 14), (16, 12)],
[(15, 15), (16, 14)],
],
"s": [
[(0, 0), (4, 2), (8, 2), (16, 0)],
[(0, 4), (2, 1)],
[(0, 6), (7, 4)],
[(0, 8), (8, 6)],
[(0, 10), (7, 8)],
[(0, 12), (7, 10)],
[(0, 14), (7, 13)],
[(8, 16), (7, 13), (7, 8), (8, 6), (10, 4), (16, 0)],
[(10, 16), (11, 10)],
[(10, 6), (12, 4), (12, 7), (10, 6)],
[(13, 7), (15, 5), (15, 8), (13, 7)],
[(12, 16), (13, 13), (15, 9), (16, 8)],
[(13, 13), (16, 14)],
[(14, 11), (16, 12)],
[(15, 9), (16, 10)],
],
}
# fmt: on
names = "pqrs"
blank = strut(1, 1)
θ = 90
def normalize(coords):
def center(val: float) -> float:
return (val - 8) / 16
return [(center(x), -center(y)) for x, y in coords]
def make_tile(name):
return concat(make_path(normalize(coords)) for coords in markings[name])
def quartet(tl, tr, bl, br):
diagram = (tl | tr) / (bl | br)
return diagram.center_xy().scale(0.5)
def cycle(diagram):
tl = diagram
tr = diagram.rotate(θ).rotate(θ).rotate(θ)
bl = diagram.rotate(θ)
br = diagram.rotate(θ).rotate(θ)
return quartet(tl, tr, bl, br)
fish = {name: make_tile(name) for name in names}
fish_t = quartet(fish["p"], fish["q"], fish["r"], fish["s"])
fish_u = cycle(fish["q"].rotate(θ))
side_1 = quartet(blank, blank, fish_t.rotate(θ), fish_t)
side_2 = quartet(side_1, side_1, fish_t.rotate(θ), fish_t)
corner_1 = quartet(blank, blank, blank, fish_u)
corner_2 = quartet(corner_1, side_1, side_1.rotate(θ), fish_u)
pseudocorner = quartet(corner_2, side_2, side_2.rotate(θ), fish_t.rotate(θ))
pseudolimit = cycle(pseudocorner).line_width(0.05)
output_path = "examples/output/escher-square-limit.png"
pseudolimit.render(output_path, height=512)
# SVG render
output_path = "examples/output/escher-square-limit.svg"
pseudolimit.render_svg(output_path, height=512)
output_path = "examples/output/escher-square-limit.pdf"
pseudolimit.render_pdf(output_path, height=512)
================================================
FILE: examples/hanoi.py
================================================
# Based on the following example from Diagrams
# https://archives.haskell.org/projects.haskell.org/diagrams/gallery/Hanoi.html
from PIL import Image as PILImage
from typing import Dict, List, Tuple
from colour import Color # type: ignore
from chalk import Diagram, rectangle, concat, hcat, vcat
Disk = int
Stack = List[Disk] # disks on one peg
Hanoi = List[Stack] # disks on all three pegs
Move = Tuple[int, int]
colors: List[Color] = [
Color("#9FB4CC"),
Color("#CCCC9F"),
Color("#DB4105"),
]
black = Color("black")
def draw_disk(n: Disk) -> Diagram:
return (
rectangle(n + 2, 1)
.fill_color(colors[n])
.line_color(colors[n])
.line_width(0.05)
)
draw_disk(0)
def draw_stack(s: Stack) -> Diagram:
disks = vcat(map(draw_disk, s))
post = rectangle(0.8, 6).fill_color(black)
return post.align_b() + disks.align_b()
draw_stack([0, 1])
def draw_hanoi(state: Hanoi) -> Diagram:
hsep = 7
return concat(
draw_stack(stack).translate(7 * i, 0) for i, stack in enumerate(state)
)
draw_hanoi([[0], [1, 2], []])
def solve_hanoi(num_disks: int) -> List[Move]:
def solve_hanoi_1(num_disks, *, source, spare, target):
if num_disks <= 0:
return []
else:
return (
solve_hanoi_1(num_disks - 1, source=source, spare=target, target=spare)
+ [(source, target)]
+ solve_hanoi_1(num_disks - 1, source=spare, spare=source, target=target)
)
return solve_hanoi_1(num_disks, source=0, spare=1, target=2)
def do_move(move: Move, state: Hanoi) -> Hanoi:
def remove_disk(src, state):
disk, *src_new = state[src]
state_new = state[:src] + [src_new] + state[src + 1 :]
return disk, state_new
def add_disk(tgt, disk, state):
tgt_new = [disk] + state[tgt]
state_new = state[:tgt] + [tgt_new] + state[tgt + 1 :]
return state_new
src, tgt = move
disk, state1 = remove_disk(src, state)
state2 = add_disk(tgt, disk, state1)
return state2
def state_sequence(num_disks: int) -> List[Hanoi]:
state: Hanoi = [list(range(num_disks)), [], []]
states: List[Hanoi] = [state]
for move in solve_hanoi(num_disks):
state = do_move(move, state)
states.append(state)
return states
def draw_state_sequence(seq: List[Hanoi]) -> Diagram:
return concat(draw_hanoi(state).translate(0, 7.5 * i) for i, state in enumerate(seq))
diagram = draw_state_sequence(state_sequence(3))
path = "examples/output/hanoi.svg"
diagram.render_svg(path, height=700)
try:
path = "examples/output/hanoi.png"
diagram.render(path, height=700)
PILImage.open(path)
path = "examples/output/hanoi.pdf"
diagram.render_pdf(path, height=700)
except ModuleNotFoundError:
print("Need to install Cairo")
================================================
FILE: examples/hex_variation.py
================================================
import math
import random
from itertools import product
from chalk import *
random.seed(1337)
h = math.sqrt(3) / 2
h1 = math.cos(math.pi / 3)
def hexagon_tile():
arc1 = arc(0.5, -from_radians(math.pi / 3), from_radians(math.pi / 3))
return (
arc1.translate(-1, 0)
+ vrule(2 * h)
+ arc1.rotate_by(1 / 2).translate(1, 0)
# + polygon(6, 1)
)
def rotated_hexagon_tile(n):
return hexagon_tile().rotate_rad(-n * 2 * math.pi / 3)
def center_position(x, y):
if x % 2 == 0:
return (2 - h1) * x, 2 * y * h
else:
return (2 - h1) * x, (2 * y - 1) * h
def hex_variation(num_tiles):
rows = list(range(num_tiles))
cols = list(range(num_tiles))
get_angle = lambda: random.randint(0, 2)
diagrams = [rotated_hexagon_tile(get_angle()) for _ in product(rows, cols)]
grid = [center_position(x, y) for x, y in product(rows, cols)]
return place_at(diagrams, grid)
dia = hex_variation(12).line_width(0.05)
dia = dia.rotate_by(-1 / 4)
dia.render_svg("examples/output/hex-variation.svg", height=512)
try:
dia.render("examples/output/hex-variation.png", height=512)
dia.render_pdf("examples/output/hex-variation.pdf", height=512)
except ModuleNotFoundError:
print("Need to install Cairo")
================================================
FILE: examples/hilbert.py
================================================
# Based on the following example from Diagrams
# https://archives.haskell.org/projects.haskell.org/diagrams/gallery/Hilbert.html
from PIL import Image as PILImage
from chalk import *
from chalk.transform import *
unit_x, unit_y = Trail.hrule(1), Trail.vrule(1)
# Draw a space filling Hilbert curve
def hilbert(n):
def hilbert2(m): return hilbert(m).rotate_by(0.25)
if n == 0: return Trail.empty()
h, h2 = hilbert(n -1), hilbert2(n-1)
return (h2.reflect_y() + unit_y
+ h + unit_x
+ h + unit_y.reflect_y()
+ h2.reflect_x())
d = hilbert(5).stroke().center_xy().line_width(0.05)
d.render_svg("examples/output/hilbert.svg", 500)
try:
d.render_pdf("examples/output/hilbert.pdf", 500)
d.render("examples/output/hilbert.png", 500)
PILImage.open("examples/output/hilbert.png")
except ModuleNotFoundError:
print("Need to install Cairo")
================================================
FILE: examples/intro.py
================================================
from colour import Color
from chalk import *
# define some colors
papaya = Color("#ff9700")
blue = Color("#005FDB")
path = "examples/output/intro-01.png"
d = circle(1).fill_color(papaya)
d.render(path, height=64)
# # Alternative, render as svg
path = "examples/output/intro-01.svg"
d.render_svg(path, height=64)
# Alternative, render as pdf
path = "examples/output/intro-01.pdf"
d.render_pdf(path, height=64)
path = "examples/output/intro-02.png"
d = circle(0.5).fill_color(papaya) | square(1).fill_color(blue)
d.render(path, height=64)
path = "examples/output/intro-02.svg"
d.render_svg(path, height=64)
path = "examples/output/intro-02.pdf"
d.render_pdf(path)
path = "examples/output/intro-03.png"
d = hcat(circle(0.1 * i) for i in range(1, 6)).fill_color(blue)
d.render(path, height=64)
# Alternative, render as svg
path = "examples/output/intro-03.svg"
d.render_svg(path, height=64)
# Alternative, render as pdf
path = "examples/output/intro-03.pdf"
d.render_pdf(path)
path = "examples/output/intro-04.png"
def sierpinski(n: int, size: int) -> Diagram:
if n <= 1:
return triangle(size)
else:
smaller = sierpinski(n - 1, size / 2)
return smaller.above((smaller | smaller).center_xy())
d = sierpinski(5, 4).fill_color(papaya)
d.render(path, height=256)
path = "examples/output/intro-04.svg"
d.render_svg(path, height=256)
path = "examples/output/intro-04.pdf"
d.render_pdf(path, height=256)
================================================
FILE: examples/isometric.py
================================================
from dataclasses import dataclass
from PIL import Image as PILImage
from chalk import *
from colour import Color
import numpy as np
from numpy.typing import ArrayLike
h = hstrut(2.5)
papaya = Color("#ff9700")
white = Color("white")
black = Color("black")
def lookAt(eye: ArrayLike, center: ArrayLike, up: ArrayLike):
"Python version of the haskell lookAt function in linear.projections"
f = (center - eye) / np.linalg.norm(center - eye)
s = np.cross(f, up) / np.linalg.norm(np.cross(f, up))
u = np.cross(s, f)
return np.array([[*s, 0], [*u, 0], [*-f, 0], [0, 0, 0, 1]])
def scale3(x, y, z):
return np.array([[x, 0, 0, 0], [0, y, 0, 0], [0, 0, z, 0], [0, 0, 0, 1]])
@dataclass
class D3:
x: float
y: float
z: float
def to_np(self):
return np.array([self.x, self.y, self.z])
V3 = D3
def homogenous(trails: List[List[D3]]):
"Convert list of directions to a np.array of homogenous coordinates"
return np.array([[[*o.to_np(), 1] for o in offsets] for offsets in trails])
def cube():
"3 faces of a cube drawn as offsets from the origin."
return homogenous(
[
[D3(*v) for v in offset]
for offset in [
[(1, 0, 0), (0, 1, 0), (-1, 0, 0), (0, -1, 0)],
[(1, 0, 0), (0, 0, 1), (-1, 0, 0), (0, 0, -1)],
[(0, 0, 1), (0, 1, 0), (0, 0, -1), (0, -1, 0)],
]
]
)
def to_trail(trail: ArrayLike, locations: ArrayLike):
return [
(
Path(
[Trail.from_offsets([V2(*v[:2]) for v in trail]).close().at(V2(*l[:2]))]
),
l[2],
)
for l in locations
]
def project(projection, shape3, positions):
p = homogenous([positions for _ in range(shape3.shape[0])])
locations = p @ projection.T
trails = shape3 @ projection.T
return [out for t, l in zip(trails, locations) for out in to_trail(t, l)]
# Create Data
x = np.random.rand(20, 30, 40) > 0.9
a, b, c = x.nonzero()
# Big Cube
s = scale3(*x.shape)
big_cube = cube() @ s.T
s_ = x.shape
# Isometric projection of tensor
projection = lookAt(
V3(s_[1] + s_[2], s_[0] + s_[2], s_[0] + s_[1]).to_np(),
V3(0, 0, 0).to_np(),
V3(0, 0, 1).to_np(),
)
outer = project(projection, big_cube, [V3(0, 0, 0)])
d = (
concat([p.stroke().fill_color(white).fill_opacity(0.1) for p, _ in outer])
.line_width(0.2)
.line_color(white)
)
cubes = project(projection, cube(), [V3(x, y, z) for x, y, z in zip(a, b, c)])
cubes.sort(key=lambda x: x[1], reverse=True)
d2 = concat([p.stroke() for p, _ in cubes])
d = d2.fill_color(papaya).fill_opacity(0.9).line_width(0.05).with_envelope(d) + d
d.render("output/tensor2.png", 500)
d.render_svg("output/tensor2.svg", 500)
================================================
FILE: examples/koch.py
================================================
# Based on the following example from Diagrams
# https://archives.haskell.org/projects.haskell.org/diagrams/gallery/Koch.html
from PIL import Image as PILImage
from chalk import *
from chalk.transform import *
import chalk
unit_x = Trail.hrule(1)
def koch(n):
if n == 0:
return unit_x.scale_x(5)
else:
return (
koch(n - 1).scale(1 / 3)
+ koch(n - 1).scale(1 / 3).rotate_by(+1 / 6)
+ koch(n - 1).scale(1 / 3).rotate_by(-1 / 6)
+ koch(n - 1).scale(1 / 3)
)
d = vcat(koch(i).stroke().line_width(0.01) for i in range(1, 5))
# Render
height = 512
d.render_svg("examples/output/koch.svg", height)
try:
d.render("examples/output/koch.png", height)
d.render_pdf("examples/output/koch.pdf", height)
PILImage.open("examples/output/koch.png")
except ModuleNotFoundError:
print("Need to install Cairo")
================================================
FILE: examples/latex.py
================================================
from chalk import *
from colour import Color
grey = Color("#bbbbbb")
papaya = Color("#ff9700")
left_arrow = make_path([(0, 0), (1, 0)]).reflect_x().line_width(0.03).center_xy()
def box(t):
return rectangle(1.5, 1).line_width(0.05).fill_color(papaya) + latex(t).scale(0.7)
def label(text):
return latex(text).scale(0.5).pad(0.4)
def arrow(text, d=True):
return label(text) // left_arrow
# Autograd 1
d = hcat([arrow(r"$f'_x(g(x))$"), box("$f$"), arrow(r"$f'_{g(x)}(g(x))$"), box("$g$"), arrow("1")], 0.2)
d.render_svg("examples/output/latex.svg", 100)
================================================
FILE: examples/lattice.py
================================================
import sys
from chalk import *
from colour import Color
sys.setrecursionlimit(100_000)
BLACK = Color("black")
STEPS = 7
NODES = 7
def node(i, j):
name = Name((i, j))
r = rectangle(1, 0.4, 0.1).named(name)
t = text(f"Node {i} {j}", 0.2).fill_color(BLACK)
return r + t
d = hcat([vcat([node(i, j) for j in range(NODES)], sep=1) for i in range(STEPS)], sep=2)
for i in range(NODES - 1):
for j in range(STEPS):
for j2 in range(STEPS):
src = Name((i, j))
tgt = Name((i + 1, j2))
d = d.connect_perim(src, tgt, unit_x, -unit_x)
path = "examples/output/lattice.svg"
d.render_svg(path, height=256)
path = "examples/output/lattice.png"
d.render(path, height=256)
================================================
FILE: examples/lenet.py
================================================
from PIL import Image as PILImage
from chalk import *
from colour import Color
from chalk import BoundingBox
# Colors
papaya = Color("#ff9700")
blue = Color("#005FDB")
black = Color("#000000")
white = Color("#ffffff")
grey = Color("#bbbbbb")
# Some general functions
def label(te):
"Create text."
return text(te, 2).fill_color(black).line_width(0)
def cover(d, a, b, n):
"Draw a bounding_box around a subdiagram"
e1 = d.get_subdiagram(a).get_envelope()
e2 = d.get_subdiagram(b).get_envelope()
envelope = e1 + e2
bbox = rectangle(envelope.width, envelope.height)
return bbox.named(n).translate(envelope.center.x, envelope.center.y)
def tile(d, m, n, name=""):
"Tile a digram with names"
return hcat(vcat(d.named((name, j, i)) for j in range(n)) for i in range(m)).center_xy()
def connect_all(d, a, b):
"Connect all corners of two diagrams"
for x_border in [-unit_x, unit_x]:
for y_border in [-unit_y, unit_y]:
p = x_border + y_border
d = d.connect_perim(a, b, p, p, ArrowOpts(head_arrow=empty()))
return d
# NN drawing
def cell():
return rectangle(1, 1).line_width(0.01)
def matrix(n, r, c):
return tile(cell(), c, r, n)
def back(r, n):
"Backing stack"
return concat((r.translate(-i/2, -i/2).fill_opacity((n - i + n /2) / n)
for i in range(n-1, -1, -1)))
lw = 0.05
def stack(n, size, l, top, bot):
"Feature map stack"
m = matrix(n, size, size).fill_color(Color("#dddddd"))
r = rectangle(size, size).fill_color(grey).line_width(lw)
return (label(top) / (back(r, l) + m) / label(bot)).center_xy()
stack("a", 32, 0, "", "")
def network(n, size, top, bot):
"Draw a network layer"
return (label(top) / rectangle(2, size).fill_color(grey).line_width(lw).named(n) / label(bot)).center_xy()
# The number 7
draw = make_path([(-10, -10), (10, -10 ), (-10, 10)]).line_width(0.09).line_color(blue).fill_opacity(0)
# Draw the main diagram.
h = hstrut(6.5)
d = ((stack("a", 32, 0, "", "") + draw) | (label("conv") / h) |
stack("b", 28, 6, "", "C1") | (label("pool") / h) |
stack("c", 14, 6, "", "S2") | (label("conv") / h) |
stack("d", 10, 16, "", "C3") | (label("pool") / h) | hstrut(-0.5) |
stack("e", 5, 16, "", "S4") | (label("dense") / h) |
network("dense1", 12, "", "") | (label("dense") / (h)) |
network("dense2", 8.4, "", "") | (label("dense") / h) |
network("dense3", 1, "", ""))
d = d.scale_uniform_to_x(5)
# Draw the orange boxes
boxes = [(("a", 2, 2), ("a", 6, 6)),
(("b", 2, 2), ("b", 2, 2)),
(("b", 20, 2), ("b", 23, 5)),
(("c", 10, 2), ("c", 11, 3)),
(("c", 4, 6), ("c", 8, 10)),
(("d", 4, 6), ("d", 4, 6)),
(("d", 6, 4), ("d", 9, 7)),
(("e", 3, 2), ("e", 4, 3))]
d += concat([cover(d, *b, ("box", i)).fill_color(papaya).fill_opacity(0.3) for i, b in enumerate(boxes)])
connect = [(("box", i), ("box", i + 1)) for i in range(0, 6, 2)]
for b in connect:
d = connect_all(d, *b)
d
d.render_svg("examples/output/lenet.svg", 400)
try:
d.render("examples/output/lenet.png", 400)
PILImage.open("examples/output/lenet.png")
d.render_pdf("examples/output/lenet.pdf", 400)
except ModuleNotFoundError:
print("Need to install Cairo")
================================================
FILE: examples/logo.py
================================================
from colour import Color
from chalk import *
# This code is for a Vogel subflower, ported from:
# https://diagrams.github.io/gallery/Sunflower.html
black = Color("#000000")
white = Color("white")
grey = Color("#cccccc")
def coord(m):
return from_polar(math.sqrt(m)/1.2, 2.4 * m)
def from_polar(r, theta):
return (r * math.cos(theta), r * math.sin(theta))
def mkCoords(n):
return [coord(i) for i in range(1, n+1)]
def floret(r):
n = math.floor(1.8 * math.sqrt(r)) % 5
# Hippie color palette.
colors = [Color(h) for h in ["#18b0dc",
"#056753",
"#b564ac",
"#e0b566",
"#e52828"]
]
return circle(0.6).line_width(0).fill_color(colors[n])
def florets(m):
return [floret(math.sqrt(i)) for i in range(1,m+1)]
def sunflower(n):
return concat(flor.translate(cord[0], cord[1]) for cord, flor in zip(mkCoords(n), florets(n)))
floret = sunflower(1900).center_xy().scale_uniform_to_x(1).center_xy()
background = rectangle(1.6, 1).fill_color(black).line_width(0).translate(-0.15, 0)
logo = text("Chalk", 0.35).fill_color(grey).line_width(0.1).line_color(black).translate(-0.4, -0.1)
mask = rectangle(1.6, 0.6).translate(-0.15, 0)
# assemble
d = (background + floret + logo).align_t().with_envelope(mask.align_t())
d.render_svg("examples/output/logo.svg", 500)
try:
d.render("examples/output/logo.png", 500)
d.render_pdf("examples/output/logo.pdf", 50)
except ModuleNotFoundError:
print("Need to install Cairo")
================================================
FILE: examples/normalized.py
================================================
from chalk import *
d = triangle(1).line_width(0.1) / triangle(0.5).line_width(0.1).scale(2) / triangle(0.5).line_width(0.1).scale_x(2).scale_y(2) / triangle(1)
height = 100
d.render_svg("examples/output/normalized.svg", height)
d.render("examples/output/normalized.png", height)
d.render_pdf("examples/output/normalized.pdf", height)
================================================
FILE: examples/output/index.html
================================================
intro-01
SVG
PNG
PDF
intro-02
SVG
PNG
PDF
intro-03
SVG
PNG
PDF
intro-04
SVG
PNG
PDF
normalized
SVG
PNG
PDF
escher-square-limit
SVG
PNG
PDF
hex-variation
SVG
PNG
PDF
koch
SVG
PNG
PDF
squares
SVG
PNG
PDF
hanoi
SVG
PNG
PDF
hilbert
SVG
PNG
PDF
lenet
SVG
PNG
PDF
logo
SVG
PNG
PDF
tournament-network
SVG
PNG
PDF
arrows
SVG
PNG
PDF
path
SVG
PNG
PDF
tensor
SVG
PNG
PDF
tree
SVG
PNG
PDF
================================================
FILE: examples/output/path.tex
================================================
\documentclass{standalone}%
\usepackage[T1]{fontenc}%
\usepackage[utf8]{inputenc}%
\usepackage{lmodern}%
\usepackage{textcomp}%
\usepackage{lastpage}%
\usepackage{tikz}%
%
%
%
\begin{document}%
\normalsize%
\begin{tikzpicture}%
\begin{scope}[cm={1.0, 0.0, 0.0, -1.0, (0.0, 0.0)}]%
\begin{scope}[cm={1.7025000519869151, 0.0, 0.0, 1.7025000519869151, (0.0, 0.0)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (1.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 1.5)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 2.5)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (-0.5,-0.5) -- (0.5,-0.5) -- (0.5,0.5) -- (-0.5,0.5) -- (-0.5,-0.5) -- cycle (-0.25,-0.25) -- (-0.25,0.25) -- (0.25,0.25) -- (0.25,-0.25) -- (-0.25,-0.25) -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 1.0)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 3.5)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (2.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=2.0, y radius=2.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=2.0, y radius=2.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=2.0, y radius=2.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=2.0, y radius=2.0]} -- cycle (1.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=90.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-270.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 6.0)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 7.5)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=-90.0] arc [
start angle=-90.0, end angle=90.0,
x radius=1.0, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 0.6)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 1.2000000000000002)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=90.0] arc [
start angle=-270.0, end angle=-450.0,
x radius=1.0, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\end{scope}%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 10.2)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 11.126776695296636)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=-44.999999999999986] arc [
start angle=-109.4712206344907, end angle=109.47122063449068,
x radius=0.7499999999999999, y radius=0.7499999999999999]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 1.5)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 3.0)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=135.00000000000003] arc [
start angle=-109.47122063449072, end angle=109.47122063449066,
x radius=0.7499999999999999, y radius=0.7499999999999999]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 3.9267766952966365)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 4.526776695296636)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=135.00000000000003] arc [
start angle=-250.52877936550934, end angle=-469.4712206344907,
x radius=0.7499999999999999, y radius=0.7499999999999999]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 1.9267766952966368)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 3.924452891525279)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=-135.0] arc [
start angle=270.0, end angle=450.0,
x radius=0.5, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 20.178006282118552)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 23.428006282118552)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (-0.7500000000000001, -2.25)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (0.0,0.0) -- (0.0,4.5) {[rotate=135.00000000000003] arc [
start angle=-315.0, end angle=-405.0,
x radius=0.5000000000000001, y radius=0.5000000000000001]} -- (1.0,5.0) {[rotate=45.000000000000014] arc [
start angle=45.0, end angle=-45.000000000000014,
x radius=0.5000000000000001, y radius=0.5000000000000001]} -- (1.5000000000000002,0.0) {[rotate=-44.999999999999986] arc [
start angle=44.99999999999999, end angle=-45.000000000000014,
x radius=0.5000000000000001, y radius=0.5000000000000001]} -- (0.5000000000000002,-0.5000000000000002) {[rotate=-135.0] arc [
start angle=45.0, end angle=-45.0,
x radius=0.5000000000000001, y radius=0.5000000000000001]} -- (0.0,0.009999999999999778) -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 3.25)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (-2.625, 4.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (0.0,0.0) -- (0.0,0.75) {[rotate=135.00000000000003] arc [
start angle=-315.0, end angle=-405.0,
x radius=0.25000000000000006, y radius=0.25000000000000006]} -- (5.0,1.0) {[rotate=45.000000000000014] arc [
start angle=45.0, end angle=-45.000000000000014,
x radius=0.25000000000000006, y radius=0.25000000000000006]} -- (5.25,0.0) {[rotate=-44.999999999999986] arc [
start angle=44.99999999999999, end angle=-45.000000000000014,
x radius=0.25000000000000006, y radius=0.25000000000000006]} -- (0.25,-0.2500000000000001) {[rotate=-135.0] arc [
start angle=45.0, end angle=-45.0,
x radius=0.25000000000000006, y radius=0.25000000000000006]} -- (-1.1102230246251565e-16,0.00999999999999989) -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 5.5)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 7.0)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (-1.0000000000000002, -2.220446049250313e-16)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (0.0,0.0) -- (0.0,0.0) {[rotate=135.00000000000003] arc [
start angle=-315.0, end angle=-405.0,
x radius=1.0, y radius=1.0]} -- (1.0,1.0000000000000004) {[rotate=45.000000000000014] arc [
start angle=45.0, end angle=-45.000000000000014,
x radius=1.0, y radius=1.0]} -- (2.0000000000000004,4.440892098500626e-16) {[rotate=-44.999999999999986] arc [
start angle=44.99999999999999, end angle=-45.000000000000014,
x radius=1.0, y radius=1.0]} -- (1.0000000000000004,-1.0) {[rotate=-135.0] arc [
start angle=45.0, end angle=-45.0,
x radius=1.0, y radius=1.0]} -- (0.0,0.01) -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 1.5000000000000002)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 2.5)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (-0.5, -0.5)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (0.0,0.0) -- (1.0,0.0) -- (1.0,1.0) -- (0.0,1.0) -- (0.0,0.0) -- cycle;%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 33.92800628211855)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 35.42800628211855)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=0.0] arc [
start angle=-180.0, end angle=-45.000000000000014,
x radius=1.0, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (1.9571067811865475, 0.0)}]%
\path (-0.25,0.0) rectangle (0.25,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (3.914213562373095, 0.0)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=180.0] arc [
start angle=-180.0, end angle=-315.0,
x radius=1.0, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.35, 0.0)}]%
\path (-0.25,0.0) rectangle (0.25,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (2.3071067811865476, 0.0)}]%
\begin{scope}[cm={-1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=0.0] arc [
start angle=-180.0, end angle=-45.000000000000014,
x radius=1.0, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (3.303817427962057, -33.0960958756463)}]%
\path (-7.996333196250992,-34.883720930232556) rectangle (7.996333196250992,34.883720930232556);%
\end{scope}%
\end{tikzpicture}%
\end{document}
================================================
FILE: examples/output/path.tex.tex
================================================
\documentclass{standalone}%
\usepackage[T1]{fontenc}%
\usepackage[utf8]{inputenc}%
\usepackage{lmodern}%
\usepackage{textcomp}%
\usepackage{lastpage}%
\usepackage{tikz}%
%
%
%
\begin{document}%
\normalsize%
\begin{tikzpicture}%
\begin{scope}[cm={1.0, 0.0, 0.0, -1.0, (0.0, 0.0)}]%
\begin{scope}[cm={1.7025000519869151, 0.0, 0.0, 1.7025000519869151, (0.0, 0.0)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (1.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 1.5)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 2.5)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (-0.5,-0.5) -- (0.5,-0.5) -- (0.5,0.5) -- (-0.5,0.5) -- (-0.5,-0.5) -- cycle (-0.25,-0.25) -- (-0.25,0.25) -- (0.25,0.25) -- (0.25,-0.25) -- (-0.25,-0.25) -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 1.0)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 3.5)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (2.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=2.0, y radius=2.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=2.0, y radius=2.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=2.0, y radius=2.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=2.0, y radius=2.0]} -- cycle (1.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=90.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-270.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 6.0)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 7.5)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=-90.0] arc [
start angle=-90.0, end angle=90.0,
x radius=1.0, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 0.6)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 1.2000000000000002)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=90.0] arc [
start angle=-270.0, end angle=-450.0,
x radius=1.0, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\end{scope}%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 10.2)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 11.126776695296636)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=-44.999999999999986] arc [
start angle=-109.4712206344907, end angle=109.47122063449068,
x radius=0.7499999999999999, y radius=0.7499999999999999]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 1.5)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 3.0)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=135.00000000000003] arc [
start angle=-109.47122063449072, end angle=109.47122063449066,
x radius=0.7499999999999999, y radius=0.7499999999999999]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 3.9267766952966365)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 4.526776695296636)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=135.00000000000003] arc [
start angle=-250.52877936550934, end angle=-469.4712206344907,
x radius=0.7499999999999999, y radius=0.7499999999999999]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 1.9267766952966368)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 3.924452891525279)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=-135.0] arc [
start angle=270.0, end angle=450.0,
x radius=0.5, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 20.178006282118552)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 23.428006282118552)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (-0.7500000000000001, -2.25)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (0.0,0.0) -- (0.0,4.5) {[rotate=135.00000000000003] arc [
start angle=-315.0, end angle=-405.0,
x radius=0.5000000000000001, y radius=0.5000000000000001]} -- (1.0,5.0) {[rotate=45.000000000000014] arc [
start angle=45.0, end angle=-45.000000000000014,
x radius=0.5000000000000001, y radius=0.5000000000000001]} -- (1.5000000000000002,0.0) {[rotate=-44.999999999999986] arc [
start angle=44.99999999999999, end angle=-45.000000000000014,
x radius=0.5000000000000001, y radius=0.5000000000000001]} -- (0.5000000000000002,-0.5000000000000002) {[rotate=-135.0] arc [
start angle=45.0, end angle=-45.0,
x radius=0.5000000000000001, y radius=0.5000000000000001]} -- (0.0,0.009999999999999778) -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 3.25)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (-2.625, 4.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (0.0,0.0) -- (0.0,0.75) {[rotate=135.00000000000003] arc [
start angle=-315.0, end angle=-405.0,
x radius=0.25000000000000006, y radius=0.25000000000000006]} -- (5.0,1.0) {[rotate=45.000000000000014] arc [
start angle=45.0, end angle=-45.000000000000014,
x radius=0.25000000000000006, y radius=0.25000000000000006]} -- (5.25,0.0) {[rotate=-44.999999999999986] arc [
start angle=44.99999999999999, end angle=-45.000000000000014,
x radius=0.25000000000000006, y radius=0.25000000000000006]} -- (0.25,-0.2500000000000001) {[rotate=-135.0] arc [
start angle=45.0, end angle=-45.0,
x radius=0.25000000000000006, y radius=0.25000000000000006]} -- (-1.1102230246251565e-16,0.00999999999999989) -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 5.5)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 7.0)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (-1.0000000000000002, -2.220446049250313e-16)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (0.0,0.0) -- (0.0,0.0) {[rotate=135.00000000000003] arc [
start angle=-315.0, end angle=-405.0,
x radius=1.0, y radius=1.0]} -- (1.0,1.0000000000000004) {[rotate=45.000000000000014] arc [
start angle=45.0, end angle=-45.000000000000014,
x radius=1.0, y radius=1.0]} -- (2.0000000000000004,4.440892098500626e-16) {[rotate=-44.999999999999986] arc [
start angle=44.99999999999999, end angle=-45.000000000000014,
x radius=1.0, y radius=1.0]} -- (1.0000000000000004,-1.0) {[rotate=-135.0] arc [
start angle=45.0, end angle=-45.0,
x radius=1.0, y radius=1.0]} -- (0.0,0.01) -- cycle;%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 1.5000000000000002)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 2.5)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (-0.5, -0.5)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt] (0.0,0.0) -- (1.0,0.0) -- (1.0,1.0) -- (0.0,1.0) -- (0.0,0.0) -- cycle;%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\begin{scope}[cm={0.0, -1.0, 1.0, 0.0, (0.0, 33.92800628211855)}]%
\path (-0.5,0.0) rectangle (0.5,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 35.42800628211855)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=0.0] arc [
start angle=-180.0, end angle=-45.000000000000014,
x radius=1.0, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (1.9571067811865475, 0.0)}]%
\path (-0.25,0.0) rectangle (0.25,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (3.914213562373095, 0.0)}]%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=180.0] arc [
start angle=-180.0, end angle=-315.0,
x radius=1.0, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (0.35, 0.0)}]%
\path (-0.25,0.0) rectangle (0.25,0.0);%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (2.3071067811865476, 0.0)}]%
\begin{scope}[cm={-1.0, 0.0, 0.0, 1.0, (0.0, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},line width=10.5pt,fill opacity=0] (0.0,0.0) {[rotate=0.0] arc [
start angle=-180.0, end angle=-45.000000000000014,
x radius=1.0, y radius=1.0]};%
\end{scope}%
\begin{scope}[cm={0.1, 0.0, 0.0, 0.1, (0.1, 0.0)}]%
\path[draw,fill={rgb,1:red,0.0; green,0.0; blue,1.0},draw={rgb,1:red,1.0; green,0.0; blue,0.0},line width=10.5pt] (0.0,0.0) {[rotate=0.0] arc [
start angle=-0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=-90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} {[rotate=180.0] arc [
start angle=-360.0, end angle=-450.0,
x radius=1.0, y radius=1.0]} {[rotate=90.0] arc [
start angle=0.0, end angle=-90.0,
x radius=1.0, y radius=1.0]} -- cycle;%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\end{scope}%
\begin{scope}[cm={1.0, 0.0, 0.0, 1.0, (3.303817427962057, -33.0960958756463)}]%
\path (-7.996333196250992,-34.883720930232556) rectangle (7.996333196250992,34.883720930232556);%
\end{scope}%
\end{tikzpicture}%
\end{document}
================================================
FILE: examples/path.py
================================================
from chalk import *
from chalk.shapes.segment import Segment
from chalk.shapes.arc import ArcSegment
from colour import Color
import math
# d = Path([ArcSegment.arc_between(P2(0, 0), P2(2, 0), 1), ArcSegment.arc_between(P2(2, 0), P2(0, 0), 1)]).stroke()
# d = Primitive.from_shape(Path([Segment(P2(0, 0), P2(1, 1))]))
# d = Primitive.from_shape(Path([Segment(P2(0, 0), P2(1, 1)),
# Segment(P2(1, 1), P2(1, 2))]))
# d = Path([ArcSegment.arc_between(P2(0, 0), P2(2, 0), 1)]).stroke()
r = 0.2
b = 1 - r
rad = 0.2 / 4
a = ArcSegment(10, 50).rotate(90)
a = ArcSegment.arc_between(P2(-1, 0), P2(0, 1.0), 1)
# print(a.p, a.q, a.r_x, a.r_y, a.angle, a.tangle)
d = []
d += [circle(1).show_origin()]
d += [(Trail.rectangle(1, 1).centered().to_path() + Trail.rectangle(0.5, 0.5).reverse().centered().to_path()).stroke()]
d += [(Trail.circle(2).centered().to_path() + Trail.circle(1.0, False).centered().to_path()).stroke()]
d += [arc_seg(2*unit_x, 1).stroke().show_origin()]
d += [arc_seg(2*unit_x, -1).stroke().show_origin()]
d += [arc_seg(unit_x + unit_y, 1).stroke().show_origin()]
d += [arc_seg(unit_x + unit_y, 1).scale(-1).stroke().show_origin()]
d += [arc_seg(unit_x + unit_y, -1).stroke().show_origin()]
d += [arc_seg(2 * unit_x, 1).scale_y(0.5).rotate(45).stroke().show_origin()]
d += [rectangle(1, 5, 0.5), rectangle(5, 1, 0.25), rectangle(1, 1, 1)]
d += [Trail.rectangle(1, 1).stroke().center_xy().show_origin()]
d += [cat(
[
arc_seg_angle(180, 135).stroke().show_origin(),
arc_seg_angle(180, 135).scale_x(-1).stroke().show_origin(),
arc_seg_angle(180, 135).stroke().scale_x(-1).show_origin(),
],
unit_x,
sep=0.5
)]
d = vcat(d, sep=1.0)
d = d.fill_color(Color("blue"))
d.render_svg("examples/output/path.svg", height=300)
d.render_pdf("examples/output/path.pdf", height=300)
d.render("examples/output/path.png", height=300)
================================================
FILE: examples/rectangle_parade.py
================================================
import random
from colour import Color
from chalk import *
blue = Color("#005FDB")
path = "examples/output/rectangle-parade.png"
d = hcat(rectangle(1 + 5*random.random(), 1 + 5*random.random()).rotate_by(random.random()).fill_color(blue).show_envelope()
for i in range(1, 20))
d.render(path, height=64)
================================================
FILE: examples/squares.py
================================================
from PIL import Image as PILImage
import math
import random
from itertools import product
from colour import Color
from chalk import square, concat, empty
random.seed(0)
def make_square():
colors = [
Color("#ff9700"), # papaya
Color("#005FDB"), # blue
]
# generate uniformly a value in [-max_angle, max_angle]
max_angle = math.pi / 24.0
θ = 2 * max_angle * random.random() - max_angle
# pick a random color
i = random.random() > 0.75
color = colors[i]
return square(0.75).line_color(color).rotate_rad(-θ)
make_square()
def make_group(num_squares=4):
return concat(make_square() for _ in range(num_squares))
make_group()
disps = range(4)
diagram = concat(make_group().translate(x, y) for x, y in product(disps, disps))
diagram = diagram.line_width(0.02)
path = "examples/output/squares.svg"
diagram.render_svg(path, height=256)
try:
path = "examples/output/squares.png"
diagram.render(path, height=256)
PILImage.open(path)
path = "examples/output/squares.pdf"
diagram.render_pdf(path, height=256)
except ModuleNotFoundError:
print("Need to install Cairo")
================================================
FILE: examples/subdiagrams.py
================================================
import pdb
from colour import Color
from chalk import *
def example1():
dia1 = square(1).translate(0, -4).named(Name("bob")) | circle(1).named(Name("joe"))
dia1 = dia1.connect(Name("bob"), Name("joe"))
dia2 = square(1).named(Name("bob")).translate(0, -4) | circle(1).named(Name("joe"))
dia2 = dia2.connect(Name("bob"), Name("joe"))
dia = hcat([dia1, dia2], sep=2)
dia.render_svg("examples/output/subdiagrams-1.svg")
def example2():
red = Color("red")
def attach(subs, dia):
sub1, sub2 = subs
p1 = tuple(sub1.get_location())
p2 = tuple(sub2.get_location())
return dia + make_path([p1, p2]).line_color(red)
def squares():
s = square(1)
return (
(s.named(Name("NW")) | s.named(Name("NE"))) /
(s.named(Name("SW")) | s.named(Name("SE"))))
dia = hcat([squares().qualify(Name(i)) for i in range(5)], sep=0.5)
pairs = [
[Name(0) + Name("NE"), Name(2) + Name("SW")],
[Name(1) + Name("SE"), Name(4) + Name("NE")],
[Name(3) + Name("NW"), Name(3) + Name("SE")],
[Name(0) + Name("SE"), Name(1) + Name("NW")],
]
for pair in pairs:
dia = dia.with_names(pair, attach)
dia = dia.show_labels(0.3)
dia.render_svg("examples/output/subdiagrams-2.svg")
def example3():
root = circle(1).named(Name("root"))
leaves = hcat([circle(1).named(Name(c)) for c in "abcde"], sep=0.5).center()
def connect(subs, nodes):
subp, subc = subs
pp = tuple(subp.boundary_from(unit_y))
pc = tuple(subc.boundary_from(-unit_y))
return nodes + make_path([pp, pc])
nodes = root / vstrut(2) / leaves
for c in "abcde":
nodes = nodes.with_names([Name("root"), Name(c)], connect)
nodes.render_svg("examples/output/subdiagrams-3.svg")
example1()
example2()
example3()
================================================
FILE: examples/tensor.py
================================================
from PIL import Image as PILImage
from chalk import *
from colour import Color
h = hstrut(2.5)
papaya = Color("#ff9700")
white = Color("white")
black = Color("black")
def draw_cube():
# Assemble cube
face_m = rectangle(1, 1).align_tl()
face_t = rectangle(1, 0.5).shear_x(-1).align_bl()
face_r = rectangle(0.5, 1).shear_y(-1).align_tr()
cube = (face_t + face_m).align_tr() + face_r
# Replace envelope with front face.
return cube.align_bl().with_envelope(face_m.align_bl())
def draw_tensor(depth, rows, columns):
"Draw a tensor"
cube = draw_cube()
# Fix this ...
hyp = (unit_y * 0.5).shear_x(-1)
# Build a matrix.
front = cat([hcat([cube for i in range(columns)])
for j in reversed(range(rows))], -unit_y).align_t()
# Build depth
return concat(front.translate(-k * hyp.x, -k * hyp.y)
for k in reversed(range(depth)))
draw_tensor(2, 3, 4)
def t(d, r, c):
return draw_tensor(d, r, c).fill_color(white)
def label(te, s=1.5):
return (text(te, s).fill_color(black).line_color(white).center_xy())
# Create a diagram.
d, r, c = 3, 4, 5
base = t(d, r, c).line_color(papaya)
m = hcat([t(1, r, c), t(d, 1, c), label("→"), (base + t(1, r, c)), (base + t(d, 1, c) ), label("="), t(d, r, c)], sep=2.5).line_width(0.02)
pathsvg = "examples/output/tensor.svg"
m.render_svg(pathsvg, 500)
path = "examples/output/tensor.png"
m.render(path, 500)
PILImage.open(path)
m.render_pdf("examples/output/tensor.pdf", 50)
================================================
FILE: examples/tests/index.tpl.html
================================================
{% for x, h in [("intro-01", 64), ("intro-02", 64), ("intro-03", 64), ("intro-04", 256), ("normalized", 100),
("escher-square-limit", 512), ("hex-variation", 512), ("koch", 512), ("squares", 256), ("hanoi", 700), ("hilbert", 500), ("lenet", 400), ("logo", 500), ("tournament-network", 128), ("arrows", 200), ("path", 300), ("tensor", 500), ("tree", 1200)] %}
{{x}}
SVG
PNG
PDF
{% endfor %}
================================================
FILE: examples/tournament-network.py
================================================
# Example taken from
# https://diagrams.github.io/doc/quickstart.html
from colour import Color
from chalk import *
white = Color("white")
green = Color("green")
pink = Color("pink")
def make_node(n):
c = circle(0.2).fill_color(green)
t = text(str(n), 0.2).fill_color(white).line_color(white).line_width(0)
return c + t
n = 6
hexagon = Trail.regular_polygon(n, 1)
nodes = [make_node(i).named(i) for i in range(n)]
nodes = [node.translate(point.x, point.y) for node, point in zip(nodes, hexagon.points())]
dia = concat(nodes)
for i in range(n):
for j in range(i + 1, n):
dia = dia.connect_outside(i, j, ArrowOpts(head_pad=0.1, tail_pad=0.1))
dia.render("examples/output/tournament-network.png")
dia.render_svg("examples/output/tournament-network.svg")
================================================
FILE: examples/tree.py
================================================
from PIL import Image as PILImage
from chalk import *
from chalk.transform import *
import random
from chalk import transform as tx
from colour import Color
blue = Color("blue")
red = Color("red")
random.seed(10)
def flip(p=0.4):
return random.random() > p
def sample_tree(n=1):
"Sample a most right-branching tree"
if n > 20:
return None
else:
return (flip(),
sample_tree(n+1) if flip(0.55) else None,
sample_tree(n+1) if flip(0.2) else None)
def draw_tree(tree, name="", ysep=5, xsep=1):
node = circle(5).named(name)
if tree is None:
node = node.fill_color(blue)
return name, node
node = node.fill_color(blue if tree[0] else red)
# Draw subtrees.
lname, l = draw_tree(tree[1], name + "l")
rname, r = draw_tree(tree[2], name + "r")
# Position node an origin and subtrees to both sides.
off = (l.get_envelope()(unit_x) + r.get_envelope()(-unit_x) + xsep) / 2
x = node / vstrut(ysep) / (l | hstrut(xsep) | r).translate(-off, 0)
# Connect to children
x = x.connect_outside(name, lname, ArrowOpts(head_arrow=empty()))
x = x.connect_outside(name, rname, ArrowOpts(head_arrow=empty()))
return name, x
_, d = draw_tree((True, (True, None, None), (False, (True, None, None), None)))
d.line_width(0.01)
_, d = draw_tree(sample_tree())
d = d.line_width(0.01)
d.render_svg("examples/output/tree.svg", 1200)
d.render("examples/output/tree.png", 1200)
PILImage.open("examples/output/tree.png")
================================================
FILE: mkdocs.yml
================================================
site_name: chalk-diagrams
site_url: https://chalk-diagrams.github.io
site_description: Chalk Diagrams - A declarative drawing API
site_author: Dan Oneață and Alexander Rush
### Repository
# repo_name: chalk-diagrams/chalk-diagrams.github.io
repo_url: https://github.com/chalk-diagrams/chalk
edit_uri: '' # comment this out to disable allowing editing of the docs from the website.
remote_branch: gh-pages
remote_name: origin
### Copyright
copyright: |
Maintained by Dan Oneață and Alexander Rush.
### Preview Controls
use_directory_urls: true
strict: false
dev_addr: localhost:8000
### Configuration
docs_dir: docs
# watch a list of directories for changes
# and automatically regenerate the docs
watch:
- chalk
### Theme
theme:
name: material
include_sidebar: true
custom_dir: docs/overrides
#custom_dir: overrides
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
primary: white
accent: amber
# toggle:
# # icon: material/lightbulb-outline
# icon: material/toggle-switch-off-outline
# name: Switch to dark mode
# - media: "(prefers-color-scheme: dark)"
# scheme: slate
# primary: white
# accent: amber
# toggle:
# # icon: material/lightbulb
# icon: material/toggle-switch
# name: Switch to light mode
features:
- content.code.annotate
- content.tabs.link
# - header.autohide
# - navigation.expand
- navigation.indexes # @regular
- navigation.instant # @regular | enables "instant-loading"; good for a very large docs repo.
- navigation.sections # @regular | extending top level sections.
- navigation.tabs # @regular | enables showing toplevel sections as tabs (horizontal).
- navigation.tabs.sticky # @regular | keeps the tabs visible even when you have scrolled down.
- navigation.top # @regular | adds a "back-to-top" is shown after the user scrolls down and then starts to come back up again.
- navigation.tracking # @insiders
- search.highlight
- search.share
- search.suggest
- toc.integrate: false # @regular | integrates the nav (on-left) with toc (on-right) and places the integrated nav+toc on-left.
icon:
# repo: fontawesome/brands/git-square
repo: fontawesome/brands/git-alt
# repo: fontawesome/brands/github
# repo: fontawesome/brands/github-alt
# repo: fontawesome/brands/github-square
logo: logo.png # img/icon-white.svg
# favicon: logo.png # img/favicon.png
font:
text: Roboto
code: Roboto Mono # Source Code Pro, JetBrains Mono, Roboto Mono
language: en
### Plugins
plugins:
- exclude:
glob:
- '*/storage/*'
- search:
indexing: 'full' # 'full' (default), 'sections', 'titles'
- autorefs
- git-revision-date
# macros must be placed after plugin: git-revision-date
- macros:
include_dir: docs/assets/snippets # snippets
# j2_block_start_string: '{{%'
# j2_block_end_string: '%}}'
# j2_variable_start_string: '{{'
# j2_variable_end_string: '}}'
- markdownextradata:
data: data
- minify:
minify_html: true
# - social # @insiders
- mkdocs-jupyter:
include_source: true
ignore_h1_titles: true
execute: true
- tooltips
- mkdocstrings
### Extensions
markdown_extensions:
# - abbr
# - admonition
# - attr_list
# - codehilite
# - def_list
# - extra
# - footnotes
# - meta
# - md_in_html
# - smarty
# - tables
# - toc
##! Controls: markdown.extensions
- markdown.extensions.abbr # same as: - abbr
- markdown.extensions.admonition # same as: - admonition
- markdown.extensions.attr_list # same as: - attr_list
- markdown.extensions.codehilite: # same as: - codehilite
guess_lang: false
- markdown.extensions.def_list # same as: - def_list
- markdown.extensions.extra # same as: - extra
- markdown.extensions.footnotes # same as: - footnotes
- markdown.extensions.meta: # same as: - meta
- markdown.extensions.md_in_html # same as: - md_in_html
- markdown.extensions.smarty: # same as: - smarty
smart_quotes: false
- markdown.extensions.tables # same as: - tables
- markdown.extensions.toc: # same as: - toc
slugify: !!python/name:pymdownx.slugs.uslugify
permalink: true
toc_depth: 6 # default: 6
#separator: "-"
- markdown_include.include:
base_path: docs
##! Controls: mdx
- mdx_include:
base_path: docs
- mdx_truly_sane_lists:
nested_indent: 2
truly_sane: true
##! Controls: pymdownx
- pymdownx.arithmatex:
generic: true
# - pymdownx.b64:
# base_path: '.'
- pymdownx.betterem:
smart_enable: all # default: 'underscore' ; options: 'underscore', 'all', 'asterisk', or 'none'
- pymdownx.caret: # "super^script^" will render as superscript text: superscript.
smart_insert: true # default: true
insert: true # default: true
superscript: true # default: true
- pymdownx.critic
- pymdownx.details
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
- pymdownx.escapeall:
hardbreak: false
nbsp: false
# Uncomment these 2 lines during development to more easily add highlights
- pymdownx.highlight:
use_pygments: true # this uses pygments
linenums: false # Set "linenums" to true for enabling
# code-block line-numbering
# globally.
# None: only enable line-numbering on a per code-block basis.
# False: disable line-numbering globally.
auto_title: false
auto_title_map: {
"Python Console Session": "Python", # lang: pycon
}
linenums_style: pymdownx-inline # table or pymdownx-inline
- pymdownx.inlinehilite:
custom_inline:
- name: math
class: arithmatex
format: !!python/name:pymdownx.arithmatex.inline_mathjax_format
- pymdownx.keys:
separator: "\uff0b"
- pymdownx.magiclink:
repo_url_shortener: true
repo_url_shorthand: true #
social_url_shorthand: true
social_url_shortener: true
user: !ENV REPO_OWNER # sugatoray, danoneata (github userid)
repo: chalk #
normalize_issue_symbols: true
- pymdownx.mark:
smart_mark: true
- pymdownx.pathconverter:
base_path: 'chalk' # default: ''
relative_path: '' # default ''
absolute: true # default: false
tags: 'a script img link object embed'
- pymdownx.progressbar:
level_class: true
add_classes: ''
#'progress-0plus progress-10plus progress-20plus progress-30plus progress-40plus progress-50plus progress-60plus progress-70plus progress-80plus progress-90plus progress-100plus'
progress_increment: 10
- pymdownx.saneheaders
- pymdownx.superfences:
# highlight_code: true # This was removed from pymdownx v9.0
preserve_tabs: false
disable_indented_code_blocks: false # default: false | set this to "true"
# if you only use fenced code-blocks.
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format ''
- name: math
class: arithmatex
format: !!python/name:pymdownx.arithmatex.fence_mathjax_format
# - name: md-render
# class: md-render
# format: !!python/name:tools.pymdownx_md_render.md_sub_render
- pymdownx.smartsymbols
- pymdownx.snippets:
base_path:
- '.'
- './docs_src'
- './LICENSE'
- './README.md'
- './doc' # [TODO: move the contents of this folder to the docs folder]
encoding: 'utf-8' # Encoding to use when reading in the snippets.
check_paths: true # Make the build fail if a snippet can't be found.
- pymdownx.striphtml
- pymdownx.tabbed
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.tilde # ~~text~~ will render as strikethrough text. "sub~script" will render as subscript text: subscript.
### Customization
# extra:
# version:
# default: latest
# provider: mike
# disqus: !ENV REPO_OWNER
#alternate:
#- name: en - English
# link: /
# lang: en
### Extra CSS
extra_css:
## for: termynal (terminal animation)
- assets/css-js/termynal/css/termynal.css
- assets/css-js/termynal/css/custom.css
## for: pymdownx.progressbar
- assets/css-js/general/css/progressbar.css
# - assets/css-js/pymdownx-extras/css/extra.css # (for striped progress bar)
## for: mkdocs-tooltips
- assets/css-js/mkdocs-tooltips/css/hint.min.css
- assets/css-js/mkdocs-tooltips/css/custom.css
## for: mkdocs-material using highlight.js
- https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/styles/default.min.css
## for: fastapi like side-theme
- assets/css-js/fastapi/custom.css
### Extra JS
extra_javascript:
## for: pymdownx.arithmatex
- https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML
## for: markdown.extensions.tables
- https://cdnjs.cloudflare.com/ajax/libs/tablesort/5.2.1/tablesort.min.js
- assets/css-js/general/js/tables.js
## for: termynal (terminal animation)
- assets/css-js/termynal/js/termynal.js
- assets/css-js/termynal/js/custom.js
# Set the environment variable "FONTAWESOME_KIT" with the value of the kit.
- !ENV FONTAWESOME_KIT
## for: lottiefiles
- https://unpkg.com/@lottiefiles/lottie-player@latest/dist/lottie-player.js
## for: mkdocs-material using highlight.js
- https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/highlight.min.js
- assets/css-js/general/js/highlight-config.js
## for: mkdocs-markmap
- https://unpkg.com/d3@6.7.0/dist/d3.min.js
- https://unpkg.com/markmap-lib@0.11.5/dist/browser/index.min.js
- https://unpkg.com/markmap-view@0.2.6/dist/index.min.j
## Others
- https://polyfill.io/v3/polyfill.min.js?features=es6
# - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
## for: fastapi like side-theme
- assets/css-js/fastapi/custom.js
- assets/css-js/fastapi/chat.js
### Pages: Navigation
## @@ Begin NAVIGATION
nav:
- Home: index.md
- API:
- Shapes: api/shapes.py
- Alignment: api/alignment.py
- Combinators: api/combinators.py
- Transformations: api/transformations.py
- Style: api/style.py
- Rendering: api/rendering.py
- Trails: api/trails.py
- Connections: api/names.py
- Utils: api/utils.md
- Internals: api/internals.md
- Examples:
- BigBen: examples/bigben.py
- Hanoi: examples/hanoi.py
- Koch: examples/koch.py
- LeNet: examples/lenet.py
- Squares: examples/squares.py
- Tensor: examples/tensor.py
- Tree: examples/tree.py
- About:
- about/index.md
- License: about/license.md
## @@ End NAVIGATION
================================================
FILE: pyproject.toml
================================================
[build-system]
requires = [
"setuptools",
"wheel"
]
build-backend = "setuptools.build_meta"
================================================
FILE: requirements/dev.txt
================================================
flake8>=3.6.0
black>=19.3b0
mypy>=0.95
interrogate>=1.5.0
isort>=5.10.0
darglint>=1.8.0
pre-commit>=2.2.0
# flake8-print>=4.4.0
pytest>=4.0.2
hypothesis
================================================
FILE: requirements/docs.txt
================================================
mkdocs
mkdocs-material==8.1.3
mkdocs-material-extensions>=1.0.3
pymdown-extensions>=9.0
mdx-include>=1.4.1
markdown-include>=0.6.0
mdx_truly_sane_lists>=1.2
pygments
jupyter
## Navigation & page building
# source: https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins#navigation--page-building
mkdocs-exclude>=1.0.2
mkdocs-awesome-pages-plugin>=2.5.0
mkdocs-markdownextradata-plugin>=0.2.4
## Links & references
# source: https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins#links--references
mkdocs-redirects>=1.0.3
mkdocs-tooltipster-links-plugin>=0.1.0
## HTML processing & CSS styling
# source: https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins#html-processing--css-styling
mkdocs-minify-plugin>=0.4.1
mkdocs-enumerate-headings-plugin>=0.4.5
## API documentation building
mkapi
mkautodoc
mkdocstrings[python]>=0.16.2
mkdocs-gen-files>=0.3.3
mkdocs-autorefs>=0.3.1
## Citations & bibliography
# source: https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins#citations--bibliography
mkdocs-bibtex>=1.0.0
## Code execution, variables & templating
# source: https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins#code-execution-variables--templating
pydoc-markdown>=4.6.3
mkdocs-jupyter>=0.18.2
mkdocs-markdownextradata-plugin>=0.2.4
mkdocs-markmap>=2.1.2
## Git repos and info
# source: https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins#git-repos--info
mkdocs-macros-plugin>=0.6.0
mkdocs-git-revision-date-plugin>=0.3.1
## Images, Tables, Charts & Graphs
# source: https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins#images-tables-charts--graphs
mkdocs-kroki-plugin>=0.2.0
mkdocs-drawio-exporter>=0.8.0
mkdocs-table-reader-plugin>=0.6
## PDF & site conversion
# source: https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins#pdf--site-conversion
# https://doc.courtbouillon.org/weasyprint/latest/first_steps.html#linux
mkdocs-pdf-export-plugin>=0.5.9
## Other
# source: https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins#other
mkdocs-tooltips>=0.1.0
mkdocs-coverage>=0.2.4
## Reusing content, snippets & includes
# source: https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins#reusing-content-snippets--includes
mkdocs-include-markdown-plugin>=3.2.3
================================================
FILE: requirements.txt
================================================
toolz
colour
svgwrite
cairosvg
Pillow
git+https://github.com/chalk-diagrams/planar
latextools
loguru
typing-extensions
importlib-metadata
================================================
FILE: setup.cfg
================================================
[bdist_wheel]
# what is this for?
# - https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#wheels
universal=0
[metadata]
license_file = LICENSE
[black]
line-length = 79
# exclude = '''
# /(
# \.archive
# | \.git
# | \.hg
# | \.mypy_cache
# | \.tox
# | \.venv
# | \.vscode
# | _build
# | buck-out
# | build
# | dist
# | migrations
# | site
# )/
# '''
[isort]
# make it compatible with black
profile = black
# # Make sure this matches `*.py` in .editorconfig
# ensure_newline_before_comments = true
# force_single_line = true
# lines_after_imports = 3
# include_trailing_comma = true
# use_parentheses = true
[flake8]
per-file-ignores=chalk/__init__.py: F401
max-line-length = 88
extend-ignore = E203
[darglint]
##? Source: https://github.com/terrencepreilly/darglint
## Ignore properties
ignore_properties = 1
## Ignore private methods
ignore_regex = ^_(.*)
## Use message template
# message_template = {msg_id}@{path}:{line}
## Docstring style to use:
# - google (default)
# - sphinx
# - numpy
docstring_style = google
## How strict?
# short: One-line descriptions are acceptable; anything
# more and the docstring will be fully checked.
#
# long: One-line descriptions and descriptions without
# arguments/returns/yields/etc. sections will be
# allowed. Anything more, and the docstring will
# be fully checked.
#
# full: (Default) Docstrings will be fully checked.
strictness = long
## Ignore common exceptions
# ignore_raise = ValueError,MyCustomError
## Ignore Specific Error Codes
# Example: ignore = DAR402,DAR103
#------------------------------------------------------------------------
# DAR001 # The docstring was not parsed correctly due to a syntax error.
# DAR002 # An argument/exception lacks a description
# DAR003 # A line is under-indented or over-indented.
# DAR004 # The docstring contains an extra newline where it shouldn't.
# DAR005 # The item contains a type section (parentheses), but no type.
# DAR101 # The docstring is missing a parameter in the definition.
# DAR102 # The docstring contains a parameter not in function.
# DAR103 # The docstring parameter type doesn't match function.
# DAR104 # (disabled) The docstring parameter has no type specified
# DAR105 # The docstring parameter type is malformed.
# DAR201 # The docstring is missing a return from definition.
# DAR202 # The docstring has a return not in definition.
# DAR203 # The docstring parameter type doesn't match function.
# DAR301 # The docstring is missing a yield present in definition.
# DAR302 # The docstring has a yield not in definition.
# DAR401 # The docstring is missing an exception raised.
# DAR402 # The docstring describes an exception not explicitly raised.
# DAR501 # The docstring describes a variable which is not defined.
#------------------------------------------------------------------------
ignore = DAR103
[mypy]
strict = true
warn_unreachable = true
pretty = true
show_column_numbers = true
show_error_codes = true
show_error_context = true
[mypy-chalk]
implicit_reexport = true
[mypy-chalk.shapes]
implicit_reexport = true
================================================
FILE: setup.py
================================================
import pathlib
from setuptools import find_packages, setup
LICENSE: str = "MIT"
README: str = pathlib.Path("README.md").read_text(encoding="utf-8")
# ---------------------------------------------------------------
# NOTE:
# Since the library name (chalk-diagrams) is different from
# the module (chalk), we set the custom dunder attribute
# __libname__ in chalk/__init__.py and use it there to fetch
# and set __version__ with library metadata inside
# chalk/__init__.py.
# Since, library name will not be changed in future, it is
# being maintained at two places
# 1. setup.py
# 1. chalk/__init__.py
#
# The version will be updated often only from setup.py.
# ---------------------------------------------------------------
LIBNAME: str = "chalk-diagrams"
setup(
name=LIBNAME,
version="0.2.2",
packages=find_packages(
include=["chalk", "chalk*"],
exclude=["examples", "docs", "test*"],
),
description="A declarative drawing API",
install_requires=[
"toolz",
"colour",
"svgwrite",
"Pillow",
"loguru",
"chalk-planar",
"typing-extensions",
"importlib-metadata",
],
extras_require={
"tikz": ["pylatex"],
"latex": ["latextools"],
"png": ["pycairo"],
"svg": ["cairosvg"],
},
long_description=README,
long_description_content_type="text/markdown",
author="Dan Oneață",
author_email="dan.oneata@gmail.com",
url="https://github.com/chalk-diagrams/chalk",
project_urls={
"Documentation": "https://chalk-diagrams.github.io",
"Source Code": "https://github.com/chalk-diagrams/chalk",
"Issue Tracker": "https://github.com/chalk-diagrams/chalk/issues",
},
license=LICENSE,
license_files=("LICENSE",),
classifiers=[
"Intended Audience :: Science/Research",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
f"License :: OSI Approved :: {LICENSE} License",
"Topic :: Scientific/Engineering",
],
)
================================================
FILE: tests/test_envelope.py
================================================
import math
import pytest
from hypothesis import given
from hypothesis.strategies import (
DrawFn,
composite,
integers,
lists,
one_of,
sampled_from,
)
import chalk
from chalk import (
P2,
V2,
Diagram,
Trail,
circle,
empty,
make_path,
origin,
rectangle,
unit_x,
unit_y,
)
@composite
def vectors(draw: DrawFn) -> V2:
x = draw(integers(min_value=-2, max_value=2).filter(lambda x: x != 0))
y = draw(integers(min_value=-2, max_value=2).filter(lambda x: x != 0))
return V2(x, y)
small_nat = integers(min_value=1, max_value=10)
@composite
def trails(draw: DrawFn) -> Trail:
vs = draw(lists(vectors(), min_size=1))
return Trail.from_offsets(vs)
@composite
def paths(draw: DrawFn) -> Diagram:
return draw(trails()).stroke().center_xy()
@composite
def circles(draw: DrawFn) -> Diagram:
return circle(draw(small_nat))
@composite
def rects(draw: DrawFn) -> Diagram:
return rectangle(draw(small_nat), draw(small_nat))
@composite
def shapes(draw: DrawFn) -> Diagram:
return draw(one_of(paths(), rects(), circles()))
@composite
def diagrams(draw: DrawFn) -> Diagram:
shape = empty()
for j in range(3):
lshape = draw(shapes())
shape += chalk.transform.apply_affine(draw(transforms()), lshape)
return shape
@composite
def transforms(draw: DrawFn) -> chalk.transform.Affine:
v2 = draw(vectors())
return draw(
sampled_from(
[
chalk.transform.Affine.scale(v2),
chalk.transform.Affine.translation(v2),
chalk.transform.Affine.rotation(v2.angle),
]
)
)
@given(diagrams(), vectors())
def test_envelope_trail(diagram: Diagram, vec: V2) -> None:
"Property -> Envelope bounds trace."
trace = diagram.get_trace()
env = diagram.get_envelope()
ts = trace(P2(0, 0), vec)
e = env(vec)
for t in ts:
assert e == pytest.approx(t) or e > t
@given(diagrams(), vectors())
def test_pad(diagram: Diagram, vec: V2) -> None:
orig = diagram.get_envelope()(vec)
p = diagram.pad(2)
assert p.get_envelope()(vec) == pytest.approx(2 * orig)
vec = vec.normalized()
orig = diagram.get_envelope()(vec)
f = diagram.frame(2)
assert f.get_envelope()(vec) == pytest.approx(2 + orig)
# Some specific tests.
def test_square() -> None:
square = make_path([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)])
env = square.get_envelope()
assert env(unit_x) == 1
assert env(2 * unit_x) == 0.5
assert env(unit_y) == 1
assert env((unit_x + unit_y).normalized()) == pytest.approx(
math.sqrt(1 + 1)
)
def test_circle() -> None:
d = circle(1)
env = d.get_envelope()
assert env(unit_x) == 1
assert env(2 * unit_x) == 0.5
assert env(unit_y) == 1
assert env((unit_x + unit_y).normalized()) == pytest.approx(1)
def test_circle_trace() -> None:
d = circle(1)
trace = d.get_trace()
assert set(trace(origin, unit_x)) == set([-1.0, 1.0])
assert set(trace(origin, (2 * unit_x))) == set([-0.5, 0.5])
assert set(trace(origin, unit_y)) == set([-1.0, 1.0])
trace(origin, (unit_x + unit_y))
def test_path_trace() -> None:
d = make_path([(1, 0), (1, 1)])
trace = d.get_trace()
assert trace.trace_v(origin, (unit_x + unit_y)) == V2(1.0, 1.0)
assert trace.trace_v(origin, (unit_x + unit_y).normalized()) == V2(
1.0, 1.0
)
def test_transform() -> None:
square = make_path([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)])
env = square.scale_x(2).scale_y(3).get_envelope()
assert env(unit_x) == 2
assert env(2 * unit_x) == 1
assert env(unit_y) == 3
env = square.rotate(45).get_envelope()
assert env((unit_x + unit_y).normalized()) == pytest.approx(1)
env = square.translate(-2, -2).get_envelope()
assert env(unit_x) == pytest.approx(-1)
================================================
FILE: tests/test_reverse_trail.py
================================================
from hypothesis import given
from hypothesis.strategies import (
DrawFn,
composite,
integers,
one_of,
sampled_from,
)
import chalk
from chalk import V2, Trail, unit_x
from chalk.shapes.arc import arc_seg_angle
from chalk.shapes.segment import seg
@composite
def vectors(draw: DrawFn) -> V2:
x = draw(integers(-2, 2))
y = draw(integers(-2, 2))
return V2(x, y)
@composite
def transforms(draw: DrawFn) -> chalk.transform.Affine:
v2 = draw(vectors())
return draw(
sampled_from(
[
chalk.transform.Affine.scale(unit_x),
chalk.transform.Affine.scale(v2),
chalk.transform.Affine.translation(v2),
chalk.transform.Affine.rotation(v2.angle),
]
)
)
@composite
def segment(draw: DrawFn) -> Trail:
dx = draw(integers())
dy = draw(integers())
return seg(V2(dx, dy))
@composite
def arc(draw: DrawFn) -> Trail:
angle = draw(integers(-360, 360))
dangle = draw(integers(0, 360))
return arc_seg_angle(angle, dangle)
small_nat = integers(min_value=1, max_value=10)
@composite
def trails(draw: DrawFn) -> Trail:
parts = (
draw(one_of(segment(), arc())).apply_transform(draw(transforms()))
for _ in range(draw(small_nat))
)
return sum(parts, Trail.empty())
@given(trails())
def test_involution(t: Trail) -> None:
"Reverse should be an involution."
assert t.reverse().reverse() == t
@given(trails(), trails())
def test_order(t1: Trail, t2: Trail) -> None:
assert (t1 + t2).reverse() == t2.reverse() + t1.reverse()
# Other possible tests?
# - End point of reversed trail should correspond to start point of original
# trail (and vicevers);
# - The shape of the trail is preserved.