diff --git a/_quarto.yml b/_quarto.yml index 5f13720b..4984ce79 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -11,6 +11,7 @@ project: - inputs - outputs - display-messages + - layouts - docs - in-depth - development @@ -46,12 +47,12 @@ website: open-graph: site-name: Shiny for Python locale: es_ES - image: images/shiny-for-python.jpg + image: https://shiny.posit.co/py/images/shiny-for-python.jpg description: Build interactive web applications easily with the power of Python’s data and scientific stack. twitter-card: title: "Shiny for Python" description: "Build interactive web applications easily with the power of Python’s data and scientific stack." - image: "images/shiny-for-python.jpg" + image: https://shiny.posit.co/py/images/shiny-for-python.jpg image-width: 1200 image-height: 630 card-style: "summary_large_image" @@ -74,6 +75,8 @@ website: - docs/shinylive.qmd - text: "Components" file: components/index.qmd + - text: "Layouts" + file: layouts/index.qmd - text: "Gallery" file: gallery/index.qmd - text: "Examples" diff --git a/layouts/_partials/components-list.css b/layouts/_partials/layouts-list.css similarity index 93% rename from layouts/_partials/components-list.css rename to layouts/_partials/layouts-list.css index 774f1807..7cd72e4f 100644 --- a/layouts/_partials/components-list.css +++ b/layouts/_partials/layouts-list.css @@ -11,14 +11,14 @@ body { background: linear-gradient(175deg, rgba(250, 250, 250, 1), rgba(248, 248, 248, 1), - rgba(193, 0, 0, .04), /* red */ - rgba(193, 0, 0, .05), /* red */ - rgba(191, 0, 127, .04), /* pink */ - rgba(191, 0, 127, .04), /* pink */ + rgba(75, 0, 193, .05), /* indigo */ + rgba(75, 0, 193, .05), /* indigo */ rgba(116, 20, 156, .04), /* purple */ rgba(116, 20, 156, .04), /* purple */ - rgba(75, 0, 193, .05), /* indigo */ - rgba(75, 0, 193, .05) /* indigo */ + rgba(191, 0, 127, .04), /* pink */ + rgba(191, 0, 127, .04), /* pink */ + rgba(193, 0, 0, .04), /* red */ + rgba(193, 0, 0, .05) /* red */ 100%); } diff --git a/layouts/_partials/layouts.css b/layouts/_partials/layouts.css index f4c25add..f87d5124 100644 --- a/layouts/_partials/layouts.css +++ b/layouts/_partials/layouts.css @@ -163,7 +163,7 @@ pre.console code { } /* Tab styling */ -/* + .panel-tabset .nav-tabs { display: flex !important; align-items: flex-end !important; @@ -213,7 +213,7 @@ a.nav-link:hover { .panel-tabset .nav-tabs .nav-link { padding: 0.35rem 1.25rem; margin-bottom: 0px; -}*/ +} .iframe-border { border: 1px solid #E9ECEF; diff --git a/layouts/_partials/layouts.lottie b/layouts/_partials/layouts.lottie new file mode 100644 index 00000000..17822bfd Binary files /dev/null and b/layouts/_partials/layouts.lottie differ diff --git a/layouts/arrange.qmd b/layouts/arrange.qmd new file mode 100644 index 00000000..2f619c3a --- /dev/null +++ b/layouts/arrange.qmd @@ -0,0 +1,345 @@ +--- +title: "Arrange Elements" +--- + +## Description + +Shiny's premade layouts, such as [`ui.page_sidebar()`](TODO ADD LINK) and [`ui.page_navbar()`](TODO ADD LINK) make use of Shiny's lower-level grid layout functions: + +* Rows are created by the `ui.row()` function and include columns. +* Columns are defined by the `ui.column()` function. Column widths are based on the [Bootstrap](https://getbootstrap.com/) 12-wide grid system, so column widths should add up to 12 within a row. + +You can use these functions directly to create your own layout. Grid layouts can be used within a page, panel, or card and can even be nested within each other. + +## Relevant functions + +- [ui.row](https://shiny.posit.co/py/api/ui.row.html) + `ui.row(*args, **kwargs)` + +- [ui.column](https://shiny.posit.co/py/api/ui.column.html) + `ui.column(width, *args, offset=0, **kwargs)` + +- [ui.page_fluid](https://shiny.posit.co/py/api/ui.page_fluid.html) + `ui.page_fluid(*args, title=None, lang=None, **kwargs)` + +- [ui.page_fixed](https://shiny.posit.co/py/api/ui.page_fixed.html) + `ui.page_fixed(*args, title=None, lang=None, **kwargs)` + +- [ui.page_fillable](https://shiny.posit.co/py/api/ui.page_fillable.html) + `ui.page_fillable(*args, padding=None, gap=None, fillable_mobile=False, title=None, lang=None, **kwargs)` + +## Grid Layouts + +To create a layout using the grid system, first build a grid by interlacing calls to [`ui.row()`](TODO ADD LINK) and [`ui.column()`](TODO ADD LINK). Then place UI elements within the grid by passing them to a `ui.row()` or `ui.column()` function. For example, the app below arranges three cards into a simple pattern. + + + +::: {.panel-tabset} + +## Preview + + +

Edit in Shinylive

+ + +## Code + +```{.python filename="app.py" } +from shiny import App, render, ui + +app_ui = ui.page_fluid( + ui.row( #<< + ui.column(12, ui.card("Card 1")) #<< + ), #<< + ui.row( #<< + ui.column(6, ui.card("Card 2")), #<< + ui.column(6, ui.card("Card 3")) #<< + ) #<< +) + +def server(input, output, session): + return None + +app = App(app_ui, server) +``` +

Edit in Shinylive

+::: + +Notice three things about the app: + +1. You always create rows before columns, and then embed columns within the rows. + +2. Rows are always as wide as the container they appear in, but columns take a width parameter. The width should be an integer from 1 to 12. Bootstrap uses the `width` to determine the width of the column relative to the row that contains it: + + - A column of `width=12` will span the entire row. + - A column of `width=6` will span half the row. + - A column of `width=3` will span a quarter of the row. + - And so on. + +3. You pass UI elements to `ui.row()` or `ui.column()` to place them in the grid. Here we pass `ui.card()`s to various parts of the grid. Each element is fitted to the column or row that it appears in. + +In addition to setting a column's width, you can also set its offset. This controls how many units of padding should appear to the left of the column. Once again the units should be an integer from 1 to 12. Here we use offsets to make a new arrangement: + + +::: {.panel-tabset} + +## Preview + + +

Edit in Shinylive

+ + +## Code + +```{.python filename="app.py" } +from shiny import App, render, ui + +app_ui = ui.page_fluid( + ui.row( + ui.column(4, ui.card("Chart 1")), + ui.column(4, ui.card("Chart 2"), offset=4) #<< + ), + ui.row( + ui.column(4, ui.card("Chart 3"), offset=4) #<< + ), + ui.row( + ui.column(4, ui.card("Chart 4")), + ui.column(4, ui.card("Chart 5"), offset=4) #<< + ) +) + +def server(input, output, session): + return None + +app = App(app_ui, server) +``` +

Edit in Shinylive

+::: + +## Column nesting + +When you nest rows and columns within a column, each nested level of column widths should add up to 12. This is because bootstrap divides every row into 12 units, no matter the actual width of the row. + +Consider this page layout: + +::: {.panel-tabset} + +## Preview + + +

Edit in Shinylive

+ + +## Code + +Each width is relative to the row that immediately contains it. To create this layout in a Shiny application you'd use the following code: + +```{.python filename="app.py" } +from shiny import App, render, ui + + app_ui = ui.page_fluid( + ui.row( + ui.column(12, + ui.card("Width 12", + ui.row( + ui.column(6, + ui.card("Width 6", + ui.row( + ui.column(6, ui.card("Width 6")), + ui.column(6, ui.card("Width 6")) + ) + ) + ), + ui.column(6, ui.card("Width 6")) + ) + ) + ) + ) + ) + + def server(input, output, session): + return None + + app = App(app_ui, server) +``` +

Edit in Shinylive

+::: + + +## Controlling for page width and height + +There are multiple types of Shiny grids: fluid, fixed, and fillable. The examples so far have used the fluid grid system exclusively and that's the system that's recommended for most applications (and the default for Shiny functions like `ui.page_navbar()` and `ui.page_sidebar()`). + +Each grid system uses a flexibly sub-dividable 12-column grid for layout. They differ in how they interact with the viewer's browser window: + +* The fluid system always occupies the full width of the web page and re-sizes it's components dynamically as the size of the page changes. + +* The fixed system occupies a fixed width of 940 pixels by default and may assume other widths when Bootstrap responsive layout kicks in (e.g. when on a tablet). + +* The fillable system always occupies the full width _and height_ of the web page and re-sizes it's components dynamically as the size of the page changes. + +### Fluid Grid System + + + +::: {.panel-tabset} + +## Preview + + +

Edit in Shinylive

+ + +## Code + +```{.python filename="app.py" } +import matplotlib.pyplot as plt +import numpy as np +from shiny import App, render, ui + +app_ui = ui.page_fluid( #<< + ui.layout_sidebar( + ui.panel_sidebar( + ui.input_slider("n", "N", 0, 100, 20), + ), + ui.panel_main( + ui.output_plot("histogram"), + ), + ), +) #<< + + +def server(input, output, session): + @output + @render.plot(alt="A histogram") + def histogram(): + np.random.seed(19680801) + x = 100 + 15 * np.random.randn(437) + plt.hist(x, input.n(), density=True) + + +app = App(app_ui, server, debug=True) +``` +

Edit in Shinylive

+::: + +To make a fluid grid that adapts to the width of the user's viewing window, build your app ui with [`ui.page_fluid()`](TODO ADD LINK). + +### Fixed Grid System + + + +::: {.panel-tabset} + +## Preview + + +

Edit in Shinylive

+ + +## Code + +```{.python filename="app.py" } +import matplotlib.pyplot as plt +import numpy as np +from shiny import App, render, ui + +app_ui = ui.page_fixed( #<< + ui.layout_sidebar( + ui.panel_sidebar( + ui.input_slider("n", "N", 0, 100, 20), + ), + ui.panel_main( + ui.output_plot("histogram"), + ), + ), +) #<< + + +def server(input, output, session): + @output + @render.plot(alt="A histogram") + def histogram(): + np.random.seed(19680801) + x = 100 + 15 * np.random.randn(437) + plt.hist(x, input.n(), density=True) + + +app = App(app_ui, server, debug=True) +``` +

Edit in Shinylive

+::: + +To make a fixed grid that maintains a constant maximum width, build your app ui with [`ui.page_fluid()`](TODO ADD LINK). + +The fixed grid system maintains a fixed page width of 940 pixels by default. If Bootstrap responsive features are enabled (they are by default in Shiny) then the grid will also adapt to be 724px or 1170px wide depending on your viewport (e.g. when on a tablet). The fixed system does this by using Bootstrap `.container`s, whereas the fluid system uses Bootstrap `.container-fluid`s. Learn more about the difference [here](https://getbootstrap.com/docs/5.3/layout/containers/#how-they-work). + +The main benefit of a fixed grid is that it provides stronger guarantees about how users will see the various elements of your UI laid out (this is because it's not being dynamically laid out according to the width of the browser). The main drawback is that it's a bit more complex to work with. In general we recommend using fluid grids unless you absolutely require the lower level layout control afforded by a fixed grid. + +### Fillable Grid System + + + +::: {.panel-tabset} + +## Preview + + +

Edit in Shinylive

+ + +## Code + +```{.python filename="app.py" } +import matplotlib.pyplot as plt +import numpy as np +from shiny import App, render, ui + +app_ui = ui.page_fillable( #<< + ui.layout_sidebar( + ui.panel_sidebar( + ui.input_slider("n", "N", 0, 100, 20), + ), + ui.panel_main( + ui.output_plot("histogram", height="100%"), #<< + ), + ), +) #<< + + +def server(input, output, session): + @output + @render.plot(alt="A histogram") + def histogram(): + np.random.seed(19680801) + x = 100 + 15 * np.random.randn(437) + plt.hist(x, input.n(), density=True) + + +app = App(app_ui, server, debug=True) +``` +

Edit in Shinylive

+::: + + + +To make a fixed grid that maintains a constant maximum width, build your app ui with [`ui.page_fillable()`](TODO ADD LINK). + +`ui.page_fluid()` and `ui.page_fixed()` are used for creating web pages that are laid out from the top down, leaving whitespace at the bottom if the page content's height is smaller than the browser window, and scrolling if the content is larger than the window. + +`ui.page_fillable()` is designed to latch the document body's size to the size of the window. This makes it possible to fill it with content that also scales to the size of the window. + +For example, `ui.page_fluid(ui.output_plot("plot", height = "100%"))` will not work as expected; the plot element's effective height will be 0, because the plot's containing elements (`
` and ``) have automatic height; that is, they determine their own height based on the height of their contained elements. However, `ui.page_fillable(ui.output_plot("plot", height = "100%"))` will work because fillPage fixes the `` height at 100% of the window height. + +Note that `ui.page_fillable(ui.output_plot("plot"))` may not cause the plot to fill the page. Like most Shiny output widgets, plotOutput's default height is a fixed number of pixels. You must explicitly set `height = "100%"` if you want a plot (or htmlwidget, say) to fill its container. + +One must be careful what layouts/panels/elements come between the `ui.page_fillable()` and the plots/widgets. Any container that has an automatic height will cause children with `height = "100%"` to misbehave. Stick to functions that are designed for fill layouts, such as the ones in the Shiny package. + + + diff --git a/layouts/arrange.qmd.Rmd b/layouts/arrange.qmd.Rmd deleted file mode 100644 index 11f40486..00000000 --- a/layouts/arrange.qmd.Rmd +++ /dev/null @@ -1,275 +0,0 @@ ---- -title: "Arrange Elements" ---- - -## Description - -Shiny's premade layouts, such as [`ui.page_sidebar()`](TODO ADD LINK) and [`ui.page_navbar()`](TODO ADD LINK) make use of Shiny's lower-level grid layout functions: - -* Rows are created by the `ui.row()` function and include columns. -* Columns are defined by the `ui.column()` function. Column widths are based on the [Bootstrap](https://getbootstrap.com/) 12-wide grid system, so column widths should add up to 12 within a row. - -You can use these functions directly to create your own layout. Grid layouts can be used within a page, panel, or card and can even be nested within each other. - -## Relevant functions - -- title: ui.row - href: https://shiny.posit.co/py/api/ui.row.html - signature: ui.row(*args, **kwargs) - -- title: ui.column - href: https://shiny.posit.co/py/api/ui.column.html - signature: ui.column(width, *args, offset=0, **kwargs) - -- title: ui.page_fluid - href: https://shiny.posit.co/py/api/ui.page_fluid.html - signature: ui.page_fluid(*args, title=None, lang=None, **kwargs) - -- title: ui.page_fixed - href: https://shiny.posit.co/py/api/ui.page_fixed.html - signature: ui.page_fixed(*args, title=None, lang=None, **kwargs) - -- title: ui.page_fillable - href: https://shiny.posit.co/py/api/ui.page_fillable.html - signature: ui.page_fillable(*args, padding=None, gap=None, fillable_mobile=False, title=None, lang=None, **kwargs) - -## Grid Layouts - -To create a layout using the grid system, first build a grid by interlacing calls to [`ui.row()`](TODO ADD LINK) and [`ui.column()`](TODO ADD LINK). Then place UI elements within the grid by passing them to a `ui.row()` or `ui.column()` function. For example, the app below arranges three cards into a simple pattern. - -- preview: https://shinylive.io/py/app/#h=0&code=NobwRAdghgtgpmAXGKAHVA6VBPMAaMAYwHsIAXOcpMAMwCdiYACAZwAsBLCbJjmVYnTJMAgujxM6lACZw6EgK4cAOhFVpUAfSVMAvEyVYoAcziaaAGyXSAFKqYGOGBgHc7EBw8MkrMCDYBGACYJRwxCKDpbZTAAYUjpJgCYgEoU+yYUvAzDV3dPMJ8FPxsANkUnCKi7OISmINSsjK9K4l9-csKEmviopgBmRoKHDPSIMdVZGlY5ADc5Gy5UBTIJYhXl1ZmWFg5SFMRmyTgyBToPJgA5UjhVdXQ9UXQbDW0OCRY5uRSwAF8AXSAA -- code: | - - from shiny import App, render, ui - - app_ui = ui.page_fluid( - ui.row( #<< - ui.column(12, ui.card("Card 1")) #<< - ), #<< - ui.row( #<< - ui.column(6, ui.card("Card 2")), #<< - ui.column(6, ui.card("Card 3")) #<< - ) #<< - ) - - def server(input, output, session): - return None - - app = App(app_ui, server) - -Notice three things about the app: - -1. You always create rows before columns, and then embed columns within the rows. - -2. Rows are always as wide as the container they appear in, but columns take a width parameter. The width should be an integer from 1 to 12. Bootstrap uses the `width` to determine the width of the column relative to the row that contains it: - - - A column of `width=12` will span the entire row. - - A column of `width=6` will span half the row. - - A column of `width=3` will span a quarter of the row. - - And so on. - -3. You pass UI elements to `ui.row()` or `ui.column()` to place them in the grid. Here we pass `ui.card()`s to various parts of the grid. Each element is fitted to the column or row that it appears in. - -In addition to setting a column's width, you can also set its offset. This controls how many units of padding should appear to the left of the column. Once again the units should be an integer from 1 to 12. Here we use offsets to make a new arrangement: - -- preview: https://shinylive.io/py/app/#h=0&code=NobwRAdghgtgpmAXGKAHVA6VBPMAaMAYwHsIAXOcpMAMwCdiYACAZwAsBLCbJjmVYnTJMAgujxM6lACZw6EgK4cAOhFVpUAfSVMAvEyVYoAcziaaHAB5xpAClVMDHDAwDu9iI8eGSAGwUwELYALIrOhFB0dspgAMJskcIAjDEAlKl4Dl4+xP6BIWEYEVH2cQlCTABMaRLENDQscGS6walZGVmGbh5eTkW5AUGhfcXRZYlMAMw1THUNTS1tnkwdy13E7lne4QP5wz6RY-ETwWmrvTl5Q4WjpccVAKwzc43Nre2qS6qyNKxyAG5yWxcVAKMi1MGg8F-FgsDikVKILaSJoKOjLABypDgqnU6D0onQtg02g4EkadEBdFSYAAvgBdIA -- code: | - - from shiny import App, render, ui - - app_ui = ui.page_fluid( - ui.row( - ui.column(4, ui.card("Chart 1")), - ui.column(4, ui.card("Chart 2"), offset=4) #<< - ), - ui.row( - ui.column(4, ui.card("Chart 3"), offset=4) #<< - ), - ui.row( - ui.column(4, ui.card("Chart 4")), - ui.column(4, ui.card("Chart 5"), offset=4) #<< - ) - ) - - def server(input, output, session): - return None - - app = App(app_ui, server) - - -## Column nesting - -When you nest rows and columns within a column, each nested level of column widths should add up to 12. This is because bootstrap divides every row into 12 units, no matter the actual width of the row. - -Consider this page layout: - -- preview: https://shinylive.io/py/app/#h=0&code=NobwRAdghgtgpmAXGKAHVA6VBPMAaMAYwHsIAXOcpMAMwCdiYACAZwAsBLCbJjmVYnTJMAgujxM6lACZw6EgK4cAOhFVpUAfSVMAvEyVYoAcziaaAGyXSAFKqYODHDAwDudiI69OMJKzAgbAEYAJgl7b0jDQig6W2UwAHUOaTI2JlCEvAjI3J83Dzyix2jif0CANmzPYtqHaNj4pJS0pgqsnLquwwLOrv6fPwUAmyrBxrtm1PT2sABKOeqB5cGy4crFZxi4yeTptoSFvpXIueOTs5qLpZPV8tHN3wmEvdbZo6uuy7rv3N+HS6XVSyGisOQANzkNi4qAUZAkxDhsPhYJYLA4pDmiE6UjICjoNQAcqQ4Kp1Og9KJ0DYNNoOBIWBC5JcwABfAC6QA - -Each width is relative to the row that immediately contains it. To create this layout in a Shiny application you'd use the following code: - -- code: | - - from shiny import App, render, ui - - app_ui = ui.page_fluid( - ui.row( - ui.column(12, - ui.card("Width 12", - ui.row( - ui.column(6, - ui.card("Width 6", - ui.row( - ui.column(6, ui.card("Width 6")), - ui.column(6, ui.card("Width 6")) - ) - ) - ), - ui.column(6, ui.card("Width 6")) - ) - ) - ) - ) - ) - - def server(input, output, session): - return None - - app = App(app_ui, server) - -## Controlling for page width and height - -There are multiple types of Shiny grids: fluid, fixed, and fillable. The examples so far have used the fluid grid system exclusively and that's the system that's recommended for most applications (and the default for Shiny functions like `ui.page_navbar()` and `ui.page_sidebar()`). - -Each grid system uses a flexibly sub-dividable 12-column grid for layout. They differ in how they interact with the viewer's browser window: - -* The fluid system always occupies the full width of the web page and re-sizes it's components dynamically as the size of the page changes. - -* The fixed system occupies a fixed width of 940 pixels by default and may assume other widths when Bootstrap responsive layout kicks in (e.g. when on a tablet). - -* The fillable system always occupies the full width _and height_ of the web page and re-sizes it's components dynamically as the size of the page changes. - -### Fluid Grid System - -- preview: https://shinylive.io/py/app/#h=0&code=NobwRAdghgtgpmAXGKAHVA6VBPMAaMAYwHsIAXOcpMASxlWICcyACGKM1AG2LK5oBGWbN14soAZxbcyAHQh0GzFhACu9bOKkRU8gGaNiMFhIAWNCJsVNWAQXR4WjSgBM4jR6prz5aVAH0vFgBeFi8sKABzOH89Li8XAAp5FlSwmgwuKGxiVTJ-CRo3AShGZIg0yvSIiDguAqK4ErKUqrbwi1Q8gv43FshZfBZBgDlBxwAGRwBGCamWACYJgEo8VrbV9arw1Cha+vYLcrb2jNzObtEyZLBzCTJiSMZYQc2Kk7fKt+WfCHk3PQmdwAN3ciU6eUc5y6ZEcEjgEkKpGWiC2AAFoXl0c4IH0sDxrlAuGRgoNbCw7g8ni8wD93qkARSaPdHs8YIkUVtKjoMM9cUYMPC4ElpgBOABsAA4JtLpnSTiwAB4hFizCYsADUqoArCwAFQqTB8lwC40QRIAFgAzAB2eUnGQYSmJRWOCFkDDm1YsNwQQpkbDBAAqjFUcDpvz8KvsqESfkCNDhIPcjmKqkiwdD4fkYAAvgBdIA -- code: | - - import matplotlib.pyplot as plt - import numpy as np - from shiny import App, render, ui - - app_ui = ui.page_fluid( #<< - ui.layout_sidebar( - ui.panel_sidebar( - ui.input_slider("n", "N", 0, 100, 20), - ), - ui.panel_main( - ui.output_plot("histogram"), - ), - ), - ) #<< - - - def server(input, output, session): - @output - @render.plot(alt="A histogram") - def histogram(): - np.random.seed(19680801) - x = 100 + 15 * np.random.randn(437) - plt.hist(x, input.n(), density=True) - - - app = App(app_ui, server, debug=True) - - --details: To make a fluid grid that adapts to the width of the user's viewing window, build your app ui with [`ui.page_fluid()`](TODO ADD LINK). - -### Fixed Grid System - -- preview: https://shinylive.io/py/app/#h=0&code=NobwRAdghgtgpmAXGKAHVA6VBPMAaMAYwHsIAXOcpMASxlWICcyACGKM1AG2LK5oBGWbN14soAZxbcyAHQh0GzFhACu9bOKkRU8gGaNiMFhIAWNCJsVNWAQXR4WjSgBM4jR6prz5aVAH0vFgBeFi8sKABzOH89GgAPOBcACnkWdLCaDC4obGJVMn8JGjcBKEZUiAzqzIiIOC4ikrgyirSajvCLVAKi-jc2yFl8FmGAOWHHAAZHAEYpmZYAJimASjx2jvXNmvDUKHrG9gtKjs6s-M5e0TJUsHMJMmJIxlhh7aqzj+qP1Z8IeRuPQmdwAN3cyW6BUclx6ZEcEjgEmKpFWiB2AAFYQVMc4IAMsDxblAuGRgsNbCwHk8Xm8wH9PukgVSaI9nq8YMk0TtqjoMK98UYMIikslZgBOABsAA4prLZgyzix4iEWPMpiwANRqgCsLAAVCpMAKXEKTRBkgAWADMAHZFWcZBhqcl4o4oWQMBb1iw3BBimRsMEACqMVRwBn-Pyq+yoZJ+QI0BFg9yOUqqSIhsMR+RgAC+AF0gA -- code: | - - import matplotlib.pyplot as plt - import numpy as np - from shiny import App, render, ui - - app_ui = ui.page_fixed( #<< - ui.layout_sidebar( - ui.panel_sidebar( - ui.input_slider("n", "N", 0, 100, 20), - ), - ui.panel_main( - ui.output_plot("histogram"), - ), - ), - ) #<< - - - def server(input, output, session): - @output - @render.plot(alt="A histogram") - def histogram(): - np.random.seed(19680801) - x = 100 + 15 * np.random.randn(437) - plt.hist(x, input.n(), density=True) - - - app = App(app_ui, server, debug=True) - - --details: | - - To make a fixed grid that maintains a constant maximum width, build your app ui with [`ui.page_fluid()`](TODO ADD LINK). - - The fixed grid system maintains a fixed page width of 940 pixels by default. If Bootstrap responsive features are enabled (they are by default in Shiny) then the grid will also adapt to be 724px or 1170px wide depending on your viewport (e.g. when on a tablet). The fixed system does this by using Bootstrap `.container`s, whereas the fluid system uses Bootstrap `.container-fluid`s. Learn more about the difference [here](https://getbootstrap.com/docs/5.3/layout/containers/#how-they-work). - - The main benefit of a fixed grid is that it provides stronger guarantees about how users will see the various elements of your UI laid out (this is because it's not being dynamically laid out according to the width of the browser). The main drawback is that it's a bit more complex to work with. In general we recommend using fluid grids unless you absolutely require the lower level layout control afforded by a fixed grid. - -### Fillable Grid System - -- preview: https://shinylive.io/py/app/#h=0&code=NobwRAdghgtgpmAXGKAHVA6VBPMAaMAYwHsIAXOcpMASxlWICcyACGKM1AG2LK5oBGWbN14soAZxbcyAHQh0GzFhACu9bOKkRU8gGaNiMFhIAWNCJsVNWAQXR4WjSgBM4jR6prz5aVAH0vFgBeFi8sKABzOH89Gi4uKAEuOAAKeRZMsJoMROxiVTJ-CRo3AShGdIgsmuyIiDguYtK4csqM2s7wi1RC4v43dshZfBYRgDkRxwAGRwBGadmWACZpgEo8Ds6Nrdrw1CgGpvYLKs6unILOPtEydLBzCTJiSMZYEZ3q88+az7WfCDyNx6EzuABu7lSPUKjiuvTIjgkcAkJVIa0QuwAAnDCljnBBBlgeHcoFwyMERrYWI9nq93mB-l9MsDqTQni83jBUujdjUdBg3gSjBgkXAXKk5gBOABsAA5pvK5ozziwAB4hFgLaYsADUmoArCwAFQqTCClzC80QVIAFgAzAB2ZXnGQYGmpVWOaFkDDWjYsNwQEpkbDBAAqjFUcEZAL8GvsqFSfkCNER4PcjjKqki4cj0fkYAAvgBdIA -- code: | - - import matplotlib.pyplot as plt - import numpy as np - from shiny import App, render, ui - - app_ui = ui.page_fillable( #<< - ui.layout_sidebar( - ui.panel_sidebar( - ui.input_slider("n", "N", 0, 100, 20), - ), - ui.panel_main( - ui.output_plot("histogram", height="100%"), #<< - ), - ), - ) #<< - - - def server(input, output, session): - @output - @render.plot(alt="A histogram") - def histogram(): - np.random.seed(19680801) - x = 100 + 15 * np.random.randn(437) - plt.hist(x, input.n(), density=True) - - - app = App(app_ui, server, debug=True) - - --details: | - - To make a fixed grid that maintains a constant maximum width, build your app ui with [`ui.page_fillable()`](TODO ADD LINK). - - `ui.page_fluid()` and `ui.page_fixed()` are used for creating web pages that are laid out from the top down, leaving whitespace at the bottom if the page content's height is smaller than the browser window, and scrolling if the content is larger than the window. - - `ui.page_fillable()` is designed to latch the document body's size to the size of the window. This makes it possible to fill it with content that also scales to the size of the window. - - For example, `ui.page_fluid(ui.output_plot("plot", height = "100%"))` will not work as expected; the plot element's effective height will be 0, because the plot's containing elements (`
` and ``) have automatic height; that is, they determine their own height based on the height of their contained elements. However, `ui.page_fillable(ui.output_plot("plot", height = "100%"))` will work because fillPage fixes the `` height at 100% of the window height. - - Note that `ui.page_fillable(ui.output_plot("plot"))` may not cause the plot to fill the page. Like most Shiny output widgets, plotOutput's default height is a fixed number of pixels. You must explicitly set `height = "100%"` if you want a plot (or htmlwidget, say) to fill its container. - - One must be careful what layouts/panels/elements come between the `ui.page_fillable()` and the plots/widgets. Any container that has an automatic height will cause children with `height = "100%"` to misbehave. Stick to functions that are designed for fill layouts, such as the ones in the Shiny package. - - - diff --git a/layouts/index.qmd b/layouts/index.qmd index 212a857f..41458882 100644 --- a/layouts/index.qmd +++ b/layouts/index.qmd @@ -2,16 +2,16 @@ pagetitle: "Shiny Layouts" anchor-sections: false sidebar: false -pagedescription: Frameworks that will allow the simplest and most complicated app to be useable and scalable. Is it bursting at the seams with content? Quickly change your layout to give your app a fresh start. +pagedescription: Frameworks that will allow the simplest and most complicated app to be useable and scalable. Is it bursting at the seams with content? Quickly change the layout for a fresh start. toc: false page-layout: article resources: - - components/_partials/animation.lottie + - _partials/layouts.lottie format: html: css: - _partials/layouts.css - - components/_partials/components-list.css + - _partials/layouts-list.css code-overflow: wrap --- @@ -22,13 +22,13 @@ format: Shiny Layouts ::: -##### Layouts allow the simplest or most complicated app to be useable and scalable. Is it bursting at the seams with content? Quickly change your layout to give your app a fresh start. Fill these layouts with [Shiny Components](https://shiny.posit.co/py/docs/ui-page-layouts.html) to make your app reactive and interactive. +##### Layouts allow the simplest or most complicated app to be useable and scalable. Is it bursting at the seams with content? Quickly change the layout for a fresh start. Fill these layouts with [Shiny Components](https://shiny.posit.co/py/docs/ui-page-layouts.html) to make your app reactive and interactive. :::: :::: {.g-col-md-5 .g-col-10 .g-start-4 .components-hero-img-container}
- +
:::: @@ -60,6 +60,10 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i justify-content: space-evenly; overflow: hidden; } + .container-fluid { + padding-right: 0px; + padding-left: 0px; + } /*.layout-list-card .nav-link { padding: 0.5rem 0.75rem; color: white; @@ -80,22 +84,34 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i

-
+
+ +```{shinylive-python} +#| standalone: true + +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.navset_tab_card( + # left hand side ---- + ui.nav("c", "tab c content"), + ui.nav_control( + ui.a("RStudio", href="https://rstudio.com", target="_blank") + ), + + # create gap ---- + ui.nav_spacer(), + + # right hand side ---- + ui.nav_control( + ui.a("Python", href="https://python.org", target="_blank") + ), + ), +) + +app = App(app_ui, None) - +```
@@ -116,20 +132,20 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i
- +```{shinylive-python} +#| standalone: true + +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.navset_pill( + ui.nav("a", "tab a content"), + ui.nav("b", "tab b content"), + ) +) + +app = App(app_ui, None) +```
@@ -148,20 +164,20 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i
- +```{shinylive-python} +#| standalone: true +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.navset_tab( + ui.nav("a", "tab a content"), + ui.nav("b", "tab b content"), + ) +) + +app = App(app_ui, None) + +```
@@ -189,6 +205,123 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i :::: :::: {.g-col-xl-9 .g-col-12 .pt-3 .pt-xl-5 .ps-0 .ps-xl-5 .ms-0 .ms-xl-4} ::: {#sidebar .grid} + + + +
+
+ +
Sidebar on the Left
+
+
+

+ +

+
+
+
+ +```{shinylive-python} +#| standalone: true + +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.layout_sidebar( #<< + ui.sidebar("Sidebar"), #<< + "Main content" + ), #<< +) + +def server(input, output, session): + pass + +app = App(app_ui, server) + +``` + +
+
+ + + +
+
+ +
Sidebar on the Right
+
+
+

+ +

+
+
+
+ + +```{shinylive-python} +#| standalone: true + +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.layout_sidebar( #<< + ui.sidebar("Sidebar", position="right"), #<< + "Main content" + ), #<< +) + +def server(input, output, session): + pass + +app = App(app_ui, server) +``` + +
+
+ + +
+
+ +
Sidebars: Left & Right
+
+
+

+ +

+
+
+
+ +```{shinylive-python} +#| standalone: true +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.layout_sidebar( #<< + ui.sidebar("Left sidebar"), #<< + ui.layout_sidebar( #<< + ui.sidebar("Right sidebar", position="right"), #<< + "Main content", + border=False #<< + ), #<< + padding=0 #<< + ), #<< +) + +def server(input, output, session): + pass + +app = App(app_ui, server) + +``` + +
+
+ + + ::: :::: @@ -206,6 +339,147 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i :::: :::: {.g-col-xl-9 .g-col-12 .pt-3 .pt-xl-5 .ps-0 .ps-xl-5 .ms-0 .ms-xl-4} ::: {#tab .grid} + + + +
+
+ +
Tabset with Pill
+
+
+

+ +

+
+
+
+ +```{shinylive-python} +#| standalone: true + +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.navset_pill( + ui.nav("A", "Page A content"), + ui.nav("B", "Page B content"), + ui.nav("C", "Page C content"), + ui.nav_menu( + "Other links", + ui.nav("D", "Page D content"), + "----", + "Description:", + ui.nav_control( + ui.a("Weblink", href="URL", target="_blank") + ), + ), + id = "tab" + ) +) + +def server(input, output, session): + pass + +app = App(app_ui, server) +``` + +
+
+ + + +
+
+ +
Tabset with Pill List Nav
+
+
+

+ +

+
+
+
+ + +```{shinylive-python} +#| standalone: true + +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.navset_pill_list( + ui.nav("A", "Page A content"), + ui.nav("B", "Page B content"), + ui.nav("C", "Page C content"), + ui.nav_menu( + "Other links", + ui.nav("D", "Page D content"), + "----", + "Description:", + ui.nav_control( + ui.a("Weblink", href="URL", target="_blank") + ), + ), + id = "tab" + ) +) + +def server(input, output, session): + pass + +app = App(app_ui, server) +``` + +
+
+ + +
+
+ +
Tabset with Tab Nav
+
+
+

+ +

+
+
+
+ +```{shinylive-python} +#| standalone: true +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.navset_tab( + ui.nav("A", "Page A content"), + ui.nav("B", "Page B content"), + ui.nav("C", "Page C content"), + ui.nav_menu( + "Other links", + ui.nav("D", "Page D content"), + "----", + "Description:", + ui.nav_control( + ui.a("Weblink", href="URL", target="_blank") + ), + ), + id = "tab" + ) +) + +def server(input, output, session): + pass + +app = App(app_ui, server) +``` + +
+
+ ::: :::: @@ -224,6 +498,120 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i :::: :::: {.g-col-xl-9 .g-col-12 .pt-3 .pt-xl-5 .ps-0 .ps-xl-5 .ms-0 .ms-xl-4} ::: {#panel .grid} + + + +
+
+ +
Navbar with Links
+
+
+

+ +

+
+
+
+ +```{shinylive-python} +#| standalone: true + +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.page_navbar( + # left hand side ---- + ui.nav("c", "tab c content"), + ui.nav_control( + ui.a("RStudio", href="https://rstudio.com", target="_blank") + ), + + # create gap ---- + ui.nav_spacer(), + + # right hand side ---- + ui.nav_control( + ui.a("Python", href="https://python.org", target="_blank") + ), + ), +) + +app = App(app_ui, None) + +``` + +
+
+ + + +
+
+ +
Navbar with Pills
+
+
+

+ +

+
+
+
+ + +```{shinylive-python} +#| standalone: true + +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.navset_pill( + ui.nav("a", "tab a content"), + ui.nav("b", "tab b content"), + ) +) + +app = App(app_ui, None) +``` + +
+
+ + +
+
+ +
Navbar with Tabs
+
+
+

+ +

+
+
+
+ +```{shinylive-python} +#| standalone: true +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.navset_tab( + ui.nav("a", "tab a content"), + ui.nav("b", "tab b content"), + ) +) + +app = App(app_ui, None) + +``` + +
+
+ + + ::: ::::