Place the chart in a popup

I use plotly for R, although I am open to using the Python version. When I wrap myself around a datapoint, is there a way to get the popup to contain another graph? Ideally, the chart will be created from the data, although I can use a static image as a backup.

I'm not sure where to start, and I apologize in advance for the lack of MWE.

+7
python r plot plotly
source share
3 answers

Solution 1: stick with R

Thanks @MLavoie. In the following example, use pure R to create two plots, "mainplot" and "hover," which respond to the hover event of the first.

 library(shiny) library(plotly) ui <- fluidPage( plotlyOutput("mainplot"), plotlyOutput("hover") ) server <- function(input, output) { output$mainplot <- renderPlotly({ # https://plot.ly/r/ d <- diamonds[sample(nrow(diamonds), 1000), ] plot_ly(d, x = carat, y = price, text = paste("Clarity: ", clarity), mode = "markers", color = carat, size = carat, source="main") }) output$hover <- renderPlotly({ eventdat <- event_data('plotly_hover', source="main") # get event data from source main if(is.null(eventdat) == T) return(NULL) # If NULL dont do anything point <- as.numeric(eventdat[['pointNumber']]) # Index of the data point being charted # draw plot according to the point number on hover plot_ly( x = c(1,2,3), y = c(point, point*2, point*3), mode = "scatter") }) } shinyApp(ui, server) 

In this example, use shiny binds for plotly . For each hover event, a POST request is sent to the server, after which the server updates the pop-up window. This is very inefficient, and therefore may not work well on slow connections.

The above code is for demonstration purposes only and has not yet been verified. See a working and more complex example here (with source ).

Solution 2: Javascript

Yes, you can do this using the graphical Javascript API .

Short answer

  • Create your schedule using R or Python or any other supported language.
  • Paste the graph into a new HTML page and add a callback function, as shown in the example below. If you have good knowledge of the DOM , you can also add JS to the original HTML instead of creating a new one.
  • Draw a popup graph inside the callback function that takes parameters containing datatype data on hover.

More details

As mentioned in @MLavoie, a good example is shown in plotly.hover-events

Let me paste the code. The JS file has a callback function attached to Plot :

 Plot.onHover = function(message) { var artist = message.points[0].x.toLowerCase().replace(/ /g, '-'); var imgSrc = blankImg; if(artistToUrl[artist] !== undefined) imgSrc = artistToUrl[artist]; Plot.hoverImg.src = imgSrc; }; 

Above, artistToUrl is a huge object filled with a base64 string that I will not insert here to flood the message. But you can see it under the JS tab on the example page. It has the following structure:

 var artistToUrl = { 'bob-dylan': 'data:image/jpeg;base64,/...',...} 

Working example:

For a demonstration, I will prepare a simple example here (click to try):

 <!DOCTYPE html> <html> <head> <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> </head> <body> <iframe id="plot" style="width: 900px; height: 600px;" src="https://plot.ly/~jackp/10816.embed" seamless></iframe> <div id="myDiv"></div> <script> (function main() { var Plot = { id: 'plot', domain: 'https://plot.ly' }; Plot.onHover = function(message) { var y = message.points[0].y; /*** y value of the data point(bar) under hover ***/ var line1 = { x: [0.25,0.5,1], /*** dummy x array in popup-chart ***/ y: [1/y, 2, y], /*** dummy y array in popup-chart ***/ mode: 'lines+markers' }; var layout = { title:'Popup graph on hover', height: 400, width: 480 }; Plotly.newPlot('myDiv', [ line1 ], layout); // this finally draws your popup-chart }; Plot.init = function init() { var pinger = setInterval(function() { Plot.post({task: 'ping'}); }, 500); function messageListener(e) { var message = e.data; if(message.pong) { console.log('Initial pong, frame is ready to receive'); clearInterval(pinger); Plot.post({ 'task': 'listen', 'events': ['hover'] }); } else if(message.type === 'hover') { Plot.onHover(message); } } window.removeEventListener('message', messageListener); window.addEventListener('message', messageListener); }; Plot.post = function post(o) { document.getElementById(Plot.id).contentWindow.postMessage(o, Plot.domain); }; Plot.init(); })(); </script> </body> </html> 

This is modified from poltly.hover-events for python. Instead of onhover up the image, I modify the onhover to build a curve based on the y value for each row.

The main diagram is generated by python and inserted here as an iframe . You can make your own in any language, including R On this page, we will add <div id="myDiv"></div> and use plotly.js to draw a pop-up chart.

Export R data frame to JS enviornment

Shiny uses jsonlite to convert R objects to json and send them to the client. We can use the same mechanism to pack and send our data frame so that the JS callback can use the data to display a pop-up chart.

server.r

 output$json <- reactive({ paste('<script>data =', RJSONIO::toJSON(your_data_frame, byrow=T, colNames=T),'</script>') 

ui.r

 fluidPage(..., htmlOutput("json"), ...) 

In the JS callback function, you can use data like any other JS objects.

More details here and here .

+8
source share

If you want to stick with R , you can use Shiny to get an almost desired result. When you hover over each point, the image will be displayed under the main chart. In the example below, I used the first three rows of the mtcars . To run the code you need only 3 logos / images corresponding to the name of the first three lines (in mtcars$name , Mazda RX4 , Mazda RX4 Wag , Datsun 710 in this example).

  library(shiny) library(plotly) datatest <- diamonds %>% count(cut) datatest$ImageNumber <- c(0, 1, 2, 3, 4) datatest$name <- c("Image0", "Image1", "Image2", "Image3", "Image4") ui <- fluidPage( plotlyOutput("plot"), # verbatimTextOutput("hover2"), #imageOutput("hover"), plotlyOutput("hover3") ) server <- function(input, output, session) { output$plot <- renderPlotly({ plot_ly(datatest, x = cut, y = n, type = "bar", marker = list(color = toRGB("black"))) }) selected_image <- reactive({ eventdat <- event_data('plotly_hover', source = 'A') ImagePick <- as.numeric(eventdat[['pointNumber']]) sub <- datatest[datatest$ImageNumber %in% ImagePick, ] return(sub) }) # output$hover2 <- renderPrint({ #d <- event_data("plotly_hover") #if (is.null(d)) "Hover events appear here (unhover to clear)" else d #}) # output$hover <- renderImage({ # datag <- selected_image() #filename <- normalizePath(file.path('/Users/drisk/Desktop/temp', # paste(datag$name, '.png', sep=''))) # Return a list containing the filename and alt text # list(src = filename, # alt = paste("Image number", datag$name)) # }, deleteFile = FALSE) output$hover3 <- renderPlotly({ datag <- selected_image() # draw plot according to the point number on hover plot_ly(data=datag, x = ImageNumber, y = n, mode = "scatter") }) } shinyApp(ui, server) 

enter image description here

+3
source share

It seems that the answers you posted are not working for you @Adam_G. I studied similar libraries for my own work and determined that Plot.ly not always the right way when you need advanced features. Have you seen the bokeh ? It is mainly designed for this type of task and is much easier to implement (also the Plot.ly library, for example Plot.ly ). Here is a copy of his example in which you can move the slider to change the graph of the data (similar to the example posted by @gdlmx for Plot.ly, but you can use it without posting it on the website). I added the flexx package flexx that you can use this entry in pure Python (without JavaScript - it can translate Python functions to JavaScript ( CustomJS.from_py_func(callback) ) https://github.com/zoofIO/flexx-notebooks/blob/master /flexx_tutorial_pyscript.ipynb ):

 from bokeh.io import vform from bokeh.models import CustomJS, ColumnDataSource, Slider from bokeh.plotting import figure, output_file, show import flexx output_file("callback.html") x = [x*0.005 for x in range(0, 200)] y = x source = ColumnDataSource(data=dict(x=x, y=y)) plot = figure(plot_width=400, plot_height=400) plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6) def callback(source=source): data = source.get('data') f = cb_obj.get('value') #this is the bokeh callback object, linked to the slider below x, y = data['x'], data['y'] for i in range(len(x)): y[i] = x[i]**f #the slider value passed to this function as f will alter chart as a function of x and y source.trigger('change') #as the slider moves, the chart will change slider = Slider(start=0.1, end=4, value=1, step=.1, title="power", callback=CustomJS.from_py_func(callback)) layout = vform(slider, plot) show(layout) 

See here the actual example in action: http://bokeh.pydata.org/en/0.10.0/docs/user_guide/interaction.html#customjs-for-widgets

To integrate with hover events, see here ( from bokeh.models import HoverTool ): http://bokeh.pydata.org/en/0.10.0/docs/user_guide/interaction.html#customjs-for-hover

Guidance Example:

 from bokeh.plotting import figure, output_file, show, ColumnDataSource from bokeh.models import HoverTool output_file("toolbar.html") source = ColumnDataSource( data=dict( x=[1, 2, 3, 4, 5], y=[2, 5, 8, 2, 7], desc=['A', 'b', 'C', 'd', 'E'], ) ) hover = HoverTool( tooltips=[ ("index", "$index"), ("(x,y)", "($x, $y)"), ("desc", "@desc"), ] ) p = figure(plot_width=400, plot_height=400, tools=[hover], title="Mouse over the dots") p.circle('x', 'y', size=20, source=source) show(p) 

Looking at the 1st code, you can put any formula that you need under the def callback function - some of them are required. You can get a hang to change the graph next to it ( hform(leftchart, rightchart) or above / below it ( vform(topchart, bottomchart) )). This is passed as CustomJS , which uses bokeh to allow expandability, and flexx allows you to write this in Python.

An alternative is to set up what you want to configure on the hover tooltips using HTML (although this example puts images in dictionaries instead of new graphs from the base data): http://bokeh.pydata.org/en/0.10.0/docs/user_guide /tools.html#custom-tooltip

+2
source share

All Articles