{"id":19700388,"url":"https://github.com/pablrod/perl-dash","last_synced_at":"2025-04-29T13:32:12.836Z","repository":{"id":55405202,"uuid":"230910701","full_name":"pablrod/perl-Dash","owner":"pablrod","description":"Analytical Web Apps in Perl (Port of Plotly's Dash to Perl)","archived":false,"fork":false,"pushed_at":"2022-08-14T14:02:22.000Z","size":5636,"stargazers_count":4,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-08-20T23:19:53.446Z","etag":null,"topics":["charting","data","data-visualization","perl","reactjs","web-app"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/pablrod.png","metadata":{"files":{"readme":"README.md","changelog":"Changes","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-30T12:19:07.000Z","updated_at":"2022-08-14T14:28:23.000Z","dependencies_parsed_at":"2022-08-14T23:40:23.964Z","dependency_job_id":null,"html_url":"https://github.com/pablrod/perl-Dash","commit_stats":null,"previous_names":[],"tags_count":11,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pablrod%2Fperl-Dash","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pablrod%2Fperl-Dash/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pablrod%2Fperl-Dash/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pablrod%2Fperl-Dash/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pablrod","download_url":"https://codeload.github.com/pablrod/perl-Dash/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224175731,"owners_count":17268390,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["charting","data","data-visualization","perl","reactjs","web-app"],"created_at":"2024-11-11T21:05:48.556Z","updated_at":"2024-11-11T21:05:49.254Z","avatar_url":"https://github.com/pablrod.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NAME\n\nDash - Analytical Web Apps in Perl (Port of Plotly's Dash to Perl)\n\n# VERSION\n\nversion 0.11\n\n# SYNOPSIS\n\n```perl\nuse Dash;\nuse aliased 'Dash::Html::Components' =\u003e 'html';\nuse aliased 'Dash::Core::Components' =\u003e 'dcc';\nuse aliased 'Dash::Dependencies' =\u003e 'deps';\n\nmy $external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css'];\n\nmy $app = Dash-\u003enew(\n    app_name             =\u003e 'Basic Callbacks',\n    external_stylesheets =\u003e $external_stylesheets\n);\n\n$app-\u003elayout(\n    html-\u003eDiv([\n        dcc-\u003eInput(id =\u003e 'my-id', value =\u003e 'initial value', type =\u003e 'text'),\n        html-\u003eDiv(id =\u003e 'my-div')\n    ])\n);\n\n$app-\u003ecallback(\n    deps-\u003eOutput('my-div', 'children'),\n    [deps-\u003eInput('my-id', 'value')],\n    sub {\n        my $input_value = shift;\n        return \"You've entered '$input_value'\";\n    }\n);\n\n$app-\u003erun_server();\n\nuse Dash;\nuse aliased 'Dash::Html::Components' =\u003e 'html';\nuse aliased 'Dash::Core::Components' =\u003e 'dcc';\n\nmy $external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css'];\n\nmy $app = Dash-\u003enew(\n    app_name             =\u003e 'Random chart',\n    external_stylesheets =\u003e $external_stylesheets\n);\n\nmy $initial_number_of_values = 20;\n$app-\u003elayout(\n    html-\u003eDiv(children =\u003e [\n        dcc-\u003eInput(id =\u003e 'my-id', value =\u003e $initial_number_of_values, type =\u003e 'number'),\n        dcc-\u003eGraph(id =\u003e 'my-graph')\n    ])\n);\n\nmy $serie = [ map { rand(100) } 1 .. $initial_number_of_values];\n$app-\u003ecallback(\n    Output =\u003e {component_id =\u003e 'my-graph', component_property =\u003e 'figure'},\n    Inputs =\u003e [{component_id=\u003e'my-id', component_property=\u003e 'value'}],\n    callback =\u003e sub {\n        my $number_of_elements = shift;\n        my $size_of_serie = scalar @$serie;\n        if ($number_of_elements \u003e= $size_of_serie) {\n            push @$serie, map { rand(100) } $size_of_serie .. $number_of_elements;\n        } else {\n            @$serie = @$serie[0 .. $number_of_elements];\n        }\n        return { data =\u003e [ {\n            type =\u003e \"scatter\",\n            y =\u003e $serie\n            }]};\n    }\n);\n\n$app-\u003erun_server();\n```\n\n# DESCRIPTION\n\nThis package is a port of [Plotly's Dash](https://dash.plot.ly/) to Perl.\n\nDash makes building analytical web applications very easy. No JavaScript required.\n\nIt's a great way to put a nice interactive web interface to your data analysis application \nwithout having to make a javascript interface and without having to setup servers or web frameworks.\nThe typical use case is you just have new data to your ML/AI model and you want to explore\ndiferent ways of training or just visualize the results of different parameter configurations.\n\n# Basics\n\nThe main parts of a Dash App are:\n\n- Layout\n\n    Declarative part of the app where you specify the view. This layout is composed of components arranged in a hierarchy, just like html. \n    This components are available as component suites (for example: [Dash::Html::Components](https://metacpan.org/pod/Dash%3A%3AHtml%3A%3AComponents), [Dash::Core::Components](https://metacpan.org/pod/Dash%3A%3ACore%3A%3AComponents), ...) \n    and they can be simple html elements (for example [Dash::Html::Components::H1](https://metacpan.org/pod/Dash%3A%3AHtml%3A%3AComponents%3A%3AH1)) or as complex as you want like\n    [Dash::Core::Components::Graph](https://metacpan.org/pod/Dash%3A%3ACore%3A%3AComponents%3A%3AGraph) that is a charting component based on [Plotly.js](https://plot.ly/javascript/).\n    Most of the time you'll be using Dash Components already built and ready to use.\n\n- Callbacks\n\n    This is the Perl code that gets executed when some component changes \n    and the result of this execution another component (or components) gets updated.\n    Every callback declares a set of inputs, a set of outputs and optionally a set of \"state\" inputs. \n    All inputs, outputs and \"state\" inputs are known as callback dependencies. Every dependency is related to \n    some property of some component, so the inputs determine that if a property of a component declared as input\n    in a callback will trigger that callback, and the output returned by the callback will update the property of\n    the component declared as output.\n\nSo to make a Dash app you just need to setup the layout and the callbacks. The basic skeleton will be:\n\n```perl\nmy $app = Dash-\u003enew(app_name =\u003e 'My Perl Dash App'); \n$app-\u003elayout(...);\n$app-\u003ecallback(...);\n$app-\u003erun_server();\n```\n\nIn the SYNOPSIS you can get a taste of how this works and also in [the examples folder of the distribution](https://metacpan.org/release/Dash)\n\n# Layout\n\nThe layout is the declarative part of the app and its the DOM of our app. The root element can be any component,\nand after the root element is done the rest are \"children\" of this root component, that is they are the value of\nthe children property of the parent component and children can be one \"thing\" (text, component, whatever as long as can be converted to JSON)\nor an arrayref of \"things\". So the components can be composed as much as you want. For example:\n\n```perl\n$app-\u003elayout(html-\u003eDiv(children =\u003e [\n        html-\u003eH1(children =\u003e 'Making Perl Dash Apps'),\n        html-\u003eImg(src =\u003e 'https://raw.githubusercontent.com/kraih/perl-raptor/master/example.png' )\n    ]));\n```\n\n## Components\n\nThis package ships the following component suites and are ready to use:\n\n- [Dash Core Components](https://dash.plot.ly/dash-core-components) as Dash::Core::Components. Main components for interactive analytical web apps: forms and charting\n- [Dash Html Components](https://dash.plot.ly/dash-html-components) as Dash::Html::Components. Basically the html elements.\n- [Dash DataTable](https://dash.plot.ly/datatable) as Dash::Table\n\nThe plan is to make the packages also for [Dash-Bio](https://dash.plot.ly/dash-bio), [Dash-DAQ](https://dash.plot.ly/dash-daq), [Dash-Canvas](https://dash.plot.ly/canvas) and [Dash-Cytoscape](https://dash.plot.ly/cytoscape).\n\n### Using the components\n\nEvery component has a class of its own. For example dash-html-component Div has the class: [Dash::Html::Components::Div](https://metacpan.org/pod/Dash%3A%3AHtml%3A%3AComponents%3A%3ADiv) and you can use it the perl standard way:\n\n```perl\nuse Dash::Html::Components::Div;\n...\n$app-\u003elayout(Dash::Html::Components::Div-\u003enew(id =\u003e 'my-div', children =\u003e 'This is a simple div'));\n```\n\nBut with every component suite could be a lot of components. So to ease the task of importing them (one by one is a little bit tedious) we could use two ways:\n\n#### Factory methods\n\nEvery component suite has a factory method for every component. And using this factory methods children keyword is optional as long as the children is the first element.\nFor example [Dash::Html::Components](https://metacpan.org/pod/Dash%3A%3AHtml%3A%3AComponents) has the factory method Div to load and build a [Dash::Html::Components::Div](https://metacpan.org/pod/Dash%3A%3AHtml%3A%3AComponents%3A%3ADiv) component:\n\n```perl\nuse Dash::Html::Components;\n...\n$app-\u003elayout(Dash::Html::Components-\u003eDiv(id =\u003e 'my-div', children =\u003e 'This is a simple div'));\n# same as\n$app-\u003elayout(Dash::Html::Components-\u003eDiv('This is a simple div', id =\u003e 'my-div');\n```\n\nBut this factory methods are meant to be aliased so this gets less verbose:\n\n```perl\nuse aliased 'Dash::Html::Components' =\u003e 'html';\n...\n$app-\u003elayout(html-\u003eDiv(id =\u003e 'my-div', children =\u003e 'This is a simple div'));\n# same as\n$app-\u003elayout(html-\u003eDiv('This is a simple div', id =\u003e 'my-div'));\n```\n\n#### Functions\n\nMany modules use the [Exporter](https://metacpan.org/pod/Exporter) \u0026 friends to reduce typing. If you like that way every component suite gets a Functions package to import all this functions\nto your namespace. Using this functions also allows for ommiting the children keyword if the children is the first element.\n\nSo for example for [Dash::Html::Components](https://metacpan.org/pod/Dash%3A%3AHtml%3A%3AComponents) there is a package [Dash::Html::ComponentsFunctions](https://metacpan.org/pod/Dash%3A%3AHtml%3A%3AComponentsFunctions) with one factory function to load and build the component with the same name:\n\n```perl\nuse Dash::Html::ComponentsFunctions;\n...\n$app-\u003elayout(Div(id =\u003e 'my-div', children =\u003e 'This is a simple div'));\n# same as\n$app-\u003elayout(Div('This is a simple div', id =\u003e 'my-div'));\n```\n\n# Callbacks\n\nCallbacks are the reactive part of the web app. They listen to changes in properties of components and get fired by those changes.\nThe output of the callbacks can update properties for other componentes (or different properties for the same components) and\npotentially firing other callbacks. So your app is \"reacting\" to changes. These properties that fire changes and the properties \nthat get updated are dependencies of the callback, they are the \"links\" between components and callbacks.\n\nEvery component that is expected to fire a callback must have a unique id property.\n\nTo define a callback is necessary at least:\n\n- Inputs\n\n    The component property (or components properties) which fire the callback on every change. The values of this properties are inputs for the callbacks\n\n- Output\n\n    The component (or components) whose property (or properties) get updated\n\n- callback\n\n    The code that gets executed\n\nA minimun callback will be:\n\n```perl\n$app-\u003ecallback(\n    Output =\u003e {component_id =\u003e 'my-div', component_property =\u003e 'children'},\n    Inputs =\u003e [{component_id=\u003e'my-id', component_property=\u003e 'value'}],\n    callback =\u003e sub {\n        my $input_value = shift;\n        return \"You've entered '$input_value'\";\n    }\n);\n```\n\n## Dependencies\n\nDependencies \"link\" components and callbacks. Every callback dependency has the following attributes:\n\n- component\\_id\n\n    Value of the id property for the component\n\n- component\\_property\n\n    Name of the property\n\n### Inputs\n\nA callback can have one or more inputs and for every input declared for a callback the value\nof the property will be a parameter for the callback in the same order as the input dependencies are declared.\n\n### Outputs\n\nA callback can have one or more output dependencies. When there is only one\noutput the value returned by the callback updates the value of the property of the component.\nIn the second case the output of the callback has to be a list\nin the list returned will be mapped one by one to the outputs in the same order as the output dependencies are declared.\n\n### State\n\nApart from Inputs, a callback could need the value of other properties of other components but without \nfiring the callback. State dependencies are for this case. So for every state dependency declared for a callback\nthe value os the property will be a parameter for the callback in the same order the state dependencies are declared\nbut after all inputs. \n\n### Dependencies using objects\n\nDependencies can be declared using just a hash reference but the preferred way is using the classes and factory methods and functions as with the components.\n\nUsing objects:\n\n```perl\nuse Dash::Dependencies::Input;\nuse Dash::Dependencies::Output;\n...\n$app-\u003ecallback(\n    Output =\u003e Dash::Dependencies::Output-\u003enew(component_id =\u003e 'my-div', component_property =\u003e 'children'),\n    Inputs =\u003e [Dash::Dependencies::Input-\u003enew(component_id=\u003e'my-id', component_property=\u003e 'value')],\n    callback =\u003e sub {\n        my $input_value = shift;\n        return \"You've entered '$input_value'\";\n    }\n);\n```\n\nUsing objects allows to omit the keyword arguments in the callback method:\n\n```perl\nuse Dash::Dependencies::Input;\nuse Dash::Dependencies::Output;\n...\n$app-\u003ecallback(\n    Dash::Dependencies::Output-\u003enew(component_id =\u003e 'my-div', component_property =\u003e 'children'),\n    [Dash::Dependencies::Input-\u003enew(component_id=\u003e'my-id', component_property=\u003e 'value')],\n    sub {\n        my $input_value = shift;\n        return \"You've entered '$input_value'\";\n    }\n);\n```\n\nThere are also factory methods to use this dependencies, which allows to omit the keyword arguments for the dependencies:\n\n```perl\nuse Dash::Dependencies;\n...\n$app-\u003ecallback(\n    Dash::Dependencies-\u003eOutput('my-div', 'children'),\n    [Dash::Dependencies-\u003eInput(component_id=\u003e'my-id', component_property=\u003e 'value')],\n    sub {\n        my $input_value = shift;\n        return \"You've entered '$input_value'\";\n    }\n);\n```\n\nThis can be aliased\n\n```perl\nuse aliased 'Dash::Dependencies' =\u003e 'deps';\n...\n$app-\u003ecallback(\n    deps-\u003eOutput(component_id =\u003e 'my-div', component_property =\u003e 'children'),\n    [deps-\u003eInput('my-id', 'value')],\n    sub {\n        my $input_value = shift;\n        return \"You've entered '$input_value'\";\n    }\n);\n```\n\nBut if you prefer using just functions in your namespace:\n\n```perl\nuse Dash::DependenciesFunctions;\n...\n$app-\u003ecallback(\n    Output('my-div', 'children'),\n    [Input(component_id=\u003e'my-id', component_property=\u003e 'value')],\n    sub {\n        my $input_value = shift;\n        return \"You've entered '$input_value'\";\n    }\n);\n```\n\n# Running App\n\nThe last step is running the app. Just call: \n\n```\n$app-\u003erun_server();\n```\n\nAnd it will start a server on port 8080 and open a browser to start using your app!\n\n# Making new components\n\nThere are [a lot of components... for Python](https://github.com/ucg8j/awesome-dash#component-libraries). So if you want to contribute I'll be glad to help.\n\nMeanwhile you can build your own component. I'll make a better guide and an automated builder but right now you should use [https://github.com/plotly/dash-component-boilerplate](https://github.com/plotly/dash-component-boilerplate) for all the javascript part (It's [React](https://github.com/facebook/react) based) and after that the Perl part is very easy (the components are mostly javascript, or typescript):\n\n- For every component must be a Perl class inheriting from [Dash::BaseComponent](https://metacpan.org/pod/Dash%3A%3ABaseComponent), overloading the hash dereferencing %{} with the props that the React component has (check [Dash::BaseComponent](https://metacpan.org/pod/Dash%3A%3ABaseComponent) TO\\_JSON method), and with this methods:\n    - DashNamespace\n\n        Namespace of the component\n\n    - \\_js\\_dist\n\n        Javascript dependencies for the component\n\n    - \\_css\\_dist\n\n        Css dependencies for the component\n\nOptionally the component suite will have the Functions package and the factory methods for ease of using.\n\nThen you just have to publish the component suite as a Perl package. For new component suites you could use whatever package name you like, but if you want to use Dash:: namespace please use Dash::Components:: to avoid future collisions with further development. Besides this will make easier to find more components.\n\nAs mentioned early, I'll make an automated builder but contributions are more than welcome!! In the meantime please check [CONTRIBUTING.md](https://github.com/pablrod/perl-Dash/blob/master/CONTRIBUTING.md)\n\nMaking a component for Dash that is not React based is a little bit difficult so please first get the javascript part React based and after that, integrating it with Perl, R or Python will be easy.\n\n# STATUS\n\nAt this moment this library is experimental and still under active\ndevelopment and the API is going to change!\n\nThe ultimate goal of course is to support everything that the Python and R versions supports.\n\nThe use will follow the Python version of Dash, as close as possible, so the Python doc can be used with\nminor changes:\n\n- Use of -\u003e (arrow operator) instead of .\n- Main package and class for apps is Dash\n- Component suites will use Perl package convention, I mean: dash\\_html\\_components will be Dash::Html::Components\n- Instead of decorators we'll use plain old callbacks\n- Callback context is available as the last parameter of the callback but without the response part\n- Instead of Flask we'll be using [Mojolicious](https://metacpan.org/pod/Mojolicious) (Maybe in the future [Dancer2](https://metacpan.org/pod/Dancer2))\n\nIn the SYNOPSIS you can get a taste of how this works and also in [the examples folder of the distribution](https://metacpan.org/release/Dash) or directly in [repository](https://github.com/pablrod/perl-Dash/tree/master/examples). The full Dash tutorial is ported to Perl in those examples folder.\n\n## Missing parts\n\nRight now there are a lot of parts missing:\n\n- Prefix mount\n- Debug mode \u0026 hot reloading\n- Dash configuration (supporting environment variables)\n- Callback dependency checking\n- Clientside functions\n- Support for component properties data-\\* and aria-\\*\n- Dynamic layout generation\n\nAnd many more, but you could use it right now to make great apps! (If you need some inspiration... just check [https://dash-gallery.plotly.host/Portal/](https://dash-gallery.plotly.host/Portal/))\n\n## Security\n\n**Warning**: this module is not tested for security so test yourself if you are going to run the app server in a public facing server.\n\n# DISCLAIMER\n\nThis is an unofficial Plotly Perl module. Currently I'm not affiliated in any way with Plotly. \nBut I think Dash is a great library and I want to use it with perl.\n\nIf you like Dash please consider supporting them purchasing professional services: [Dash Enterprise](https://plot.ly/dash/)\n\n# SEE ALSO\n\n- [Dash](https://dash.plot.ly/)\n- [Dash Repository](https://github.com/plotly/dash)\n- [Chart::Plotly](https://metacpan.org/pod/Chart%3A%3APlotly)\n- [Chart::GGPlot](https://metacpan.org/pod/Chart%3A%3AGGPlot)\n- [Alt::Data::Frame::ButMore](https://metacpan.org/pod/Alt%3A%3AData%3A%3AFrame%3A%3AButMore)\n- [AI::MXNet](https://metacpan.org/pod/AI%3A%3AMXNet)\n\n# AUTHOR\n\nPablo Rodríguez González \u003cpablo.rodriguez.gonzalez@gmail.com\u003e\n\n# COPYRIGHT AND LICENSE\n\nThis software is Copyright (c) 2022 by Pablo Rodríguez González.\n\nThis is free software, licensed under:\n\n```\nThe MIT (X11) License\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpablrod%2Fperl-dash","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpablrod%2Fperl-dash","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpablrod%2Fperl-dash/lists"}