I have a data set with 3 of the columns having categorical values. I want to create 3 drop downs in Bokeh or HoloViews in which the first drop down selection determines the values of the list in the other 2 drop downs. Can anyone point me to any of the tutorials or blog or docs that show how to this. I don't seem to fine any.
I appreciate your time.
Thanks!
If you are working in a Jupyter notebook, you can use
paramnb to do this, taking advantage of the way a notebook separates code into different cells:
Here I did "Run all", then selected c3 in the first widget, which re-runs the two cells below it to update them. I then selected a "high" value in the second set of widgets, which re-runs the plot to update it.
This pattern will let you do arbitrary chaining like this if you have notebooks, and if Jupyter Dashboards is an option for you then you can string these cells together to make an application. But this is just one approach...
Here's an example where the values of one dropdown change dependent of the selection made in the other dropdown.
In the example, when you select a continent in one dropdown, the dropdown with possible countries changes in the other dropdown. This happens because of: #pn.depends(continent.param.value, watch=True)
import panel as pn
_countries = {
'Africa': ['Ghana', 'Togo', 'South Africa'],
'Asia' : ['China', 'Thailand', 'Japan'],
'Europe': ['Austria', 'Bulgaria', 'Greece']
}
continent = pn.widgets.Select(
value='Asia',
options=['Africa', 'Asia', 'Europe']
)
country = pn.widgets.Select(
value=_countries[continent.value][0],
options=_countries[continent.value]
)
# the countries dropdown is dependent on the continent dropdown
#pn.depends(continent.param.value, watch=True)
def _update_countries(continent):
countries = _countries[continent]
country.options = countries
country.value = countries[0]
pn.Row(continent, country)
This holoviews + panel question has an example of dropdowns that are dependent on the value of another dropdown:
How do i automatically update a dropdown selection widget when another selection widget is changed? (Python panel pyviz)
The example with dropdowns dependent on other dropdowns comes from the GoogleMapViewer on this tutorial page:
https://panel.pyviz.org/user_guide/Param.html
Related
I have a list of pandas dataframes I named entries, which I want to visualize after running code from the same cell. Below is the code I used :
alt.data_transformers.disable_max_rows()
for entry in entries :
entry['ds'] = entry.index
entry['y'] = entry['count']
entry['floor'] = 0
serie = alt.Chart(entry).mark_line(size=2, opacity=0.7, color = 'Black').encode(
x=alt.X('ds:T', title ='date'),
y='y'
).interactive().properties(
title='Evolution of '+entry.event.iloc[0]+' events over time'
)
alt.layer(serie)\
.properties(width=870, height=450)\
.configure_title(fontSize=20)
When i run the same code out of the 'for' loop, I get to see the one chart that corresponds to one dataframe, but once I run the code above, I don't get any graphs at all.
Does anyone know why It's not working or how to solve this issue?
TLDR: use chart.display()
Unless a chart appears at the end of the cell, you must manually display it.
By analogy, if you run
x + 1
by itself, Python will display the result. However, if you run
for x in range(10):
x + 1
Python will not display anything, because the last statement in the cell (in this case the for loop) has no return value to display. Instead you have to write
for x in range(10):
print(x + 1)
For altair, the mechanism is similar: if the chart is defined in the last statement in the cell, it will be automatically displayed. Otherwise, you have to manually trigger the display, which you can do using the display method:
for i in range(10:
chart = alt.Chart(...)
chart.display()
For more information on display troubleshooting in Altair, see https://altair-viz.github.io/user_guide/troubleshooting.html
I am creating a fairly simple GUI in R that creates figures of different data analysis based on values selected by a user. I am having trouble figuring out how to enable a user to select multiple values from a list. The method I am working on is below. The problem area is in the if statement which is where I need to place the user selections into a list.
CallSpecies<-function(options){
dialog<-gtkMessageDialog(NULL,0,"question","ok-cancel","Choose a species",show=FALSE)
sppmodel<-rGtkDataFrame(Species)
sppview<-gtkTreeView(sppmodel)
sppview$getSelection()$setMode("multiple")
column<-gtkTreeViewColumn("Species Code",gtkCellRendererText(),text=0)
column1<-gtkTreeViewColumn("Common Name",gtkCellRendererText(),text=1)
sppview$appendColumn(column)
sppview$appendColumn(column1)
scrolled_window<-gtkScrolledWindow()
scrolled_window$setSizeRequest(-1,150)
scrolled_window$add(sppview)
dialog[["vbox"]]$add(scrolled_window)
if (dialog$run()==GtkResponseType["ok"]){
}
dialog$destroy()
}
I ended up solving my own issue after quite a bit of reading documentation from other languages and translating it to R syntax. I have edited the code to show my solution. I am by no means an expert in R or GTK but this seems to work.
CallSpecies<-function(options){
dialog<-gtkMessageDialog(NULL,0,"question","ok-cancel","Choose a species. Hold control and click to select multiple species.",show=FALSE)
sppmodel<-rGtkDataFrame(Species)
sppview<-gtkTreeView(sppmodel)
sppview$getSelection()$setMode("multiple")
column<-gtkTreeViewColumn("Species Code",gtkCellRendererText(),text=0)
column1<-gtkTreeViewColumn("Common Name",gtkCellRendererText(),text=1)
sppview$appendColumn(column)
sppview$appendColumn(column1)
scrolled_window<-gtkScrolledWindow()
scrolled_window$setSizeRequest(-1,150)
scrolled_window$add(sppview)
dialog[["vbox"]]$add(scrolled_window)
spplist<-c()
if (dialog$run()==GtkResponseType["ok"]){
selection<-sppview$getSelection()
sel_paths<-selection$getSelectedRows()$retval
i=1
for (p in sel_paths){
sel_row<-sel_paths[[i]]$getIndices()[[1]]
sel_row<-sel_row+1
elem<-Species[sel_row,"SpeciesCode"]
elem<-as.character(elem)
spplist<-c(spplist,elem)
i<-i+1
}
print("spplist")
print(spplist)
}
dialog$destroy()
}
So what I currently want to do is pretty much implement rofi in awesome.
The reason I want to do this and I don't just use rofi is because I want to learn how to 'auto-generate' widgets in awesome.
This will come in handy later when I'll implement things like network widgets that when clicked, shows you a panel, shows you the wifi hotspots available as rows, etc etc. So it's just for me to learn how awesome works better. But also, I want a program launcher.
And also, before someone suggests it, I already know that there's a built-in launcher in awesome, and I also know that there's this. This is not what I'm looking for. I want to have the same thing thing rofi and dmenu have: I want to have suggestions pop up when you press keys. and I want to be able to click on the suggestions, etc.
What I want is something like this: uhhhh
So what I'm having problems is this: how do I auto-generate the rows? I want to be able to specify in only one place how many rows I want, and have awesome do the rest.
I've looked through Elv's github and I found radical and even though what he made is a menu system, I thought that I could use some of his code to do what I want. But I can't for the love of god figure out how it works. No offense to him, but it's not all too well docummented, even for users, and for actually explaining how the code works there's no docummentation.
So My question is: How can I make this work? How would I go about making the widgets that act as the rows automatically?
TL;DR:
i want to write a program launcher like rofi in awesome
i want to be able to specify only in one place the number of rows
therefore, (((I think))) I need to automatically generate widgets as rows somehow, how can I do it?
EDIT:
What I want is to be able to create the rows of my launcher automatically. I know I can hardcode the rows myself, have each row have a different id and then I can write a function that on each keypress, will update each widget with the most relevant matches. So it would be something like (not tested at all):
local wibox = require("wibox")
local awful = require("awful")
local num_rows = 10
local row_height = 40
-- set the height of the background in accordance to how many rows there are,
-- and how high each row should be
local prompt_height = row_height * num_rows
local prompt_width = 300
-- make a widget in the middle of the screen
local background = wibox({
x = awful.screen.focused().geometry.width / 2 - prompt_width / 2,
y = awful.screen.focused().geometry.height / 2 - prompt_height / 2,
width = prompt_width,
height = prompt_height,
bg = "#111111",
visible = false,
ontop = false
})
local rofi_launcher = wibox.widget({
widget = background,
{
-- get a flexible layout so the searchbox and the suggestion boxes get
-- scaled to take up all the space of the background
layout = wibox.layout.flex.vertical,
{ -- the prompt you actually type in
-- set id here so we can adjust its ratio later, so the magnifying
-- glass will end up on the right, and the texbox will take up the left side
id = "searchbox_and_mangifying_glass",
layout = wibox.layout.ratio.horizontal,
{
-- set id so we can use it as a prompt later
id = "searchbox",
widget = wibox.widget.textbox,
},
{
widget = wibox.widget.imagebox,
icon = '~/path/to/magnifying_glass_icon.svg',
},
},
{ -- this is where I actually create the rows that will display suggestions
{ -- row number 1
-- make a background for the textbox to sit in, so you can change
-- background color later for the selected widget, etc etc.
widget = wibox.widget.background,
{
-- give it an id so we can change what's displayed in the
-- textbox when we press keys in the prompt
id = "suggestion_1",
widget = wibox.widget.textbox,
},
},
{ -- row number 2
-- background, again
widget = wibox.widget.background,
{
-- id and textbox again
id = "suggestion_2",
widget = wibox.widget.textbox,
},
},
-- and another 8 (according to the `num_rows` variable) of the same two
-- textboxes above. This is exactly my problem. How can I make these
-- textboxes automatically and still be able to interact with them to
-- display suggestions on the fly, as the user types keys into the prompt?
},
},
})
If this is not clear enough please do let me know what you don't understand and I will update my question.
Equally untested as your code, but this creates a tables of textboxes instead of using the declarative layout to create all these textboxes:
[SNIP; For shorter code I removed some stuff at the beginning]
local textboxes = {}
local widgets = {}
for i = 1, num_rows do
local tb = wibox.widget.textbox()
local bg = wibox.widget.background(tb)
bg:set_bg("#ff0000") -- The original code did not set a bg color, but that would make the bg widget useless...?
tb.id = "suggestion_" .. tostring(i) -- This is likely unnecessary, but the original code set these IDs, too
table.insert(textboxes, tb)
table.insert(widgets, bg)
end
local rofi_launcher = wibox.widget({
widget = background,
{
-- get a flexible layout so the searchbox and the suggestion boxes get
-- scaled to take up all the space of the background
layout = wibox.layout.flex.vertical,
{ -- the prompt you actually type in
[SNIP - I did not change anything here; I only removed this part to make the code shorter]
},
widgets
},
})
-- Now make the textboxes display something
textboxes[3].text = "I am the third row"
textboxes[5].text = "I am not"
So when trying to add a HoverTool to a plot, the MultiLine Hover works.
But the problem I am having is, that I have another highlighting Single Line, that I do not want the Hover to act on.
So I wanted to input just the multiline to the renderers keyword
p.add_tools(HoverTool(tooltips = [('Name: ', '#Name'),
('Value', '#Value')],
renderers = [multiline]
)
and I am getting the following error:
ValueError: expected an element of either Auto or List(Instance(Renderer)), got [MultiLine(id='4982e76f-7dda-4d78-b729-240c9a29bdef', ...)]
What am I missing?
Glyphs (such as MultiLine) are more like a description of what to draw. There is a seperate GlyphRenderer that takes glyphs and uses them to draw (it can actually have several versions of a glyph to use in different cases, e.g. for selecting and highlighting and decimating). The renderers arg of the hover tool expects the GlyphRenderer, not the glyph.
If you are using bokeh.plotting, then the glyph renderer is returned by the method on the figure:
r = plot.multi_line(...) # r is what to configure on the hover tool
If you are using the low level bokeh.models API then you must already be configuring a GlyphRenderer manually for your MultiLine. Pass that to the hover tool instead.
How to add the standard drilldown navigation to children ($member.children), but keep the orginal data as well. Preferable, as generic as possible, so I do not have to know what is on the rows at all (might be 1 hierarchy or a combination of multiple).
It's part of the new release (6.6). You can now us $axis in the MDX expression :
$axis +$member.children
and a variant that shows only one drilldown path :
Filter($axis as t, t.currentMember.level_number <= $member.level_number) + $member.children
The result is something like :
After clicking 2006: