Skip to content

Commit

Permalink
Adds three-panel layout configuration option.
Browse files Browse the repository at this point in the history
This change is designed to be backward-compatible with existing LitCanonicalLayouts, i.e., the two-panel layouts with upper/lower sections.

It is now possible to have four different LIT layouts configurations, all of which support tabbing:

* Single-panel: As before, define only the `upper=` parameter for the layout.
* Two-panel, upper/lower: As before, define the `upper=` and `lower=` parameters of your layout.
* Two-panel, left/right: New in this version, define the `left=` and `upper=` parameters of your layout. The `upper=` section will be shown on the right.
* Three-panel: New in this version, define the `left=`, `upper=`, and `lower=` parameters of your layout. The `upper=` and `lower=` sections will be shown on the right.

PiperOrigin-RevId: 558207202
  • Loading branch information
RyanMullins authored and LIT team committed Aug 18, 2023
1 parent d19ed85 commit a95ed67
Show file tree
Hide file tree
Showing 12 changed files with 524 additions and 280 deletions.
44 changes: 43 additions & 1 deletion lit_nlp/api/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class LitCanonicalLayout(dtypes.DataTuple):
"""Frontend UI layout; should match client/lib/types.ts."""
upper: LitTabGroupLayout
lower: LitTabGroupLayout = attr.ib(factory=dict)
left: LitTabGroupLayout = attr.ib(factory=dict)
layoutSettings: LayoutSettings = attr.ib(factory=LayoutSettings)
description: Optional[str] = None

Expand Down Expand Up @@ -170,6 +171,46 @@ def to_json(self) -> dtypes.JsonDict:
'on the page rather than being full width.'),
)

THREE_PANEL_LAYOUT = LitCanonicalLayout(
left={
'Tabular Exploration': [modules.DataTableModule],
'Current Example': [modules.DatapointEditorModule],
'Visual Exploration': [modules.DiveModule],
'Embeddings': [modules.EmbeddingsModule],
'Documentation': [modules.DocumentationModule],
},
upper={
'Predictions': MODEL_PREDS_MODULES,
'Current Example': [modules.DatapointEditorModule],
'Counterfactuals': [modules.GeneratorModule],
},
lower={
'Metrics': [
modules.MetricsModule,
modules.ConfusionMatrixModule,
modules.ThresholderModule,
],
'Charts': [
modules.ScalarModule,
modules.PdpModule,
modules.CurvesModule,
],
'Explanations': [
modules.SalienceMapModule,
modules.SequenceSalienceModule,
modules.FeatureAttributionModule,
],
'Clustering': [modules.SalienceClusteringModule],
'Influence': [modules.TrainingDataAttributionModule],
'TCAV': [modules.TCAVModule],
},
description=(
'A three-panel layout with tools for exploring data in the aggregate or'
' per-example (on the left) or reviewing predition results (upper'
' right) and performance characteristics, etc. (lower left).'
),
)

##
# A "kitchen sink" layout with maximum functionality.
STANDARD_LAYOUT = LitCanonicalLayout(
Expand Down Expand Up @@ -215,5 +256,6 @@ def to_json(self) -> dtypes.JsonDict:

DEFAULT_LAYOUTS = {
'simple': SIMPLE_LAYOUT,
'default': STANDARD_LAYOUT,
'legacy': STANDARD_LAYOUT,
'default': THREE_PANEL_LAYOUT,
}
25 changes: 17 additions & 8 deletions lit_nlp/client/core/global_settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -762,16 +762,24 @@ export class GlobalSettingsComponent extends MobxLitElement {
const layouts = Object.keys(this.appState.layouts);

const renderLayoutAreaInfo = (groupLayout: LitTabGroupLayout) => {
return Object.keys(groupLayout).map((tabName: string) => {
const entries = Object.entries(groupLayout);

if (entries.length === 0) {
return html`<div class='info-group'>
<div class="info-group-subtitle">Unused in this layout</div>
</div>`;
}

return entries.map(([tabName, tabModules]) => {
// clang-format off
return html`
<div class='info-group'>
<div class='info-group-subtitle'>
${tabName}
</div>
${groupLayout[tabName].map(module => html`
${tabModules.map(tabModule => html`
<div class='indent-line'>
${resolveModuleConfig(module).title}
${resolveModuleConfig(tabModule).title}
</div>`)}
</div>`;
// clang-format on
Expand Down Expand Up @@ -801,19 +809,20 @@ export class GlobalSettingsComponent extends MobxLitElement {
const disabled = false;

// The expanded info contains info about the components.
const layout = this.appState.layouts[name];
const {description, left, lower, upper} = this.appState.layouts[name];
// clang-format off
const expandedInfoHtml = html`
<div class='info-group-title'>Left</div>
${renderLayoutAreaInfo(left)}
<div class='info-group-title'>Upper</div>
${renderLayoutAreaInfo(layout.upper)}
${renderLayoutAreaInfo(upper)}
<div class='info-group-title'>Lower</div>
${renderLayoutAreaInfo(layout.lower)}
${renderLayoutAreaInfo(lower)}
`;
// clang-format on
const description = this.appState.layouts[name].description || '';
return this.renderLine(
name, selectorHtml, selected, disabled, expanderOpen,
onExpanderClick, false, expandedInfoHtml, description);
onExpanderClick, false, expandedInfoHtml, (description || ''));
};

const configListHTML = layouts.map(name => renderLayoutOption(name));
Expand Down
134 changes: 95 additions & 39 deletions lit_nlp/client/core/modules.css
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
:host {
--left-column-width: calc(50% - 4px);
--tab-bar-height: 32px;
/* 5x LitWidget.header.height */
--right-column-min-section-content-height: 180px;

flex: 1;
display: flex;
flex-direction: column;
background: #f5f9fa;
--tab-bar-height: 30px;
max-height: calc(100hv - 77px); /* lit-app-bar is 77px tall */
}

.outer-container {
display: flex;
flex-direction: column;
overflow: hidden;
flex-direction: row;
height: 100%;
max-height: 100%;
/* full-width, overflow if window is < 1000px */
min-width: 1000px;
max-width: 100vw;
padding: 0 16px;
overflow: hidden;
}

.outer-container-centered {
Expand All @@ -24,34 +31,79 @@
max-width: 1000px;
}

#upper-group-area {
#left-column,
#right-column {
position: relative;
height: calc(var(--upper-height) - var(--upper-tab-bar-visible) * var(--tab-bar-height));
background-color: var(--lit-mintonal-p-1);
height: 100%;
max-height: 100%;

display: flex;
flex-direction: column;
overflow: hidden;
}

#lower-group-area {
#left-column {
flex-shrink: 0;
min-width: 20%;
width: var(--left-column-width);
max-width: 80%;
}

#right-column {
flex-grow: 1;
}

.group-area {
position: relative;
flex: 1;
max-height: calc(100% - var(--upper-height) - var(--tab-bar-height));
background-color: var(--lit-mintonal-p-3);
display: flex;
flex-direction: column;
background-color: var(--lit-mintonal-p-1);
}

#upper-right {
--upper-tab-bar-height: calc(
var(--upper-tab-bar-visible) * var(--tab-bar-height)
);
min-height: calc(
var(--right-column-min-section-content-height) + var(--upper-tab-bar-height)
);
height: var(--upper-height);
max-height: var(--upper-height);
}

.outer-container-centered #lower-group-area {
background-color: unset;
#lower-right {
flex-grow: 1;
min-height: calc(
var(--right-column-min-section-content-height) + var(--tab-bar-height)
);
max-height: calc(100% - var(--upper-height));
margin-top: 8px;
}

.components-group-holder {
--top-offset: var(--tab-bar-height);
position: absolute;
top: var(--top-offset);
overflow: hidden; /* no scrollbars, for they are the path to the dark side */
display: flex;
flex-grow: 1;
visibility: hidden;
height: 100%;
height: calc(100% - var(--top-offset));
max-height: calc(100% - var(--top-offset));
width: 100%;
padding: 8px;
max-width: 100%;
padding: 8px 0;
box-sizing: border-box;
}

#left-column .components-group-holder {
--top-offset: calc(var(--left-tab-bar-visible) * var(--tab-bar-height));
}

#upper-right .components-group-holder {
--top-offset: var(--upper-tab-bar-height);
}

.components-group-holder.selected {
visibility: visible;
}
Expand Down Expand Up @@ -81,24 +133,22 @@ lit-widget-group[maximized] {
}

.tab-bar {
padding: 0 40px;
color: #5f6368;
background: white;
--bar-button-offset: 0;

height: var(--tab-bar-height);
padding: 0 8px;

display: flex;
flex-direction: row;
align-items: center;
height: var(--tab-bar-height);
border-bottom: 1px solid var(--lit-neutral-300);
border-top: 1px solid var(--lit-neutral-300);
}

/* If in centered mode, tab bars should align to modules */
.outer-container-centered .tab-bar {
margin: 0 8px;
border: 1px solid rgb(218, 220, 224);
box-sizing: border-box;
color: var(--lit-neutral-700);
background: white;
border: 1px solid var(--lit-neutral-300);
}

.tab-bar .preset-buttons {
height: 100%;
display: flex;
flex-direction: row;
align-items: center;
Expand All @@ -110,40 +160,48 @@ lit-widget-group[maximized] {
}

#drag-container{
position: relative;
width: 50%;
height: 100%;
margin-left: auto;
margin: 0 24px;

display: flex;
align-items: center;
}

#drag-handler {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
cursor: ns-resize;
opacity: 0;
}

.tabs-container {
align-items: end; /* bottom */
display: flex;
font-size: 12px;
height: 100%;
margin-right: 38px;
max-width: 100%;
padding: 2px 0;

display: flex;
flex-direction: row;
flex-grow: 1;
align-items: end; /* bottom */

font-size: 12px;
overflow-x: scroll;
}

#center-bar .tabs-container {
/* 120 = 48 for preset buttons + 3 * 24 for the drag handle and its margin. */
max-width: calc(100% - 120px);
}

.tab {
font-family: 'Google Sans', sans;
border-bottom: 2px solid #dadce0;
box-sizing: border-box;
cursor: pointer;
padding: 4px;
padding: 4px 16px;
text-align: center;
white-space: nowrap;
width: 150px;
}

.tab:hover{
Expand All @@ -158,6 +216,4 @@ lit-widget-group[maximized] {

.drag-icon {
pointer-events: none;
position: absolute;
left: 0%;
}

0 comments on commit a95ed67

Please sign in to comment.