Skip to content

Add WordClouds gramplet - #993

Merged
GaryGriffin merged 1 commit into
gramps-project:maintenance/gramps61from
dsblank:add-wordclouds-gramplet
Jul 29, 2026
Merged

Add WordClouds gramplet#993
GaryGriffin merged 1 commit into
gramps-project:maintenance/gramps61from
dsblank:add-wordclouds-gramplet

Conversation

@dsblank

@dsblank dsblank commented Jul 19, 2026

Copy link
Copy Markdown
Member

Summary

Adds three word-cloud gramplets — Given Name Word Cloud, Surname Word
Cloud
, and Place Word Cloud — that render names/places as a
size-weighted, click-to-navigate word cloud instead of the old plain-text
link list.

Screenshot from 2026-07-19 09-33-52
  • wordcloudwidget.py — a Cairo/Pango WordCloudWidget (Gtk.DrawingArea)
    that lays out words with a spiral placement algorithm, sized and colored
    by frequency.
  • slideroption.py — a SliderOption/GuiSliderOption pair (a
    NumberOption rendered as a slider + text entry), registered via
    BasePluginManager.register_option() so no changes to Gramps core are
    required
    .
  • cloudgramplet.py — shared CloudGramplet base class handling the
    common option set (top-N count, colors, layout quality, filter
    missing/unknown values) and word-cloud wiring.
  • givennamewordcloudgramplet.py, surnamewordcloudgramplet.py,
    placewordcloudgramplet.py — the three concrete gramplets.

This is based on ideas from ClmntPnd's Gramps core PR
gramps-project/gramps#2223,
which added the WordCloudWidget-based rendering (including a Place Cloud
gramplet and autosave_options support) directly to Gramps core. This PR
adapts that work into a self-contained addon instead, so it:

  • Works with unmodified, current stable Gramps releases (no core patches).
  • Uses new gramplet ids/class names (Given Name Word Cloud /
    GivenNameWordCloudGramplet, Surname Word Cloud /
    SurnameWordCloudGramplet, Place Word Cloud /
    PlaceWordCloudGramplet) that are distinct from the built-in
    Given Name Cloud / Surname Cloud gramplets, to avoid any plugin
    registration collision between the addon and the core gramplets of the
    same name.
  • Uses the standard Save-button option flow (rather than the core-patched
    autosave_options instant-apply behavior), since that required a
    grampletpane.py change.

Test plan

  • tests/test_imports.py — all modules import cleanly; each gramplet
    class is a proper Gramplet subclass.
  • tests/test_wordcloudwidget.py — font-size/color interpolation and
    bounding-box overlap helpers.
  • tests/test_slideroption.pySliderOption value/min/max/step
    behavior and GuiSliderOption widget wiring (run under xvfb-run,
    since it needs a real display connection).
  • tests/test_cloudgramplet_logic.pyget_items() for each
    gramplet against a real in-memory Gramps database, including the
    filter_missing option and backlink-based place filtering.
  • Manual: install the addon, open each of the three gramplets in a
    running Gramps 6.1, verify word clicks navigate correctly and
    options apply on Save.

Adds three word-cloud gramplets (Given Name, Surname, Place) that render
names/places as a size-weighted, click-to-navigate word cloud instead of
the old plain-text link list, using a new Cairo/Pango WordCloudWidget with
a spiral placement algorithm. Includes a slider+entry option widget
(SliderOption/GuiSliderOption) registered via BasePluginManager.register_option
so no changes to Gramps core are required.

Based on ideas from ClmntPnd's gramps core PR
gramps-project/gramps#2223, adapted here as a
self-contained addon so it works with unmodified stable Gramps releases.
Given Name/Surname/Place Word Cloud use new ids and class names distinct
from the built-in Given Name Cloud / Surname Cloud gramplets to avoid any
plugin registration collision.
@GaryGriffin

Copy link
Copy Markdown
Member

One unittest had warning:

python3 -m unittest WordClouds.tests.test_imports     
/Users/GrampsTest61/gtk/inst/lib/python3.14/site-packages/gi/overrides/__init__.py:159: PyGIDeprecationWarning: GLib.unix_signal_add_full is deprecated; use GLibUnix.signal_add_full instead
  value = getattr(proxy, attr)
....
----------------------------------------------------------------------
Ran 4 tests in 0.448s

OK

Another unittest popped up a WarningDialog. This could be Mac-specific as gexiv2 is built within the Mac bundle and is not in a separate pip package. Plz confirm that you do not see this on Linux/Win.

Screenshot 2026-07-24 at 10 39 46 AM
python3 -m unittest WordClouds.tests.test_cloudgramplet_logic

/Users/GrampsTest61/gtk/inst/lib/python3.14/site-packages/gi/events.py:803: DeprecationWarning: 'asyncio.AbstractEventLoopPolicy' is deprecated and slated for removal in Python 3.16
  AbstractEventLoopPolicy = getattr(asyncio, "AbstractEventLoopPolicy", object)
/Users/GrampsTest61/gtk/inst/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16

.......
----------------------------------------------------------------------
Ran 7 tests in 5.238s

OK

@dsblank - Plz confirm if I can merge these with these warnings.
@eduralph - any issues with CI if these tests are merged?

@dsblank

dsblank commented Jul 26, 2026

Copy link
Copy Markdown
Member Author

@GaryGriffin The deprecation warnings in test_imports are harmless (upstream PyGObject/asyncio noise, not from this addon).

I dug into the WarningDialog and it's not a WordClouds bug — it's core Gramps. gramps/plugins/gramplet/gramplet.gpr.py has module-level code that pops a MessageHideDialog ("GExiv2 module not loaded") whenever has_display() returns True and GExiv2 isn't importable. Our test's make_database("sqlite") call goes through BasePluginManager.get_instance() (gramps/gen/db/utils.py), which scans every registered .gpr.py, including that core one — so this fires for any addon test that ends up touching the plugin manager, on any machine with a live display and no GExiv2, not just WordClouds. On Linux here it doesn't reproduce because there's no display attached in that environment.

Your read on it being Mac-specific was right — it's the classic Mac GExiv2-bundling gap, unrelated to this PR's code.

For now: re-running with GDK_BACKEND=- set (per this repo's documented test-running convention) should suppress it, since that makes has_display() return False even with a physical display attached.

@eduralph — heads up, this also affects the new shared harness on gramps60: neutralize_gui_dialogs() in tests/gramps_test_env.py stubs out ErrorDialog/WarningDialog/OkDialog/etc. but not MessageHideDialog, which is what core's gramplet.gpr.py uses here. Since get_plugin_manager_and_registry() scans PLUGINS_DIR (core's own plugins tree, not just addons), test_plugin_registration.py / make.py test could hang on this exact modal on a GExiv2-less host with a display. Not a problem in the CI container itself since the Dockerfile bundles gir1.2-gexiv2-0.10, but it'll bite local runs. Following up with a comment on #980 about it.

Safe to merge WordClouds as-is from my side.

@GaryGriffin
GaryGriffin merged commit 8a32cbc into gramps-project:maintenance/gramps61 Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants