{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "This page explains the multiple layouts components and all the options to control the layout of the dashboard.\n", "\n", "There are 4 main components in a jupyter-flex dashboard in this hierarchy: \n", "\n", "1. Pages\n", "2. Sections\n", "3. Cards\n", "4. Cells\n", "\n", "Meaning that Pages contain one or more Sections, Sections contains one or multiple Cards and Cards contain one or multiple Cells.\n", "\n", "Cells are pretty self explanatory as they are the same as in Jupyter, they can be Markdown or Code cells and can contain one output (text or images)." ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "## Cards\n", "\n", "A Card is an object that holds one or more Cells, these can be markdown cells or code cells that have outputs such as plots, text, widgets and more. \n", "\n", "To define a new Card you use a level-3 markdown header (`###`). Each card belongs in a Section and one Section can have one or more Cards.\n", "\n", "Any tagged Cell will be added to the current Card until a new Card, Section or Page is defined.\n", "\n", "The components of a Card are:\n", "\n", "1. Title: Based on the value of level-3 markdown header (`###`) used to define it\n", "2. One (or more) code cells tagged with `body` that contain outputs\n", "3. One (or more) markdown cells tagged with `body` that contain some narrative for the dashboard\n", "4. Footer: one or more markdown or code cells tagged with `footer`\n", "5. Info dialog: one or more markdown or code cells tagged with `info`\n", "\n", "For example take this notebook with one Card, two plots and some text. Note that code cells get expanded to ocupy all the space in the Card while markdown cells get just use the space they need to display its content." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Card header" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# This is a markdown cell, **all** *regular* syntax ~~should~~ work." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# This is another markdown cell. Any output from a code cell will have priority and be expanded." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "import altair as alt\n", "from vega_datasets import data" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "source" ] }, "outputs": [], "source": [ "alt.renderers.set_embed_options(actions=False)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "source" ] }, "outputs": [], "source": [ "source = data.cars()\n", "\n", "plot = alt.Chart(source).mark_circle(size=60).encode(\n", " x='Horsepower',\n", " y='Miles_per_Gallon',\n", " color='Origin',\n", " tooltip=['Name', 'Origin', 'Horsepower', 'Miles_per_Gallon']\n", ")\n", "plot" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "plot.properties(\n", " width='container',\n", " height='container'\n", ")" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "body" ] }, "source": [ "This is more markdown below the main content" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "body" ] }, "source": [ "Click on the help button in the corner to open the help modal." ] }, { "cell_type": "markdown", "metadata": { "tags": [ "footer" ] }, "source": [ "This is a MD cell on the footer, we can use [regular md](https://google.com) an even show code, for example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "footer" ] }, "outputs": [], "source": [ "\"Altair version: \" + alt.__version__" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "help" ] }, "source": [ "This is the help modal, the title above ^^ is the same card header and this is just a regular markdown cell." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "help" ] }, "outputs": [], "source": [ "\"This is code output\"" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "help" ] }, "source": [ "You can have also have plots here" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "help" ] }, "outputs": [], "source": [ "plot" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[![](/assets/img/screenshots/jupyter_flex.tests.test_examples/plots_card-complete-reference.png)](/examples/card-complete.html)\n", "\n", "

Click on the image to open dashboard

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sections\n", "\n", "A Section is an object that holds one or more Cards, those Cards can be arrangend as rows (default) or columns inside the Section.\n", "\n", "To define a new Section you use a level-2 markdown header (`##`). Each Section belongs in a Page and one Page can have one or more Sections.\n", "The default orientation of Sections in a Page is to show each section as a column.\n", "\n", "For example take this Notebook with two Sections, the first with one Card and the second one with two:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Column 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Column 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Column 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Column 2 - Row 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Column 2 - Row 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[![](/assets/img/screenshots/jupyter_flex.tests.test_layouts/layouts_section-columns-rows-reference.png \"Section Columns\")](/examples/section-columns-rows.html)\n", "\n", "

Click on the image to open dashboard

\n", "\n", "### Orientation\n", "\n", "The default orientation for Sections is `columns` and for Cards is `rows`. This means that each Section will be shown as one column in a Page and each Card in a Section will be shown as a row.\n", "\n", "Each Section default parameters can be overwritten by adding tags to the Section markdown cell (the one with a level-2 header: `##`).\n", "\n", "For example in the last Notebook to make the second Section (right column) to also be divided by colums, instead of the defualt of rows, we add an `orientation=columns` tag like this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "orientation=columns" ] }, "outputs": [], "source": [ "## Column 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[![](/assets/img/screenshots/jupyter_flex.tests.test_layouts/layouts_section-columns-columns-reference.png)](/examples/section-columns-columns.html)\n", "\n", "

Click on the image to open dashboard

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To change the orientation of Sections in a Page use the global `flex_orientation` parameter.\n", "\n", "The default is to use the oposite orientation between Sections and Cards as follows:\n", "- If dashboard `flex_orientation` is `columns` (default), then section orientation will default to `rows`\n", "- If dashboard `flex_orientation` is `rows`, then section orientation well default to `columns`\n", "\n", "To set the global parameters you tag one code Cell in the Notebook with `parameters`.\n", "\n", "
\n", "

The parameters tag

\n", "
    \n", "
  1. It's usually a good idea to have this cell at the begining of the notebook
  2. \n", "
  3. This is the same tag used by papermill so you can use it as part of a pipeline
  4. \n", "
\n", "
\n", "\n", "For example adding the following cell as the first cell of the Notebook we had before:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "parameters" ] }, "outputs": [], "source": [ "flex_orientation = \"rows\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[![](/assets/img/screenshots/jupyter_flex.tests.test_layouts/layouts_section-rows-columns-reference.png)](/examples/section-rows-columns.html)\n", "\n", "

Click on the image to open dashboard

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Size: Width and Height\n", "\n", "You might have noticed that by default all the Cards and Section space is divided equally. If there are 2 Cards in a Section each Card will get 50% of the space, if there are 3 Cards in one Section each will get 33.3% of the space and so on and the same applies for multiple Sections in one Page.\n", "\n", "These proportions can be controlled using the `size={value}` tag in Sections and Cards cells.\n", "\n", "For example take this notebook that focuses most of the dashboard space on the top Section with one Card." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "parameters" ] }, "outputs": [], "source": [ "flex_orientation = \"rows\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "size=8" ] }, "outputs": [], "source": [ "## Row 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Row 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "size=4" ] }, "outputs": [], "source": [ "## Row 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Row 2 - Card 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Row 2 - Card 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[![](/assets/img/screenshots/jupyter_flex.tests.test_layouts/layouts_focal-chart-top-reference.png)](/examples/focal-chart-top.html)\n", "\n", "
\n", "

What does the value of size mean?

\n", "

Interally juptyer-flex uses Material UI and it heavily uses the Grid component.\n", "

The size tag is passed directly to the `xs` property of the Grid items.

\n", "

These items size should add up to 12

\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Card size\n", "\n", "In the same way that you can control Section proportions in a Page, you can control the Card proportions inside a Section using the `size` parameter as a tag in the Card header (level-3 markdown header: `###`).\n", "\n", "In the last example if we change these two cells:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "size=9" ] }, "outputs": [], "source": [ "### Row 2 - Card 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "size=3" ] }, "outputs": [], "source": [ "### Row 2 - Card 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[![](/assets/img/screenshots/jupyter_flex.tests.test_layouts/layouts_focal-chart-top-card-size-reference.png)](/examples/focal-chart-top-card-size.html)\n", "\n", "

Click on the image to open dashboard

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Section Tabs\n", "\n", "You can make a Section display all it's Cards as tabs making each Card it's own tab. This allows more screen space for each Card. Tabs are especially useful when you have a large number of components to display.\n", "\n", "To do this just tag a Section with `tabs` (the one with the level-2 markdown header: `##`).\n", "\n", "For example this notebook:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "tabs" ] }, "outputs": [], "source": [ "## Column 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Tab 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Tab 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Column 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Regular Column" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "tabs", "no-nav-fill", "no-fade" ] }, "outputs": [], "source": [ "## Column 3" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Tab A" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "\"A\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Tab B" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "\"B\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Tab C" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "\"C\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[![](/assets/img/screenshots/jupyter_flex.tests.test_layouts/layouts_section-tabs-columns-reference.png \"Section tabs columns\")](/examples/section-tabs-columns.html)\n", "\n", "

Click on the image to open dashboard

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Pages\n", "\n", "For bigger dashboards with a lot components you can divide the dashboard into multiple pages using level-1 markdown headers (`#`).\n", "\n", "A Page is an object that holds one or more Sections, those Sections can be shown as columns (default) or rows inside the Page.\n", "\n", "If a dashboard has one or more Pages the top navigation of the dashboard will include links to change between those.\n", "\n", "Page parameters, such as orientation and size, can be overwritten by tagging the level-1 (`#`) markdown header cell.\n", "\n", "Take this example Notebook with 2 Pages and multiple sections (including tabs):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Page 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Column 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Column 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "\"page 1 - col 1\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "tabs" ] }, "outputs": [], "source": [ "## Column 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Column 2 - Card 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "\"page 1 - col 2 - card 1\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Column 2 - Card 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "\"page 1 - col 2 - card 2\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "orientation=rows" ] }, "outputs": [], "source": [ "# Page 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Row 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Row 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "\"page 2 - row 1\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "tabs" ] }, "outputs": [], "source": [ "## Row 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Card 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "\"page 2 - row 2 - card 1\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Card 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "\"page 2 - row 2 - card 2\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[![](/assets/img/screenshots/jupyter_flex.tests.test_layouts/layouts_pages-reference.png)](/examples/pages.html)\n", "\n", "

Click on the image to open dashboard

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sidebars\n", "\n", "Sidebars are one special type of Section or Page. They behave in the same way as regular Section, they can contain one or more Cards that will be shown in the Sidebar of the dashboard.\n", "\n", "If you tag a Page with `sidebar` it will be a global Sidebar, meaning that all pages will have the same sidebar.\n", "\n", "If you tag a Section with `sidebar` then it will only appear for the page that contains that Section.\n", "\n", "This is mostly useful when defining inputs and using Jupyter widgets, see [Voila and Widgets](/voila-widgets) but it can also be used to display other type of information.\n", "\n", "This example uses a global sidebar by tagging the first page with `sidebar`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "sidebar" ] }, "outputs": [], "source": [ "# Sidebar" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Sidebar" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "\"\"\"\n", "The sidebar is the sidebar of the dashboard.\n", "\n", "It will always be there even after switching pages.\n", "\n", "This content is a regular Card, for example *this* **is** [markdown](https://daringfireball.net/projects/markdown/).\n", "\"\"\"\n", "\"\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### This is a second card" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# Since we have two cards in the sidebar the content was split equaly as it happens in Sections by default but it can be controlled by the `size` tag." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# This is a code cell output on the side bar" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Page 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Col 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### This is the first page" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Col 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Column 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "orientation=rows" ] }, "outputs": [], "source": [ "# Page 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Row 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### This is the second page" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Row 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Row 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "body" ] }, "outputs": [], "source": [ "# " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[![](/assets/img/screenshots/jupyter_flex.tests.test_layouts/layouts_sidebar-global-reference.png)](/examples/sidebar-global.html)\n", "\n", "

Click on the image to open dashboard

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Section sidebar\n", "\n", "If you want a sidebar that is only available to one of the Pages, tag a Section with `sidebar`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[![](/assets/img/screenshots/jupyter_flex.tests.test_layouts/layouts_sidebar-pages-reference.png)](/examples/sidebar-pages.html)\n", "\n", "

Click on the image to open dashboard

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vertical Layouts: Scroll\n", "\n", "By default Jupyter-flex components are laid out to fill the height of the browser. So that multiple components (Sections, Cards) get expanded to the available space and there is no vertical scroll in the body.\n", "\n", "This is a good default that works well for a small to medium number of components, however if you have lots of charts you’ll probably want to scroll rather than fit them all onto the page.\n", "\n", "You can control this behavior globally using the `flex_vertical_layout` option which has a default value of `fill`, change it to `scroll` to layout charts at their natural height, scrolling the page if necessary." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "parameters" ] }, "outputs": [], "source": [ "flex_vertical_layout = \"scroll\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This can also be set for each page using the `layout=scroll` tag.\n", "\n", "[![](/assets/img/screenshots/jupyter_flex.tests.test_layouts/layouts_pages-diff-layouts-reference.png)](/examples/pages-diff-layouts.html)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Examples\n", "\n", "" ] } ], "metadata": { "celltoolbar": "Tags", "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.12" } }, "nbformat": 4, "nbformat_minor": 4 }