{ "cells": [ { "cell_type": "markdown", "id": "a2d556ea-37b0-47c5-a199-2cbfc68c95a9", "metadata": {}, "source": [ "# 4) Creating publication-ready game images" ] }, { "cell_type": "code", "execution_count": null, "id": "338dd237-2280-453c-a687-d65b9f9a56b6", "metadata": {}, "outputs": [], "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 `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", "execution_count": null, "id": "7f1dfa89-84fb-45cd-ab99-0a8ed44c17bc", "metadata": {}, "outputs": [], "source": [ "g = gbt.read_efg(\"../../contrib/games/2smp.efg\")" ] }, { "cell_type": "markdown", "id": "f4141e1a-9728-4186-b547-d37050a63e66", "metadata": {}, "source": "Now let's see how `gtdraw` renders it with default settings:" }, { "cell_type": "code", "execution_count": null, "id": "e76fc30e-c03c-4fc6-ada1-733500609ca0", "metadata": {}, "outputs": [], "source": "draw(g)" }, { "cell_type": "markdown", "id": "76363e9d-94df-430a-8ca9-c16b95f3880a", "metadata": {}, "source": [ "Already this looks good, but perhaps it would look neater if the terminal nodes were all extended to the bottom of the image for consistency.\n", "To achieve this, set `shared_terminal_depth=True`:" ] }, { "cell_type": "code", "execution_count": null, "id": "c9d4639a-8dc6-42c5-99a0-0a831117b551", "metadata": {}, "outputs": [], "source": "draw(\n g,\n shared_terminal_depth=True\n)" }, { "cell_type": "markdown", "id": "e6f72192-1ba3-4252-9a4c-40c37df98ef0", "metadata": {}, "source": [ "This image is quite large, but the game isn't overly complex, so we can reduce the size with the `scale_factor`:" ] }, { "cell_type": "code", "execution_count": null, "id": "d6e7638e-9380-45ac-8809-9fd4da71be46", "metadata": {}, "outputs": [], "source": "draw(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5\n)" }, { "cell_type": "markdown", "id": "98614120-85e4-4d6c-b1b0-3f03755e094e", "metadata": {}, "source": [ "Perhaps the size of the image is roughly correct, but we want to reduce the distance between node levels; we can scale the level spacing with `level_scaling`:" ] }, { "cell_type": "code", "execution_count": null, "id": "0abb278d-2887-46fd-b9c3-0dc987d2da25", "metadata": {}, "outputs": [], "source": "draw(\n g,\n shared_terminal_depth=True,\n scale_factor=0.5,\n level_scaling=0.75\n)" }, { "cell_type": "markdown", "id": "dd962391-8d52-4e45-81ae-137a65b393dd", "metadata": {}, "source": [ "By default, Gambit's layout algorithm has split nodes at the same level (depth) of the game across sublevels.\n", "For this game, it will probably look better to `sublevel_scaling` to zero:" ] }, { "cell_type": "code", "execution_count": null, "id": "b96266fb-4bcb-414b-b78b-ee53e40af210", "metadata": {}, "outputs": [], "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", "id": "f0991616-248f-4f90-b1ef-492d93d9db67", "metadata": {}, "source": [ "The player labels are looking a little cramped. Let's adjust the width by increasing the `width_scaling`:" ] }, { "cell_type": "code", "execution_count": null, "id": "7cb624c2-b3c3-4775-b1cd-7ef0e9d24eb1", "metadata": {}, "outputs": [], "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", "id": "7e06766f-91aa-4eea-aca8-d4ef8d8270b0", "metadata": {}, "source": [ "If we want to use color in our image, we can set the `color_scheme`. Here let's use the \"gambit\" color scheme:" ] }, { "cell_type": "code", "execution_count": null, "id": "6d326b08-87e2-4d49-80bf-e16981ee221f", "metadata": {}, "outputs": [], "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", "id": "35b1415d-84b9-45c2-a4e0-a05f04651042", "metadata": {}, "source": [ "An advantage to using a color scheme is that nodes no longer require player labels, which are handled by the legend, de-cluttering the image further.\n", "\n", "Let's make our image more striking by increasing the `edge_thickness`:" ] }, { "cell_type": "code", "execution_count": null, "id": "bf4926bf-47eb-4758-8916-4893ae04e88d", "metadata": {}, "outputs": [], "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", "id": "eec80871-03cd-4f8b-9b47-3d4a4ad16ce5", "metadata": {}, "source": [ "One final adjustment we could make would be to adjust the positioning of action labels on the image.\n", "This can be helpful in cases where the action labels overlap visually with information sets boundaries or other features.\n", "The default value of 0.5 places the labels halfway along the edges, which for this game looks about right, but we can change this by setting `action_label_position`:" ] }, { "cell_type": "code", "execution_count": null, "id": "0f82b80c-8f7d-41ff-9e24-ffb1524a95be", "metadata": {}, "outputs": [], "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\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", "execution_count": null, "id": "e6045291-653e-4702-a95c-5c00159d4b43", "metadata": {}, "outputs": [], "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\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\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": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.5" } }, "nbformat": 4, "nbformat_minor": 5 }