I have created a grid plot using bokeh consisting of multiple vertically stacked line charts senter code hereharing same X axis.My requirement is to have a tooltip displayed on all the charts on hovering over a point on one of the charts.Tried multiple ways, but couldn't find a solution.It would be great if someone out there assist me in resolving this issue.
from bokeh.palettes import RdBu3, RdYlGn3
from bokeh.plotting import figure, output_notebook, show
from bokeh.io import show
from bokeh.models import ColumnDataSource, BoxAnnotation, Button, HoverTool, Text, Circle
from bokeh.models.callbacks import CustomJS
from bokeh.layouts import column, gridplot
from bokeh.models.widgets import TextInput, Div, Select
output_notebook()
#Main Data Source
source = ColumnDataSource(df)
#Filtering the data source based on some condition
df1 = df[Some_Condition]
#Filtered Data Source
sc = ColumnDataSource(df1)
#Callback to be executed on selecting a value from Select widget
callback_select = CustomJS(args=dict(source=source, sc=sc),code="""
var indices = [];
var val = cb_obj.value
sc.data['xx'] = []
sc.data['yy'] = []
sc.data['Date'] = []
for (var i = 0; i < source.get_length(); i++){
if (source.data['ZZ'][i] == val){
sc.data['xx'].push(source.data['xx'][i])
sc.data['yy'].push(source.data['yy'][i])
sc.data['Date'].push(source.data['Date'][i])
} else {
}
}
sc.change.emit();
""")
#Select Widget
select = Select(title="ZZ:", value="Select", options=["Opt1", "Opt2", "Opt3"], callback = callback_select)
#Tooltips to be displayed
TOOLTIPS = [("Value: ", "#{xx}")]
TOOLTIPS1 = [("Value: ", "#{yy}")]
#Tools to be shown on plot
_tools_to_show = 'box_zoom,pan,save,reset,tap,wheel_zoom,crosshair'
#First Chart
p1 = figure(x_axis_type="datetime", plot_height=200, tools = _tools_to_show)
p1.xaxis.visible = False
p1.xgrid.grid_line_color=None
p1.ygrid.grid_line_alpha=0.5
p1.xaxis.axis_label = 'Date'
p1.yaxis.axis_label = 'xx'
#Second Chart
p2 = figure(x_axis_type="datetime", plot_height=200, tools = _tools_to_show)
p2.xgrid.grid_line_color=None
p2.ygrid.grid_line_alpha=0.5
p2.xaxis.axis_label = 'Date'
p2.yaxis.axis_label = 'yy'
#Line charts
c11 = p1.line(x='Date', y='xx', source = sc, color = "green")
c12 = p1.circle(x='Date', y='xx', source = sc)
c21 = p2.line(x='Date', y='yy', source = sc, color = "blue")
c22 = p2.circle(x='Date', y='yy', source = sc)
#Text to be displayed over points on the charts.
visible_text1 = Text(x='Date', y='xx', text='xx', text_color='black', text_alpha=0.5)
visible_text2 = Text(x='Date', y='yy', text='yy', text_color='black', text_alpha=0.5)
#Adding text to the graphs
crt1 = p1.add_glyph(sc, visible_text, selection_glyph=visible_text1)
crt2 = p2.add_glyph(sc, visible_text2, selection_glyph=visible_text2)
#This piece of code does display multiple tooltips but shows vague behaviour viz. displaying a tooltip where there is no glyph
hover1 = HoverTool(renderers=[c12, c22], tooltips = TOOLTIPS)
hover2 = HoverTool(renderers=[c22, c12], tooltips = TOOLTIPS1)
#Adding hover tools
p1.add_tools(hover1)
p2.add_tools(hover2)
#Creating a grid for plotting
grid = gridplot([select, p1, p2, p3, p4], ncols=1, plot_width=1000, plot_height=1000)
show(grid)
As of Bokeh 1.2 there is not a good way to accomplish this. There is an open issue about this on GitHub #1547 - Coordinate tooltips across multiple plots that you can follow for updates or add your voice to.
Related
I am working on the project the application is working fine
but small issue with list box,
I created a class where we can call get suggestion from the entry data a sample code is given below
from tkinter import *
root = Tk()
root.geometry('300x300')
search = StringVar()
search1 = StringVar()
search_list = ["Apple", "Ball", "cat", "dog"]
Label(root, text="Search :").pack(pady=15)
search1_ent = Entry(root, textvariable=search)
search1_ent.pack(pady=15)
search2_ent = Entry(root, textvariable=search1)
search2_ent.pack(pady=15)
list_box = Listbox(root, height=10, width=20)
EntryList.EntryBoxListLink(search_list, list_box, search1_ent, search, 90, 87, 20)
root.mainloop()
I created a py file on the name Entry list in that created a class Entry box list link,
It may not be perfect code but worked fine.
the class code is
import contextlib
from tkinter import *
class EntryBoxListLink:
"""this class is created to link entry box and the listbox"""
def __init__(self, list_data='', list_box='', entry_box=None, set_variable='', x_axis=38, y_axis=52, width=20,
next_entry=None):
self.list_data = list_data
self.list_box = list_box
self.entry_box = entry_box
self.set_variable = set_variable
self.x_axis = x_axis
self.y_axis = y_axis
self.width = width
def destroyListBox(event):
"""this is the command when the list box to place forget"""
with contextlib.suppress(BaseException):
self.list_box.place_forget()
def searchIList(event):
"""this gives the list box where the data no are aligned"""
self.list_box.config(width=self.width)
self.list_box.place(x=self.x_axis, y=self.y_axis)
self.list_box.bind('<Leave>', destroyListBox)
self.list_box.bind('<Double-1>', itemsSelected)
self.list_box.bind('<Return>', itemsSelected)
if self.list_data is not None:
match = [i for i in self.list_data if
(self.set_variable.get().lower() or self.set_variable.get().capitalize()) in i]
self.list_box.delete(0, END)
for c in match:
try:
self.list_box.insert(END, c.title())
except BaseException:
self.list_box.insert(END, c)
if not match:
destroyListBox(None)
if self.set_variable.get() == "":
destroyListBox(None)
def itemsSelected(event):
"""when the no is selected from list box it aligned to
the phone number and gives the data"""
for i in self.list_box.curselection():
self.set_variable.set(self.list_box.get(i))
self.entry_box.focus_set()
destroyListBox(None)
if next_entry is not None:
next_entry.focus()
def set_entry_focus(event):
if list_box.curselection()[0] == 0:
return self.entry_box.focus_set()
def focusAndSelect():
self.list_box.focus_set()
self.list_box.select_set(0)
self.entry_box.bind("<KeyRelease>", searchIList)
self.entry_box.bind("<Down>", lambda event: focusAndSelect())
self.list_box.bind("<Up>", set_entry_focus)
the issue is when I select the second entry box the list box should be gone,
to be more frank when the search1 and listbox are not in focus the list box should be place forget!
I would like to add dropdown to a layout that I already have but I'm having issues when I add it. the layout randomly displays the options but not the mainbutton. Is there something am I adding the incorrect widget?
NOTE: I prefer to create my layouts dynamically, so I am not using the kv files. All of the examples I have seen just use the runapp function instead of adding the dropdown to an existing layout.
My Code:
Window.size = (Config.getint('graphics','width'),Config.getint('graphics','height'))
Window.top = 30
Window.left = 10
screen_width = 700
screen_height = 775
Window.clearcolor = color_palette["Royal Purple"]
Window.size = (screen_width,screen_height)
Config.write()
##~ dropdown function ~##
def createDropDown():
dropdown = DropDown()
categories = ['Cat1','Cat2','Cat3','Cat4']
for index in range(len(categories)):
btn = Button(text=categories[index], size_hint_y=None, height=44)
btn.bind(on_release=lambda btn: dropdown.select(btn.text))
dropdown.add_widget(btn)
mainbutton = Button(text='Hello', size_hint=(None, None))
mainbutton.bind(on_release=dropdown.open)
dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
return dropdown
##~~ My main layout class ~~##
class SimpleKivy0(App):
App.title = "New GUI"
btn_width = 0.2
btn_height = 0.05
txt_fld1 = None
entry_fld_Label = None
def build(self):
layout = FloatLayout()
banner_bground = layout.canvas.before
with banner_bground:
Rectangle(pos=(0,screen_height-(screen_height*0.1)),size=(screen_width, screen_height*0.1))
Color(68/255,210/255,201/255,1)
banner_Lbl = Label(text='Quick Query GUI',halign='left',valign='middle',font_size=((screen_height*0.1)*0.7),pos=(0,screen_height-(screen_height*0.1)),size_hint=(1,0.1))
banner_Lbl.bind(size=banner_Lbl.setter('text_size'))
layout.canvas.add(banner_bground)
layout.add_widget(banner_Lbl)
dropdown = createDropDown()
dropdown.size_hint=(.25,.1)
dropdown.pos = (screen_width*0.2,screen_height*0.2)
return layout
if __name__ == "__main__":
SimpleKivy0().run()
The screenshot:
The main thing you were missing is to add the mainbutton to your layout. Here is a working version of some of your code:
def createDropDown(layout):
dropdown = DropDown()
categories = ['Cat1','Cat2','Cat3','Cat4']
for index in range(len(categories)):
btn = Button(text=categories[index], size_hint=(None, None), size=(100,44))
btn.bind(on_release=lambda btn: dropdown.select(btn.text))
dropdown.add_widget(btn)
mainbutton = Button(text='Hello', size_hint=(None, None), size=(100,40), pos=(100,100))
mainbutton.bind(on_release=dropdown.open)
dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
# Add mainbutton to the layout
layout.add_widget(mainbutton)
##~~ My main layout class ~~##
class SimpleKivy0(App):
App.title = "New GUI"
btn_width = 0.2
btn_height = 0.05
txt_fld1 = None
entry_fld_Label = None
def build(self):
layout = FloatLayout()
banner_bground = layout.canvas.before
with banner_bground:
Rectangle(pos=(0,screen_height-(screen_height*0.1)),size=(screen_width, screen_height*0.1))
Color(68/255,210/255,201/255,1)
banner_Lbl = Label(text='Quick Query GUI',halign='left',valign='middle',font_size=((screen_height*0.1)*0.7),pos=(0,screen_height-(screen_height*0.1)),size_hint=(1,0.1))
banner_Lbl.bind(size=banner_Lbl.setter('text_size'))
layout.canvas.add(banner_bground)
layout.add_widget(banner_Lbl)
# create the dropdown and add the mainbutton to the layout
createDropDown(layout)
return layout
For those who are also having an issue with this, I came across an alternative called a spinner. The spinner object worked the same as I intended for the popup.
This is the code I added instead of the dropdown:
def get_spinner_selection(spinner,text):
print(text)
spinner = Spinner(text='Option1',values=('Option1','Option2','Option3'),size_hint=(0.2,0.1),background_color=(169/255,80/255,18/255,1))
spinner.bind(text=get_spinner_selection)
layout.add_widget(spinner)
queryType_Lbl = Label(text='Query Type:',valign='middle',size_hint=self.spinner.size_hint,pos=(spinner.x,spinner.top))
I want to display a decomposition wavelet in 3 level.
so can any help me in give a Matlab function to display it?
[cA cH cV cD]=dwt2(a,waveletname);
out=[cA cH;cV cD];
figure;imshow(out,[]);
That only works for the first level.
actually, I want to representation square mode such wavemenu in Matlab.
example of the view decomposition
I am fairly new to it.
thanx.
You should use the function wavedec2(Image,numberOfLevels,'wname') with the amount of levels that you need.
For more information look at
http://www.mathworks.com/help/wavelet/ref/wavedec2.html
Code for example with db1
clear all
im = imread('cameraman.tif');
[c,s] = wavedec2(im,3,'db1');
A1 = appcoef2(c,s,'db1',1);
[H1,V1,D1] = detcoef2('all',c,s,1);
A2 = appcoef2(c,s,'db1',2);
[H2,V2,D2] = detcoef2('all',c,s,2);
A3 = appcoef2(c,s,'db1',3);
[H3,V3,D3] = detcoef2('all',c,s,3);
V1img = wcodemat(V1,255,'mat',1);
H1img = wcodemat(H1,255,'mat',1);
D1img = wcodemat(D1,255,'mat',1);
A1img = wcodemat(A1,255,'mat',1);
V2img = wcodemat(V2,255,'mat',1);
H2img = wcodemat(H2,255,'mat',1);
D2img = wcodemat(D2,255,'mat',1);
A2img = wcodemat(A2,255,'mat',1);
V3img = wcodemat(V3,255,'mat',1);
H3img = wcodemat(H3,255,'mat',1);
D3img = wcodemat(D3,255,'mat',1);
A3img = wcodemat(A3,255,'mat',1);
mat3 = [A3img,V3img;H3img,D3img];
mat2 = [mat3,V2img;H2img,D2img];
mat1 = [mat2,V1img;H1img,D1img];
imshow(uint8(mat1))
The final result
General question on the speed of (rCharts) highcharts rendering.
Given the following code
rm(list = ls())
require(rCharts)
set.seed(2)
time_stamp<-seq(from=as.POSIXct("2014-05-20 01:00",tz=""),to=as.POSIXct("2014-05-22 20:00",tz=""),by="1 min")
Data1<-abs(rnorm(length(time_stamp))*50)
Data2<-rnorm(length(time_stamp))
time<-as.numeric(time_stamp)*1000
CombData=data.frame(time,Data1,Data2)
CombData$Data1=round(CombData$Data1,2);CombData$Data2=round(CombData$Data2,2);
HCGraph <- Highcharts$new()
HCGraph$yAxis(list(list(title = list(text = 'Data1')),
list(title = list(text = 'Data2'),
opposite =TRUE)))
HCGraph$series(data = toJSONArray2(CombData[,c('time','Data1')], json = F, names = F),enableMouseTracking=FALSE,shadow=FALSE,name = "Data1",type = "line")
HCGraph$series(data = toJSONArray2(CombData[,c('time','Data2')], json = F, names = F),enableMouseTracking=FALSE,shadow=FALSE,name = "Data2",type = "line",yAxis=1)
HCGraph$xAxis(type = "datetime"); HCGraph$chart(zoomType = "x")
HCGraph$plotOptions(column=list(animation=FALSE),shadow=FALSE,line=list(marker=list(enabled=FALSE)));
HCGraph
Produces a highcharts graph of 2 series each 4021 points in length and renders immediately.
However, if I increase the timespan to say 10 days (8341 points) the resulting plot can take several minutes to generate.
I'm aware there are several modifications that can be made to highcharts for better performance,
Highcharts Performance Enhancement Method?,
however, are there any changes I can make from an R / rCharts perspective to speed up performance?
Cheers
I am new to the MVC Framework. Im working on a dashboard project in the MVC framework. The project consists of a bunch of charting control in a user controls contained in a master page. I did a test on a charting control on a aspx page..and it works...but when I moved the code to a ascx (usercontrol) the chart doesnt render. Any ideas?!?!?!...I'm stuck. Thanks in advance
Jeff
Code that is in in the .aspx
<%
System.Web.UI.DataVisualization.Charting.Chart Chart1 = new System.Web.UI.DataVisualization.Charting.Chart();
Chart1.Width = 450;
Chart1.Height = 296;
Chart1.RenderType = RenderType.ImageTag;
Chart1.ImageLocation = "..\\..\\TempImages\\ChartPic_#SEQ(200,30)";
Chart1.Palette = ChartColorPalette.BrightPastel;
Title t = new Title("Program Pipeline", Docking.Top, new System.Drawing.Font("Trebuchet MS", 14, System.Drawing.FontStyle.Bold), System.Drawing.Color.FromArgb(26, 59, 105));
Chart1.Titles.Add(t);
Chart1.ChartAreas.Add("Prog 1");
// create a couple of series
Chart1.Series.Add("Backlog");
Chart1.Series.Add("Constructed");
Chart1.Series.Add("Billed");
Chart1.Series.Add("BudgetUsed");
Chart1.Series.Add("Total");
Chart1.Series["Backlog"].ChartType = SeriesChartType.StackedBar100;
Chart1.Series["Constructed"].ChartType = SeriesChartType.StackedBar100;
Chart1.Series["Billed"].ChartType = SeriesChartType.StackedBar100;
Chart1.Series["Total"].ChartType = SeriesChartType.StackedBar100;
Chart1.Series["BudgetUsed"].ChartType = SeriesChartType.StackedBar100;
Chart1.Series["Backlog"]["DrawingStyle"] = "Cylinder";
Chart1.Series["Constructed"]["DrawingStyle"] = "Cylinder";
Chart1.Series["Billed"]["DrawingStyle"] = "Cylinder";
Chart1.Series["BudgetUsed"]["DrawingStyle"] = "Cylinder";
Chart1.Series["Total"]["DrawingStyle"] = "Cylinder";
// Bar Size
Chart1.Series["Backlog"]["PointWidth"] = "0.6";
Chart1.Series["Constructed"]["PointWidth"] = "0.6";
Chart1.Series["Billed"]["PointWidth"] = "0.6";
Chart1.Series["BudgetUsed"]["PointWidth"] = "0.6";
Chart1.Series["Total"]["PointWidth"] = "0.6";
int _total = 0;
int _newTotalAmt = 100 - _total;
foreach (MvcApplication1.Models.Amount obj in Model.GetTotalAmt("plm1"))
{
_total += obj.TotalAmount;
Chart1.Series[obj.PLMType].Points.AddY(obj.TotalAmount);
}
Chart1.Series["BudgetUsed"].Points.AddY(0);
Chart1.Series["Total"].Points.AddY(_newTotalAmt);
_total = 0;
_newTotalAmt = 100 - _total;
foreach (MvcApplication1.Models.Amount obj in Model.GetTotalAmtForPLM2("plm2"))
{
_total += obj.TotalAmount;
Chart1.Series[obj.PLMType].Points.AddY(obj.TotalAmount);
}
Chart1.Series["BudgetUsed"].Points.AddY(0);
Chart1.Series["Total"].Points.AddY(_newTotalAmt);
_total = 0;
_newTotalAmt = 100 - _total;
foreach (MvcApplication1.Models.Amount obj in Model.GetTotalAmt("plm3"))
{
_total += obj.TotalAmount;
Chart1.Series[obj.PLMType].Points.AddY(obj.TotalAmount);
}
Chart1.Series["BudgetUsed"].Points.AddY(0);
Chart1.Series["Total"].Points.AddY(_newTotalAmt);
// MvcApplication1.Models.TotalPOAmount oTotal = Model.GetOverAllBudget();
// add points to series 3
Chart1.Series["Billed"].Points.AddY(0);
Chart1.Series["Constructed"].Points.AddY(0);
Chart1.Series["Backlog"].Points.AddY(0);
Chart1.Series["BudgetUsed"].Points.AddY(39);
Chart1.Series["Total"].Points.AddY(100);
Chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
Chart1.BorderColor = System.Drawing.Color.FromArgb(26, 59, 105);
Chart1.BorderlineDashStyle = ChartDashStyle.Solid;
Chart1.BorderWidth = 2;
Chart1.Legends.Add("Legend");
// show legend based on check box value
// Chart1.Legends["Legend1"].Enabled = ShowLegend.Checked;
// Render chart control
Chart1.Page = this;
HtmlTextWriter writer = new HtmlTextWriter(Page.Response.Output);
Chart1.RenderControl(writer);
//IList<SelectListItem> list = new List<SelectListItem>();
//SelectListItem sli = new SelectListItem();
//sli.Text = "test1";
//sli.Value = "1";
//list.Add(sli);
//ViewData["Test"] = list;
%>
I've had exactly the same issue. My problem was to do with the paths to the image file. The chart control was getting it wrong when placed on a usercontrol. If I changed the chart to use Imagestoragemode of HttpHandler then it worked as intended.
unfortunatly this stopped me being able to unit test my views. In the end I put the chart control on an aspx page & then used jQuery to load it when needed. (Luckily my dashboard page used javascript to load the contents of the portlets)
I've just been trying to get round what seems to be the same problem. When I moved the code (similar to yours above) to a UserControl the System.Web.UI.DataVisualization namespace wasn't recognised and I received the error:
The type or namespace name
'DataVisualization' does not exist in
the namespace 'System.Web.UI' (are you
missing an assembly reference?)
The namespace only seemed to be recognised when the Chart code lay within an asp control (in the aspx page it was within an <asp:Content> control). So I put the Chart code within an <asp:Panel> control and it worked.