solara-ui 1.31.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. prefix/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
  2. prefix/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
  3. solara/__init__.py +124 -0
  4. solara/__main__.py +734 -0
  5. solara/alias.py +6 -0
  6. solara/autorouting.py +546 -0
  7. solara/cache.py +303 -0
  8. solara/checks.html +71 -0
  9. solara/checks.py +224 -0
  10. solara/comm.py +28 -0
  11. solara/components/__init__.py +59 -0
  12. solara/components/alert.py +155 -0
  13. solara/components/applayout.py +393 -0
  14. solara/components/button.py +85 -0
  15. solara/components/card.py +87 -0
  16. solara/components/checkbox.py +50 -0
  17. solara/components/code_highlight_css.py +11 -0
  18. solara/components/code_highlight_css.vue +63 -0
  19. solara/components/columns.py +159 -0
  20. solara/components/component_vue.py +110 -0
  21. solara/components/cross_filter.py +335 -0
  22. solara/components/dataframe.py +546 -0
  23. solara/components/datatable.py +221 -0
  24. solara/components/datatable.vue +175 -0
  25. solara/components/details.py +21 -0
  26. solara/components/download.vue +35 -0
  27. solara/components/echarts.py +75 -0
  28. solara/components/echarts.vue +128 -0
  29. solara/components/figure_altair.py +39 -0
  30. solara/components/file_browser.py +182 -0
  31. solara/components/file_download.py +199 -0
  32. solara/components/file_drop.py +139 -0
  33. solara/components/file_drop.vue +83 -0
  34. solara/components/file_list_widget.vue +78 -0
  35. solara/components/head.py +27 -0
  36. solara/components/head_tag.py +49 -0
  37. solara/components/head_tag.vue +60 -0
  38. solara/components/image.py +173 -0
  39. solara/components/input.py +436 -0
  40. solara/components/link.py +55 -0
  41. solara/components/markdown.py +378 -0
  42. solara/components/markdown_editor.py +25 -0
  43. solara/components/markdown_editor.vue +362 -0
  44. solara/components/matplotlib.py +74 -0
  45. solara/components/meta.py +47 -0
  46. solara/components/misc.py +333 -0
  47. solara/components/pivot_table.py +258 -0
  48. solara/components/pivot_table.vue +158 -0
  49. solara/components/progress.py +47 -0
  50. solara/components/select.py +182 -0
  51. solara/components/select.vue +27 -0
  52. solara/components/slider.py +442 -0
  53. solara/components/slider_date.vue +56 -0
  54. solara/components/spinner-solara.vue +105 -0
  55. solara/components/spinner.py +30 -0
  56. solara/components/sql_code.py +33 -0
  57. solara/components/sql_code.vue +128 -0
  58. solara/components/style.py +105 -0
  59. solara/components/switch.py +68 -0
  60. solara/components/tab_navigation.py +37 -0
  61. solara/components/title.py +90 -0
  62. solara/components/title.vue +38 -0
  63. solara/components/togglebuttons.py +200 -0
  64. solara/components/tooltip.py +61 -0
  65. solara/datatypes.py +143 -0
  66. solara/express.py +241 -0
  67. solara/hooks/__init__.py +4 -0
  68. solara/hooks/dataframe.py +99 -0
  69. solara/hooks/misc.py +263 -0
  70. solara/hooks/use_reactive.py +129 -0
  71. solara/hooks/use_thread.py +129 -0
  72. solara/kitchensink.py +8 -0
  73. solara/lab/__init__.py +34 -0
  74. solara/lab/components/__init__.py +6 -0
  75. solara/lab/components/chat.py +203 -0
  76. solara/lab/components/confirmation_dialog.py +163 -0
  77. solara/lab/components/cross_filter.py +7 -0
  78. solara/lab/components/input_date.py +298 -0
  79. solara/lab/components/menu.py +181 -0
  80. solara/lab/components/menu.vue +38 -0
  81. solara/lab/components/tabs.py +274 -0
  82. solara/lab/components/theming.py +98 -0
  83. solara/lab/components/theming.vue +72 -0
  84. solara/lab/hooks/__init__.py +0 -0
  85. solara/lab/hooks/dataframe.py +12 -0
  86. solara/lab/toestand.py +3 -0
  87. solara/lab/utils/__init__.py +2 -0
  88. solara/lab/utils/cookies.py +5 -0
  89. solara/lab/utils/dataframe.py +115 -0
  90. solara/lab/utils/headers.py +5 -0
  91. solara/layout.py +44 -0
  92. solara/lifecycle.py +46 -0
  93. solara/minisettings.py +133 -0
  94. solara/py.typed +0 -0
  95. solara/reactive.py +93 -0
  96. solara/routing.py +268 -0
  97. solara/scope/__init__.py +88 -0
  98. solara/scope/types.py +55 -0
  99. solara/server/__init__.py +0 -0
  100. solara/server/app.py +491 -0
  101. solara/server/assets/custom.css +1 -0
  102. solara/server/assets/custom.js +1 -0
  103. solara/server/assets/favicon.png +0 -0
  104. solara/server/assets/favicon.svg +5 -0
  105. solara/server/assets/style.css +1665 -0
  106. solara/server/assets/theme-dark.css +437 -0
  107. solara/server/assets/theme-light.css +420 -0
  108. solara/server/assets/theme.js +3 -0
  109. solara/server/cdn_helper.py +77 -0
  110. solara/server/esm.py +69 -0
  111. solara/server/fastapi.py +5 -0
  112. solara/server/flask.py +286 -0
  113. solara/server/jupyter/__init__.py +2 -0
  114. solara/server/jupyter/cdn_handler.py +28 -0
  115. solara/server/jupyter/server_extension.py +29 -0
  116. solara/server/jupytertools.py +46 -0
  117. solara/server/kernel.py +338 -0
  118. solara/server/kernel_context.py +357 -0
  119. solara/server/patch.py +552 -0
  120. solara/server/reload.py +242 -0
  121. solara/server/server.py +456 -0
  122. solara/server/settings.py +215 -0
  123. solara/server/shell.py +251 -0
  124. solara/server/starlette.py +601 -0
  125. solara/server/static/ansi.js +270 -0
  126. solara/server/static/highlight-dark.css +82 -0
  127. solara/server/static/highlight.css +43 -0
  128. solara/server/static/main-vuetify.js +260 -0
  129. solara/server/static/main.js +163 -0
  130. solara/server/static/solara_bootstrap.py +129 -0
  131. solara/server/static/sun.svg +23 -0
  132. solara/server/static/webworker.js +42 -0
  133. solara/server/telemetry.py +212 -0
  134. solara/server/templates/index.html.j2 +1 -0
  135. solara/server/templates/loader-plain.css +11 -0
  136. solara/server/templates/loader-plain.html +20 -0
  137. solara/server/templates/loader-solara.css +111 -0
  138. solara/server/templates/loader-solara.html +40 -0
  139. solara/server/templates/plain.html +82 -0
  140. solara/server/templates/solara.html.j2 +446 -0
  141. solara/server/threaded.py +75 -0
  142. solara/server/utils.py +30 -0
  143. solara/server/websocket.py +45 -0
  144. solara/settings.py +56 -0
  145. solara/tasks.py +837 -0
  146. solara/template/button.py +16 -0
  147. solara/template/markdown.py +42 -0
  148. solara/template/portal/.flake8 +6 -0
  149. solara/template/portal/.pre-commit-config.yaml +28 -0
  150. solara/template/portal/LICENSE +21 -0
  151. solara/template/portal/Procfile +7 -0
  152. solara/template/portal/mypy.ini +3 -0
  153. solara/template/portal/pyproject.toml +26 -0
  154. solara/template/portal/solara_portal/__init__.py +4 -0
  155. solara/template/portal/solara_portal/components/__init__.py +2 -0
  156. solara/template/portal/solara_portal/components/article.py +28 -0
  157. solara/template/portal/solara_portal/components/data.py +28 -0
  158. solara/template/portal/solara_portal/components/header.py +6 -0
  159. solara/template/portal/solara_portal/components/layout.py +6 -0
  160. solara/template/portal/solara_portal/content/articles/equis-in-vidi.md +85 -0
  161. solara/template/portal/solara_portal/content/articles/substiterat-vati.md +70 -0
  162. solara/template/portal/solara_portal/data.py +60 -0
  163. solara/template/portal/solara_portal/pages/__init__.py +67 -0
  164. solara/template/portal/solara_portal/pages/article/__init__.py +26 -0
  165. solara/template/portal/solara_portal/pages/tabular.py +29 -0
  166. solara/template/portal/solara_portal/pages/viz/__init__.py +70 -0
  167. solara/template/portal/solara_portal/pages/viz/overview.py +14 -0
  168. solara/test/__init__.py +0 -0
  169. solara/test/pytest_plugin.py +697 -0
  170. solara/toestand.py +772 -0
  171. solara/util.py +308 -0
  172. solara/website/__init__.py +0 -0
  173. solara/website/assets/custom.css +468 -0
  174. solara/website/assets/images/logo-small.png +0 -0
  175. solara/website/assets/images/logo.svg +17 -0
  176. solara/website/assets/images/logo_white.svg +50 -0
  177. solara/website/assets/theme.js +8 -0
  178. solara/website/components/__init__.py +5 -0
  179. solara/website/components/algolia.vue +24 -0
  180. solara/website/components/algolia_api.vue +187 -0
  181. solara/website/components/docs.py +118 -0
  182. solara/website/components/header.py +72 -0
  183. solara/website/components/hero.py +15 -0
  184. solara/website/components/mailchimp.py +12 -0
  185. solara/website/components/mailchimp.vue +47 -0
  186. solara/website/components/markdown.py +30 -0
  187. solara/website/components/notebook.py +171 -0
  188. solara/website/pages/__init__.py +575 -0
  189. solara/website/pages/apps/__init__.py +16 -0
  190. solara/website/pages/apps/authorization/__init__.py +119 -0
  191. solara/website/pages/apps/authorization/admin.py +12 -0
  192. solara/website/pages/apps/authorization/users.py +12 -0
  193. solara/website/pages/apps/jupyter-dashboard-1.py +116 -0
  194. solara/website/pages/apps/layout-demo.py +40 -0
  195. solara/website/pages/apps/multipage/__init__.py +38 -0
  196. solara/website/pages/apps/multipage/page1.py +26 -0
  197. solara/website/pages/apps/multipage/page2.py +34 -0
  198. solara/website/pages/apps/scatter.py +136 -0
  199. solara/website/pages/apps/scrolling.py +63 -0
  200. solara/website/pages/apps/tutorial-streamlit.py +18 -0
  201. solara/website/pages/changelog/__init__.py +8 -0
  202. solara/website/pages/changelog/changelog.md +204 -0
  203. solara/website/pages/contact/__init__.py +8 -0
  204. solara/website/pages/contact/contact.md +17 -0
  205. solara/website/pages/doc_use_download.py +85 -0
  206. solara/website/pages/documentation/__init__.py +184 -0
  207. solara/website/pages/documentation/advanced/__init__.py +9 -0
  208. solara/website/pages/documentation/advanced/content/00-overview.md +1 -0
  209. solara/website/pages/documentation/advanced/content/10-howto/00-overview.md +6 -0
  210. solara/website/pages/documentation/advanced/content/10-howto/10-multipage.md +196 -0
  211. solara/website/pages/documentation/advanced/content/10-howto/20-layout.md +125 -0
  212. solara/website/pages/documentation/advanced/content/10-howto/30-testing.md +162 -0
  213. solara/website/pages/documentation/advanced/content/10-howto/31-debugging.md +69 -0
  214. solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +49 -0
  215. solara/website/pages/documentation/advanced/content/10-howto/50-ipywidget_libraries.md +124 -0
  216. solara/website/pages/documentation/advanced/content/15-reference/00-overview.md +3 -0
  217. solara/website/pages/documentation/advanced/content/15-reference/40-static_files.md +31 -0
  218. solara/website/pages/documentation/advanced/content/15-reference/41-asset-files.md +36 -0
  219. solara/website/pages/documentation/advanced/content/15-reference/60-static-site-generation.md +59 -0
  220. solara/website/pages/documentation/advanced/content/15-reference/70-search.md +34 -0
  221. solara/website/pages/documentation/advanced/content/15-reference/80-reloading.md +34 -0
  222. solara/website/pages/documentation/advanced/content/15-reference/90-notebook-support.md +7 -0
  223. solara/website/pages/documentation/advanced/content/15-reference/95-caching.md +148 -0
  224. solara/website/pages/documentation/advanced/content/20-understanding/00-introduction.md +10 -0
  225. solara/website/pages/documentation/advanced/content/20-understanding/05-ipywidgets.md +35 -0
  226. solara/website/pages/documentation/advanced/content/20-understanding/06-ipyvuetify.md +42 -0
  227. solara/website/pages/documentation/advanced/content/20-understanding/10-reacton.md +28 -0
  228. solara/website/pages/documentation/advanced/content/20-understanding/12-reacton-basics.md +108 -0
  229. solara/website/pages/documentation/advanced/content/20-understanding/15-anatomy.md +23 -0
  230. solara/website/pages/documentation/advanced/content/20-understanding/17-rules-of-hooks.md +7 -0
  231. solara/website/pages/documentation/advanced/content/20-understanding/18-containers.md +166 -0
  232. solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md +18 -0
  233. solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +240 -0
  234. solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +97 -0
  235. solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md +12 -0
  236. solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +1 -0
  237. solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +171 -0
  238. solara/website/pages/documentation/advanced/content/40-development/00-overview.md +0 -0
  239. solara/website/pages/documentation/advanced/content/40-development/01-contribute.md +45 -0
  240. solara/website/pages/documentation/advanced/content/40-development/10-setup.md +76 -0
  241. solara/website/pages/documentation/api/__init__.py +19 -0
  242. solara/website/pages/documentation/api/cross_filter/__init__.py +9 -0
  243. solara/website/pages/documentation/api/cross_filter/cross_filter_dataframe.py +23 -0
  244. solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +22 -0
  245. solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +22 -0
  246. solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +22 -0
  247. solara/website/pages/documentation/api/hooks/__init__.py +9 -0
  248. solara/website/pages/documentation/api/hooks/use_cross_filter.py +25 -0
  249. solara/website/pages/documentation/api/hooks/use_dark_effective.py +12 -0
  250. solara/website/pages/documentation/api/hooks/use_effect.md +43 -0
  251. solara/website/pages/documentation/api/hooks/use_effect.py +9 -0
  252. solara/website/pages/documentation/api/hooks/use_exception.py +33 -0
  253. solara/website/pages/documentation/api/hooks/use_memo.md +16 -0
  254. solara/website/pages/documentation/api/hooks/use_memo.py +9 -0
  255. solara/website/pages/documentation/api/hooks/use_previous.py +33 -0
  256. solara/website/pages/documentation/api/hooks/use_reactive.py +16 -0
  257. solara/website/pages/documentation/api/hooks/use_state.py +10 -0
  258. solara/website/pages/documentation/api/hooks/use_state_or_update.py +69 -0
  259. solara/website/pages/documentation/api/hooks/use_thread.md +58 -0
  260. solara/website/pages/documentation/api/hooks/use_thread.py +44 -0
  261. solara/website/pages/documentation/api/hooks/use_trait_observe.py +12 -0
  262. solara/website/pages/documentation/api/routing/__init__.py +9 -0
  263. solara/website/pages/documentation/api/routing/generate_routes.py +10 -0
  264. solara/website/pages/documentation/api/routing/generate_routes_directory.py +10 -0
  265. solara/website/pages/documentation/api/routing/resolve_path.py +35 -0
  266. solara/website/pages/documentation/api/routing/route.py +31 -0
  267. solara/website/pages/documentation/api/routing/use_route.py +80 -0
  268. solara/website/pages/documentation/api/routing/use_router.py +16 -0
  269. solara/website/pages/documentation/api/utilities/__init__.py +9 -0
  270. solara/website/pages/documentation/api/utilities/component_vue.py +10 -0
  271. solara/website/pages/documentation/api/utilities/computed.py +16 -0
  272. solara/website/pages/documentation/api/utilities/display.py +16 -0
  273. solara/website/pages/documentation/api/utilities/get_kernel_id.py +16 -0
  274. solara/website/pages/documentation/api/utilities/get_session_id.py +16 -0
  275. solara/website/pages/documentation/api/utilities/memoize.py +35 -0
  276. solara/website/pages/documentation/api/utilities/on_kernel_start.py +27 -0
  277. solara/website/pages/documentation/api/utilities/reactive.py +16 -0
  278. solara/website/pages/documentation/api/utilities/widget.py +104 -0
  279. solara/website/pages/documentation/components/__init__.py +12 -0
  280. solara/website/pages/documentation/components/advanced/__init__.py +9 -0
  281. solara/website/pages/documentation/components/advanced/link.py +27 -0
  282. solara/website/pages/documentation/components/advanced/meta.py +20 -0
  283. solara/website/pages/documentation/components/advanced/style.py +45 -0
  284. solara/website/pages/documentation/components/common.py +9 -0
  285. solara/website/pages/documentation/components/data/__init__.py +9 -0
  286. solara/website/pages/documentation/components/data/dataframe.py +44 -0
  287. solara/website/pages/documentation/components/data/pivot_table.py +81 -0
  288. solara/website/pages/documentation/components/enterprise/__init__.py +9 -0
  289. solara/website/pages/documentation/components/enterprise/avatar.py +24 -0
  290. solara/website/pages/documentation/components/enterprise/avatar_menu.py +25 -0
  291. solara/website/pages/documentation/components/input/__init__.py +9 -0
  292. solara/website/pages/documentation/components/input/button.py +23 -0
  293. solara/website/pages/documentation/components/input/checkbox.py +10 -0
  294. solara/website/pages/documentation/components/input/file_browser.py +32 -0
  295. solara/website/pages/documentation/components/input/file_drop.py +76 -0
  296. solara/website/pages/documentation/components/input/input.py +19 -0
  297. solara/website/pages/documentation/components/input/select.py +22 -0
  298. solara/website/pages/documentation/components/input/slider.py +29 -0
  299. solara/website/pages/documentation/components/input/switch.py +10 -0
  300. solara/website/pages/documentation/components/input/togglebuttons.py +21 -0
  301. solara/website/pages/documentation/components/lab/__init__.py +9 -0
  302. solara/website/pages/documentation/components/lab/chat.py +109 -0
  303. solara/website/pages/documentation/components/lab/confirmation_dialog.py +55 -0
  304. solara/website/pages/documentation/components/lab/cookies_headers.py +48 -0
  305. solara/website/pages/documentation/components/lab/input_date.py +20 -0
  306. solara/website/pages/documentation/components/lab/menu.py +22 -0
  307. solara/website/pages/documentation/components/lab/tab.py +25 -0
  308. solara/website/pages/documentation/components/lab/tabs.py +45 -0
  309. solara/website/pages/documentation/components/lab/task.py +11 -0
  310. solara/website/pages/documentation/components/lab/theming.py +72 -0
  311. solara/website/pages/documentation/components/lab/use_task.py +11 -0
  312. solara/website/pages/documentation/components/layout/__init__.py +9 -0
  313. solara/website/pages/documentation/components/layout/app_bar.py +16 -0
  314. solara/website/pages/documentation/components/layout/app_bar_title.py +16 -0
  315. solara/website/pages/documentation/components/layout/app_layout.py +24 -0
  316. solara/website/pages/documentation/components/layout/card.py +15 -0
  317. solara/website/pages/documentation/components/layout/card_actions.py +16 -0
  318. solara/website/pages/documentation/components/layout/column.py +30 -0
  319. solara/website/pages/documentation/components/layout/columns.py +27 -0
  320. solara/website/pages/documentation/components/layout/columns_responsive.py +68 -0
  321. solara/website/pages/documentation/components/layout/griddraggable.py +62 -0
  322. solara/website/pages/documentation/components/layout/gridfixed.py +21 -0
  323. solara/website/pages/documentation/components/layout/hbox.py +18 -0
  324. solara/website/pages/documentation/components/layout/row.py +30 -0
  325. solara/website/pages/documentation/components/layout/sidebar.py +24 -0
  326. solara/website/pages/documentation/components/layout/vbox.py +19 -0
  327. solara/website/pages/documentation/components/output/__init__.py +9 -0
  328. solara/website/pages/documentation/components/output/file_download.py +11 -0
  329. solara/website/pages/documentation/components/output/html.py +21 -0
  330. solara/website/pages/documentation/components/output/image.py +11 -0
  331. solara/website/pages/documentation/components/output/markdown.py +57 -0
  332. solara/website/pages/documentation/components/output/markdown_editor.py +51 -0
  333. solara/website/pages/documentation/components/output/sql_code.py +85 -0
  334. solara/website/pages/documentation/components/output/tooltip.py +11 -0
  335. solara/website/pages/documentation/components/page/__init__.py +9 -0
  336. solara/website/pages/documentation/components/page/head.py +18 -0
  337. solara/website/pages/documentation/components/page/title.py +27 -0
  338. solara/website/pages/documentation/components/status/__init__.py +9 -0
  339. solara/website/pages/documentation/components/status/error.py +40 -0
  340. solara/website/pages/documentation/components/status/info.py +40 -0
  341. solara/website/pages/documentation/components/status/progress.py +10 -0
  342. solara/website/pages/documentation/components/status/spinner.py +11 -0
  343. solara/website/pages/documentation/components/status/success.py +40 -0
  344. solara/website/pages/documentation/components/status/warning.py +47 -0
  345. solara/website/pages/documentation/components/viz/__init__.py +9 -0
  346. solara/website/pages/documentation/components/viz/altair.py +42 -0
  347. solara/website/pages/documentation/components/viz/echarts.py +75 -0
  348. solara/website/pages/documentation/components/viz/matplotlib.py +30 -0
  349. solara/website/pages/documentation/components/viz/plotly.py +63 -0
  350. solara/website/pages/documentation/components/viz/plotly_express.py +41 -0
  351. solara/website/pages/documentation/examples/__init__.py +52 -0
  352. solara/website/pages/documentation/examples/ai/__init__.py +11 -0
  353. solara/website/pages/documentation/examples/ai/chatbot.py +95 -0
  354. solara/website/pages/documentation/examples/ai/tokenizer.py +107 -0
  355. solara/website/pages/documentation/examples/basics/__init__.py +10 -0
  356. solara/website/pages/documentation/examples/basics/sine.py +28 -0
  357. solara/website/pages/documentation/examples/fullscreen/__init__.py +10 -0
  358. solara/website/pages/documentation/examples/fullscreen/authorization.py +3 -0
  359. solara/website/pages/documentation/examples/fullscreen/layout_demo.py +3 -0
  360. solara/website/pages/documentation/examples/fullscreen/multipage.py +3 -0
  361. solara/website/pages/documentation/examples/fullscreen/scatter.py +3 -0
  362. solara/website/pages/documentation/examples/fullscreen/scrolling.py +3 -0
  363. solara/website/pages/documentation/examples/fullscreen/tutorial_streamlit.py +3 -0
  364. solara/website/pages/documentation/examples/general/__init__.py +10 -0
  365. solara/website/pages/documentation/examples/general/custom_storage.py +70 -0
  366. solara/website/pages/documentation/examples/general/deploy_model.py +115 -0
  367. solara/website/pages/documentation/examples/general/live_update.py +38 -0
  368. solara/website/pages/documentation/examples/general/login_oauth.py +81 -0
  369. solara/website/pages/documentation/examples/general/mycard.vue +58 -0
  370. solara/website/pages/documentation/examples/general/pokemon_search.py +51 -0
  371. solara/website/pages/documentation/examples/general/vue_component.py +50 -0
  372. solara/website/pages/documentation/examples/ipycanvas.py +49 -0
  373. solara/website/pages/documentation/examples/libraries/__init__.py +10 -0
  374. solara/website/pages/documentation/examples/libraries/altair.py +64 -0
  375. solara/website/pages/documentation/examples/libraries/bqplot.py +39 -0
  376. solara/website/pages/documentation/examples/libraries/ipyleaflet.py +33 -0
  377. solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +66 -0
  378. solara/website/pages/documentation/examples/utilities/__init__.py +10 -0
  379. solara/website/pages/documentation/examples/utilities/calculator.py +157 -0
  380. solara/website/pages/documentation/examples/utilities/countdown_timer.py +64 -0
  381. solara/website/pages/documentation/examples/utilities/todo.py +196 -0
  382. solara/website/pages/documentation/examples/visualization/__init__.py +6 -0
  383. solara/website/pages/documentation/examples/visualization/annotator.py +69 -0
  384. solara/website/pages/documentation/examples/visualization/linked_views.py +84 -0
  385. solara/website/pages/documentation/examples/visualization/plotly.py +44 -0
  386. solara/website/pages/documentation/faq/__init__.py +12 -0
  387. solara/website/pages/documentation/faq/content/99-faq.md +76 -0
  388. solara/website/pages/documentation/getting_started/__init__.py +9 -0
  389. solara/website/pages/documentation/getting_started/content/00-quickstart.md +89 -0
  390. solara/website/pages/documentation/getting_started/content/01-introduction.md +125 -0
  391. solara/website/pages/documentation/getting_started/content/02-installing.md +134 -0
  392. solara/website/pages/documentation/getting_started/content/04-tutorials/00-overview.md +14 -0
  393. solara/website/pages/documentation/getting_started/content/04-tutorials/10_data_science.py +13 -0
  394. solara/website/pages/documentation/getting_started/content/04-tutorials/20-web-app.md +89 -0
  395. solara/website/pages/documentation/getting_started/content/04-tutorials/30-ipywidgets.md +124 -0
  396. solara/website/pages/documentation/getting_started/content/04-tutorials/40-streamlit.md +146 -0
  397. solara/website/pages/documentation/getting_started/content/04-tutorials/50-dash.md +144 -0
  398. solara/website/pages/documentation/getting_started/content/04-tutorials/60-jupyter-dashboard-part1.py +64 -0
  399. solara/website/pages/documentation/getting_started/content/04-tutorials/SF_crime_sample.csv.gz +0 -0
  400. solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb +445 -0
  401. solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +1000 -0
  402. solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md +11 -0
  403. solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +223 -0
  404. solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +88 -0
  405. solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md +7 -0
  406. solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +273 -0
  407. solara/website/pages/documentation/getting_started/content/07-deploying/20-cloud-hosted.md +80 -0
  408. solara/website/pages/documentation/getting_started/content/80-what-is-lab.md +7 -0
  409. solara/website/pages/documentation/getting_started/content/90-troubleshoot.md +26 -0
  410. solara/website/pages/docutils.py +38 -0
  411. solara/website/pages/showcase/__init__.py +105 -0
  412. solara/website/pages/showcase/domino_code_assist.py +60 -0
  413. solara/website/pages/showcase/planeto_tessa.py +19 -0
  414. solara/website/pages/showcase/solara_dev.py +54 -0
  415. solara/website/pages/showcase/solarathon_2023_team_2.py +22 -0
  416. solara/website/pages/showcase/solarathon_2023_team_4.py +22 -0
  417. solara/website/pages/showcase/solarathon_2023_team_5.py +23 -0
  418. solara/website/pages/showcase/solarathon_2023_team_6.py +34 -0
  419. solara/website/pages/showcase/wanderlust.py +27 -0
  420. solara/website/public/beach.jpeg +0 -0
  421. solara/website/public/logo.svg +6 -0
  422. solara/website/public/social/discord.svg +1 -0
  423. solara/website/public/social/github.svg +1 -0
  424. solara/website/public/social/twitter.svg +3 -0
  425. solara/website/public/success.html +25 -0
  426. solara/website/templates/index.html.j2 +117 -0
  427. solara/website/utils.py +51 -0
  428. solara/widgets/__init__.py +1 -0
  429. solara/widgets/vue/gridlayout.vue +110 -0
  430. solara/widgets/vue/html.vue +4 -0
  431. solara/widgets/vue/navigator.vue +104 -0
  432. solara/widgets/vue/vegalite.vue +115 -0
  433. solara/widgets/widgets.py +66 -0
  434. solara_ui-1.31.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
  435. solara_ui-1.31.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
  436. solara_ui-1.31.0.dist-info/METADATA +158 -0
  437. solara_ui-1.31.0.dist-info/RECORD +439 -0
  438. solara_ui-1.31.0.dist-info/WHEEL +5 -0
  439. solara_ui-1.31.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,66 @@
1
+ """
2
+ # ipyleaflet advanced
3
+
4
+ Extends the [basic ipyleaflet example](/documentation/examples/libraries/ipyleaflet) with a marker that can be dragged around, and a
5
+ dropdown to select the map style. Two buttons allow to reset the map to the default zoom and center and to zoom
6
+ to the marker.
7
+ """
8
+
9
+ import ipyleaflet
10
+
11
+ import solara
12
+
13
+ center_default = (53.2305799, 6.5323552)
14
+ zoom_default = 5
15
+ maps = {
16
+ "OpenStreetMap.Mapnik": ipyleaflet.basemaps.OpenStreetMap.Mapnik,
17
+ "OpenTopoMap": ipyleaflet.basemaps.OpenTopoMap,
18
+ "Esri.WorldTopoMap": ipyleaflet.basemaps.Esri.WorldTopoMap,
19
+ }
20
+
21
+ zoom = solara.reactive(zoom_default)
22
+ center = solara.reactive(center_default)
23
+ marker_location = solara.reactive(center_default)
24
+
25
+ map_name = solara.reactive(list(maps)[0])
26
+
27
+
28
+ @solara.component
29
+ def Page():
30
+ def location_changed(location):
31
+ # do things with the location
32
+ marker_location.set(location)
33
+
34
+ with solara.Column(style={"min-width": "500px", "height": "500px"}):
35
+ solara.Markdown(f"Market set to: {marker_location.value}", style={"color": "#6e6e6e"})
36
+
37
+ map = maps[map_name.value]
38
+ url = map.build_url()
39
+
40
+ def goto_marker():
41
+ center.value = marker_location.value
42
+ zoom.value = 13
43
+
44
+ def reset_view():
45
+ center.value = center_default
46
+ zoom.value = zoom_default
47
+
48
+ solara.Select(label="Map", value=map_name, values=list(maps))
49
+ solara.SliderInt(label="Zoom level", value=zoom, min=1, max=20)
50
+ with solara.Row():
51
+ solara.Button(label="Zoom to marker", on_click=goto_marker)
52
+ solara.Button(label="Reset view", on_click=reset_view)
53
+
54
+ # Isolation is required to prevent the map from overlapping navigation (when screen width < 960px)
55
+ with solara.Column(style={"isolation": "isolate"}):
56
+ ipyleaflet.Map.element( # type: ignore
57
+ zoom=zoom.value,
58
+ on_zoom=zoom.set,
59
+ center=center.value,
60
+ on_center=center.set,
61
+ scroll_wheel_zoom=True,
62
+ layers=[
63
+ ipyleaflet.TileLayer.element(url=url),
64
+ ipyleaflet.Marker.element(location=marker_location.value, draggable=True, on_location=location_changed),
65
+ ],
66
+ )
@@ -0,0 +1,10 @@
1
+ """Utility apps, slightly more complex."""
2
+
3
+ import solara
4
+
5
+ redirect = None
6
+
7
+
8
+ @solara.component
9
+ def Page():
10
+ return solara.Markdown("Should not see me")
@@ -0,0 +1,157 @@
1
+ """# Calculator
2
+
3
+ This shows how to use `use_reducer` to implement a simple calculator.
4
+
5
+ Note that the `reducer` implements all the logic of the calculator, and the `Calculator` component is just a thin wrapper around it.
6
+
7
+
8
+
9
+ """
10
+
11
+ import ast
12
+ import dataclasses
13
+ import operator
14
+ from typing import Any, Optional
15
+
16
+ import solara
17
+
18
+ DEBUG = False
19
+ operator_map = {
20
+ "x": operator.mul,
21
+ "/": operator.truediv,
22
+ "+": operator.add,
23
+ "-": operator.sub,
24
+ }
25
+
26
+
27
+ @dataclasses.dataclass(frozen=True)
28
+ class CalculatorState:
29
+ input: str = ""
30
+ output: str = ""
31
+ left: float = 0
32
+ right: Optional[float] = None
33
+ operator: Any = operator.add
34
+ error: str = ""
35
+
36
+
37
+ initial_state = CalculatorState()
38
+
39
+
40
+ def calculate(state: CalculatorState):
41
+ result = state.operator(state.left, state.right)
42
+ return dataclasses.replace(state, left=result)
43
+
44
+
45
+ def calculator_reducer(state: CalculatorState, action):
46
+ action_type, payload = action
47
+ if DEBUG:
48
+ print("reducer", state, action_type, payload) # noqa
49
+ state = dataclasses.replace(state, error="")
50
+
51
+ if action_type == "digit":
52
+ digit = payload
53
+ input = state.input + digit
54
+ return dataclasses.replace(state, input=input, output=input)
55
+ elif action_type == "percent":
56
+ if state.input:
57
+ try:
58
+ value = ast.literal_eval(state.input)
59
+ except Exception as e:
60
+ return dataclasses.replace(state, error=str(e))
61
+ state = dataclasses.replace(state, right=value / 100)
62
+ state = calculate(state)
63
+ output = f"{value / 100:,}"
64
+ return dataclasses.replace(state, output=output, input="")
65
+ else:
66
+ output = f"{state.left / 100:,}"
67
+ return dataclasses.replace(state, left=state.left / 100, output=output)
68
+ elif action_type == "negate":
69
+ if state.input:
70
+ input = state.output
71
+ input = input[1:] if input[0] == "-" else "-" + input
72
+ output = input
73
+ return dataclasses.replace(state, input=input, output=output)
74
+ else:
75
+ output = f"{-state.left:,}"
76
+ return dataclasses.replace(state, left=-state.left, output=output)
77
+ elif action_type == "clear":
78
+ return dataclasses.replace(state, input="", output="")
79
+ elif action_type == "reset":
80
+ return initial_state
81
+ elif action_type == "calculate":
82
+ if state.input:
83
+ try:
84
+ value = ast.literal_eval(state.input)
85
+ except Exception as e:
86
+ return dataclasses.replace(state, error=str(e))
87
+ state = dataclasses.replace(state, right=value)
88
+ state = calculate(state)
89
+ output = f"{state.left:,}"
90
+ state = dataclasses.replace(state, output=output, input="")
91
+ return state
92
+ elif action_type == "operator":
93
+ if state.input:
94
+ state = calculator_reducer(state, ("calculate", None))
95
+ state = dataclasses.replace(state, operator=payload, input="")
96
+ else:
97
+ # e.g. 2+3=*= should give 5,25
98
+ state = dataclasses.replace(state, operator=payload, right=state.left)
99
+ return state
100
+ else:
101
+ print("invalid action", action) # noqa
102
+ return state
103
+
104
+
105
+ @solara.component
106
+ def Calculator():
107
+ state, dispatch = solara.use_reducer(calculator_reducer, initial_state)
108
+ if DEBUG:
109
+ print("->", state) # noqa
110
+ with solara.Card("Calculator", elevation=10, classes=["ma-4"]) as main:
111
+ with solara.VBox(grow=False):
112
+ solara.Text(state.error or state.output or "0")
113
+ class_ = "pa-0 ma-1"
114
+
115
+ with solara.HBox(grow=False):
116
+ if state.input:
117
+ solara.Button("C", on_click=lambda: dispatch(("clear", None)), dark=True, class_=class_)
118
+ else:
119
+ solara.Button("AC", on_click=lambda: dispatch(("reset", None)), dark=True, class_=class_)
120
+ solara.Button("+/-", on_click=lambda: dispatch(("negate", None)), dark=True, class_=class_)
121
+ solara.Button("%", on_click=lambda: dispatch(("percent", None)), dark=True, class_=class_)
122
+ solara.Button("/", color="primary", on_click=lambda: dispatch(("operator", operator_map["/"])), class_=class_)
123
+
124
+ column_op = ["x", "-", "+"]
125
+ for i in range(3):
126
+ with solara.HBox(grow=False):
127
+ for j in range(3):
128
+ digit = str(j + (2 - i) * 3 + 1)
129
+
130
+ def on_click(digit=digit):
131
+ dispatch(("digit", digit))
132
+
133
+ solara.Button(digit, on_click=on_click, class_=class_)
134
+ op_symbol = column_op[i]
135
+ op = operator_map[op_symbol]
136
+
137
+ def on_click_op(op=op):
138
+ dispatch(("operator", op))
139
+
140
+ solara.Button(op_symbol, color="primary", on_click=on_click_op, class_=class_)
141
+ with solara.HBox(grow=False):
142
+
143
+ def boom():
144
+ print("boom") # noqa
145
+ raise ValueError("lala")
146
+
147
+ solara.Button("?", on_click=boom, class_=class_)
148
+
149
+ solara.Button("0", on_click=lambda: dispatch(("digit", "0")), class_=class_)
150
+ solara.Button(".", on_click=lambda: dispatch(("digit", ".")), class_=class_)
151
+
152
+ solara.Button("=", color="primary", on_click=lambda: dispatch(("calculate", None)), class_=class_)
153
+
154
+ return main
155
+
156
+
157
+ Page = Calculator
@@ -0,0 +1,64 @@
1
+ """# Countdown timer.
2
+
3
+ This example shows how to use [use_thread](/documentation/api/hooks/use_thread) to create a countdown timer.
4
+
5
+ The UI code demonstrates a lot of conditional rendering.
6
+
7
+ """
8
+
9
+ import time
10
+
11
+ import solara
12
+ from solara.alias import rv
13
+
14
+
15
+ @solara.component
16
+ def Page():
17
+ seconds, set_seconds = solara.use_state(5)
18
+ running, set_running = solara.use_state(False)
19
+ duration, set_duration = solara.use_state(seconds)
20
+
21
+ def on_duration(duration):
22
+ try:
23
+ set_duration(int(duration))
24
+ set_seconds(int(duration))
25
+ except ValueError:
26
+ pass
27
+
28
+ def run_timer():
29
+ if running:
30
+ time_start = time.time()
31
+ next_tick = time_start + 1
32
+ i = seconds
33
+ while i:
34
+ # instead of sleeping for 1 second, we sleep until the next second
35
+ # this takes into account overhead and makes the timer more accurate
36
+ time.sleep(max(0, next_tick - time.time()))
37
+ i -= 1
38
+ set_seconds(i)
39
+ next_tick += 1
40
+ set_running(False)
41
+
42
+ solara.use_thread(run_timer, dependencies=[duration, running])
43
+
44
+ with solara.VBox() as main:
45
+ if not running:
46
+ if duration < 1:
47
+ solara.Error("Duration must be at least 1 second")
48
+ else:
49
+ solara.Markdown(f"# Timer set to {seconds} seconds")
50
+ else:
51
+ if seconds:
52
+ solara.Markdown(f"# {seconds} seconds left")
53
+ else:
54
+ solara.solara.Markdown("# Time's up!")
55
+ rv.TextField(type="number", v_model=duration, on_v_model=on_duration, disabled=running)
56
+ with solara.HBox():
57
+ if running:
58
+ solara.Button("Stop", on_click=lambda: set_running(False), icon_name="mdi-stop")
59
+ else:
60
+ if duration != seconds:
61
+ solara.Button("Reset", on_click=lambda: set_seconds(duration), icon_name="mdi-restart")
62
+ else:
63
+ solara.Button("Start", on_click=lambda: set_running(True), icon_name="mdi-play", disabled=seconds < 1)
64
+ return main
@@ -0,0 +1,196 @@
1
+ """# Todo application
2
+
3
+ Demonstrates the use of reactive variables in combinations with dataclasses.
4
+
5
+ With solara we can get a type safe view onto a field in a dataclass, pydantic model, or
6
+ attr object.
7
+
8
+ This is using the experimental `solara.lab.Ref` class, which is not yet part of the
9
+ official API.
10
+
11
+
12
+ ```python
13
+ import dataclasses
14
+ import solara
15
+ from solara.lab import Ref
16
+
17
+ @dataclasses.dataclass(frozen=True)
18
+ class TodoItem:
19
+ text: str
20
+ done: bool
21
+
22
+ todo_item = solara.reactive(TodoItem("Buy milk", False))
23
+
24
+ # now text is a reactive variable that is always in sync with todo_item.text
25
+ text = Ref(todo_item.fields.text)
26
+
27
+
28
+ # we can now modify the reactive text variable
29
+ # and see its value reflect in the todo_item
30
+ text.value = "Buy skimmed milk"
31
+ assert todo_item.value.text == "Buy skimmed milk"
32
+
33
+ # Or, the other way around
34
+ todo_item.value = TodoItem("Buy whole milk", False)
35
+ assert text.value == "Buy whole milk"
36
+ ```
37
+
38
+ Apart from dataclasses, pydantic models etc, we also supports dictionaries and lists.
39
+
40
+ ```python
41
+ todo_items = solara.reactive([TodoItem("Buy milk", False), TodoItem("Buy eggs", False)])
42
+ todo_item_eggs = Ref(todo_items.fields[1])
43
+ todo_item_eggs.value = TodoItem("Buy eggs", True)
44
+ assert todo_items.value[1].done == True
45
+
46
+ # However, if a list becomes shorter, and the valid index is now out of range, the
47
+ # reactive variables will act as if it is "not connected", and will not trigger
48
+ # updates anymore. Accessing the value will raise an IndexError.
49
+
50
+ todo_items.value = [TodoItem("Buy milk", False)]
51
+ # anyone listening to todo_item_eggs will *not* be notified.
52
+ try:
53
+ value = todo_item_eggs.value
54
+ except IndexError:
55
+ print("this is expected")
56
+ else:
57
+ raise AssertionError("Expected an IndexError")
58
+ ```
59
+
60
+ """
61
+
62
+ import dataclasses
63
+ from typing import Callable
64
+
65
+ import reacton.ipyvuetify as v
66
+
67
+ import solara
68
+ from solara.lab.toestand import Ref
69
+
70
+
71
+ # our model for a todo item, immutable/frozen avoids common bugs
72
+ @dataclasses.dataclass(frozen=True)
73
+ class TodoItem:
74
+ text: str
75
+ done: bool
76
+
77
+
78
+ @solara.component
79
+ def TodoEdit(todo_item: solara.Reactive[TodoItem], on_delete: Callable[[], None], on_close: Callable[[], None]):
80
+ """Takes a reactive todo item and allows editing it. Will not modify the original item until 'save' is clicked."""
81
+ copy = solara.use_reactive(todo_item.value)
82
+
83
+ def save():
84
+ todo_item.value = copy.value
85
+ on_close()
86
+
87
+ with solara.Card("Edit", margin=0):
88
+ solara.InputText(label="", value=Ref(copy.fields.text))
89
+ with solara.CardActions():
90
+ v.Spacer()
91
+ solara.Button("Save", icon_name="mdi-content-save", on_click=save, outlined=True, text=True)
92
+ solara.Button("Close", icon_name="mdi-window-close", on_click=on_close, outlined=True, text=True)
93
+ solara.Button("Delete", icon_name="mdi-delete", on_click=on_delete, outlined=True, text=True)
94
+
95
+
96
+ @solara.component
97
+ def TodoListItem(todo_item: solara.Reactive[TodoItem], on_delete: Callable[[TodoItem], None]):
98
+ """Displays a single todo item, modifications are done 'in place'.
99
+
100
+ For demonstration purposes, we allow editing the item in a dialog as well.
101
+ This will not modify the original item until 'save' is clicked.
102
+ """
103
+ edit, set_edit = solara.use_state(False)
104
+ with v.ListItem():
105
+ solara.Button(icon_name="mdi-delete", icon=True, on_click=lambda: on_delete(todo_item.value))
106
+ solara.Checkbox(value=Ref(todo_item.fields.done)) # , color="success")
107
+ solara.InputText(label="", value=Ref(todo_item.fields.text))
108
+ solara.Button(icon_name="mdi-pencil", icon=True, on_click=lambda: set_edit(True))
109
+ with v.Dialog(v_model=edit, persistent=True, max_width="500px", on_v_model=set_edit):
110
+ if edit: # 'reset' the component state on open/close
111
+
112
+ def on_delete_in_edit():
113
+ on_delete(todo_item.value)
114
+ set_edit(False)
115
+
116
+ TodoEdit(todo_item, on_delete=on_delete_in_edit, on_close=lambda: set_edit(False))
117
+
118
+
119
+ @solara.component
120
+ def TodoNew(on_new: Callable[[TodoItem], None]):
121
+ """Component that managed entering new todo items"""
122
+ new_text, set_new_text = solara.use_state("")
123
+ text_field = v.TextField(v_model=new_text, on_v_model=set_new_text, label="Enter a new todo item")
124
+
125
+ def create_new_item(*ignore_args):
126
+ if not new_text:
127
+ return
128
+ new_item = TodoItem(text=new_text, done=False)
129
+ on_new(new_item)
130
+ # reset text
131
+ set_new_text("")
132
+
133
+ v.use_event(text_field, "keydown.enter", create_new_item)
134
+ return text_field
135
+
136
+
137
+ initial_items = [
138
+ TodoItem("Learn Solara", done=True),
139
+ TodoItem("Write cool apps", done=False),
140
+ TodoItem("Relax", done=False),
141
+ ]
142
+
143
+
144
+ # We store out reactive state, and our logic in a class for organization
145
+ # purposes, but this is not required.
146
+ # Note that all the above components do not refer to this class, but only
147
+ # to do the Todo items.
148
+ # This means all above components are reusable, and can be used in other
149
+ # places, while the components below use 'application'/'global' state.
150
+ # They are not suited for reuse.
151
+
152
+
153
+ class State:
154
+ todos = solara.reactive(initial_items)
155
+
156
+ @staticmethod
157
+ def on_new(item: TodoItem):
158
+ State.todos.value = [item] + State.todos.value
159
+
160
+ @staticmethod
161
+ def on_delete(item: TodoItem):
162
+ new_items = list(State.todos.value)
163
+ new_items.remove(item)
164
+ State.todos.value = new_items
165
+
166
+
167
+ @solara.component
168
+ def TodoStatus():
169
+ """Status of our todo list"""
170
+ items = State.todos.value
171
+ count = len(items)
172
+ items_done = [item for item in items if item.done]
173
+ count_done = len(items_done)
174
+
175
+ if count != count_done:
176
+ with solara.Row():
177
+ percent = count_done / count * 100
178
+ solara.ProgressLinear(value=percent)
179
+ with solara.Row():
180
+ solara.Text(f"Remaining: {count - count_done}")
181
+ solara.Text(f"Completed: {count_done}")
182
+ else:
183
+ solara.Success("All done, awesome!", dense=True)
184
+
185
+
186
+ @solara.component
187
+ def Page():
188
+ with solara.Card("Todo list", style="min-width: 500px"):
189
+ TodoNew(on_new=State.on_new)
190
+ if State.todos.value:
191
+ TodoStatus()
192
+ for index, item in enumerate(State.todos.value):
193
+ todo_item = Ref(State.todos.fields[index])
194
+ TodoListItem(todo_item, on_delete=State.on_delete)
195
+ else:
196
+ solara.Info("No todo items, enter some text above, and hit enter")
@@ -0,0 +1,6 @@
1
+ import solara
2
+
3
+
4
+ @solara.component
5
+ def Page():
6
+ return solara.Markdown("Click an example on the left")
@@ -0,0 +1,69 @@
1
+ """# Image annotation with Solara
2
+
3
+ This example displays how to annotate images with different drawing tools in plotly figures. Use the canvas
4
+ below to draw shapes and visualize the canvas callback.
5
+
6
+
7
+ Check [plotly docs](https://dash.plotly.com/annotations) for more information about image annotation.
8
+ """
9
+
10
+ import json
11
+
12
+ import plotly.graph_objects as go
13
+
14
+ import solara
15
+
16
+ title = "Plotly Image Annotator"
17
+ shapes = solara.reactive(None)
18
+
19
+
20
+ class CustomEncoder(json.JSONEncoder):
21
+ """
22
+ Custom JSON encoder for Plotly objects.
23
+
24
+ Plotly may return objects that the standard JSON encoder can't handle. This
25
+ encoder converts such objects to str, allowing serialization by json.dumps
26
+ """
27
+
28
+ def default(self, o):
29
+ if isinstance(o, object):
30
+ return str(o)
31
+ return super().default(o)
32
+
33
+
34
+ @solara.component
35
+ def Page():
36
+ def on_relayout(data):
37
+ if data is None:
38
+ return
39
+
40
+ relayout_data = data["relayout_data"]
41
+
42
+ if "shapes" in relayout_data:
43
+ shapes.value = relayout_data["shapes"]
44
+
45
+ fig = go.FigureWidget(
46
+ layout=go.Layout(
47
+ showlegend=False,
48
+ autosize=False,
49
+ width=600,
50
+ height=600,
51
+ dragmode="drawrect",
52
+ modebar={
53
+ "add": [
54
+ "drawclosedpath",
55
+ "drawcircle",
56
+ "drawrect",
57
+ "eraseshape",
58
+ ]
59
+ },
60
+ )
61
+ )
62
+
63
+ solara.FigurePlotly(fig, on_relayout=on_relayout)
64
+ if not shapes.value:
65
+ solara.Markdown("## Draw on the canvas")
66
+ else:
67
+ solara.Markdown("## Data returned by drawing")
68
+ formatted_shapes = str(json.dumps(shapes.value, indent=2, cls=CustomEncoder))
69
+ solara.Preformatted(formatted_shapes)
@@ -0,0 +1,84 @@
1
+ """# Linked views
2
+
3
+ This example shows how to create linked views. The clicked row information is passed up to the parent component using an event,
4
+ and then passed down to both child components.
5
+
6
+ """
7
+
8
+ import dataclasses
9
+ from typing import Callable, cast
10
+
11
+ import plotly.express as px
12
+
13
+ import solara
14
+
15
+ df = px.data.iris()
16
+ columns = list(df.columns)
17
+
18
+
19
+ @dataclasses.dataclass
20
+ class ClickPoint:
21
+ row_index: int
22
+ x_column: str
23
+ y_column: str
24
+
25
+
26
+ def find_row_index(fig, click_data):
27
+ # goes from trace index and point index to row index in a dataframe
28
+ # requires passing df.index as to custom_data
29
+ trace_index = click_data["points"]["trace_indexes"][0]
30
+ point_index = click_data["points"]["point_indexes"][0]
31
+ trace = fig.data[trace_index]
32
+ return trace.customdata[point_index][0]
33
+
34
+
35
+ @solara.component
36
+ def ClickScatter(df, x, y, color, click_row, on_click: Callable[[ClickPoint], None]):
37
+ x, set_x = solara.use_state(x)
38
+ y, set_y = solara.use_state(y)
39
+ fig = px.scatter(df, x, y, color=color, custom_data=[df.index])
40
+
41
+ def on_click_trace(click_data):
42
+ # sanity checks
43
+ assert click_data["event_type"] == "plotly_click"
44
+ row_index = find_row_index(fig, click_data)
45
+ on_click(ClickPoint(row_index, x, y))
46
+
47
+ if click_row:
48
+ click_x = df[x].values[click_row]
49
+ click_y = df[y].values[click_row]
50
+ fig.add_trace(px.scatter(x=[click_x], y=[click_y], text=["⭐️"]).data[0])
51
+ # make the figure a bit smaller
52
+ fig.update_layout(width=400)
53
+ with solara.VBox() as main:
54
+ solara.FigurePlotly(fig, on_click=on_click_trace)
55
+ solara.Select(label="X-axis", value=x, values=columns, on_value=set_x)
56
+ solara.Select(label="Y-axis", value=y, values=columns, on_value=set_y)
57
+ return main
58
+
59
+
60
+ @solara.component
61
+ def Page():
62
+ click_point, set_click_point = solara.use_state(cast(ClickPoint, None))
63
+ if click_point:
64
+ clicked_row = click_point.row_index
65
+ else:
66
+ clicked_row = None
67
+
68
+ with solara.VBox() as main:
69
+ with solara.HBox():
70
+ ClickScatter(df, "sepal_length", "sepal_width", "species", clicked_row, on_click=set_click_point)
71
+ ClickScatter(df, "petal_length", "petal_width", "species", clicked_row, on_click=set_click_point)
72
+ if click_point is not None:
73
+ clicked_row = click_point.row_index
74
+ solara.Success(f"Clicked on row {clicked_row}. Which is highlighted in the both plots.")
75
+ solara.Markdown(
76
+ f"""
77
+ ```python
78
+ row_data = {df.iloc[clicked_row].to_dict()}
79
+ ```"""
80
+ )
81
+ else:
82
+ solara.Info("Click to select a point")
83
+
84
+ return main