{"id":32399209,"url":"https://github.com/espdev/mpl-events","last_synced_at":"2026-07-16T09:32:24.284Z","repository":{"id":46052466,"uuid":"186320925","full_name":"espdev/mpl-events","owner":"espdev","description":"A high-level API for matplotlib events handling","archived":false,"fork":false,"pushed_at":"2023-09-18T02:31:15.000Z","size":72,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-07-16T09:28:45.363Z","etag":null,"topics":["event-handling","interaction","matplotlib","mpl","plotting"],"latest_commit_sha":null,"homepage":"https://mpl-events.readthedocs.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/espdev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-13T00:44:28.000Z","updated_at":"2021-11-17T14:45:32.000Z","dependencies_parsed_at":"2022-09-05T09:31:30.694Z","dependency_job_id":null,"html_url":"https://github.com/espdev/mpl-events","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/espdev/mpl-events","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/espdev%2Fmpl-events","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/espdev%2Fmpl-events/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/espdev%2Fmpl-events/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/espdev%2Fmpl-events/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/espdev","download_url":"https://codeload.github.com/espdev/mpl-events/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/espdev%2Fmpl-events/sbom","scorecard":{"id":382835,"data":{"date":"2025-08-11","repo":{"name":"github.com/espdev/mpl-events","commit":"0c73a71cf99710c57e0d5b3d6dd3fde4dea372c2"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/2 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T15:53:03.774Z","repository_id":46052466,"created_at":"2025-08-18T15:53:03.774Z","updated_at":"2025-08-18T15:53:03.774Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35539516,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-16T02:00:06.687Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["event-handling","interaction","matplotlib","mpl","plotting"],"created_at":"2025-10-25T08:18:37.062Z","updated_at":"2026-07-16T09:32:24.269Z","avatar_url":"https://github.com/espdev.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mpl-events\n\n[![PyPI version](https://img.shields.io/pypi/v/mpl-events.svg)](https://pypi.python.org/pypi/mpl-events)\n[![Build status](https://travis-ci.org/espdev/mpl-events.svg?branch=master)](https://travis-ci.org/espdev/mpl-events)\n[![Docs status](https://readthedocs.org/projects/mpl-events/badge/)](https://mpl-events.readthedocs.io/en/latest/)\n[![License](https://img.shields.io/pypi/l/mpl-events.svg)](LICENSE)\n\n**mpl-events** is a tiny library for simple and convenient [matplotlib](https://matplotlib.org/) event handling \nwith minimum boilerplate code. In other words, the library provides high-level API for using [matplotlib event system](https://matplotlib.org/users/event_handling.html).\n\nYou need to handling matplotlib events if you want to manipulate figures and plots/visualizations interactively.\nMatplotlib contains a low-level API for event handling: using ``FigureCanvasBase.mpl_connect`` and\n``FigureCanvasBase.mpl_disconnect`` methods, string-based event names and integer connection identifiers.\n\n## Pros and cons\n\n**Pros**:\n\n* mpl-events provides high-level API, auto disconnecting and cleanup\n* Strings-based event types/names are not used. Intstead, `MplEvent` enum class is used for all event types.\n* Integer connection identifiers are not used. Instead, the connection between event and handler is incapsulated via class `MplEventConnection`\n* mpl-events objects do not own mpl figure and do not create additional references to figure or canvas\n* mpl-events provides convenient base class `MplEventDispatcher` that contains handlers API (with type-hints) for handling all mpl events inside one class without boilerplate code\n\n**Cons**:\n\n* Additional level of abstraction (if this can be considered a disadvantage)\n* Additional dependency in your project\n\n## Installation\n\n![Supported Python versions](https://img.shields.io/pypi/pyversions/mpl-events.svg)\n\nYou can use pip to install mpl-events:\n\n```bash\npip install mpl-events\n```\n\nor from github repo:\n\n```bash\npip install git+https://github.com/espdev/mpl-events.git\n```\n\n## Usage\n\n### Event dispatchers\n\nCustom event dispatcher class might be created to handle some matplotlib events just \ninheriting `MplEventDispatcher` class and implementing the required event handlers.\n\nThe following example shows how we can create the dispatcher for handling all mouse events:\n\n```python\nfrom matplotlib import pyplot as plt\nfrom mpl_events import MplEventDispatcher, mpl\n\nclass MouseEventDispatcher(MplEventDispatcher):\n    \n    def on_mouse_button_press(self, event: mpl.MouseEvent):\n        print(f'mouse button {event.button} pressed')\n    \n    def on_mouse_button_release(self, event: mpl.MouseEvent):\n        print(f'mouse button {event.button} released')\n    \n    def on_mouse_move(self, event: mpl.MouseEvent):\n        print(f'mouse moved')\n\n    def on_mouse_wheel_scroll(self, event: mpl.MouseEvent):\n        print(f'mouse wheel scroll {event.step}')\n\nfigure = plt.figure()\n\n# setup figure and make plots is here ...\n\nmouse_dispatcher = MouseEventDispatcher(figure)\n\nplt.show()\n```\n\n`MplEventDispatcher` class provides API (handler methods interface) for all matplotlib events. \nYou may override and implement some of these methods for handling corresponding events.\n\nThe dispatcher might be connected to a canvas using mpl objects `figure` or `axes` (or `canvas`). \nIn general, we do not need to think about it. We just pass `figure` instance to constructor usually.\nBy default connection to events is made automatically. This behavior is controlled by `connect` argument.\n\nAnd it is all. We do not need to worry about connecting/disconnecting or remember mpl event names.\n\nIf we want to use another methods (not `MplEventDispatcher` API) for handling events we can \nuse `mpl_event_handler` decorator inside our dispatcher class.\n\n```python\nfrom mpl_events import MplEventDispatcher, MplEvent, mpl_event_handler, mpl\n\nclass CloseEventDispatcher(MplEventDispatcher):\n\n    @mpl_event_handler(MplEvent.FIGURE_CLOSE)\n    def _close_event_handler(self, event: mpl.CloseEvent):\n        print(f'figure {event.canvas.figure} closing')\n```\n\nAlso we can create event dispatchers hierarchies:\n\n```python\nfrom mpl_events import MplEventDispatcher, mpl\n\nclass MyEventDispatcherBase(MplEventDispatcher):\n    def on_figure_close(self, event: mpl.CloseEvent):\n        print('figure closing from MyEventDispatcherBase')\n\nclass MyEventDispatcher(MyEventDispatcherBase):\n\n    def on_figure_close(self, event: mpl.CloseEvent):\n        super().on_figure_close(event)\n        print('figure closing from MyEventDispatcher')\n\n    def on_figure_resize(self, event: mpl.ResizeEvent):\n        print('figure resizing')\n\n```\n\n### Event connections\n\nThe connection between event and handler incapsulated in `MplEventConnection` class. \nThis class is high level wrapper for `figure.canvas.mpl_connect`/`figure.canvas.mpl_disconnect` mpl API.\n\n`MplEventConnection` can be used if we want to handle events and do not use event dispatcher interface.\n\nIn this case we just create instance of `MplEventConnection` class and pass to constructor\nmpl object for connecting (`figure`, `axes` or `canvas`), event type as `MplEvent` enum and handler as callable.\nBy default connection is made automatically. This behavior is controlled by `connect` argument.\n\n```python\nfrom matplotlib import pyplot as plt\nfrom mpl_events import MplEventConnection, MplEvent, mpl\n\ndef close_handler(event: mpl.CloseEvent):\n    print('figure closing')\n\nfigure = plt.figure()\n\nconn = MplEventConnection(figure, MplEvent.FIGURE_CLOSE, close_handler)\n\nprint(conn)\n# MplEventConnection(event=\u003cFIGURE_CLOSE:close_event\u003e, handler=\u003cfunction close_handler at 0x0000013FD1002E18\u003e, id=5)\n\nplt.show()\n```\n\nAlso we can use the shortcut for `MplEventConnection` constuction using `make_connection` method of `MplEvent` class:\n\n```python\nfrom mpl_events import MplEvent\n\n...\n\nconn = MplEvent.FIGURE_CLOSE.make_connection(figure, close_handler)\n```\n\n### Disable default key press event handler\n\nMatplotlib figures usually contain navigation bar for some interactions with axes and this navigation bar handles key presses. \nBy default key press handler is connected in `FigureManagerBase` mpl class. \nmpl-events provides `disable_default_key_press_handler` function to disconnect the default key press handler.\nAlso in event dispatcher classes we can use `disable_default_handlers` attribute.\n\nHere is a simple example:\n\n```python\nfrom matplotlib import pyplot as plt\nfrom mpl_events import MplEventDispatcher, mpl\n\nclass KeyEventDispatcher(MplEventDispatcher):\n    disable_default_handlers = True\n\n    def on_key_press(self, event: mpl.KeyEvent):\n        print(f'Pressed key {event.key}')\n\n    def on_key_release(self, event: mpl.KeyEvent):\n        print(f'Released key {event.key}')\n\nfigure = plt.figure()\n\ndispatcher = KeyEventDispatcher(figure)\n\nplt.show()\n```\n\n## Testing\n\nWe use pytest and tox for testing.\n\n## Documentation\n\nPlease see [the latest documentation](https://mpl-events.readthedocs.io/en/latest/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fespdev%2Fmpl-events","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fespdev%2Fmpl-events","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fespdev%2Fmpl-events/lists"}