How to keep selected data persistent through callback in Dash/Plotly's clustered bar chart - callback

I'm using Dash to plot some data. I currently have a clustered bar chart with two data sets (one for each bar in the clusters.) These data sets have their name and the corresponding color of the bars displayed in the top, left-hand corner of the figure. They can be clicked to be toggled on and off, which will remove their corresponding bars from the chart.
Separately, I have a checklist of items that can be displayed in the chart. I am using a callback to update the graph so that it only displays what the user has checked. This updates the graph as expected, however, it also resets the bars/datasets such that both are enabled. Ie. if you select only one of the bars, then select some new checklist items, it will display the new checklist items and both of the bars.
My thinking is that the logical way to do this is to pass some variable as a second input to the callback function, then set up the outputted figure within the function to only display the proper bars. However, I can't seem to find a variable that contains this data.
From what I can tell, the accessible properties of the Plotly graph object are 'id', 'clickData', 'clickAnnotationData', 'hoverData', 'clear_on_unhover', 'selectedData', 'relayoutData', 'figure', 'style', 'className', 'animate', 'animation_options', 'config', and 'loading_state'.
I've investigated all of these, and it seems that none hold the data that I am looking for. Does anyone know of an easy way to access this data?
This is how my callback is working right now:
#app.callback(
dash.dependencies.Output('theGraph', 'figure'),
[dash.dependencies.Input('theChecklist','values'),
dash.dependencies.Input('theGraph', 'clickData')
]
)
def updateGraph(checklistValues, figureInput):
#print to see what the variables hold
print(checklistValues)
print(figureInput)
figure=go.Figure(
data = [
go.Bar(
x = df[df['MyColumnName'].isin(checklistValues)].groupby('MyColumnName').size().index,
y = df[df['MyColumnName'].isin(checklistValues)].groupby('MyColumnName').size().values,
name = 'Bar 1'
),
go.Bar(
x = df[df['MyColumnName'].isin(checklistValues)].groupby('MyColumnName')['# cores'].sum().reset_index()['MyColumnName'],
y = df[df['MyColumnName'].isin(checklistValues)].groupby('MyColumnName')['# cores'].sum().reset_index()['MyOtherColumnName'],
name = 'Bar 2'
)
],
layout=go.Layout(
title='The Title',
showlegend=True,
legend=go.layout.Legend(
x=0,
y=1.0
),
margin=go.layout.Margin(l=40, r=40, t=40, b=110)
)
)
return figure

Related

plotly go Scattermapbox is not showing markers

I some how have encountered some odd bug. When i try to create a Scattermapbox the markers dont render. This bug came out of no where, It was working perfectly fine then my internet went out and now for the last 8 hours it has not been working.
Ive tried running it in different IDE's
running it in google colab to make sure its not my machine
different data sets.
i am unsure what i have done wrong
The tooltips do display however when i hover over the invisible points.
and if use the export to png button everything is shown.
but no matter what it wont show up on the actual map itself and i am at my wits end.
I will include the callback function bellow.
#app.callback(
Output('2dmap','figure'),
[Input('2dgraph', 'clickData'),
Input('checklist', 'value')])
def update_map_2d(clickData,checklist):
# =============================================================================
# P1. Render Map when no point is clicked
# =============================================================================
# If No point has been clicked
if clickData is None:
#make a map
maps2d = go.Figure(go.Scattermapbox(
lat=[], # set lat and long
lon=[],
mode='markers',
marker =({'size':5.5}) # make markers size variable
))
# set up map layout
maps2d.update_layout(
autosize=True, # Autosize
hovermode='closest', # Show info on the closest marker
showlegend=True, # show legend of colors
mapbox=dict(
accesstoken=mapbox_access_token, # token
bearing=0, # starting facing direction
# starting location
center=dict(
lat=td.cLat,
lon=td.cLong
),
#angle and zoom
pitch=0,
zoom=12
),
#height and width
width=1000,
height=1000
)
return maps2d
else:
xCoord = int(clickData['points'][0]['x'])
yCoord = int(clickData['points'][0]["y"])
solutionRow = preatoFrontier.loc[(preatoFrontier['x'] == xCoord)&(preatoFrontier['y'] == yCoord)]
solId = int(solutionRow['SolId'])
#solId = 49
solution = td.getSolution(solutions, solId)
color = []
for row in solution['upGrade']:
if row == 0:
color.append('grey')
if row == 1:
color.append('green')
if row == 2:
color.append('blue')
if row == 3:
color.append('red')
solution['color'] = color
solution2 = solution[solution['color'].isin(checklist)]
maps2d = go.Figure(go.Scattermapbox(
lat=solution2['lat'],
lon=solution2['long'],
mode='markers',
#marker =({'color':solution['color']},{'size':5.5})
marker=dict(
size=12,
color=solution2['color'], #set color equal to a variable
colorscale='Viridis', # one of plotly colorscales
showscale=True
)
))
#=============================================================================
# P3. Map Layout
#=============================================================================
#set up map layout
maps2d.update_layout(
autosize=False, # Autosize
hovermode='closest', # Show info on the closest marker
showlegend=True, # show legend of colors
mapbox=dict(
accesstoken=mapbox_access_token, # token
bearing=0, # starting facing direction
# starting location
center=dict(
lat=td.cLat,
lon=td.cLong
),
#angle and zoom
pitch=0,
zoom=10
),
#height and width
width=1000,
height=1000
)
return maps2d
After a lot of hair pulling, i thought to try creating a new venv and uploading packages one by one and running to see how and where it fails. The last package i installed before it broke was dash-tools and sure enough some how that was causing mapbox to bug out hard. So dont install dash-tools

Is there a way to get the ECharts series symbol to be passed in as the marker in the tooltip

I've got an ECharts chart that has multiple line series and a scatter series that represents events. For the line series, we left the symbol at the default, but for the event scatter series we set the symbol to 'diamond'. These symbols show up on the chart & in the series legend as expected. However, the tooltip always shows a 10 pixel dot for the marker. The color however is picked up from the series (and even from the visualMap config!). My initial assumption had been that the symbol would also be picked up from the series. In our case we wanted to use a function for tooltip.formatter and even in that function we couldn't figure out how to access and swap in the series symbol for the marker. We ended up working around it by just custom styling our own html to plug in for the marker that matched the diamond symbol pretty well.
So the open questions are:
Is there a way to have the tooltip marker pick up the symbol from the series?
If not, is this a bug? I'm happy to put in an issue on the project but I don't want to do that until I understand a bit more.
Here's some code to illustrate what we had to do to get the diamond in there in case it helps the discussion or if others want to leverage this workaround:
formatTooltip(args){
let time = DateTime.fromISO(args[0].data[0], { zone: this.user.timeZone })
let tooltip = `<div><b>${time.toFormat(TOOLTIP_FORMAT)}</b></div>`
args.forEach(({ marker, seriesName, value }) => {
if (seriesName === 'Events'){
let myMarker = `<span style="display:inline-block;margin-right:4px;width:10px;height:10px;background:${value[4]};transform:rotate(45deg);"></span>`
tooltip += `<div>${myMarker} ${value[3] ? value[3]: ''}</div>`
} else {
value = value || [0, 0]
tooltip += `<div>${marker} ${seriesName}: ${value[1]}</div>`
}
})
return tooltip
},

bar chart display all cateogries

I have a bar chart. It has 25 bars all representing a different category. The chart is fine however it only prints out a few of the categories.
I thought by using the line below that it would display all 25 categories that I have specified in x_labels.
set(gca,'XtickL',x_labels);
I also use the method rotateXLabel and rotate the labels 90 degrees so they are not over writing each other. However still only display some of the categories. How can I display all of them?
update
Here is my data,
'Health Care' 4.72629799981083
'Capital Goods' 4.09458147368759
'Transp' 3.98149295925542
'Media' 1.79439005788530
'Insurance' 1.69956150439052
'Commer Serv' 1.39773924375053
'Food & Staples' 1.37870312358688
'Tech Hardw' 1.14006008338028
'Div Finan' 1.07437424540054
'Retailing' 0.799227696500581
'Cons Durab' 0.484704646767555
'Semiconduct' -0.0668927175281457
'Cons Serv' -0.0994263844790881
'Software' -1.13770277184728
'Auto&Comp' -1.14193637823934
'Materials' -1.52052729345776
'Real Estate' -1.58166267932780
'HH & Prod' -1.68076878183555
'Food Bever' -1.73283367572542
'Pharma' -1.90119783888618
'Telecom' -2.04480219189470
'Utilities' -2.20510498991084
'Energy' -2.36405808621777
'Banks' -5.09421924506606
another update
Found the solution here. Its not quite 100% perfect though as some of my labels are too long so the chart cuts them off. Need to work out how to get round that issue
[pp,h1,h2]=plotyy((1:length(risk_tot)),risk_tot,(1:length(risk_tot)),risk_cont,'bar','stem');
xData = get(h1,'XData');
set(gca,'Xtick',linspace(xData(1),xData(end),length(x_labels(:, 1))));
Is this what you are looking for?:
value is vector with the provided values
label is a cell with the provided strings
bar(value);
set(gca, 'XTick', 1:length(value))
set(gca, 'XTickLabel', label)
grid on
rotateXLabels(gca(), 90)

Using several popupmenues different rows of a uitable

To generate a ui-table I'm using GUIDE. To insert a popup menu into the ui-table I'm using the following code(for example):
data = {1;2;3,'A';'B';'C'}
set(handles.uitable,'ColumnFormat',{'1','2','3'},'char',data)
Then i will get the same popup menu in every row of the ui-table.
But I want to have different popup menus in different rows of a ui-table, as shown in the picture below.
If I understood correctly, you want to set the 'ColumnEditTable' property of selected columns to true during the creation of your table, and depending of the columnformat you specify you can get popupmenus or checkboxes for example.. Consider this code, which I modified form the doc (look here)
function MyTable
f = figure('Position',[300 300 400 400]);
% Column names and column format
columnname = {'Greeting','Amount','Available','Fixed/Adj'};
columnformat = {{'Hello' 'Hi'},'bank','logical',{'Fixed' 'Adjustable'}}; %// Set the entries of the popup menu in a cell array. When the format is 'logical', the output in the table is a checkbox.
% Define the initial displayed data
d = {'Hi' 456.3457 true 'Fixed';...
'Hello' 510.2342 false 'Adjustable';...
'Hi' 658.2 false 'Fixed';};
% Create the uitable
t = uitable('Data', d,...
'ColumnName', columnname,...
'ColumnFormat', columnformat,...
'ColumnEditable', [true false true true],... %// That's the important line. Entries set to true will allow you to create a popup menu for the whole column.
'RowName',[]);
The table looks like this:
As you can see you can select 'Hi' or 'Hello' in the first columns and either 'Fixed' or 'Adjustable' in the last column.
Hope it gets you started and it's somewhat what you wanted!

Is there a limit to the amount of data you can put in a MATLAB pie/pie3 chart?

I have everything going swimmingly on my pie chart and 3D pie charts within MATLAB for a dataset, however, I noticed that even though I have 21 pieces of data for this pie-chart being fed into the pie-chart call, only 17 appear.
PieChartNums = [ Facebook_count, Google_count, YouTube_count, ThePirateBay_count, StackOverflow_count, SourceForge_count, PythonOrg_count, Reddit_count, KUmail_count, Imgur_count, WOWhead_count, BattleNet_count, Gmail_count, Wired_count, Amazon_count, Twitter_count, IMDB_count, SoundCloud_count, LinkedIn_count, APOD_count, PhysOrg_count];
labels = {'Facebook','Google','YouTube','ThePirateBay','StackOverflow', 'SourceForge', 'Python.org', 'Reddit', 'KU-Email', 'Imgur', 'WOWhead', 'BattleNet', 'Gmail', 'Wired', 'Amazon', 'Twitter', 'IMDB', 'SoundCloud', 'LinkedIn', 'APOD', 'PhysOrg'};
pie3(PieChartNums)
legend(labels,'Location','eastoutside','Orientation','vertical')
This goes for the labels and the physical graph itself.
Excuse the poor formatting in terms of the percentage cluster, this is just a rough version. I tried every orientation and even splitting labels between the orientations without any luck.
Quasi-better resolution for Pie Chart -- Imgur Link
Like Daniel said - it appears that there simply isn't any non-negative data for the missing slices. I tried reproducing your problem with the following initialization, yet it resulted in normal-looking chart:
[ Facebook_count, Google_count, YouTube_count, ThePirateBay_count, ...
StackOverflow_count, SourceForge_count, PythonOrg_count, Reddit_count, ...
KUmail_count, Imgur_count, WOWhead_count, BattleNet_count, Gmail_count, ...
Wired_count, Amazon_count, Twitter_count, IMDB_count, SoundCloud_count, ...
LinkedIn_count, APOD_count, PhysOrg_count] = deal(0.04);
In order to verify this hypothesis - could you provide the data you're using for the chart? Do you get any warnings when plotting the chart?
From inside the code of pie.m:
if any(nonpositive)
warning(message('MATLAB:pie:NonPositiveData'));
x(nonpositive) = [];
end
and:
for i=1:length(x)
if x(i)<.01,
txtlabels{i} = '< 1%';
else
txtlabels{i} = sprintf('%d%%',round(x(i)*100));
end
end
You can see that MATLAB doesn't delete valid slices, but only renames them if the data values are small.