Layouts
Create layouts programmatically and use them in your Python notebooks.
What is a layout?
A layout in Foxglove is a data visualization environment configured to support a particular robot or simulation. Layouts include an arrangement of panels, their configurations, and any global variables or user scripts necessary to visualize your data.
Layouts use JSON configuration under the hood. Generally, you would create and configure layouts using the app. To create a layout programmatically, use the Layout class in the foxglove-sdk package.
from foxglove.layouts import *
# Create a layout with a single Markdown panel and a global variable
layout = Layout(
content=MarkdownPanel(
config=MarkdownConfig(markdown="Hello, world!"),
),
variables={
"my_variable": 1,
}
)
The content of a layout can be any panel or panel container.
Panel containers
Layouts typically include multiple panels. There are three containers for arranging panels in a layout:
- Splits arrange children side-by-side in a row or column
- Tabs arrange children in tabs, with one child visible at a time
- Stacks arrange children in a vertically-scrolling list
Split container
A SplitContainer arranges its children in a row or column based on its direction parameter. The children are represented as a list of SplitItem objects, each of which has a proportion and a content.
The space each split item takes up is determined by dividing an item's proportion by the sum of all proportions of all items in the container. For example, if a Split had three children whose proportion values were 4, 6, and 10, then the children would take up 20%, 30%, and 50% of the space, respectively.
When creating a SplitItem, the proportion defaults to 1 if not specified. This will evenly distribute the space between all items if none of the proportions are specified.
Layouts can get complex quickly. If they become deeply-nested, consider extracting sub-sections into named variables and then combining them into a single layout.
from foxglove.layouts import *
# Create a row of panels where the width is evenly distributed between the two panels
split = SplitContainer(
direction="row",
items=[
SplitItem(content=MarkdownPanel(
config=MarkdownConfig(markdown="Hello, world!"),
)),
SplitItem(content=MarkdownPanel(
config=MarkdownConfig(markdown="Hello, world!"),
)),
]
)
layout = Layout(
content=split,
)
Tab container
Use the TabContainer to create a set of tabs, allowing you to quickly switch between different sections of the layout. The container has a list of TabItem objects, each of which has a title and content, and a selected tab index which defaults to 0.
from foxglove.layouts import *
# Create a tab container with two tabs
tabs = TabContainer(
selected_tab_index=1, # Select the second tab
tabs=[
TabItem(
title="Tab 1",
content=MarkdownPanel(
config=MarkdownConfig(markdown="Hello, world!"),
),
),
TabItem(
title="Tab 2",
content=MarkdownPanel(
config=MarkdownConfig(markdown="Hello, world!"),
),
),
]
)
layout = Layout(
content=tabs,
)
Stack container
Use the StackContainer to create a scrollable list of panels. The container has a title and a list of StackItem, each of which has a panel and a size. The size is represented as a fraction of the height of the stack container (for example, 0.5 is 50% of the height of the stack container).
from foxglove.layouts import *
# Create a stack container with two panels
stack = StackContainer(
title="Stack",
panels=[
StackItem(
panel=MarkdownPanel(
config=MarkdownConfig(markdown="Hello, world!"),
),
size=0.25,
),
StackItem(
panel=MarkdownPanel(
config=MarkdownConfig(markdown="Hello, world!"),
),
size=0.25,
),
]
)
layout = Layout(
content=stack,
)
Nesting containers
You can nest the SplitContainer and TabContainer inside each other, and nest the StackContainer inside a SplitContainer or TabContainer.
This enables you to create more complex layouts with multiple levels of nesting.
from foxglove.layouts import *
# Create a tab container with a single tab
# The content of the tab is a 2x2 grid of markdown panels
column1 = SplitContainer(
direction="column",
items=[
SplitItem(content=MarkdownPanel(
config=MarkdownConfig(markdown="Hello, world!"),
)),
SplitItem(content=MarkdownPanel(
config=MarkdownConfig(markdown="Hello, world!"),
)),
]
)
column2 = SplitContainer(
direction="column",
items=[
SplitItem(content=MarkdownPanel(
config=MarkdownConfig(markdown="Hello, world!"),
)),
SplitItem(content=MarkdownPanel(
config=MarkdownConfig(markdown="Hello, world!"),
)),
]
)
row = SplitContainer(
direction="row",
items=[
SplitItem(content=column1),
SplitItem(content=column2),
]
)
tabs = TabContainer(
tabs=[
TabItem(title="Grid", content=row)
]
)
layout = Layout(
content=tabs,
)