Skip to content

Commit

Permalink
UI/UX tweaks for layer tabs (#2574)
Browse files Browse the repository at this point in the history
* adds support for styling the tabs for colormaps (instead of just showing as gray), in a way that will also allow us to expose the representation in the colormap dropdown in the future
* allows showing color and colormap side-by-side and merging duplicate entries (3 viewers with 1 colormap and 1 color will now show half and half, instead of 1/3 and 2/3)
* updates the tooltip text on the tabs
* small padding tweaks, and shrinking size of tabs to fit more without needing to scroll
* changes the tab "outline" color from orange to blue
* separates the multiselect button into layer and viewer with a deprecation warning (deprecated method does not work on properties or setters, so had to use a logger warning)
* prevents deselecting all tabs
* smarter handling of visibility of stretch histogram, now allowing interacting with the stretch histogram when multiple viewers but a single layer are selected, and no longer clearing the marks which resulted in vmin/vmax marks disappearing.
  • Loading branch information
kecnry authored Nov 27, 2023
1 parent be28971 commit c788287
Show file tree
Hide file tree
Showing 10 changed files with 314 additions and 295 deletions.
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ New Features

- Plugin APIs now include a ``close_in_tray()`` method. [#2562]

- Convert the layer select dropdown in Plot Options into a horizontal panel of buttons. [#2566]
- Convert the layer select dropdown in Plot Options into a horizontal panel of buttons. [#2566, #2574]

Cubeviz
^^^^^^^
Expand Down
30 changes: 15 additions & 15 deletions jdaviz/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,21 @@ def __init__(self, configuration=None, *args, **kwargs):
# can reference their state easily since glue does not store viewers
self._viewer_store = {}

# Add new and inverse colormaps to Glue global state. Also see ColormapRegistry in
# https://github.com/glue-viz/glue/blob/main/glue/config.py
new_cms = (['Rainbow', cm.rainbow],
['Seismic', cm.seismic],
['Reversed: Gray', cm.gray_r],
['Reversed: Viridis', cm.viridis_r],
['Reversed: Plasma', cm.plasma_r],
['Reversed: Inferno', cm.inferno_r],
['Reversed: Magma', cm.magma_r],
['Reversed: Hot', cm.hot_r],
['Reversed: Rainbow', cm.rainbow_r])
for cur_cm in new_cms:
if cur_cm not in colormaps.members:
colormaps.add(*cur_cm)

# Parse the yaml configuration file used to compose the front-end UI
self.load_configuration(configuration)

Expand Down Expand Up @@ -333,21 +348,6 @@ def __init__(self, configuration=None, *args, **kwargs):
self.hub.subscribe(self, SubsetUpdateMessage,
handler=lambda msg: self._clear_object_cache(msg.subset.label))

# Add new and inverse colormaps to Glue global state. Also see ColormapRegistry in
# https://github.com/glue-viz/glue/blob/main/glue/config.py
new_cms = (['Rainbow', cm.rainbow],
['Seismic', cm.seismic],
['Reversed: Gray', cm.gray_r],
['Reversed: Viridis', cm.viridis_r],
['Reversed: Plasma', cm.plasma_r],
['Reversed: Inferno', cm.inferno_r],
['Reversed: Magma', cm.magma_r],
['Reversed: Hot', cm.hot_r],
['Reversed: Rainbow', cm.rainbow_r])
for cur_cm in new_cms:
if cur_cm not in colormaps.members:
colormaps.add(*cur_cm)

# Subscribe to messages that result in changes to the layers
self.hub.subscribe(self, AddDataMessage,
handler=self._on_layers_changed)
Expand Down
18 changes: 0 additions & 18 deletions jdaviz/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -451,22 +451,4 @@ a:active {
font-weight: 500 !important;
}
.suppress-scrollbar {
overflow-y: scroll;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* Internet Explorer 10+ */
}
.suppress-scrollbar::-webkit-scrollbar { /* WebKit */
width: 0;
height: 0;
}
.layer-tab-selected {
background-color: rgba(0,0,0,0.1);
}
.theme--dark .layer-tab-selected {
background-color: rgba(255,255,255,0.1);
}
</style>
84 changes: 55 additions & 29 deletions jdaviz/components/plugin_layer_select_tabs.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
<template>
<div>
<span class="suppress-scrollbar" style="display: inline-block; white-space: nowrap; margin-left: -24px; width: calc(100% + 48px); overflow-x: scroll; overflow-y: hidden">
<span v-for="(item, index) in items" :class="selectedAsList.includes(item.label) ? 'layer-tab-selected' : ''" :style="'display: inline-block; padding: 12px; '+(selectedAsList.includes(item.label) ? 'border-top: 2px solid #c75109' : 'border-top: 2px solid transparent')">
<div style="margin-top: 24px">
<div v-if="show_multiselect_toggle" style="position: absolute; width: 32px; right: 0px; margin-right: 12px; margin-top: -32px">
<j-tooltip tipid='layer-multiselect-toggle'>
<v-btn
icon
style="opacity: 0.7"
@click="$emit('update:multiselect', !multiselect)"
>
<img :src="multiselect ? icon_checktoradial : icon_radialtocheck" width="24" class="invert-if-dark"/>
</v-btn>
</j-tooltip>
</div>
<span style="display: inline-block; white-space: nowrap; margin-left: -24px; width: calc(100% + 48px); overflow-x: scroll; overflow-y: hidden">
<span v-for="(item, index) in items" :class="selectedAsList.includes(item.label) ? 'layer-tab-selected' : ''" :style="'display: inline-block; padding: 8px; '+(selectedAsList.includes(item.label) ? 'border-top: 3px solid #00617E' : 'border-top: 3px solid transparent')">
<j-tooltip :tooltipcontent="tooltipContent(item)">
<v-btn
:rounded="item.is_subset"
@click="() => {if (!multiselect){$emit('update:selected', item.label)} else if(!selectedAsList.includes(item.label)) {$emit('update:selected', selected.concat(item.label))} else {$emit('update:selected', selected.filter(select => select != item.label))} }"
@click="() => {if (!multiselect){$emit('update:selected', item.label)} else if(!selectedAsList.includes(item.label)) {$emit('update:selected', selected.concat(item.label))} else if (selected.length > 1) {$emit('update:selected', selected.filter(select => select != item.label))} }"
:style="'padding: 0px; margin-bottom: 4px; background: '+visibilityStyle(item)+', '+colorStyle(item)"
width="30px"
min-width="30px"
Expand All @@ -23,7 +34,8 @@

<script>
module.exports = {
props: ['items', 'selected', 'multiselect', 'colormode'],
props: ['items', 'selected', 'multiselect', 'colormode', 'cmap_samples',
'show_multiselect_toggle', 'icon_checktoradial', 'icon_radialtocheck'],
computed: {
selectedAsList() {
if (this.$props.multiselect) {
Expand All @@ -35,50 +47,64 @@ module.exports = {
methods: {
tooltipContent(item) {
var tooltip = item.label
if (item.mixed_visibility) {
tooltip += '<br/>Visible: mixed'
if (item.visible === 'mixed') {
tooltip += '<br/>Visibility: mixed'
} else if (!item.visible) {
tooltip += '<br/>Visible: false'
tooltip += '<br/>Visibility: hidden'
}
if (this.$props.colormode === 'Colormaps' && !item.is_subset) {
tooltip += '<br/>Color mode: colormap'
} else if (this.$props.colormode === 'mixed' && !item.is_subset) {
if (this.$props.colormode === 'mixed' && !item.is_subset) {
tooltip += '<br/>Color mode: mixed'
}
if (item.mixed_color && (this.$props.colormode !== 'Colormaps' || item.is_subset)) {
tooltip += '<br/>Color: mixed'
if (item.colors.length > 1) {
if (this.$props.colormode === 'Colormaps') {
tooltip += '<br/>Colormap: mixed'
} else if (this.$props.colormode === 'mixed') {
tooltip += '<br/>Color/colormap: mixed'
} else {
tooltip += '<br/>Color: mixed'
}
}
return tooltip
},
visibilityStyle(item) {
if (item.mixed_visibility){
if (item.visible === 'mixed'){
return 'repeating-linear-gradient(30deg, rgba(0,0,0,0.3), rgba(0,0,0,0.3) 3px, transparent 3px, transparent 3px, transparent 10px)'
}
else if (item.visible) {
return 'repeating-linear-gradient(30deg, transparent, transparent 10px)'
} else {
return 'repeating-linear-gradient(30deg, rgba(0,0,0,0.8), rgba(0,0,0,0.8) 7px, transparent 7px, transparent 7px, transparent 10px)'
return 'repeating-linear-gradient(30deg, rgba(0,0,0,0.4), rgba(0,0,0,0.4) 8px, transparent 8px, transparent 8px, transparent 10px)'
}
},
colorStyle(item) {
if (this.$props.colormode == 'Colormaps' && !item.is_subset) {
return 'repeating-linear-gradient( -45deg, gray, gray 20px)'
}
if (item.mixed_color) {
colors = item.all_colors_to_label
const strip_width = 42 / colors.length
const strip_width = 42 / item.colors.length
var cmap_strip_width = strip_width
var colors = []
var style = 'repeating-linear-gradient( 135deg, '
for ([mi, color_or_cmap] of item.colors.entries()) {
if (color_or_cmap.startsWith('#')) {
colors = [color_or_cmap]
} else {
colors = this.$props.cmap_samples[color_or_cmap]
}
var style = 'repeating-linear-gradient( -45deg, '
for ([ind, color] of colors.entries()) {
style += color + ' '+ind*strip_width+'px, ' + color + ' '+(ind+1)*strip_width+'px'
if (ind !== colors.length-1) {
cmap_strip_width = strip_width / colors.length
for ([ci, color] of colors.entries()) {
var start = mi*strip_width + ci*cmap_strip_width
var end = mi*strip_width+(ci+1)*cmap_strip_width
style += color + ' '+start+'px, ' + color + ' '+end+'px'
if (ci !== colors.length-1) {
style += ', '
}
}
style += ')'
return style
}
return 'repeating-linear-gradient( -45deg, '+item.color+', '+item.color+' 20px)'
if (mi !== item.colors.length-1) {
style += ', '
}
}
style += ')'
return style
}
}
Expand Down
14 changes: 13 additions & 1 deletion jdaviz/components/plugin_viewer_select.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
<template>
<div>
<div v-if="show_multiselect_toggle" style="position: absolute; width: 32px; right: 0px; margin-right: 12px; margin-top: -6px; z-index: 999">
<j-tooltip tipid='viewer-multiselect-toggle'>
<v-btn
icon
style="opacity: 0.7"
@click="$emit('update:multiselect', !multiselect)"
>
<img :src="multiselect ? icon_checktoradial : icon_radialtocheck" width="24" class="invert-if-dark"/>
</v-btn>
</j-tooltip>
</div>
<v-row v-if="items.length > 1 || selected.length===0 || show_if_single_entry">
<v-select
:menu-props="{ left: true }"
Expand Down Expand Up @@ -64,7 +75,8 @@

<script>
module.exports = {
props: ['items', 'selected', 'label', 'hint', 'rules', 'show_if_single_entry', 'multiselect']
props: ['items', 'selected', 'label', 'hint', 'rules', 'show_if_single_entry', 'multiselect',
'show_multiselect_toggle', 'icon_checktoradial', 'icon_radialtocheck']
};
</script>

Expand Down
3 changes: 2 additions & 1 deletion jdaviz/components/tooltip.vue
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ const tooltips = {
'table-next': 'Select next row in table',
'table-play-pause-toggle': 'Toggle cycling through rows of table',
'table-play-pause-delay': 'Set delay before cycling to next entry',
'plugin-plot-options-multiselect-toggle': 'Toggle between simple (single-select) and advanced (multiselect)',
'viewer-multiselect-toggle': 'Toggle between choosing a single or multiple viewer(s)',
'layer-multiselect-toggle': 'Toggle between choosing a single or multiple layer(s)',
'plugin-plot-options-mixed-state': 'Current values are mixed, click to sync at shown value',
'plugin-model-fitting-add-model': 'Create model component',
'plugin-model-fitting-param-fixed': 'Check the box to freeze parameter value',
Expand Down
Loading

0 comments on commit c788287

Please sign in to comment.