{"id":43291574,"url":"https://github.com/idling-mind/flowfunc","last_synced_at":"2026-02-01T18:33:30.213Z","repository":{"id":99593479,"uuid":"534701225","full_name":"idling-mind/flowfunc","owner":"idling-mind","description":"A web-based node editor component for plotly dash","archived":false,"fork":false,"pushed_at":"2025-03-15T14:54:19.000Z","size":1363,"stargazers_count":79,"open_issues_count":1,"forks_count":8,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-15T15:32:40.593Z","etag":null,"topics":["dash","data-science","data-visualization","dataviz","flowchart","nodeeditor","plotly","plotly-dash","plotting","python"],"latest_commit_sha":null,"homepage":"https://najeem.pythonanywhere.com/","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/idling-mind.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-09T15:33:24.000Z","updated_at":"2025-03-15T14:51:37.000Z","dependencies_parsed_at":"2023-11-19T22:24:55.408Z","dependency_job_id":"6b963a76-0cbf-4800-a22b-4b4617ecd0d3","html_url":"https://github.com/idling-mind/flowfunc","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/idling-mind/flowfunc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idling-mind%2Fflowfunc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idling-mind%2Fflowfunc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idling-mind%2Fflowfunc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idling-mind%2Fflowfunc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/idling-mind","download_url":"https://codeload.github.com/idling-mind/flowfunc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idling-mind%2Fflowfunc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28985818,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T18:17:03.387Z","status":"ssl_error","status_checked_at":"2026-02-01T18:16:57.287Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["dash","data-science","data-visualization","dataviz","flowchart","nodeeditor","plotly","plotly-dash","plotting","python"],"created_at":"2026-02-01T18:33:29.660Z","updated_at":"2026-02-01T18:33:30.205Z","avatar_url":"https://github.com/idling-mind.png","language":"Python","readme":"![Flowfunc](./docs/source/images/logo.png)\n\nA node editor for [plotly dash](https://dash.plotly.com/)\n\nFlowfunc is a plotly dash component which works as a web based node editor.\nYou can create nodes based on python functions and connect them together to define\nthe logic during runtime.\n\n[Demo](https://najeem.pythonanywhere.com/)\n\n[![Animation](./docs/source/images/animation.gif)](https://najeem.pythonanywhere.com/)\n\nThe front end is created using the react package [Flume](https://flume.dev). The\ndata model is also heavily influenced by this package.\n## Installation\n\n**The package is still in alpha stage**. Please test out and let me know your\ncomments.\n\n### Basic installation\n\n```\npip install flowfunc\n```\n\n### Distributed\nIf you want to run your nodes using [rq](https://python-rq.org/) in a distributed\nmanner.\n```\npip install flowfunc[distributed]\n```\n\n### Full installation\n\nIn addition to the packages required for distributed run, this will install dash as well.\n```\npip install flowfunc[full]\n```\n## Basic Usage\n\nA fully functioning dash app with Flowfunc node editor would look like below.\nThe app will have the node editor and a button to evaluate the current state of\nthe node editor. The result of the evaluation will be displayed in a separate `div`\nat the bottom.\n\nThe nodes are created from regular python functions using it's function signature.\nIt is also possible to create a node manually which offers more control.\n\n```python\nfrom typing import Dict\nimport dash\nfrom dash import html, Input, Output, State\nfrom flowfunc import Flowfunc\nfrom flowfunc.config import Config\nfrom flowfunc.jobrunner import JobRunner\nfrom flowfunc.models import OutNode\n\napp = dash.Dash(__name__)\n\n# Functions can be converted to nodes\ndef add(a: int, b: int) -\u003e int:\n    \"\"\"Add two numbers\"\"\"\n    return a + b\n\ndef subtract(a: int, b: int) -\u003e int:\n    \"\"\"Find difference between two numbers\"\"\"\n    return a - b\n\n\n# A Config object contains info about the nodes and ports available in the node editor\nnodeeditor_config = Config.from_function_list([add, subtract])\n\n# A JobRunner object helps evaluate the nodes created using the node editor\nrunner = JobRunner(nodeeditor_config)\n\napp.layout = html.Div(\n    [\n        html.Button(id=\"btn_run\", children=\"Run\"),\n        Flowfunc(id=\"nodeeditor\", config=nodeeditor_config.dict()),\n        html.Div(id=\"output\"),\n    ], style={\"height\": \"600px\"}\n)\n\n\n@app.callback(\n    Output(\"output\", \"children\"),\n    Input(\"btn_run\", \"n_clicks\"),\n    State(\"nodeeditor\", \"nodes\"),\n)\ndef run_nodes(nclicks: int, output_nodes: Dict[str, OutNode]):\n    \"\"\"Run the node layout\"\"\"\n    # The result is a dictionary of OutNode objects\n    result = runner.run(output_nodes)\n    output = []\n    for node in result.values():\n        # node.result contains the result of the node\n        output.append(\n            html.Div([html.H1(f\"{node.type}: {node.id}\"), html.P(str(node.result))])\n        )\n    return output\n\nif __name__ == \"__main__\":\n    app.run() \n```\n![Basic example](docs/source/images/basic.png)\n### Explanation\n\n```python\nnodeeditor_config = Config.from_function_list([add, subtract])\n```\nThe `Flowfunc` component requires a `Config` object which contains the list of all\nnodes as an input. You can create the list of nodes easily from a list of python\nfunctions using the class method `from_function_list`. It will accept async\nfunctions also.\n\n```python\nrunner = JobRunner(nodeeditor_config)\n...\nresult = runner.run(output_nodes)\n```\n`JobRunner` object helps evaluate the output of the front end node editor by making\nsure the inputs and outputs are routed properly. It takes in the output from the\nnodeeditor, parses it using pydantic and creates a dict of `OutNode` objects, evaluates\neach of the objects by making sure the dependent inputs are routed properly.\nIt uses the functions defined in the config object to evaluate a node.\nThe output of `runner.run` is the same dictionary that it parsed initially, but\nnow with an addtional `result` attribute on each node. If you are running in\na distributed way, it will have a `job_id` attribute on every node. You can use\nthis `job_id` and the `queue` object to retrieve the results of the node.\n\n```python\nFlowfunc(id=\"nodeeditor\", config=nodeeditor_config.dict())\n```\nThis is the dash component with `id` equal to `nodeeditor`. You need to pass in\nthe config object created previously, but converted to a dictionary.\n\n## More examples\n\nLook into the examples folder to see a more elaborate example with better looking\ninterface using `dash-boostrap-components`. There is also an example which uses\nthe distributed method where each node is evaluated in a separate `rqworker`.\n\n## Nodes\n\n`Nodes` are the building blocks which you can connect together using their exposed\n`Ports`. Flowfunc let's you easily create nodes from python functions by inspecting\ntheir signature and type annotations. The parameters of the function becomes the\ninput ports and return value of the function becomes the output port. You can give\ndifferent types of type annotations. Even `dataclasses` and `pydantic` classes.\nThe parser does it's best to interpret the type annotations and render an \nequivalent node with different types of controls on it. If you aren't happy with\nthe controls that the parser creted, you can manually specify how the node should\nbe constructed.\n\nOnce the parser processed the function signature, it creates a\n`Node` object which is a `pydantic` object.\n\n## Ports\n`Ports` are the inputs and outputs of a `Node`. So they basically mean the inputs\nor outputs of a function. Ports can render controls in the node and let the user\ninteract with them and pass in data. There are some ports (read datatypes) which\ncome with a default control. They are `int`, `float`, `str`, `bool`, `color`,\n`time`, `date`, `month`, `week`. Some of these are not standard python types and\nhence, you cannot use them in type annotation directly. If you want to use type\nannotation, create a custom type with these names. In future, the plan is to create\nsome kind of interface to make this process easier and also make more controls\navailable.\n\nWhen you annotate a argument with a `dataclass` or `pydantic` object, `flowfunc`\nwill inspect the attributes of this class and it will try to create controls for\neach of the attributes of the object. As of now, `flowfunc` cannot handle nested\n`pydantic` or `dataclass` objects.\n\nA default set of ports are automatically created when the nodes are processed\nfrom python functions. `Port` object is also a pydantic object.\n\n## Config\n`Config` object holds info about all the nodes and ports available in the node\neditor. It's a direct equivalent of [Flume](https://flume.dev)'s config object,\nbut modified so that the data can be serialized at the server side and sent to\nthe client (ie; no javascript functions). In future, the plan is to make it possible\nto define functions in javascript as well.\n\n`Config.nodes` will contain all the `Node` pydantic objects and `Config.ports`\nwill contain all the `Port` pydantic objects. \n\n## JobRunner\n`JobRunner` object helps process the output of the node editor. `JobRunnber` can\nrun in as blocking (sync), return an awaitable (async), return a dict of rq\njobs (distributed) or await on a dict of rq jobs (async_distributed).\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fidling-mind%2Fflowfunc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fidling-mind%2Fflowfunc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fidling-mind%2Fflowfunc/lists"}