RangeSlider does not work with scatter plot - bokeh

Is it possible to make the range slider work with a scatter plot? The slider works if I change the scatter to a line plot but that does not work for me as I can not use the box select tool with line plots. The snippet below is simplified to demonstrate the issue. I suspect the embedded JavaScript is the issue but I may be wrong as it works just fine with a line plot. Thanks.
from bokeh.io import show
from bokeh.models import CustomJS, RangeSlider, Column, Row
from bokeh.plotting import figure
x = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
y = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
scatter_plot = figure(width=250, plot_height=600)
scatter_plot.scatter(x, y)
callback = CustomJS(args=dict(y_range=scatter_plot.y_range), code="""
var start = cb_obj.value
y_range.start = start[0]
y_range.end = start[1]
""")
depth_slider = RangeSlider(width=250, show_value=False, start=-20, end=120, value=(20, 80), step=20,
title="Y Scale")
depth_slider.js_on_change('value', callback)
layout = Column(Row(depth_slider), scatter_plot, )
show(layout)

There seems to be some race condition going on or a discrepancy between how Python and JS version of Bokeh work.
By default, all ranges are instances of DataRange1d class which recompute start and end when needed. In this case, it for some reason recomputes the values after you set them manually.
To fix it, specify the range manually from the get go:
scatter_plot = figure(..., y_range=(20, 80))

Related

Using canvas rectangles as buttons to create menus and actions

I am programing a GUI for a device that contains numerous sensors... I need to display their information accordingly... Some of them will require manual input which I want to input via using multiple rectangles used as menu items and adding a tag_bind to them to take action upon being clicked.
If you read carefully... I have attempted to erase the menu that has been pressed so it is not displayed after it is pressed. ( or at least at the last click, go back to only showing the main menu
I am running into an issue with the arguments... I little bit of help would be appreciated.
error: in onSecondClick
canvas.delete(square)
NameError: global name 'square' is not defined
I am able to delete the main menu rectangle but doesn't delete any other... I am a bit stomped
from Tkinter import *
#global square
def onObjectClick(event):
#. print(event.x, event.y)
square = canvas.create_rectangle(40, 50, 150, 100, width=1, fill="#BBB", tags="secondtag")
squaretxt = canvas.create_text(90,70, text="Sub-Menu")
canvas.delete(mainbutton)
canvas.delete(mainbuttontxt)
def onSecondClick(square, *args):
# print(event.x, event.y)
secondsquare = canvas.create_rectangle(60,70,160,110, width=1, fill="#AAA", tags="thirdtag")
secondText = canvas.create_text(110, 90, text="Final Choice")
canvas.delete(square)
def onThirdClick(secondsquare, secondText):
canvas.delete(secondsquare)
canvas.delete(secondText)
root = Tk()
canvas = Canvas(root, width=300, height=200)
mainbutton = canvas.create_rectangle(10, 30, 100, 60, width=5, fill="#666", tags="mainbuttontag")
manibuttontxt = canvas.create_text(55, 45, text="Main Menu", tags="mainbuttontag")
canvas.tag_bind("mainbuttontag", "<ButtonPress-1>", onObjectClick)
canvas.tag_bind('secondtag', "<ButtonPress-1>", onSecondClick)
canvas.tag_bind('thirdtag', "<ButtonPress-1>", onThirdClick)
canvas.pack()
root.mainloop()
I figured out how to do what I needed to do... I have dropped trying to use the canvas variable and used the "tags" option to choose what to delete upon a click action.
Here is the sample code I came up with. Feel free to butcher it if you think I am wrong or if there is a better way to approach this,
from Tkinter import *
txt2 = "Second Square"
txt3 = "Third Square"
global square
global mainbuttontxt
def onObjectClick(event):
square = canvas.create_rectangle(40, 50, 150, 100, width=1, fill="#BBB", tags="secondtag")
squaretxt = canvas.create_text(90,70, text=txt2, tags="secondtag")
canvas.delete("mainbuttontag")
def onSecondClick(event):
secondsquare = canvas.create_rectangle(60,70,160,110, width=1, fill="#AAA", tags="thirdtag")
secondText = canvas.create_text(110, 90, text=txt3, tags="thirdtag")
canvas.delete("secondtag")
def onThirdClick(event):
canvas.delete("thirdtag")
mainbutton = canvas.create_rectangle(10, 30, 100, 60, width=5, fill="#666", tags="mainbuttontag")
manibuttontxt = canvas.create_text(55, 45, text="Main Menu", tags="mainbuttontag")
root = Tk()
canvas = Canvas(root, width=300, height=200)
mainbutton = canvas.create_rectangle(10, 30, 100, 60, width=5, fill="#666", tags="mainbuttontag")
manibuttontxt = canvas.create_text(55, 45, text="Main Menu", tags="mainbuttontag")
canvas.tag_bind("mainbuttontag", '<ButtonPress-1>', onObjectClick)
canvas.tag_bind('secondtag', '<ButtonPress-1>', onSecondClick)
canvas.tag_bind('thirdtag', '<ButtonPress-1>', onThirdClick)
canvas.pack()
root.mainloop()

Problem with plotly Charts Being Deprecated in RStudio

I'm trying to get familiar with plotly's functionality and syntax and have tried several of the scripts provided to compose and render plots of data. However, when generating the plotly output using RStudio I'm getting the following error: "Warning message:
Specifying width/height in layout() is now deprecated.
Please specify in ggplotly() or plot_ly()"
The output image appears jumbled and uninterpretable in the RStudio console and I've tried a few changes like setting the plotly object's width and height equal to null etc without luck.
Here is one of the sample scripts I've used when experiencing this issue:
library(plotly)
trace1 <- list(
x = c("Aug-12", "Sep-12", "Oct-12", "Nov-12", "Dec-12", "Jan-12", "Feb-13", "Mar-13", "Apr-13", "May-13", "Jun-13", "Jul-13"),
y = c(65, 77, 112, 279, 172, 133, 152, 106, 79, 225, 99, 150),
hoverinfo = "x+y+name",
line = list(
color = "#5BC075",
width = "3"
),
mode = "lines",
name = "Median deal size",
type = "scatter",
uid = "a8e83b",
xsrc = "jackluo:508:b357d2",
ysrc = "jackluo:508:d19900"
)
trace2 <- list(
x = c("Aug-12", "Sep-12", "Oct-12", "Nov-12", "Dec-12", "Jan-12", "Feb-13", "Mar-13", "Apr-13", "May-13", "Jun-13", "Jul-13"),
y = c(116, 125, 126, 125, 244, 136, 80, 82, 89, 82, 95, 107),
hoverinfo = "x+y+name",
line = list(
color = "#CC6E55",
width = "3"
),
mode = "lines",
name = "Number of deals",
type = "scatter",
uid = "2be33b",
xsrc = "jackluo:508:b357d2",
ysrc = "jackluo:508:5d533d"
)
data <- list(trace1, trace2)
layout <- list(
autosize = TRUE,
font = list(
family = "Overpass",
size = 12
),
height = 720,
legend = list(
x = 0,
y = -0.1,
bgcolor = "rgba(255, 255, 255, 0)",
orientation = "h"
),
margin = list(
r = 40,
t = 40,
b = 40,
l = 40,
pad = 2
),
title = "",
width = 1280,
xaxis = list(
autorange = TRUE,
nticks = 12,
range = c(0, 11),
rangemode = "tozero",
type = "category"
),
yaxis = list(
autorange = TRUE,
range = c(0, 293.6842105263158),
rangemode = "tozero",
type = "linear"
)
)
p <- plot_ly()
p <- add_trace(p, x=trace1$x, y=trace1$y, hoverinfo=trace1$hoverinfo, line=trace1$line, mode=trace1$mode, name=trace1$name, type=trace1$type, uid=trace1$uid, xsrc=trace1$xsrc, ysrc=trace1$ysrc)
p <- add_trace(p, x=trace2$x, y=trace2$y, hoverinfo=trace2$hoverinfo, line=trace2$line, mode=trace2$mode, name=trace2$name, type=trace2$type, uid=trace2$uid, xsrc=trace2$xsrc, ysrc=trace2$ysrc)
p <- layout(p, autosize=layout$autosize, font=layout$font, height=layout$height, legend=layout$legend, margin=layout$margin, title=layout$title, width=layout$width, xaxis=layout$xaxis, yaxis=layout$yaxis)
p$x$layout$width <- NULL
p$x$layout$height <- NULL
p$width <- NULL
p$height <- NULL
p
Any help resolving this issue so charts are correctly scaled and legible would be much appreciated!
As #NoahOlsen suggested, you need to format your x-axis values as a date.
trace1$x <- as.Date(paste0("01-", trace1$x), format = "%d-%b-%y")
trace2$x <- as.Date(paste0("01-", trace2$x), format = "%d-%b-%y")
Explanation
as.Date() tries to format an input into a date object. It works well with ISO date strings (e.g., 2019-04-21), but needs some help with more tricky formats.
From ?strptime:
%d - Day of the month as decimal number (01–31).
%b - Abbreviated month name in the current locale on this platform. (Also matches full name on input: in some locales there are no abbreviations of names.)
%Y - Year with century. Note that whereas there was no zero in the original Gregorian calendar, ISO 8601:2004 defines it to be valid (interpreted as 1BC): see https://en.wikipedia.org/wiki/0_(year). Note that the standards also say that years before 1582 in its calendar should only be used with agreement of the parties involved. For input, only years 0:9999 are accepted.
Furthermore, we also need a specific day of the month. As it does not exist in your data, I added 01- via paste0() to every value of the date vector. Other values, such as 15-, would also have been a valid choice (depending on your data and what type of output you expect). This way, we can make the function recognize your date via format = "%d-%b-%y".
Check out ?as.Date and ?strptime for more information. Ping me if you require further guidance. Happy to help.
It looks like your X axis is a character rather than a date so the axis is sorted alphabetically rather than chronologically. I would try making the x values dates.

Resizing custom markers in Leaflet for R

I am interested in making custom icons while using Leaflet in R.
The documentation has a nice example, but when experimenting with it, I realized that there is no way to allow the custom marker to resize when the map changes size.
Since size is one of the parameters and is fixed (iconWidth = 38, iconHeight = 95,), obviously the marker will stay consistently sized as zoom changes for map beneath it.
greenLeafIcon <- makeIcon(
iconUrl = "http://leafletjs.com/docs/images/leaf-green.png",
iconWidth = 38, iconHeight = 95,
iconAnchorX = 22, iconAnchorY = 94,
shadowUrl = "http://leafletjs.com/docs/images/leaf-shadow.png",
shadowWidth = 50, shadowHeight = 64,
shadowAnchorX = 4, shadowAnchorY = 62
)
Are there any hacks / ideas / protocols for having custom icons resize along with zoom?

use sm.density.compare to plot density functions, draw lines for each mode and get the mode values back

I have got dive depth data for seabirds over several trips and I would like to find the modes for each trip, plot the density functions and a line corresponding to the modes. So far, here's the code I have been using:
maxdepths<-read.csv("maximum_depths.csv", header=T)
maxdepths_ind21<-maxdepths[maxdepths$bird=="21",]
# create value labels
trip.f <- factor(maxdepths_ind21$trip, levels= c(21.1,21.2,21.3,21.4,21.5,21.6,21.7,21.8),
labels = c("Trip1", "Trip2", "Trip3", "Trip4", "Trip5", "Trip6", "Trip7", "Trip8"))
# plot densities
z<-sm.density.compare(maxdepths_ind21$maxdep, maxdepths_ind21$trip,model="equal")
sm.density.compare(maxdepths_ind21$maxdep, maxdepths_ind21$trip, xlab="Maximum depth (m)", xlim=c(0, 90), axes=F)
title(main="Maximum dive depth by trip, individu 21")
axis(side = 1, at = c(0,5,10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90))
axis(side = 2, at = c(0,0.01,0.02,0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 1))
# add legend via mouse click
colfill<-c(2:(2+length(levels(trip.f))))
legend(locator(1), levels(trip.f), fill=colfill)
The result looks good, ie I've got one curve per trip with different colours/line types per trip.
I now would like to draw lines for each trip when the density functions are maximized, as well as find those values. I am aware of this thread
R: getting data (instead of plot) back from sm.density.compare
and I have tried assigning the result of sm.density.compare to an object and then calling it, like so:
z<-sm.density.compare(maxdepths_ind21$maxdep, maxdepths_ind21$trip,model="equal")
z
I was looking for the values of the modes within this output but I got confused by all the values that are returned.
Any help would be much appreciated!
TIA

How do I plot two models into one graph

I used DoseFinds to building the two models and I want to
plot both model on the same graph to compare.
library(DoseFinding)
doses <- c(0, 10, 25, 50, 100, 150)
fmodels <- Mods(emax = 25,
doses=doses, placEff = 0.5, maxEff = -0.4,
addArgs=list(scal=200))
fmodels2 <- Mods(emax = 25,
doses=doses, placEff = -1.5, maxEff = -1.4,
addArgs=list(scal=200))
plot(fmodels)
plot(fmodels2)
Combine the two things into one object:
doses <- c(0, 10, 25, 50, 100, 150)
fmodels2 <- Mods(emax = c(25,25),
doses=doses, placEff = c(0.5,-1.5), maxEff = c(-0.4,-1.4),
addArgs=list(scal=200))
then plot with superpose=TRUE:
plot(fmodels2, superpose=TRUE)
The two lines don't overlap much so although it looks like two separate graphs, it isnt!
I guess you want to use superpose = TRUE when you call the plot-function (?plot.Mods). This will plot the models in the same graph if they are in the same Mods-object. See ?Mods for how to have more than one model in the same object.

Resources