diff --git a/.github/workflows/test_and_build.yml b/.github/workflows/test_and_build.yml index 5f1ab7dde..e3930a853 100644 --- a/.github/workflows/test_and_build.yml +++ b/.github/workflows/test_and_build.yml @@ -206,7 +206,12 @@ jobs: else psgver="" fi - if [[ ${npver} == "=1.25" || ${npver} == "=1.26" ]] ; then + if [[ ${npver} == "=1.26" ]] ; then + numbaver="" + if [[ ${spver} == "=1.8" || ${spver} == "=1.9" ]] ; then + spver=$(python -c 'import random ; print(random.choice(["=1.10", "=1.11", ""]))') + fi + elif [[ ${npver} == "=1.25" ]] ; then numbaver="" if [[ ${spver} == "=1.8" ]] ; then spver=$(python -c 'import random ; print(random.choice(["=1.9", "=1.10", "=1.11", ""]))') @@ -260,7 +265,7 @@ jobs: pyyaml${yamlver} ${sparse} pandas${pdver} scipy${spver} numpy${npver} ${awkward} \ networkx${nxver} ${numba} ${fmm} ${psg} \ ${{ matrix.slowtask == 'pytest_bizarro' && 'black' || '' }} \ - ${{ matrix.slowtask == 'notebooks' && 'matplotlib nbconvert jupyter "ipython>=7"' || '' }} \ + ${{ matrix.slowtask == 'notebooks' && 'matplotlib nbconvert jupyter "ipython>=7" drawsvg' || '' }} \ ${{ steps.sourcetype.outputs.selected == 'upstream' && 'cython' || '' }} \ ${{ steps.sourcetype.outputs.selected != 'wheel' && '"graphblas>=7.4"' || '' }} \ ${{ contains(steps.pyver.outputs.selected, 'pypy') && 'pypy' || '' }} \ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bff5b80cd..565e1dc0d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -51,7 +51,7 @@ repos: - id: isort # Let's keep `pyupgrade` even though `ruff --fix` probably does most of it - repo: https://github.com/asottile/pyupgrade - rev: v3.13.0 + rev: v3.14.0 hooks: - id: pyupgrade args: [--py39-plus] @@ -80,14 +80,14 @@ repos: # These versions need updated manually - flake8==6.1.0 - flake8-bugbear==23.9.16 - - flake8-simplify==0.20.0 + - flake8-simplify==0.21.0 - repo: https://github.com/asottile/yesqa rev: v1.5.0 hooks: - id: yesqa additional_dependencies: *flake8_dependencies - repo: https://github.com/codespell-project/codespell - rev: v2.2.5 + rev: v2.2.6 hooks: - id: codespell types_or: [python, rst, markdown] diff --git a/README.md b/README.md index 4581ef54a..4509e44ac 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Python-graphblas](https://raw.githubusercontent.com/python-graphblas/python-graphblas/main/docs/_static/img/logo-name-medium.svg) +![Python-graphblas](https://raw.githubusercontent.com/python-graphblas/python-graphblas/main/docs/_static/img/logo-horizontal-medium-big.svg) [![conda-forge](https://img.shields.io/conda/vn/conda-forge/python-graphblas.svg)](https://anaconda.org/conda-forge/python-graphblas) [![pypi](https://img.shields.io/pypi/v/python-graphblas.svg)](https://pypi.python.org/pypi/python-graphblas/) diff --git a/binder/environment.yml b/binder/environment.yml index ef72a4d2b..11cd98e0c 100644 --- a/binder/environment.yml +++ b/binder/environment.yml @@ -2,9 +2,11 @@ name: graphblas channels: - conda-forge dependencies: - - python=3.10 + - python=3.11 - python-graphblas - matplotlib - networkx - pandas - scipy + - drawsvg + - cairosvg diff --git a/docs/_static/img/logo-horizontal-dark.svg b/docs/_static/img/logo-horizontal-dark.svg new file mode 100644 index 000000000..be9e5ccca --- /dev/null +++ b/docs/_static/img/logo-horizontal-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_static/img/logo-horizontal-light.svg b/docs/_static/img/logo-horizontal-light.svg new file mode 100644 index 000000000..5894eed9a --- /dev/null +++ b/docs/_static/img/logo-horizontal-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_static/img/logo-horizontal-medium-big.svg b/docs/_static/img/logo-horizontal-medium-big.svg new file mode 100644 index 000000000..649c2aef3 --- /dev/null +++ b/docs/_static/img/logo-horizontal-medium-big.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_static/img/logo-horizontal-medium.svg b/docs/_static/img/logo-horizontal-medium.svg new file mode 100644 index 000000000..038781a3f --- /dev/null +++ b/docs/_static/img/logo-horizontal-medium.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_static/img/logo-name-light.svg b/docs/_static/img/logo-name-light.svg index e9d9738ee..3331ae561 100644 --- a/docs/_static/img/logo-name-light.svg +++ b/docs/_static/img/logo-name-light.svg @@ -1 +1 @@ - + diff --git a/docs/_static/img/logo-name-medium-big.svg b/docs/_static/img/logo-name-medium-big.svg new file mode 100644 index 000000000..7bb245898 --- /dev/null +++ b/docs/_static/img/logo-name-medium-big.svg @@ -0,0 +1 @@ + diff --git a/docs/_static/img/logo-name-medium.svg b/docs/_static/img/logo-name-medium.svg index 2c718ba26..3128fda35 100644 --- a/docs/_static/img/logo-name-medium.svg +++ b/docs/_static/img/logo-name-medium.svg @@ -1 +1 @@ - + diff --git a/docs/_static/img/logo-vertical-dark.svg b/docs/_static/img/logo-vertical-dark.svg new file mode 100644 index 000000000..25dcefc17 --- /dev/null +++ b/docs/_static/img/logo-vertical-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_static/img/logo-vertical-light.svg b/docs/_static/img/logo-vertical-light.svg new file mode 100644 index 000000000..1cb22644d --- /dev/null +++ b/docs/_static/img/logo-vertical-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_static/img/logo-vertical-medium.svg b/docs/_static/img/logo-vertical-medium.svg new file mode 100644 index 000000000..db2fcaefe --- /dev/null +++ b/docs/_static/img/logo-vertical-medium.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_static/img/python-graphblas-logo.svg b/docs/_static/img/python-graphblas-logo.svg new file mode 100644 index 000000000..2422973ff --- /dev/null +++ b/docs/_static/img/python-graphblas-logo.svg @@ -0,0 +1 @@ + diff --git a/docs/conf.py b/docs/conf.py index 2e6f616d8..283f6d047 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -55,14 +55,16 @@ # html_theme = "pydata_sphinx_theme" +html_favicon = "_static/img/python-graphblas-logo.svg" + # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] html_theme_options = { "logo": { - "image_light": "_static/img/logo-name-light.svg", - "image_dark": "_static/img/logo-name-dark.svg", + "image_light": "_static/img/logo-horizontal-light.svg", + "image_dark": "_static/img/logo-horizontal-dark.svg", }, "github_url": "https://github.com/python-graphblas/python-graphblas", } diff --git a/environment.yml b/environment.yml index 1a7fb6fa8..4455f4ac6 100644 --- a/environment.yml +++ b/environment.yml @@ -48,6 +48,9 @@ dependencies: - numpydoc - pydata-sphinx-theme - sphinx-panels + # For building logo + - drawsvg + - cairosvg # EXTRA (optional; uncomment as desired) # - autoflake # - black diff --git a/notebooks/logos_and_colors.ipynb b/notebooks/logos_and_colors.ipynb new file mode 100644 index 000000000..7b64a2208 --- /dev/null +++ b/notebooks/logos_and_colors.ipynb @@ -0,0 +1,1467 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1ade2e62-38f4-4017-a0d3-e09f8587c376", + "metadata": {}, + "source": [ + "# Logos and Color Palette of Python-graphblas\n", + "\n", + "To create a minimal environment to run this notebook:\n", + "```bash\n", + "$ conda create -n drawsvg -c conda-forge drawsvg cairosvg scipy jupyter\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "bf42676c-190a-4803-a567-09e0ed260d6a", + "metadata": {}, + "outputs": [], + "source": [ + "import drawsvg as draw\n", + "import numpy as np\n", + "from scipy.spatial.transform import Rotation" + ] + }, + { + "cell_type": "markdown", + "id": "876a6128-94e4-4fb0-938d-0980a2033701", + "metadata": {}, + "source": [ + "## Define color palette" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "786f9c9e-d999-4286-bf79-009ca1681604", + "metadata": {}, + "outputs": [], + "source": [ + "# primary\n", + "blue = \"#409DC1\"\n", + "orange = \"#FF8552\"\n", + "dark_gray = \"#39393A\"\n", + "light_gray = \"#C3C3C7\"\n", + "\n", + "# Neutral, light/dark compatible\n", + "medium_gray = \"#848487\"\n", + "\n", + "# secondary\n", + "light_blue = \"#81B7CC\"\n", + "light_orange = \"#FFBB9E\"\n", + "red = \"#6D213C\"\n", + "light_red = \"#BA708A\"\n", + "green = \"#85FFC7\"\n", + "\n", + "french_rose = \"#FA4B88\" # ;)" + ] + }, + { + "cell_type": "markdown", + "id": "adb66550-f1e8-4846-a12a-e178fe801295", + "metadata": {}, + "source": [ + "## Display color palette" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "983b0cb8-db8b-4ad0-ad5a-36975d59289e", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "Primary\n", + "\n", + "#409DC1\n", + "\n", + "#FF8552\n", + "\n", + "#39393A\n", + "\n", + "#C3C3C7\n", + "\n", + "#848487\n", + "Secondary\n", + "\n", + "#81B7CC\n", + "\n", + "#FFBB9E\n", + "\n", + "#6D213C\n", + "\n", + "#BA708A\n", + "\n", + "#85FFC7\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d = draw.Drawing(750, 500, origin=\"center\")\n", + "d.append(\n", + " draw.Rectangle(-375, -250, 750, 500, fill=\"white\")\n", + ") # Add `stroke=\"black\"` border to see boundaries for testing\n", + "\n", + "dy = 25\n", + "dx = 0\n", + "w = h = 150\n", + "b = 25\n", + "x = -400 + 62.5 + dx\n", + "y = -200 + dy\n", + "\n", + "d.draw(\n", + " draw.Text(\n", + " \"Primary\",\n", + " x=x + 1.5 * (b + w) + w / 2,\n", + " y=y - b,\n", + " font_size=1.5 * b,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"black\",\n", + " )\n", + ")\n", + "d.draw(draw.Rectangle(x, y, w, h, fill=blue))\n", + "d.draw(\n", + " draw.Text(\n", + " blue.upper(),\n", + " x=x + w / 2,\n", + " y=y + h - b,\n", + " font_size=b,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"black\",\n", + " )\n", + ")\n", + "d.draw(draw.Rectangle(x + b + w, y, w, h, fill=orange))\n", + "d.draw(\n", + " draw.Text(\n", + " orange.upper(),\n", + " x=x + (b + w) + w / 2,\n", + " y=y + h - b,\n", + " font_size=b,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"black\",\n", + " )\n", + ")\n", + "d.draw(draw.Rectangle(x + 2 * (b + w), y, w, h, fill=dark_gray))\n", + "d.draw(\n", + " draw.Text(\n", + " dark_gray.upper(),\n", + " x=x + 2 * (b + w) + w / 2,\n", + " y=y + h - b,\n", + " font_size=b,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"white\",\n", + " )\n", + ")\n", + "d.draw(draw.Rectangle(x + 3 * (b + w), y, w, h, fill=light_gray))\n", + "d.draw(\n", + " draw.Text(\n", + " light_gray.upper(),\n", + " x=x + 3 * (b + w) + w / 2,\n", + " y=y + h - b,\n", + " font_size=b,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"black\",\n", + " )\n", + ")\n", + "\n", + "d.draw(draw.Rectangle(x, -25 + dy, 675, 45, fill=medium_gray))\n", + "d.draw(\n", + " draw.Text(\n", + " medium_gray.upper(),\n", + " x=x + 675 / 2,\n", + " y=-25 + 30 + dy,\n", + " font_size=22.5,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"black\",\n", + " )\n", + ")\n", + "\n", + "y = 40 + dy\n", + "w = h = 119\n", + "b = 20\n", + "d.draw(\n", + " draw.Text(\n", + " \"Secondary\",\n", + " x=x + 2 * (b + w) + w / 2,\n", + " y=y + h + 2 * b,\n", + " font_size=1.5 * b,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"black\",\n", + " )\n", + ")\n", + "d.draw(draw.Rectangle(x, y, w, h, fill=light_blue))\n", + "d.draw(\n", + " draw.Text(\n", + " light_blue.upper(),\n", + " x=x + w / 2,\n", + " y=y + h - b,\n", + " font_size=b,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"black\",\n", + " )\n", + ")\n", + "d.draw(draw.Rectangle(x + b + w, y, w, h, fill=light_orange))\n", + "d.draw(\n", + " draw.Text(\n", + " light_orange.upper(),\n", + " x=x + (b + w) + w / 2,\n", + " y=y + h - b,\n", + " font_size=b,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"black\",\n", + " )\n", + ")\n", + "d.draw(draw.Rectangle(x + 2 * (b + w), y, w, h, fill=red))\n", + "d.draw(\n", + " draw.Text(\n", + " red.upper(),\n", + " x=x + 2 * (b + w) + w / 2,\n", + " y=y + h - b,\n", + " font_size=b,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"white\",\n", + " )\n", + ")\n", + "d.draw(draw.Rectangle(x + 3 * (b + w), y, w, h, fill=light_red))\n", + "d.draw(\n", + " draw.Text(\n", + " light_red.upper(),\n", + " x=x + 3 * (b + w) + w / 2,\n", + " y=y + h - b,\n", + " font_size=b,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"black\",\n", + " )\n", + ")\n", + "d.draw(draw.Rectangle(x + 4 * (b + w), y, w, h, fill=green))\n", + "d.draw(\n", + " draw.Text(\n", + " green.upper(),\n", + " x=x + 4 * (b + w) + w / 2,\n", + " y=y + h - b,\n", + " font_size=b,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Arial\",\n", + " fill=\"black\",\n", + " )\n", + ")\n", + "\n", + "color_palette = d\n", + "d" + ] + }, + { + "cell_type": "markdown", + "id": "e59c3941-c73b-455e-88f2-4b3aae228421", + "metadata": {}, + "source": [ + "## Display color wheel" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c27e8ef2-04f2-4752-9c3b-cf297a0c87a5", + "metadata": {}, + "outputs": [], + "source": [ + "def create_color_wheel(color_wheel):\n", + " d = draw.Drawing(300, 300, origin=\"center\")\n", + " theta = np.pi / 3\n", + "\n", + " angle = 0\n", + " for i, color in enumerate(color_wheel):\n", + " angle = i * np.pi / 3\n", + " clip = draw.ClipPath()\n", + " if i == 5:\n", + " angle_offset = theta\n", + " else:\n", + " angle_offset = theta * 1.05\n", + " clip.append(\n", + " draw.Lines(\n", + " 0,\n", + " 0,\n", + " 300 * np.sin(angle),\n", + " 300 * np.cos(angle),\n", + " 300 * np.sin(angle + angle_offset),\n", + " 300 * np.cos(angle + angle_offset),\n", + " close=True,\n", + " )\n", + " )\n", + " if i == 0:\n", + " clip = None\n", + " d.append(draw.Circle(0, 0, 145, fill=color, clip_path=clip))\n", + "\n", + " angle = 3 * theta\n", + " for i, color in enumerate(color_wheel):\n", + " angle = ((i + 3) % 6) * np.pi / 3\n", + " clip = draw.ClipPath()\n", + " if i == 5:\n", + " angle_offset = theta\n", + " else:\n", + " angle_offset = theta * 1.05\n", + " clip.append(\n", + " draw.Lines(\n", + " 0,\n", + " 0,\n", + " 300 * np.sin(angle),\n", + " 300 * np.cos(angle),\n", + " 300 * np.sin(angle + angle_offset),\n", + " 300 * np.cos(angle + angle_offset),\n", + " close=True,\n", + " )\n", + " )\n", + " if i == 0:\n", + " clip = None\n", + " d.append(draw.Circle(0, 0, 105, fill=color, clip_path=clip))\n", + "\n", + " angle = theta\n", + " for i, color in enumerate(color_wheel):\n", + " angle = ((i + 1) % 6) * np.pi / 3\n", + " clip = draw.ClipPath()\n", + " if i == 5:\n", + " angle_offset = theta\n", + " else:\n", + " angle_offset = theta * 1.05\n", + " clip.append(\n", + " draw.Lines(\n", + " 0,\n", + " 0,\n", + " 300 * np.sin(angle),\n", + " 300 * np.cos(angle),\n", + " 300 * np.sin(angle + angle_offset),\n", + " 300 * np.cos(angle + angle_offset),\n", + " close=True,\n", + " )\n", + " )\n", + " if i == 0:\n", + " clip = None\n", + " d.append(draw.Circle(0, 0, 65, fill=color, clip_path=clip))\n", + "\n", + " d.append(draw.Circle(0, 0, 25, fill=medium_gray))\n", + " return d" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "2564bf63-8293-4828-8e38-d00a3b96b067", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Standard\n", + "standard_wheel = create_color_wheel(\n", + " [\n", + " blue,\n", + " light_gray,\n", + " light_blue,\n", + " dark_gray,\n", + " orange,\n", + " light_orange,\n", + " ]\n", + ")\n", + "standard_wheel" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "7a500a39-4114-49bb-aa19-912c6a8a8d95", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# High contrast\n", + "high_wheel = create_color_wheel(\n", + " [\n", + " light_gray,\n", + " blue,\n", + " green,\n", + " dark_gray,\n", + " orange,\n", + " red,\n", + " ]\n", + ")\n", + "high_wheel" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "8f404efe-2b88-4bdf-9102-2e6ad9389ca3", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Low contrast\n", + "low_wheel = create_color_wheel(\n", + " [\n", + " green,\n", + " light_red,\n", + " orange,\n", + " light_blue,\n", + " light_orange,\n", + " blue,\n", + " ]\n", + ")\n", + "low_wheel" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "fd913698-ea45-4219-8003-0fd30124d091", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Warm :)\n", + "warm_wheel = create_color_wheel(\n", + " [\n", + " light_gray, # or dark_gray\n", + " light_red,\n", + " french_rose, # ;)\n", + " red,\n", + " orange,\n", + " light_orange,\n", + " ]\n", + ")\n", + "warm_wheel" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "c7a3a5e6-4be4-4def-9687-00d1e3f80375", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Cool\n", + "cool_wheel = create_color_wheel(\n", + " [\n", + " light_blue,\n", + " light_gray,\n", + " blue,\n", + " light_red,\n", + " green,\n", + " dark_gray,\n", + " ]\n", + ")\n", + "cool_wheel" + ] + }, + { + "cell_type": "markdown", + "id": "343256c8-35a7-4c89-aa60-c6bf60930c09", + "metadata": {}, + "source": [ + "## Create logos" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "7855cd3f-8155-4d11-9730-b6041578e112", + "metadata": {}, + "outputs": [], + "source": [ + "default_angles = [\n", + " 180, # Don't modify this\n", + " 30, # How much of the \"left face\" to see\n", + " 22.5, # How much of the \"top face\" to see\n", + "]\n", + "R = Rotation.from_euler(\"ZYX\", default_angles, degrees=True).as_matrix()\n", + "\n", + "gcube = np.array(\n", + " [\n", + " [-1, 1, -1],\n", + " [-1, 1, 1],\n", + " [1, 1, 1],\n", + " [-1, -1, 1],\n", + " [1, -1, 1],\n", + " [1, 0, 1],\n", + " [0, 0, 1],\n", + " ]\n", + ")\n", + "gcube_major = gcube[:5] # Big circles\n", + "gcube_minor = gcube[5:] # Small circles\n", + "lines = np.array(\n", + " [\n", + " [gcube[1], gcube[0]],\n", + " ]\n", + ")\n", + "Gpath = np.array(\n", + " [\n", + " gcube[2],\n", + " gcube[1],\n", + " gcube[3],\n", + " gcube[4],\n", + " gcube[5],\n", + " gcube[6],\n", + " ]\n", + ")\n", + "\n", + "\n", + "def create_logo(\n", + " *,\n", + " bracket_color=None,\n", + " bg_color=None,\n", + " edge_color=None,\n", + " edge_width=8,\n", + " edge_border_color=\"white\",\n", + " edge_border_width=16,\n", + " node_color=None,\n", + " large_node_width=16,\n", + " small_node_width=8,\n", + " node_border_color=\"white\",\n", + " node_stroke_width=4,\n", + " large_border=True,\n", + " g_color=None,\n", + " angles=None,\n", + "):\n", + " if angles is None:\n", + " angles = default_angles\n", + " if edge_color is None:\n", + " edge_color = blue\n", + " if bracket_color is None:\n", + " bracket_color = edge_color\n", + " if node_color is None:\n", + " node_color = orange\n", + " if g_color is None:\n", + " g_color = edge_color\n", + "\n", + " d = draw.Drawing(190, 190, origin=\"center\")\n", + " if bg_color:\n", + " d.append(\n", + " draw.Rectangle(-95, -95, 190, 190, fill=bg_color)\n", + " ) # Add `stroke=\"black\"` border to see boundaries for testing\n", + "\n", + " scale = 40\n", + " dx = 0\n", + " dy = -2\n", + "\n", + " if edge_border_width:\n", + " # Add white border around lines\n", + " d.append(\n", + " draw.Lines(\n", + " *(((Gpath @ R) * scale)[:, :2] * [-1, 1]).ravel().tolist(),\n", + " fill=\"none\",\n", + " stroke=edge_border_color,\n", + " stroke_width=edge_border_width,\n", + " )\n", + " )\n", + " for (x0, y0, z0), (x1, y1, z1) in ((lines @ R) * scale).tolist():\n", + " x0 = -x0\n", + " x1 = -x1 # Just live with this\n", + " d.append(\n", + " draw.Line(\n", + " x0 + dx,\n", + " y0 + dy,\n", + " x1 + dx,\n", + " y1 + dy,\n", + " stroke=edge_border_color,\n", + " stroke_width=edge_border_width,\n", + " )\n", + " )\n", + "\n", + " # Add edges\n", + " d.append(\n", + " draw.Lines(\n", + " *(((Gpath @ R) * scale)[:, :2] * [-1, 1]).ravel().tolist(),\n", + " fill=\"none\",\n", + " stroke=g_color,\n", + " stroke_width=edge_width,\n", + " )\n", + " )\n", + " for (x0, y0, z0), (x1, y1, z1) in ((lines @ R) * scale).tolist():\n", + " x0 = -x0\n", + " x1 = -x1\n", + " d.append(\n", + " draw.Line(\n", + " x0 + dx, y0 + dy, x1 + dx, y1 + dy, stroke=edge_color, stroke_width=edge_width\n", + " )\n", + " )\n", + "\n", + " # Add vertices\n", + " for x, y, z in ((gcube_major @ R) * scale).tolist():\n", + " x = -x\n", + " d.append(\n", + " draw.Circle(\n", + " x + dx,\n", + " y + dy,\n", + " large_node_width,\n", + " fill=node_color,\n", + " stroke=node_border_color,\n", + " stroke_width=node_stroke_width if large_border else 0,\n", + " )\n", + " )\n", + " for x, y, z in ((gcube_minor @ R) * scale).tolist():\n", + " x = -x\n", + " d.append(\n", + " draw.Circle(\n", + " x + dx,\n", + " y + dy,\n", + " small_node_width,\n", + " fill=node_color,\n", + " stroke=node_border_color,\n", + " stroke_width=node_stroke_width,\n", + " )\n", + " )\n", + "\n", + " # Add brackets\n", + " d.append(\n", + " draw.Text(\n", + " \"[\",\n", + " x=-85,\n", + " y=52,\n", + " font_size=214,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Courier New\",\n", + " fill=bracket_color,\n", + " )\n", + " )\n", + " d.append(\n", + " draw.Text(\n", + " \"]\",\n", + " x=85,\n", + " y=52,\n", + " font_size=214,\n", + " text_anchor=\"middle\",\n", + " font_family=\"Courier New\",\n", + " fill=bracket_color,\n", + " )\n", + " )\n", + "\n", + " return d" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "4325e0b8-dbbb-4219-a2b3-4d9cdee2bdc8", + "metadata": {}, + "outputs": [], + "source": [ + "logo_defaults = dict(\n", + " bracket_color=blue,\n", + " edge_color=blue,\n", + " node_color=orange,\n", + " edge_border_width=0,\n", + " edge_width=12,\n", + " small_node_width=11,\n", + " large_node_width=17,\n", + " node_border_color=\"none\",\n", + " node_stroke_width=0,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "f886df89-b3b5-4671-bcc0-98e8705feb5a", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "[\n", + "]\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "create_logo(bg_color=\"white\", **logo_defaults)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "68e01137-55e3-4973-bf97-4fcd36c8c662", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "[\n", + "]\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "create_logo(bg_color=\"black\", **logo_defaults)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "b1d5e928-16c5-4377-aee1-1489ab45efc8", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "[\n", + "]\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Transparent background\n", + "logo = create_logo(**logo_defaults)\n", + "logo" + ] + }, + { + "cell_type": "markdown", + "id": "b187c131-d337-4a7b-ab54-80ebe0f48ab4", + "metadata": {}, + "source": [ + "## Alternatives with gray brackets\n", + "### Background-agnostic (works with light and dark mode)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "acca9b2e-2f54-4b86-9a33-2c57502f6160", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "[\n", + "]\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "medium_logo = create_logo(**{**logo_defaults, \"bracket_color\": medium_gray})\n", + "create_logo(bg_color=\"white\", **{**logo_defaults, \"bracket_color\": medium_gray})" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "f5d0086d-b50e-49eb-9aae-b0953cdc0045", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "[\n", + "]\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "create_logo(bg_color=\"black\", **{**logo_defaults, \"bracket_color\": medium_gray})" + ] + }, + { + "cell_type": "markdown", + "id": "c4dce89d-e34c-4190-a068-7e78cdeea745", + "metadata": {}, + "source": [ + "### For light mode" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "27137343-141a-422e-abd6-123af3416ea4", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "[\n", + "]\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "light_logo = create_logo(**{**logo_defaults, \"bracket_color\": dark_gray})\n", + "create_logo(bg_color=\"white\", **{**logo_defaults, \"bracket_color\": dark_gray})" + ] + }, + { + "cell_type": "markdown", + "id": "8a70b0f7-c3c4-44ae-af09-8992400f362e", + "metadata": {}, + "source": [ + "### For dark mode" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "3ab9bb40-d7a8-4788-9971-54a5779d284d", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "[\n", + "]\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dark_logo = create_logo(**{**logo_defaults, \"bracket_color\": light_gray})\n", + "create_logo(bg_color=\"black\", **{**logo_defaults, \"bracket_color\": light_gray})" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "d53046c1-8cbb-47fa-a88b-4d98958df26b", + "metadata": {}, + "outputs": [], + "source": [ + "if False:\n", + " logo.save_svg(\"python-graphblas-logo.svg\")\n", + " light_logo.save_svg(\"python-graphblas-logo-light.svg\")\n", + " medium_logo.save_svg(\"python-graphblas-logo-medium.svg\")\n", + " dark_logo.save_svg(\"python-graphblas-logo-dark.svg\")\n", + " color_palette.save_svg(\"color-palette.svg\")\n", + " standard_wheel.save_svg(\"color-wheel.svg\")\n", + " high_wheel.save_svg(\"color-wheel-high.svg\")\n", + " low_wheel.save_svg(\"color-wheel-low.svg\")\n", + " warm_wheel.save_svg(\"color-wheel-warm.svg\")\n", + " cool_wheel.save_svg(\"color-wheel-cool.svg\")" + ] + }, + { + "cell_type": "markdown", + "id": "51093fab-600b-47d7-9809-fa0f16e7246f", + "metadata": {}, + "source": [ + "### *NOTE: The font in the SVG files should be converted to paths, because not all systems have Courier New*\n", + "Also, SVG files can be minified here: https://vecta.io/nano" + ] + } + ], + "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.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/scripts/check_versions.sh b/scripts/check_versions.sh index a76fee1d2..9051ebe6e 100755 --- a/scripts/check_versions.sh +++ b/scripts/check_versions.sh @@ -4,12 +4,12 @@ # This may be helpful when updating dependency versions in CI. # Tip: add `--json` for more information. conda search 'flake8-bugbear[channel=conda-forge]>=23.9.16' -conda search 'flake8-simplify[channel=conda-forge]>=0.20.0' +conda search 'flake8-simplify[channel=conda-forge]>=0.21.0' conda search 'numpy[channel=conda-forge]>=1.26.0' conda search 'pandas[channel=conda-forge]>=2.1.1' -conda search 'scipy[channel=conda-forge]>=1.11.2' +conda search 'scipy[channel=conda-forge]>=1.11.3' conda search 'networkx[channel=conda-forge]>=3.1' -conda search 'awkward[channel=conda-forge]>=2.4.3' +conda search 'awkward[channel=conda-forge]>=2.4.4' conda search 'sparse[channel=conda-forge]>=0.14.0' conda search 'fast_matrix_market[channel=conda-forge]>=1.7.3' conda search 'numba[channel=conda-forge]>=0.57.1'