diff --git a/build_support/catalog/draw_tree_settings.yaml b/build_support/catalog/gtdraw_settings.yaml
similarity index 100%
rename from build_support/catalog/draw_tree_settings.yaml
rename to build_support/catalog/gtdraw_settings.yaml
diff --git a/build_support/catalog/test_update.py b/build_support/catalog/test_update.py
index b3abfa56b..645dc25f9 100644
--- a/build_support/catalog/test_update.py
+++ b/build_support/catalog/test_update.py
@@ -9,10 +9,10 @@
-----------------------
``update.py`` depends on four external resources that are replaced in tests:
-1. ``DRAW_TREE_SETTINGS_CONFIG`` (a ``Path``) — swapped for a tmp YAML file so
- ``catalog_draw_tree_settings`` reads controlled config without touching the
- real ``draw_tree_settings.yaml``. ``monkeypatch.setattr(update,
- "DRAW_TREE_SETTINGS_CONFIG", yaml_file)`` replaces the module-level path for
+1. ``GTDRAW_SETTINGS_CONFIG`` (a ``Path``) — swapped for a tmp YAML file so
+ ``catalog_gtdraw_settings`` reads controlled config without touching the
+ real ``gtdraw_settings.yaml``. ``monkeypatch.setattr(update,
+ "GTDRAW_SETTINGS_CONFIG", yaml_file)`` replaces the module-level path for
the duration of a single test and restores it automatically on teardown.
2. ``CATALOG_HIERARCHY_CONFIG`` (a ``Path``) — swapped for a tmp YAML file so
@@ -20,8 +20,8 @@
``catalog_hierarchy.yaml``. Swap via ``monkeypatch.setattr(update,
"CATALOG_HIERARCHY_CONFIG", yaml_file)``.
-3. ``generate_tex`` / ``generate_png`` / ``generate_pdf`` / ``generate_svg``
- (functions imported from ``draw_tree``) — replaced with no-ops or
+3. ``tex`` / ``png`` / ``pdf`` / ``svg``
+ (functions imported from ``gtdraw``) — replaced with no-ops or
call-tracking lambdas. This lets us test RST-generation logic without
actually invoking LaTeX, and lets us assert whether image
generation was triggered at all.
@@ -37,7 +37,7 @@
import pytest
-pytest.importorskip("draw_tree") # update.py imports draw_tree at module level
+pytest.importorskip("gtdraw") # update.py imports gtdraw at module level
pytest.importorskip("yaml")
import pandas as pd # noqa: E402
@@ -57,7 +57,7 @@
"sublevel_scaling": 0,
}
-# A self-contained draw_tree_settings YAML config used by settings tests.
+# A self-contained gtdraw_settings YAML config used by settings tests.
# Slugs are entirely fictional:
# "testgroup2000" – group-level prefix covering testgroup2000/*
# "othergroup1999" – group-level prefix covering othergroup1999/*
@@ -88,8 +88,8 @@
def _write_yaml(path, content=_YAML_CONFIG):
"""Write *content* to *path* and return *path*.
- Used to create a temporary draw_tree_settings YAML file that can be
- pointed at via ``monkeypatch.setattr(update, "DRAW_TREE_SETTINGS_CONFIG",
+ Used to create a temporary gtdraw_settings YAML file that can be
+ pointed at via ``monkeypatch.setattr(update, "GTDRAW_SETTINGS_CONFIG",
path)`` without touching the real config file.
"""
path.write_text(content, encoding="utf-8")
@@ -130,7 +130,7 @@ def _make_image_files(catalog_dir, slug, fmt="efg"):
``generate_rst_table`` checks that all expected image files exist before
deciding whether to regenerate them. Touching empty files satisfies that
- check without requiring real draw_tree output, so tests that are not
+ check without requiring real gtdraw output, so tests that are not
specifically about image generation can use this helper to set up the
pre-existing-images state.
@@ -148,40 +148,40 @@ def _make_image_files(catalog_dir, slug, fmt="efg"):
# ---------------------------------------------------------------------------
-# Tests for catalog_draw_tree_settings
+# Tests for catalog_gtdraw_settings
# ---------------------------------------------------------------------------
@pytest.mark.catalog_update
class TestCatalogDrawTreeSettings:
- """Unit tests for ``catalog_draw_tree_settings(slug) -> dict``.
+ """Unit tests for ``catalog_gtdraw_settings(slug) -> dict``.
Each test writes a temporary YAML config and redirects the module-level
- ``DRAW_TREE_SETTINGS_CONFIG`` path to it via ``monkeypatch.setattr``.
- This means the real ``draw_tree_settings.yaml`` is never read or modified.
+ ``GTDRAW_SETTINGS_CONFIG`` path to it via ``monkeypatch.setattr``.
+ This means the real ``gtdraw_settings.yaml`` is never read or modified.
"""
def test_no_override_returns_defaults(self, tmp_path, monkeypatch):
"""A slug with no matching entry in ``overrides`` returns the defaults verbatim."""
yaml_file = _write_yaml(tmp_path / "settings.yaml")
- monkeypatch.setattr(update, "DRAW_TREE_SETTINGS_CONFIG", yaml_file)
- result = update.catalog_draw_tree_settings("unknowngame/v1")
+ monkeypatch.setattr(update, "GTDRAW_SETTINGS_CONFIG", yaml_file)
+ result = update.catalog_gtdraw_settings("unknowngame/v1")
assert result == _YAML_DEFAULTS
def test_exact_slug_override_applied(self, tmp_path, monkeypatch):
"""A key in ``overrides`` that exactly matches the slug is merged into defaults."""
yaml_file = _write_yaml(tmp_path / "settings.yaml")
- monkeypatch.setattr(update, "DRAW_TREE_SETTINGS_CONFIG", yaml_file)
- result = update.catalog_draw_tree_settings("testgroup2000/fig2")
+ monkeypatch.setattr(update, "GTDRAW_SETTINGS_CONFIG", yaml_file)
+ result = update.catalog_gtdraw_settings("testgroup2000/fig2")
assert result["action_label_position"] == pytest.approx(0.4)
assert result["color_scheme"] == "gambit" # defaults still present
def test_prefix_slug_override_applied(self, tmp_path, monkeypatch):
"""A group-level key (e.g. ``"testgroup2000"``) matches any slug that starts with it."""
yaml_file = _write_yaml(tmp_path / "settings.yaml")
- monkeypatch.setattr(update, "DRAW_TREE_SETTINGS_CONFIG", yaml_file)
+ monkeypatch.setattr(update, "GTDRAW_SETTINGS_CONFIG", yaml_file)
# "testgroup2000/fig1" is not listed explicitly; it matches the group prefix
- result = update.catalog_draw_tree_settings("testgroup2000/fig1")
+ result = update.catalog_gtdraw_settings("testgroup2000/fig1")
assert result["sublevel_scaling"] == 1
def test_specific_key_wins_over_group(self, tmp_path, monkeypatch):
@@ -203,19 +203,19 @@ def test_specific_key_wins_over_group(self, tmp_path, monkeypatch):
sublevel_scaling: 2
""")
yaml_file = _write_yaml(tmp_path / "settings.yaml", config)
- monkeypatch.setattr(update, "DRAW_TREE_SETTINGS_CONFIG", yaml_file)
- result = update.catalog_draw_tree_settings("testgroup2000/fig2")
+ monkeypatch.setattr(update, "GTDRAW_SETTINGS_CONFIG", yaml_file)
+ result = update.catalog_gtdraw_settings("testgroup2000/fig2")
assert result["sublevel_scaling"] == 2
def test_group_override_does_not_bleed_to_other_game(self, tmp_path, monkeypatch):
"""A group-level override applies only to games whose slug starts with that prefix."""
yaml_file = _write_yaml(tmp_path / "settings.yaml")
- monkeypatch.setattr(update, "DRAW_TREE_SETTINGS_CONFIG", yaml_file)
+ monkeypatch.setattr(update, "GTDRAW_SETTINGS_CONFIG", yaml_file)
# "othergroup1999" override sets shared_terminal_depth = False
- result_other = update.catalog_draw_tree_settings("othergroup1999/fig1")
+ result_other = update.catalog_gtdraw_settings("othergroup1999/fig1")
assert result_other["shared_terminal_depth"] is False
# "testgroup2000" has a different override; shared_terminal_depth should be True (default)
- result_test = update.catalog_draw_tree_settings("testgroup2000/fig1")
+ result_test = update.catalog_gtdraw_settings("testgroup2000/fig1")
assert result_test["shared_terminal_depth"] is True
def test_no_overrides_section_returns_defaults(self, tmp_path, monkeypatch):
@@ -226,8 +226,8 @@ def test_no_overrides_section_returns_defaults(self, tmp_path, monkeypatch):
sublevel_scaling: 0
""")
yaml_file = _write_yaml(tmp_path / "settings.yaml", config)
- monkeypatch.setattr(update, "DRAW_TREE_SETTINGS_CONFIG", yaml_file)
- result = update.catalog_draw_tree_settings("anygame/v1")
+ monkeypatch.setattr(update, "GTDRAW_SETTINGS_CONFIG", yaml_file)
+ result = update.catalog_gtdraw_settings("anygame/v1")
assert result == {"color_scheme": "gambit", "sublevel_scaling": 0}
@@ -343,12 +343,12 @@ def test_file_without_double_underscore_excluded(self, tmp_path):
class TestGenerateRstTable:
"""Tests for ``generate_rst_table(df, rst_path, ...)``.
- Image generation (generate_tex / generate_png / etc.) is mocked out so
+ Image generation (tex / png / etc.) is mocked out so
that tests can run without LaTeX installed and without reading
from the real catalog directory.
``_mock_generates`` uses ``monkeypatch.setattr`` to replace each of the
- four draw_tree generate functions in the ``update`` module's namespace with
+ four gtdraw functions in the ``update`` module's namespace with
a no-op. Because the replacement is scoped to the test, the originals are
automatically restored afterward.
@@ -360,11 +360,11 @@ class TestGenerateRstTable:
"""
def _no_op_generate(self, *args, **kwargs):
- """Stand-in for draw_tree generate_* functions; does nothing."""
+ """Stand-in for gtdraw functions; does nothing."""
def _mock_generates(self, monkeypatch):
- """Replace all four draw_tree image-generation functions with no-ops."""
- for name in ["generate_tex", "generate_png", "generate_pdf", "generate_svg"]:
+ """Replace all four gtdraw image-generation functions with no-ops."""
+ for name in ["tex", "png", "pdf", "svg"]:
monkeypatch.setattr(update, name, self._no_op_generate)
def test_efg_row_produces_rst_with_slug_and_title(self, tmp_path, monkeypatch):
@@ -380,10 +380,10 @@ def test_efg_row_produces_rst_with_slug_and_title(self, tmp_path, monkeypatch):
assert "Fake Author (2000) Figure 1" in rst
assert f'pygambit.catalog.load("{slug}")' in rst
assert f":download:`{slug}.efg" in rst # source game file download link
- assert f":download:`{slug}.ef" in rst # draw_tree intermediate file download link
+ assert f":download:`{slug}.ef" in rst # gtdraw intermediate file download link
def test_nfg_row_produces_rst_with_save_to(self, tmp_path, monkeypatch):
- """An NFG game row uses the ``save_to`` form of the draw_tree call (no .ef involved)."""
+ """An NFG game row uses the ``save_to`` form of the draw call (no .ef involved)."""
self._mock_generates(monkeypatch)
catalog_dir = tmp_path / "catalog"
slug = "fakeauthor2001/matrix1"
@@ -423,8 +423,8 @@ def test_row_without_description_is_skipped(self, tmp_path, monkeypatch):
rst = rst_path.read_text()
assert "fakeauthor2000/fig1" not in rst
- def test_curated_ef_used_in_draw_tree_call(self, tmp_path, monkeypatch):
- """When a curated .ef file exists alongside the .efg, the RST draw_tree call
+ def test_curated_ef_used_in_draw_call(self, tmp_path, monkeypatch):
+ """When a curated .ef file exists alongside the .efg, the RST draw call
references the .ef path directly rather than ``pygambit.catalog.load``."""
self._mock_generates(monkeypatch)
catalog_dir = tmp_path / "catalog"
@@ -438,20 +438,20 @@ def test_curated_ef_used_in_draw_tree_call(self, tmp_path, monkeypatch):
rst_path = tmp_path / "out.rst"
update.generate_rst_table(df, rst_path, catalog_dir=catalog_dir)
rst = rst_path.read_text()
- # Find the draw_tree( call line in the jupyter-execute block
- draw_tree_call = next(line for line in rst.splitlines() if "draw_tree(" in line)
- assert f'"../catalog/{slug}.ef"' in draw_tree_call
- assert "catalog.load" not in draw_tree_call
+ # Find the draw( call line in the jupyter-execute block
+ draw_call = next(line for line in rst.splitlines() if "draw(" in line)
+ assert f'"../catalog/{slug}.ef"' in draw_call
+ assert "catalog.load" not in draw_call
def test_images_not_regenerated_when_all_exist(self, tmp_path, monkeypatch):
"""If all expected image files are already present and ``regenerate_images`` is
- False, none of the draw_tree generate functions are called."""
+ False, none of the gtdraw image-generation functions are called."""
calls = []
# Replace generate_* with lambdas that record invocations
- monkeypatch.setattr(update, "generate_tex", lambda *a, **k: calls.append("tex"))
- monkeypatch.setattr(update, "generate_png", lambda *a, **k: calls.append("png"))
- monkeypatch.setattr(update, "generate_pdf", lambda *a, **k: calls.append("pdf"))
- monkeypatch.setattr(update, "generate_svg", lambda *a, **k: calls.append("svg"))
+ monkeypatch.setattr(update, "tex", lambda *a, **k: calls.append("tex"))
+ monkeypatch.setattr(update, "png", lambda *a, **k: calls.append("png"))
+ monkeypatch.setattr(update, "pdf", lambda *a, **k: calls.append("pdf"))
+ monkeypatch.setattr(update, "svg", lambda *a, **k: calls.append("svg"))
catalog_dir = tmp_path / "catalog"
slug = "fakeauthor2000/fig1"
_make_image_files(catalog_dir, slug, "efg") # all images already exist
@@ -465,14 +465,14 @@ def test_images_regenerated_when_flag_set(self, tmp_path, monkeypatch):
if the image files already exist.
A curated .ef file is placed in the catalog dir so ``update.py`` uses it
- as the draw_tree source rather than calling ``gbt.catalog.load``, which
+ as the gtdraw source rather than calling ``gbt.catalog.load``, which
would require the real catalog to be present.
"""
calls = []
- monkeypatch.setattr(update, "generate_tex", lambda *a, **k: calls.append("tex"))
- monkeypatch.setattr(update, "generate_png", lambda *a, **k: calls.append("png"))
- monkeypatch.setattr(update, "generate_pdf", lambda *a, **k: calls.append("pdf"))
- monkeypatch.setattr(update, "generate_svg", lambda *a, **k: calls.append("svg"))
+ monkeypatch.setattr(update, "tex", lambda *a, **k: calls.append("tex"))
+ monkeypatch.setattr(update, "png", lambda *a, **k: calls.append("png"))
+ monkeypatch.setattr(update, "pdf", lambda *a, **k: calls.append("pdf"))
+ monkeypatch.setattr(update, "svg", lambda *a, **k: calls.append("svg"))
catalog_dir = tmp_path / "catalog"
slug = "fakeauthor2000/fig1"
_make_image_files(catalog_dir, slug, "efg")
@@ -524,8 +524,8 @@ def test_multi_variant_efg_without_primary_ef_produces_tab_set(self, tmp_path, m
assert ".. tab-set::" in rst
assert ".. tab-item:: Default" in rst
assert ".. tab-item:: Wide" in rst
- assert 'draw_tree(pygambit.catalog.load("fakevariant2001/fig1")' in rst
- assert 'draw_tree("../catalog/fakevariant2001/fig1__wide.ef"' in rst
+ assert 'draw(pygambit.catalog.load("fakevariant2001/fig1")' in rst
+ assert 'draw("../catalog/fakevariant2001/fig1__wide.ef"' in rst
def test_single_variant_efg_produces_no_tab_set(self, tmp_path, monkeypatch):
"""A single curated .ef file (or no .ef file) does not produce a ``tab-set``."""
@@ -548,10 +548,10 @@ def test_per_variant_images_generated(self, tmp_path, monkeypatch):
Two variants × four generate functions = eight total calls.
"""
calls = []
- monkeypatch.setattr(update, "generate_tex", lambda *a, **k: calls.append("tex"))
- monkeypatch.setattr(update, "generate_png", lambda *a, **k: calls.append("png"))
- monkeypatch.setattr(update, "generate_pdf", lambda *a, **k: calls.append("pdf"))
- monkeypatch.setattr(update, "generate_svg", lambda *a, **k: calls.append("svg"))
+ monkeypatch.setattr(update, "tex", lambda *a, **k: calls.append("tex"))
+ monkeypatch.setattr(update, "png", lambda *a, **k: calls.append("png"))
+ monkeypatch.setattr(update, "pdf", lambda *a, **k: calls.append("pdf"))
+ monkeypatch.setattr(update, "svg", lambda *a, **k: calls.append("svg"))
catalog_dir = tmp_path / "catalog"
slug = "fakevariant2001/fig1"
game_dir = catalog_dir / "fakevariant2001"
@@ -567,10 +567,10 @@ def test_per_variant_images_not_regenerated_when_all_exist(self, tmp_path, monke
"""If all variant image files already exist and ``regenerate_images`` is False,
generate functions are not called."""
calls = []
- monkeypatch.setattr(update, "generate_tex", lambda *a, **k: calls.append("tex"))
- monkeypatch.setattr(update, "generate_png", lambda *a, **k: calls.append("png"))
- monkeypatch.setattr(update, "generate_pdf", lambda *a, **k: calls.append("pdf"))
- monkeypatch.setattr(update, "generate_svg", lambda *a, **k: calls.append("svg"))
+ monkeypatch.setattr(update, "tex", lambda *a, **k: calls.append("tex"))
+ monkeypatch.setattr(update, "png", lambda *a, **k: calls.append("png"))
+ monkeypatch.setattr(update, "pdf", lambda *a, **k: calls.append("pdf"))
+ monkeypatch.setattr(update, "svg", lambda *a, **k: calls.append("svg"))
catalog_dir = tmp_path / "catalog"
slug = "fakevariant2001/fig1"
game_dir = catalog_dir / "fakevariant2001"
@@ -658,7 +658,7 @@ class TestHierarchicalRstOutput:
"""Tests that ``generate_rst_table`` produces correctly nested dropdown RST."""
def _mock_generates(self, monkeypatch):
- for name in ["generate_tex", "generate_png", "generate_pdf", "generate_svg"]:
+ for name in ["tex", "png", "pdf", "svg"]:
monkeypatch.setattr(update, name, lambda *a, **k: None)
def _write_hierarchy_yaml(self, tmp_path, content=_HIERARCHY_YAML):
diff --git a/build_support/catalog/update.py b/build_support/catalog/update.py
index ccfb77634..0cf51385e 100644
--- a/build_support/catalog/update.py
+++ b/build_support/catalog/update.py
@@ -5,21 +5,21 @@
import pandas as pd
import yaml
-from draw_tree import generate_pdf, generate_png, generate_svg, generate_tex
+from gtdraw import pdf, png, svg, tex
import pygambit as gbt
CATALOG_RST_TABLE = Path(__file__).parent.parent.parent / "doc" / "catalog_table.rst"
CATALOG_DIR = Path(__file__).parent.parent.parent / "catalog"
MAKEFILE_AM = Path(__file__).parent.parent.parent / "Makefile.am"
-DRAW_TREE_SETTINGS_CONFIG = Path(__file__).parent / "draw_tree_settings.yaml"
+GTDRAW_SETTINGS_CONFIG = Path(__file__).parent / "gtdraw_settings.yaml"
CATALOG_HIERARCHY_CONFIG = Path(__file__).parent / "catalog_hierarchy.yaml"
SUPPORTED_GAME_FORMATS = {"efg", "nfg"}
-def catalog_draw_tree_settings(slug: str) -> dict:
- """Return the draw_tree settings for a given catalog slug."""
- with open(DRAW_TREE_SETTINGS_CONFIG, encoding="utf-8") as f:
+def catalog_gtdraw_settings(slug: str) -> dict:
+ """Return the gtdraw settings for a given catalog slug."""
+ with open(GTDRAW_SETTINGS_CONFIG, encoding="utf-8") as f:
config = yaml.safe_load(f)
settings = dict(config["defaults"])
overrides = config.get("overrides", {})
@@ -166,8 +166,8 @@ def _write_game_entry(
if variant["ef_path"].exists()
else gbt.catalog.load(slug)
)
- for func in [generate_tex, generate_png, generate_pdf, generate_svg]:
- func(source, save_to=str(viz_path), **catalog_draw_tree_settings(vkey))
+ for func in [tex, png, pdf, svg]:
+ func(source, save_to=str(viz_path), **catalog_gtdraw_settings(vkey))
img_ef = catalog_dir / "img" / f"{vkey}.ef"
if not img_ef.exists() and variant["ef_path"].exists():
shutil.copy2(variant["ef_path"], img_ef)
@@ -185,8 +185,8 @@ def _write_game_entry(
viz_path.parent.mkdir(parents=True, exist_ok=True)
curated_ef = catalog_dir / f"{slug}.ef"
source = str(curated_ef) if curated_ef.exists() else gbt.catalog.load(slug)
- for func in [generate_tex, generate_png, generate_pdf, generate_svg]:
- func(source, save_to=str(viz_path), **catalog_draw_tree_settings(slug))
+ for func in [tex, png, pdf, svg]:
+ func(source, save_to=str(viz_path), **catalog_gtdraw_settings(slug))
img_ef = catalog_dir / "img" / f"{slug}.ef"
if not img_ef.exists() and curated_ef.exists():
shutil.copy2(curated_ef, img_ef)
@@ -228,7 +228,7 @@ def _write_game_entry(
label = variant["label"]
vkey = variant["variant_key"]
settings_str = ", ".join(
- f"{k}={v!r}" for k, v in catalog_draw_tree_settings(vkey).items()
+ f"{k}={v!r}" for k, v in catalog_gtdraw_settings(vkey).items()
)
f.write(f"{i2}.. tab-item:: {label}\n")
f.write(f"{i2}\n")
@@ -236,11 +236,11 @@ def _write_game_entry(
f.write(f"{i3} :hide-code:\n")
f.write(f"{i3} \n")
f.write(f"{i4}import pygambit\n")
- f.write(f"{i4}from draw_tree import draw_tree\n")
+ f.write(f"{i4}from gtdraw import draw\n")
if variant["ef_path"].exists():
- f.write(f'{i4}draw_tree("../catalog/{vkey}.ef", {settings_str})\n')
+ f.write(f'{i4}draw("../catalog/{vkey}.ef", {settings_str})\n')
else:
- f.write(f'{i4}draw_tree(pygambit.catalog.load("{slug}"), {settings_str})\n')
+ f.write(f'{i4}draw(pygambit.catalog.load("{slug}"), {settings_str})\n')
f.write(f"{i2}\n")
f.write(f"{i1}\n")
else:
@@ -248,19 +248,19 @@ def _write_game_entry(
f.write(f"{i1} :hide-code:\n")
f.write(f"{i1} \n")
f.write(f"{i2}import pygambit\n")
- f.write(f"{i2}from draw_tree import draw_tree\n")
+ f.write(f"{i2}from gtdraw import draw\n")
if row["Format"] == "efg":
settings_str = ", ".join(
- f"{k}={v!r}" for k, v in catalog_draw_tree_settings(slug).items()
+ f"{k}={v!r}" for k, v in catalog_gtdraw_settings(slug).items()
)
curated_ef = catalog_dir / f"{slug}.ef"
if curated_ef.exists():
- f.write(f'{i2}draw_tree("../catalog/{slug}.ef", {settings_str})\n')
+ f.write(f'{i2}draw("../catalog/{slug}.ef", {settings_str})\n')
else:
- f.write(f'{i2}draw_tree(pygambit.catalog.load("{slug}"), {settings_str})\n')
+ f.write(f'{i2}draw(pygambit.catalog.load("{slug}"), {settings_str})\n')
elif row["Format"] == "nfg":
f.write(
- f'{i2}draw_tree(pygambit.catalog.load("{slug}"), '
+ f'{i2}draw(pygambit.catalog.load("{slug}"), '
f'save_to="../catalog/img/{slug}.png")\n'
)
f.write(f"{i1}\n")
@@ -403,7 +403,7 @@ def update_makefile(
help=(
"Force regeneration of all game visualisation images (PNG, PDF, SVG, TeX), "
"even if they already exist. Use this to pick up changes to game files or "
- "draw_tree_settings.yaml."
+ "gtdraw_settings.yaml."
),
)
args = parser.parse_args()
diff --git a/doc/developer.catalog.rst b/doc/developer.catalog.rst
index c37c8b567..4bde0a3c8 100644
--- a/doc/developer.catalog.rst
+++ b/doc/developer.catalog.rst
@@ -75,7 +75,7 @@ Currently supported representations are:
(e.g. ``catalog/source/game.ef``).
When present, ``update.py`` will use this file directly as input to DrawTree instead of
auto-generating the layout from the ``.efg``, preserving any hand-tuned layout.
- Consult the `DrawTree docs `_ for the ``.ef`` format.
+ Consult the `DrawTree docs `_ for the ``.ef`` format.
In general, ``.ef`` files should only be added when the layout they provide differs significantly
from what DrawTree produces automatically; if the auto-generated layout is reasonable, there is
@@ -101,10 +101,10 @@ Currently supported representations are:
Ensure you have installed the package in editable mode to automatically pick up the new game file(s) in the ``pygambit.catalog`` module without reinstalling each time.
Then use the ``update.py`` script to update Gambit's documentation & build files, as well as generating images for the new game(s).
- If you want to customise the visualisation parameters for your game(s), edit ``build_support/catalog/draw_tree_settings.yaml``.
+ If you want to customise the visualisation parameters for your game(s), edit ``build_support/catalog/gtdraw_settings.yaml``.
Add an entry under ``overrides`` keyed by your game's exact slug, or by a shared prefix (e.g. the author-year folder name) to apply settings to all games from that source.
More specific entries (longer keys) take precedence over shorter ones.
- Consult the `DrawTree docs `_ for available settings.
+ Consult the `DrawTree docs `_ for available settings.
.. code-block:: bash
@@ -129,8 +129,8 @@ Currently supported representations are:
.. tip::
- If the game visuals for extensive form games need some work and you aren't sure which settings to change in ``build_support/catalog/draw_tree_settings.yaml``, try loading the EFG in the DrawTree GUI and adjusting the layout there.
- There is an option to `download settings `_ which can be used in the Gambit catalog.
+ If the game visuals for extensive form games need some work and you aren't sure which settings to change in ``build_support/catalog/gtdraw_settings.yaml``, try loading the EFG in the DrawTree GUI and adjusting the layout there.
+ There is an option to `download settings `_ which can be used in the Gambit catalog.
5. **[Optional] Test your updates to the documentation locally:**
@@ -142,7 +142,7 @@ Currently supported representations are:
6. **Submit a pull request to GitHub with all changes.**
Submit a PR according to the :ref:`usual workflow `.
- Ensure that any additions and changes to game files, ``build_support/catalog/draw_tree_settings.yaml``, ``build_support/catalog/update.py`` and ``build_support/catalog/catalog.am`` are included.
+ Ensure that any additions and changes to game files, ``build_support/catalog/gtdraw_settings.yaml``, ``build_support/catalog/update.py`` and ``build_support/catalog/catalog.am`` are included.
.. important::
diff --git a/doc/tutorials/02_extensive_form.ipynb b/doc/tutorials/02_extensive_form.ipynb
index 5f81eeff0..1f4f6fd0e 100644
--- a/doc/tutorials/02_extensive_form.ipynb
+++ b/doc/tutorials/02_extensive_form.ipynb
@@ -4,30 +4,7 @@
"cell_type": "markdown",
"id": "96019084",
"metadata": {},
- "source": [
- "# 2) Extensive-form games\n",
- "\n",
- "In the first tutorial, we used Gambit to set up the Prisoner's Dilemma, an example of a normal (strategic) form game.\n",
- "\n",
- "Gambit can also be used to set up extensive-form games; the game is represented as a tree, where each node represents a decision point for a player, and the branches represent the possible actions they can take.\n",
- "\n",
- "**Example: One-shot trust game with binary actions**\n",
- "\n",
- "[Kreps (1990)](#references) introduced a game commonly referred to as the **trust game**.\n",
- "We will build a one-shot version of this game using Gambit's game transformation operations.\n",
- "\n",
- "The game can be defined as follows:\n",
- "- There are two players, a **Buyer** and a **Seller**.\n",
- "- The Buyer moves first and has two actions, **Trust** or **Not trust**.\n",
- "- If the Buyer chooses **Not trust**, then the game ends, and both players receive payoffs of `0`.\n",
- "- If the Buyer chooses **Trust**, then the Seller has a choice with two actions, **Honor** or **Abuse**.\n",
- "- If the Seller chooses **Honor**, both players receive payoffs of `1`;\n",
- "- If the Seller chooses **Abuse**, the Buyer receives a payoff of `-1` and the Seller receives a payoff of `2`.\n",
- "\n",
- "In addition to `pygambit`, this tutorial introduces the `draw_tree` package, which can be used to draw extensive form games in Python.\n",
- "If you're running this tutorial on your local machine, you'll need to install the requirements for [draw_tree](https://github.com/gambitproject/draw_tree), which include LaTeX, in order to run the `draw_tree` cells.\n",
- "Another option for visualising extensive form games is to install the Gambit GUI and use it to load the EFG file generated at the end of this tutorial."
- ]
+ "source": "# 2) Extensive-form games\n\nIn the first tutorial, we used Gambit to set up the Prisoner's Dilemma, an example of a normal (strategic) form game.\n\nGambit can also be used to set up extensive-form games; the game is represented as a tree, where each node represents a decision point for a player, and the branches represent the possible actions they can take.\n\n**Example: One-shot trust game with binary actions**\n\n[Kreps (1990)](#references) introduced a game commonly referred to as the **trust game**.\nWe will build a one-shot version of this game using Gambit's game transformation operations.\n\nThe game can be defined as follows:\n- There are two players, a **Buyer** and a **Seller**.\n- The Buyer moves first and has two actions, **Trust** or **Not trust**.\n- If the Buyer chooses **Not trust**, then the game ends, and both players receive payoffs of `0`.\n- If the Buyer chooses **Trust**, then the Seller has a choice with two actions, **Honor** or **Abuse**.\n- If the Seller chooses **Honor**, both players receive payoffs of `1`;\n- If the Seller chooses **Abuse**, the Buyer receives a payoff of `-1` and the Seller receives a payoff of `2`.\n\nIn addition to `pygambit`, this tutorial introduces the `gtdraw` package, which can be used to draw extensive form games in Python.\nIf you're running this tutorial on your local machine, you'll need to install the requirements for [gtdraw](https://www.gambit-project.org/gtdraw/), which include LaTeX, in order to run the `gtdraw` cells.\nAnother option for visualising extensive form games is to install the Gambit GUI and use it to load the EFG file generated at the end of this tutorial."
},
{
"cell_type": "code",
@@ -35,11 +12,7 @@
"id": "5946289b",
"metadata": {},
"outputs": [],
- "source": [
- "from draw_tree import draw_tree\n",
- "\n",
- "import pygambit as gbt"
- ]
+ "source": "from gtdraw import draw\n\nimport pygambit as gbt"
},
{
"cell_type": "markdown",
@@ -76,9 +49,7 @@
"id": "3cd94917",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(g)"
- ]
+ "source": "draw(g)"
},
{
"cell_type": "markdown",
@@ -110,9 +81,7 @@
"id": "45638fda-7e25-4c8e-b709-24b05780581b",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(g)"
- ]
+ "source": "draw(g)"
},
{
"cell_type": "markdown",
@@ -142,9 +111,7 @@
"id": "ce41e9fe-cca4-46fb-8e9d-b2c27342e5ef",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(g)"
- ]
+ "source": "draw(g)"
},
{
"cell_type": "markdown",
@@ -180,9 +147,7 @@
"id": "b3408c55-714e-4a6f-b598-e338839442e4",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(g)"
- ]
+ "source": "draw(g)"
},
{
"cell_type": "markdown",
@@ -214,9 +179,7 @@
"id": "09bedb3a-aac7-46e6-ae93-c47932c746d4",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(g)"
- ]
+ "source": "draw(g)"
},
{
"cell_type": "markdown",
@@ -248,9 +211,7 @@
"id": "cba0e562-2989-4dae-a0f0-b121635ba032",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(g)"
- ]
+ "source": "draw(g)"
},
{
"cell_type": "markdown",
@@ -297,10 +258,7 @@
"id": "56899a29-cc53-48db-9eb4-ed2295517400",
"metadata": {},
"outputs": [],
- "source": [
- "g = gbt.catalog.load(\"journals/ijgt/selten1975/fig2\")\n",
- "draw_tree(g)"
- ]
+ "source": "g = gbt.catalog.load(\"journals/ijgt/selten1975/fig2\")\ndraw(g)"
},
{
"cell_type": "markdown",
diff --git a/doc/tutorials/03_stripped_down_poker.ipynb b/doc/tutorials/03_stripped_down_poker.ipynb
index 522ac1467..5dc52da3d 100644
--- a/doc/tutorials/03_stripped_down_poker.ipynb
+++ b/doc/tutorials/03_stripped_down_poker.ipynb
@@ -4,38 +4,7 @@
"cell_type": "markdown",
"id": "98eb65d8",
"metadata": {},
- "source": [
- "# 3) Stripped-down poker\n",
- "\n",
- "In this tutorial, we'll create an extensive-form representation of a one-card poker game from [Reiley et al (2008)](#references), a classroom game under the name \"stripped-down poker\".\n",
- "This is perhaps the simplest interesting game with imperfect information.\n",
- "\n",
- "We'll use \"stripped-down poker\" to demonstrate and explain the following with Gambit:\n",
- "\n",
- "1. Setting up an extensive-form game with imperfect information using [information sets](#information-sets)\n",
- "2. [Computing and interpreting Nash equilibria](#computing-and-interpreting-nash-equilibria) and understanding mixed behaviour and mixed strategy profiles\n",
- "3. [Acceptance criteria for Nash equilibria](#acceptance-criteria-for-nash-equilibria)\n",
- "\n",
- "In our version of the game, there are two players, **Alice** and **Bob**, and a deck of cards, with equal numbers of **King** and **Queen** cards.\n",
- "\n",
- "- The game begins with each player putting \\$1 in the pot.\n",
- " - A card is dealt at random to Alice.\n",
- " - Alice observes her card.\n",
- " - Bob does not observe the card.\n",
- "- Alice then chooses either to **Bet** or to **Fold**.\n",
- " - If she chooses to Fold, Bob wins the pot and the game ends.\n",
- " - If she chooses to Bet, she adds another \\$1 to the pot.\n",
- "- Bob then chooses either to **Call** or **Fold**.\n",
- " - If he chooses to Fold, Alice wins the pot and the game ends.\n",
- " - If he chooses to Call, he adds another $1 to the pot.\n",
- "- There is then a showdown, in which Alice reveals her card.\n",
- " - If she has a King, then she wins the pot.\n",
- " - If she has a Queen, then Bob wins the pot.\n",
- "\n",
- "In addition to `pygambit`, this tutorial uses the `draw_tree` package, which can be used to draw extensive form games in Python.\n",
- "If you're running this tutorial on your local machine, you'll need to install the requirements for [draw_tree](https://github.com/gambitproject/draw_tree), which include LaTeX, in order to run the `draw_tree` cells.\n",
- "Another option for visualising extensive form games is to install the Gambit GUI and use it to load a saved EFG file."
- ]
+ "source": "# 3) Stripped-down poker\n\nIn this tutorial, we'll create an extensive-form representation of a one-card poker game from [Reiley et al (2008)](#references), a classroom game under the name \"stripped-down poker\".\nThis is perhaps the simplest interesting game with imperfect information.\n\nWe'll use \"stripped-down poker\" to demonstrate and explain the following with Gambit:\n\n1. Setting up an extensive-form game with imperfect information using [information sets](#information-sets)\n2. [Computing and interpreting Nash equilibria](#computing-and-interpreting-nash-equilibria) and understanding mixed behaviour and mixed strategy profiles\n3. [Acceptance criteria for Nash equilibria](#acceptance-criteria-for-nash-equilibria)\n\nIn our version of the game, there are two players, **Alice** and **Bob**, and a deck of cards, with equal numbers of **King** and **Queen** cards.\n\n- The game begins with each player putting \\$1 in the pot.\n - A card is dealt at random to Alice.\n - Alice observes her card.\n - Bob does not observe the card.\n- Alice then chooses either to **Bet** or to **Fold**.\n - If she chooses to Fold, Bob wins the pot and the game ends.\n - If she chooses to Bet, she adds another \\$1 to the pot.\n- Bob then chooses either to **Call** or **Fold**.\n - If he chooses to Fold, Alice wins the pot and the game ends.\n - If he chooses to Call, he adds another $1 to the pot.\n- There is then a showdown, in which Alice reveals her card.\n - If she has a King, then she wins the pot.\n - If she has a Queen, then Bob wins the pot.\n\nIn addition to `pygambit`, this tutorial uses the `gtdraw` package, which can be used to draw extensive form games in Python.\nIf you're running this tutorial on your local machine, you'll need to install the requirements for [gtdraw](https://www.gambit-project.org/gtdraw/), which include LaTeX, in order to run the `gtdraw` cells.\nAnother option for visualising extensive form games is to install the Gambit GUI and use it to load a saved EFG file."
},
{
"cell_type": "code",
@@ -43,11 +12,7 @@
"id": "69cbfe81",
"metadata": {},
"outputs": [],
- "source": [
- "from draw_tree import draw_tree\n",
- "\n",
- "import pygambit as gbt"
- ]
+ "source": "from gtdraw import draw\n\nimport pygambit as gbt"
},
{
"cell_type": "markdown",
@@ -124,9 +89,7 @@
"id": "867cb1d8-7a5d-45d1-9349-9bbc2a4e2344",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(g, color_scheme=\"gambit\")"
- ]
+ "source": "draw(g, color_scheme=\"gambit\")"
},
{
"cell_type": "markdown",
@@ -163,9 +126,7 @@
"id": "0c522c2d-992e-48b6-a1f8-0696d33cdbe0",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(g, color_scheme=\"gambit\")"
- ]
+ "source": "draw(g, color_scheme=\"gambit\")"
},
{
"cell_type": "markdown",
@@ -205,9 +166,7 @@
"id": "e85b3346-2fea-4a73-aa72-9efb436c68c1",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(g, color_scheme=\"gambit\")"
- ]
+ "source": "draw(g, color_scheme=\"gambit\")"
},
{
"cell_type": "markdown",
@@ -271,9 +230,7 @@
"id": "fdee7b53-7820-44df-9d17-d15d0b9667aa",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(g, color_scheme=\"gambit\")"
- ]
+ "source": "draw(g, color_scheme=\"gambit\")"
},
{
"cell_type": "markdown",
diff --git a/doc/tutorials/04_creating_images.ipynb b/doc/tutorials/04_creating_images.ipynb
index ec15e8f76..426cefc78 100644
--- a/doc/tutorials/04_creating_images.ipynb
+++ b/doc/tutorials/04_creating_images.ipynb
@@ -14,22 +14,13 @@
"id": "338dd237-2280-453c-a687-d65b9f9a56b6",
"metadata": {},
"outputs": [],
- "source": [
- "from draw_tree import draw_tree\n",
- "\n",
- "import pygambit as gbt"
- ]
+ "source": "from gtdraw import draw\n\nimport pygambit as gbt"
},
{
"cell_type": "markdown",
"id": "53808931-cdc1-4b39-9a62-8c5166077a84",
"metadata": {},
- "source": [
- "Using a combination of `pygambit` and the Gambit project's LaTeX graphics package `draw_tree`, we can generate publication quality images for games with just a few lines of code.\n",
- "\n",
- "This tutorial will demonstrate the key functionality of `draw_tree` when used for games built with `pygambit`, using an example game derived from the Gambit catalog.\n",
- "First, let's load the game:"
- ]
+ "source": "Using a combination of `pygambit` and the Gambit project's LaTeX graphics package `gtdraw`, we can generate publication quality images for games with just a few lines of code.\n\nThis tutorial will demonstrate the key functionality of `gtdraw` when used for games built with `pygambit`, using an example game derived from the Gambit catalog.\nFirst, let's load the game:"
},
{
"cell_type": "code",
@@ -45,9 +36,7 @@
"cell_type": "markdown",
"id": "f4141e1a-9728-4186-b547-d37050a63e66",
"metadata": {},
- "source": [
- "Now let's see how `draw_tree` renders it with default settings:"
- ]
+ "source": "Now let's see how `gtdraw` renders it with default settings:"
},
{
"cell_type": "code",
@@ -55,9 +44,7 @@
"id": "e76fc30e-c03c-4fc6-ada1-733500609ca0",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(g)"
- ]
+ "source": "draw(g)"
},
{
"cell_type": "markdown",
@@ -74,12 +61,7 @@
"id": "c9d4639a-8dc6-42c5-99a0-0a831117b551",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(\n",
- " g,\n",
- " shared_terminal_depth=True\n",
- ")"
- ]
+ "source": "draw(\n g,\n shared_terminal_depth=True\n)"
},
{
"cell_type": "markdown",
@@ -95,13 +77,7 @@
"id": "d6e7638e-9380-45ac-8809-9fd4da71be46",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(\n",
- " g,\n",
- " shared_terminal_depth=True,\n",
- " scale_factor=0.5\n",
- ")"
- ]
+ "source": "draw(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5\n)"
},
{
"cell_type": "markdown",
@@ -117,14 +93,7 @@
"id": "0abb278d-2887-46fd-b9c3-0dc987d2da25",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(\n",
- " g,\n",
- " shared_terminal_depth=True,\n",
- " scale_factor=0.5,\n",
- " level_scaling=0.75\n",
- ")"
- ]
+ "source": "draw(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5,\n level_scaling=0.75\n)"
},
{
"cell_type": "markdown",
@@ -141,15 +110,7 @@
"id": "b96266fb-4bcb-414b-b78b-ee53e40af210",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(\n",
- " g,\n",
- " shared_terminal_depth=True,\n",
- " scale_factor=0.5,\n",
- " level_scaling=0.75,\n",
- " sublevel_scaling=0\n",
- ")"
- ]
+ "source": "draw(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5,\n level_scaling=0.75,\n sublevel_scaling=0\n)"
},
{
"cell_type": "markdown",
@@ -165,16 +126,7 @@
"id": "7cb624c2-b3c3-4775-b1cd-7ef0e9d24eb1",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(\n",
- " g,\n",
- " shared_terminal_depth=True,\n",
- " scale_factor=0.5,\n",
- " level_scaling=0.75,\n",
- " sublevel_scaling=0,\n",
- " width_scaling=1.25\n",
- ")"
- ]
+ "source": "draw(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5,\n level_scaling=0.75,\n sublevel_scaling=0,\n width_scaling=1.25\n)"
},
{
"cell_type": "markdown",
@@ -190,17 +142,7 @@
"id": "6d326b08-87e2-4d49-80bf-e16981ee221f",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(\n",
- " g,\n",
- " shared_terminal_depth=True,\n",
- " scale_factor=0.5,\n",
- " level_scaling=0.75,\n",
- " sublevel_scaling=0,\n",
- " width_scaling=1.25,\n",
- " color_scheme=\"gambit\"\n",
- ")"
- ]
+ "source": "draw(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5,\n level_scaling=0.75,\n sublevel_scaling=0,\n width_scaling=1.25,\n color_scheme=\"gambit\"\n)"
},
{
"cell_type": "markdown",
@@ -218,18 +160,7 @@
"id": "bf4926bf-47eb-4758-8916-4893ae04e88d",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(\n",
- " g,\n",
- " shared_terminal_depth=True,\n",
- " scale_factor=0.5,\n",
- " level_scaling=0.75,\n",
- " sublevel_scaling=0,\n",
- " width_scaling=1.25,\n",
- " color_scheme=\"gambit\",\n",
- " edge_thickness=1.5\n",
- ")"
- ]
+ "source": "draw(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5,\n level_scaling=0.75,\n sublevel_scaling=0,\n width_scaling=1.25,\n color_scheme=\"gambit\",\n edge_thickness=1.5\n)"
},
{
"cell_type": "markdown",
@@ -247,31 +178,13 @@
"id": "0f82b80c-8f7d-41ff-9e24-ffb1524a95be",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(\n",
- " g,\n",
- " shared_terminal_depth=True,\n",
- " scale_factor=0.5,\n",
- " level_scaling=0.75,\n",
- " sublevel_scaling=0,\n",
- " width_scaling=1.25,\n",
- " color_scheme=\"gambit\",\n",
- " edge_thickness=1.5,\n",
- " action_label_position=0.6\n",
- ")"
- ]
+ "source": "draw(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5,\n level_scaling=0.75,\n sublevel_scaling=0,\n width_scaling=1.25,\n color_scheme=\"gambit\",\n edge_thickness=1.5,\n action_label_position=0.6\n)"
},
{
"cell_type": "markdown",
"id": "f77731a4-1c3a-4e83-a69e-b3b8404059b5",
"metadata": {},
- "source": [
- "## Saving images\n",
- "\n",
- "Once we are happy with our image, we can save it as a Tex file, or generate a PNG or PDF with the rendered image.\n",
- "Each of the following functions takes the same arguments as the `draw_tree` examples above.\n",
- "Setting the `save_to` argument will determine where the `.ef` file used by `draw_tree` to preserve layout information is saved, as well as the output image or Tex file:"
- ]
+ "source": "## Saving images\n\nOnce we are happy with our image, we can save it as a Tex file, or generate a PNG or PDF with the rendered image.\nEach of the following functions takes the same arguments as the `draw` examples above.\nSetting the `save_to` argument will determine where the `.ef` file used by `gtdraw` to preserve layout information is saved, as well as the output image or Tex file:"
},
{
"cell_type": "code",
@@ -279,100 +192,19 @@
"id": "e6045291-653e-4702-a95c-5c00159d4b43",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(\n",
- " g,\n",
- " shared_terminal_depth=True,\n",
- " scale_factor=0.5,\n",
- " level_scaling=0.75,\n",
- " sublevel_scaling=0,\n",
- " width_scaling=1.25,\n",
- " color_scheme=\"gambit\",\n",
- " edge_thickness=1.5,\n",
- " action_label_position=0.6,\n",
- " save_to=\"2smp\" # Creates 2smp.ef\n",
- ")"
- ]
+ "source": "draw(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5,\n level_scaling=0.75,\n sublevel_scaling=0,\n width_scaling=1.25,\n color_scheme=\"gambit\",\n edge_thickness=1.5,\n action_label_position=0.6,\n save_to=\"2smp\" # Creates 2smp.ef\n)"
},
{
"cell_type": "markdown",
"id": "d21634cc-64fd-4eed-8887-b4e3a80734fd",
"metadata": {},
- "source": [
- "### Save to TeX\n",
- "\n",
- "```python\n",
- "from draw_tree generate_tex\n",
- "generate_tex(\n",
- " g,\n",
- " shared_terminal_depth=True,\n",
- " scale_factor=0.5,\n",
- " level_scaling=0.75,\n",
- " sublevel_scaling=0,\n",
- " width_scaling=1.25,\n",
- " color_scheme=\"gambit\",\n",
- " edge_thickness=1.5,\n",
- " action_label_position=0.6,\n",
- " save_to=\"2smp\" # Creates 2smp.ef and 2smp.tex\n",
- ")\n",
- "```\n",
- "\n",
- "### Save to PDF\n",
- "\n",
- "```python\n",
- "from draw_tree import generate_pdf\n",
- "generate_pdf(\n",
- " g,\n",
- " shared_terminal_depth=True,\n",
- " scale_factor=0.5,\n",
- " level_scaling=0.75,\n",
- " sublevel_scaling=0,\n",
- " width_scaling=1.25,\n",
- " color_scheme=\"gambit\",\n",
- " edge_thickness=1.5,\n",
- " action_label_position=0.6,\n",
- " save_to=\"2smp\" # Creates 2smp.ef and 2smp.pdf\n",
- ")\n",
- "```\n",
- "\n",
- "### Save to PNG\n",
- "\n",
- "```python\n",
- "from draw_tree import generate_png\n",
- "generate_png(\n",
- " g,\n",
- " shared_terminal_depth=True,\n",
- " scale_factor=0.5,\n",
- " level_scaling=0.75,\n",
- " sublevel_scaling=0,\n",
- " width_scaling=1.25,\n",
- " color_scheme=\"gambit\",\n",
- " edge_thickness=1.5,\n",
- " action_label_position=0.6,\n",
- " save_to=\"2smp\" # Creates 2smp.ef and 2smp.png\n",
- ")\n",
- "```"
- ]
+ "source": "### Save to TeX\n\n```python\nfrom gtdraw import tex\ntex(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5,\n level_scaling=0.75,\n sublevel_scaling=0,\n width_scaling=1.25,\n color_scheme=\"gambit\",\n edge_thickness=1.5,\n action_label_position=0.6,\n save_to=\"2smp\" # Creates 2smp.ef and 2smp.tex\n)\n```\n\n### Save to PDF\n\n```python\nfrom gtdraw import pdf\npdf(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5,\n level_scaling=0.75,\n sublevel_scaling=0,\n width_scaling=1.25,\n color_scheme=\"gambit\",\n edge_thickness=1.5,\n action_label_position=0.6,\n save_to=\"2smp\" # Creates 2smp.ef and 2smp.pdf\n)\n```\n\n### Save to PNG\n\n```python\nfrom gtdraw import png\npng(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5,\n level_scaling=0.75,\n sublevel_scaling=0,\n width_scaling=1.25,\n color_scheme=\"gambit\",\n edge_thickness=1.5,\n action_label_position=0.6,\n save_to=\"2smp\" # Creates 2smp.ef and 2smp.png\n)\n```"
},
{
"cell_type": "markdown",
"id": "0fa1bb4f-4dc4-4619-b20a-f84948a69185",
"metadata": {},
- "source": [
- "## Further adjustments to game images\n",
- "\n",
- "If your image requires further adjustments, you can manually edit your game's `.ef` file.\n",
- "You can find information on EF format specs in the [draw_tree docs](https://github.com/gambitproject/draw_tree).\n",
- "\n",
- "EF files that are manually created or (exported from [Game Theory Explorer](https://gametheoryexplorer-a68c7.web.app/) can be drawn by `draw_tree` with the same functions explored in this tutorial, but you should drop the formatting parameters:\n",
- "\n",
- "```python\n",
- "draw_tree('path/to/game.ef')\n",
- "generate_tex('path/to/game.ef')\n",
- "generate_pdf('path/to/game.ef')\n",
- "generate_png('path/to/game.ef')\n",
- "```"
- ]
+ "source": "## Further adjustments to game images\n\nIf your image requires further adjustments, you can manually edit your game's `.ef` file.\nYou can find information on EF format specs in the [gtdraw docs](https://www.gambit-project.org/gtdraw/).\n\nEF files that are manually created or (exported from [Game Theory Explorer](https://gametheoryexplorer-a68c7.web.app/) can be drawn by `gtdraw` with the same functions explored in this tutorial, but you should drop the formatting parameters:\n\n```python\ndraw('path/to/game.ef')\ntex('path/to/game.ef')\npdf('path/to/game.ef')\npng('path/to/game.ef')\n```"
}
],
"metadata": {
diff --git a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb
index e1df0b2ab..e5af4cf76 100644
--- a/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb
+++ b/doc/tutorials/advanced_tutorials/agent_versus_non_agent_regret.ipynb
@@ -32,14 +32,7 @@
"id": "5142d6ba-da13-4500-bca6-e68b608bfae9",
"metadata": {},
"outputs": [],
- "source": [
- "from draw_tree import draw_tree\n",
- "\n",
- "import pygambit as gbt\n",
- "\n",
- "g = gbt.catalog.load(\"books/myerson1991/fig4_2\")\n",
- "draw_tree(g)"
- ]
+ "source": "from gtdraw import draw\n\nimport pygambit as gbt\n\ng = gbt.catalog.load(\"books/myerson1991/fig4_2\")\ndraw(g)"
},
{
"cell_type": "markdown",
diff --git a/doc/tutorials/interoperability_tutorials/openspiel.ipynb b/doc/tutorials/interoperability_tutorials/openspiel.ipynb
index c3abb6aee..65129899c 100644
--- a/doc/tutorials/interoperability_tutorials/openspiel.ipynb
+++ b/doc/tutorials/interoperability_tutorials/openspiel.ipynb
@@ -468,17 +468,7 @@
"id": "b913fc7a",
"metadata": {},
"outputs": [],
- "source": [
- "from draw_tree import draw_tree\n",
- "\n",
- "draw_tree(\n",
- " gbt_hanabi_game,\n",
- " color_scheme=\"gambit\",\n",
- " edge_thickness=2,\n",
- " action_label_position=0.8,\n",
- " shared_terminal_depth=True\n",
- ")"
- ]
+ "source": "from gtdraw import draw\n\ndraw(\n gbt_hanabi_game,\n color_scheme=\"gambit\",\n edge_thickness=2,\n action_label_position=0.8,\n shared_terminal_depth=True\n)"
},
{
"cell_type": "markdown",
@@ -751,9 +741,7 @@
"id": "ed920d33-b7c6-4cc1-b055-7244a5bf42d8",
"metadata": {},
"outputs": [],
- "source": [
- "draw_tree(gbt_one_card_poker, color_scheme=\"gambit\")"
- ]
+ "source": "draw(gbt_one_card_poker, color_scheme=\"gambit\")"
},
{
"cell_type": "markdown",
diff --git a/pyproject.toml b/pyproject.toml
index c318f952a..4fe92d3f5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -49,6 +49,7 @@ doc = [
"jupyter_sphinx",
"pyyaml",
"sphinxcontrib-bibtex",
+ "gtdraw",
]
[project.urls]