Get the label of an ObservableHQ radio button - observablehq

Is there a way to obtain the label of a radio button?
For example I have
viewof classification = radio({
options: [
{ label: "Underweight", value: "Underweight" },
{ label: "Healthy Weight", value: "Normal" },
{ label: "Overweight", value: "Overweight" },
{ label: "Obese", value: "Obese" }
],
value: "Underweight"
})
If I wanted to access the "Healthy Weight" label instead of the classification value of "Normal", is it possible?

If you have control over the definition of the radio (i.e. this radio isn't being imported from a notebook you don't own), you could restructure this a bit to make that easier.
e.g. in one cell:
options = new Map([
["Underweight", "Underweight"],
["Normal", "Healthy Weight"],
["Overweight", "Overweight"],
["Obese", "Obese"]
]);
and the radio cell:
viewof classification = radio({
options: [...options.entries()].map(([value, label]) => ({label, value})),
value: "Underweight"
})
And in the cell you need to reference the label rather than the value:
label = options.get(classification)

Related

Highcharts Multiple Series data - label mismatch

I have multiple series lets call them
A, B, C, D
I have pulled the series data like so
data:[1,2,3], data:[4,5,6], data[3,5,7], data[7,8,9]
The data is showing correctly on the bar chart
But when I click the series name/identifier on the y-Axis while the bar shows the correct data, the label that appears beside the bar, is incorrect.It seems to use an index based correlation between series and labels
Here is my code:
axios.get('/api/getData')
.then((response) => {
let data= response.data
//initialize series, category arrays
let series = [];
let categories = [];
//group data by product types
let productTypeGroups = _.groupBy(stockData, (product) => {
return product.type;
});
//loop through grouped data and create series for each product type
for(const[key,value] of Object.entries(productTypeGroups)){
let dataValues= _.map(value, (product)=>{
//push product names into category array
categories.push(product.name)
return product.current_balance < 0 ? 0 : product.current_balance;
})
//set default visibility to true if product is vaccine
let visibility = key === 'A' ? true : false
series.push({
name:key,
data:dataValues,
visible:visibility
})
}
this.dataValuesChart.highchartOptions.xAxis.categories = categories
this.dataValuesChart.dataValues.series = series
Here is the HighCharts Config:
highchartOptions: {
chart: {
type: 'bar',
height: 500
},
title: {
text: 'Stock Balance'
},
subtitle: {
text: ''
},
yAxis: {
title: {
text: 'Doses'
},
labels: {
format: '{value}'
}
},
xAxis: {
categories: [],
labels:{
step:1
}
},
plotOptions: {
series: {
label: {
connectorAllowed: false
}
}
},
series: [],
responsive: {
rules: [{
condition: {
maxWidth: 500
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom'
}
}
}]
}
}
Here is a screenshot of how the chart displays:
How does the click event know what labels to pull, should we use some sort of dynamic category setting for this to work? Is there another way to do this even?
Credit #ppoctaczek for pointing out the data array can also be a multidimensional array [x, y] as documented here: https://api.highcharts.com/highcharts/series.bar.data
In terms of hiding the unclicked series #ppoctaczek suggested I edit the plotOption section like so. NB default behaviour on click is to add or remove clicked series to already clicked series - you can retain these defaults if that works for you.
plotOptions: {
series: {
label: {
connectorAllowed: false
},
grouping:false,
events:{
legendItemClick: function(){
this.chart.series.forEach(s=>{
s.hide();
});
this.show();
return false;
}
}
}
},
Then in terms of the data array I needed to make it multidimensional, and have the x value referencing the serial indices of the categories across the multiple series. I achieved this by:
//initialize index counter
let i = 0;
//loop through grouped data and create series for each product type
for(const[key,value] of Object.entries(productTypeGroups)){
let balances = [];
_.each(value, (product)=>{
//push product names into category array
categories.push(product.name)
//push index and balance into balances array
balances.push([i, product.current_balance]);
//increment index
i++;
})
//set default visibility to true if product is vaccine
let visibility = key === 'vaccine' ? true : false
series.push({
name:key,
data:balances,
visible:visibility
})
}
Your data array on console.log your series data should look like this:

GoldenLayout hide/show component (again)

I have an issue with showing/hiding a component similar to this question:
GoldenLayout, how to hide/show component?
My layout is as follows:
let config: Config = {
settings: {
showCloseIcon: false,
showPopoutIcon: false
},
content: [
{
type: 'column',
content: [
{
type: 'row',
height: 25,
content: [
{
title: 'A react component',
type: 'react-component',
component: 'searchContainer'
}
],
},
{
type: 'row',
height: 75,
content: [
{
title: 'A react component',
type: 'react-component',
component: 'leftContainer'
},
{
title: 'Another react component',
type: 'react-component',
component: 'rightContainer'
}
],
},
],
}],
};
I have a hideSearchBar and showSearchBar functions which look like this:
function hideSearchBar() {
let container: ContentItem = layout.root.contentItems[0];
container.contentItems[1].config.height = 100;
container.contentItems[1].contentItems[0].config.height = 100;
container.contentItems[1].contentItems[1].config.height = 100;
container.config.height = 0;
container.contentItems[0].element.hide();
layout.updateSize();
//layout.updateSize($(window).width(), $(window).height());
}
function showSearchBar() {
let container: ContentItem = layout.root.contentItems[0];
container.contentItems[0].element.show();
layout.updateSize();
}
The showSearchBar works perfectly and shows both rows of the grid correctly.
The hideSearchBar hides the top row correctly but leaves the second row does not take up the whole screen. I have tried setting the config.height to 100 in various places but cannot get it to work - there is a gap the size of the top row at the bottom of the screen.
Any help much appreciated.
I solved this with a different layout config where search bar was initially set to 0:
let config: Config = {
settings: {
showCloseIcon: false,
showPopoutIcon: false
},
content: [
{
type: 'column',
content: [
{
type: 'row',
height: 0,
content: [
{
title: 'A react component',
type: 'react-component',
component: LayoutComponent.SearchContainer
}
],
},
{
type: 'row',
height: 100,
content: [
{
title: 'A react component',
type: 'react-component',
component: LayoutComponent.WindowContainer
},
{
title: 'Another react component',
type: 'react-component',
component: LayoutComponent.CollectionContainer
}
],
},
],
}],
};
showSearchBar looks like this:
function showSearchBar() {
let container: ContentItem = layout.root.contentItems[0];
if (searchRowHeight == 0) {
container.contentItems[0].config.height = SEARCH_HEIGHT;
}
else {
container.contentItems[0].config.height = searchRowHeight;
container.contentItems[1].config.height = containerRowHeight;
}
container.contentItems[0].element.show();
layout.updateSize();
}
and hideSearchBar looks like this:
function hideSearchBar() {
let container: ContentItem = layout.root.contentItems[0];
container.contentItems[0].config.height = 0;
container.contentItems[1].config.height = 100;
container.contentItems[0].element.hide();
layout.updateSize();
}
In summary, the config made the searchBar hidden and when it was opened, heights were readjusted.
I use an event listener to check for height changes:
layout.on('stateChanged', () => {
let updateConfig: Config = layout.toConfig();
if (updateConfig.content[0].content[0].height != 0) {
searchRowHeight = updateConfig.content[0].content[0].height;
containerRowHeight = updateConfig.content[0].content[1].height;
}
HTH
Extending #jmc42's answer. Pretty good work-around but once thing it doesn't do is hide the splitter when expanding on pane to 100% and the collapsing the other to 0%.
As a work-around, I thought of 2 choices:
When the pane gets hidden, get the adjacent element representing the splitter bar within the same div and hide it.
When the pane gets hidden, and you detect a resize, always re-apply the expand the top pane to 100% and the bottom pane to 0%.
I opted for option 2 as it was simpler to implement and what I have is:
if (updateConfig.content[0].content[0].height != 0) {
searchRowHeight = updateConfig.content[0].content[0].height;
containerRowHeight = updateConfig.content[0].content[1].height;
}
else {
let container = gbl_Layout.root.contentItems[0].contentItems[0];
container.contentItems[0].config.height = 100;
container.contentItems[1].config.height = 0;
layout.updateSize();
}
My 'if' statement condition is more complex that the one above as I'm performing other checks but that will give you the gist of it. Works pretty well for me.

How to set the different legend icon for different series in same chart

enter image description here
As shown in the figure above, I need to remove the circle in the middle of the third icon, but keep the shape of the other two charts rectangular.But when I set legend.icon = 'line', the shape of the other two icons changed.What should I do?
Nobody in the world knows that you did wrong because no one has seen your code but legend supports separate icons for each series.
var option = {
//...
legend: {
data: [
{ name: 'Series1', icon: 'circle' },
{ name: 'Series2', icon: 'triangle' },
{ name: 'Series3', icon: 'diamond' },
]
}
//...
}

ion picker options overlaps

Currently, I am working on a ionic application which require ion-picker (multi column picker).
I got the data perfectly as I want but just one time means when I open picker for the first time, but after that when I click second time the all options overlapped, I am not able to upload image because of stackoverflow (10 reputation) policy. so please refer the example here
, I have also tried selectedIndex: 0 as suggested in the GitHub link but nothing change.please let me know if anyone know how to solve this.
Thanks in advance
var myColumns = [
{
name: "days",
options: this.day2,
selectedIndex: 1
},
{
name: "Hours",
options: this.hours2,
selectedIndex: 1
},
{
name: "Minutes",
options: this.minutes2,
selectedIndex: 1
},
{
name: "dayType",
options: this.HourType,
selectedIndex: 1
}
];
const picker = await this.pickerCtrl.create({
buttons: [
{
text: "Done"
},
{ text: "Cancel" }
],
mode: "md",
cssClass: ["datePicker"],
columns: myColumns
});
First of all, I found that the problem is that you put the options with an array, I mean you don't put them manually.
Then I think you have 2 options:
first one is put the options manually(in my opinion is not worth it), and the second one, i found that if you put selectedIndex: 0, on the columns properties, the overlap should be gone, but the picker will open always on the first entry. And if you override this selectedIndex: 0, and put a variable that you can change when ever you want, the overlap should be gone, for the most of the entries, except for the first one and the last one.
That's what occur to me.
Hope this help you.
Edit:
I was looking around and just found this:
let picker = await this.pickerCtrl.create(opts);
picker.present();
picker.onDidDismiss().then(async data => {
let num = await picker.getColumn('num');
this.pickerData = num.options[num.selectedIndex].text;
this.pickerDataPrevious = num.selectedIndex;
num.options.forEach(element => {
delete element.selected;
delete element.duration;
delete element.transform;
});
});
If you loop the options (in that case num.options) and delete this properties, the picker data should work correctly
Just before picker.present();
Add these lines :
picker.columns[0].options.forEach(element => {
delete element.selected;
delete element.duration;
delete element.transform;
});
Ref: https://github.com/ionic-team/ionic-framework/issues/17664
Yup, this is a known issue
The problem is that there are 2 properties being added to the original column's options object: duration & transform
As a workaround, you can manually remove these 2 properties. Here's a clean way to do it.
onShowOptions(): void {
const selectedIndex = this.findOptionIndex(this.defaultLanguage, this.languagesList);
this.pickerController
.create({
columns: [
{
selectedIndex: selectedIndex,
name: 'item',
// here's where the magic happens: spread the object, remove duration & transform properties and keep the rest
options: this.options.map(({ duration, transform, ...rest }) => rest),
},
],
buttons: [
{
text: 'Cancel',
},
{
text: 'Done',
handler: ({ item }) => this.optionSelected(item),
},
],
})
.then((picker: HTMLIonPickerElement) => picker.present());
}

Relative path from colorPicker to menu button

I have an extjs menu, in which, upon clicking a button, a colorPicker is opened.
When a color is selected, onColorPickerSelect: function(colorpicker, color, eOpts) springs into action. How do I select the button element in this function, taking the value of the colorpicker variable as my start point?
items: [
{
xtype: 'button',
itemId: 'color1',
style: 'background-color:#fc0;',
text: '1. Farbe',
menu: {
xtype: 'colormenu',
listeners: {
select: {
fn: me.onColorPickerSelect,
scope: me
}
}
}
}
]
As I answer in your previous question, use var button = colorpicker.up('button');
onColorPickerSelect: function(colorpicker, color, e0pts) {
var button = colorpicker.up('button');
button.getEl().setStyle('background-color', '#' + color);
}