Embedding Bokeh graphs while maintaining linked axis - python

I have linked the x axis of my bokeh graphs together by simply sharing the same x_range:
graph2.x_range = graph1.x_range
When I zoom-in/out or change the x-axis of one graph in any way, the other graph adjust with it. I really like this functionality.
However, when I embed the bokeh graphs in an html template they are not connected anymore.
script, div = components(graphs).
The components function returns a script that contains the data for your plot and provides a target div to display the plot view.
I added script and div in the placeholders of my html template, which is then loaded with Flask.
Everything works fine, but the graphs are not connected anymore.
It looks like the graps are embedded separately and therefore they cannot be linked together. I wonder if there is a method to do this.
If anyone has had this issue before, pls help :)
I used this documentation:
https://docs.bokeh.org/en/2.4.1/docs/user_guide/embed.html

Related

Python interactive plot in browser: drag and drop arbitrary elements

I have my backend in Python and I'm trying to create an interactive plot in the web browser, where the user can drag and drop elements across the plot. The plan is then to hook onto the 'drop' event with some JS that updates values in a form and submits the form, which would then cause the backend to update the plot.
So far I have been using mpld3, but I am not invested in it. I would be open to a solution using some other package like Plotly or Bokeh.
What I am looking for is quite similar to this mpld3 example, except that I want to allow the user to drag objects other than the points. Specifically, I want to create some vertical and horizontal lines and allow the user to drag these horizontally and vertically, as illustrated in this picture:
I have gotten so far as to adapt the mpld3 plugin to actually work with the latest version of d3.js, and I am able to drag the points (see gist). However, I am not able to adapt the plugin to make the vertical lines draggable like the points in the example.
My first idea was something like
lines = ax.vlines(xdata,min(ydata),ydata)
plugins.connect(fig, DragPlugin(lines))
vlines() returns a matplotlib.collections.LineCollection item, and I don't know how to access individual lines inside that. I tried simply modifying the type check inside the __init__ (if isinstance(object, mpl.lines.Line2D) to be more permissive, but that didn't work.
My next idea was to just draw the lines using ax.plot():
lines = []
for i in range(len(xdata)):
from_xy = (xdata[i],min(ydata))
to_xy = (xdata[i],ydata[i])
xs = from_xy[0],to_xy[0]
ys = from_xy[1],to_xy[1]
lines.append(ax.plot(xs,ys, 'k-')[0])
In this case the list lines contains matplotlib.lines.Line2D objects, which I thought would be easier to manipulate individually in mpld3 than a LineCollection. However, the Plugin seems to be written to deal with a the entire set of red points as a Line2D object (like a polygonal chain with invisible edges, if you see what I mean). This is what I conclude from the fact that the string 'pts' is used to find the mpld3 id of the points. Just passing a Line2D object to DragPlugin, however, does not work:
# don't use the suffix:
def __init__(self, object):
self.dict_ = {"type": "drag","id": utils.get_id(object)}
# after defining `lines` as above:
plugins.connect(fig, DragPlugin(lines[0]))
I get the following in the browser console:
Uncaught TypeError: obj.elements(...).data(...).style is not a function
Which gets raised at the following part of the JS:
obj.elements()
.data(obj.offsets)
.style("cursor", "default")
.call(drag);
But I have no idea what that JS is doing and it's not documented in the plugin.
Another thing I will need is to restrict the vertical lines to be only draggable horizontally, and conversely for the horizontal lines. But first I would like to get dragging the lines to work at all.

Generate HTML with plotly graphs and a navbar

I am running a Python pipeline that generates some data files. As a last step of the pipeline, I want to generate a HTML file containing nicely styled graphs representing that data with plotly and a navbar at the top (I will probably have 2 tabs, each one containing different set of charts). This sounds like hard to do with plotly only. How can I achieve this? Should I make an html file with some styling, then just embed the plotly graphs in it? Or should I try to do it solely using plotly?
I did some something similar writing the html (and nav elements) from python and then embedding the charts using the to_html method:
fig.to_html(full_html=False, include_plotlyjs=True)

Folium Multiple map overlays

I'm fairly new to folium so this might be a bit noobish but I'm currently trying to plot several heatmaps of different data-points and add the ability to switch between the heatmaps all on the same plot. So for example I have such:
# The base map
hmap = folium.Map(location=[38.908111, -77.008871], tiles="Stamen Terrain", zoom_start=12)
# And each layer
# Homicide
HeatMap(list(zip(crime_homicide.LATITUDE.values, crime_homicide.LONGITUDE.values))).add_to(folium.FeatureGroup(name='Homicides').add_to(hmap))
# Robbery
HeatMap(list(zip(crime_robbery.LATITUDE.values, crime_robbery.LONGITUDE.values))).add_to(folium.FeatureGroup(name='Robbery').add_to(hmap))
# Assault
HeatMap(list(zip(crime_assault.LATITUDE.values, crime_assault.LONGITUDE.values))).add_to(folium.FeatureGroup(name='Assault').add_to(hmap))
folium.LayerControl(collapsed=False).add_to(hmap)
folium.GeoJson(dc_shape).add_to(hmap)
I tried using folium's FeatureGroup functionality but it looks like thats only specific markers as opposed to whole maps. Is there a way to switch between different maps if they're all heatmaps?
Your code seems fine.
Try this -
hmap.add_child
Or you can try heatmapwithtime as well, specifying different metrics which you can adjust in realtime to see different heatmaps.
But,FeatureGroup() will not seem to work with HeatMapWithTime and adding layers directly to the heatmap results in multiple time sliders on the side when there should be only one (common) time slider for all added layers.
So if you want to have a single control you'll have to put all your data in a single geojson and use that.
Why do you add a feature group? If you want to be able to select which instance of HeatMapWithTime you want to display, you can add both add them to the map, and they should both turn up in layer control.
m = Map()
HeatMapWithTime(data1).add_to(m)
HeatMapWithTime(data2).add_to(m)
FYI, a feature group is meant to group items and display them together. The items themselves don't get added to the map directly. For example:
fg = FeatureGroup().add_to(m)
fg.add_child(Item1)
fg.add_child(Item2)
Also this is the link, might help you :)
https://python-visualization.github.io/folium/plugins.html

Select text in Bokeh plot

I would like to be able to search for specific words in my Bokeh plot. Say that I have a very simple plot:
import numpy as np
from bokeh.plotting import figure, show, output_file
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
TOOLS = "pan,wheel_zoom,box_zoom,reset,save,box_select"
p1 = figure(title="Some sample title", tools=TOOLS)
p1.circle(x,y, legend="sin(x)")
output_file("legend.html", title="legend.py example")
show(p1)
Which results in
I would like to be able to search the text in my browser using [ctrl+f] or [cmd+f]. Is there any way to do that? I would like to be able to search for the title and/or for labels, so in this case, example queries would be one of {sample, title,1,0.5}. Of course this example is hypothetical, but I think it's enough to illustrate the question.
Is there any way to use browser search functionality inside a Bokeh plot?
There is no way to do this in Boken currently, as it renders to an HTML5 canvas object, so the browser just sees the final result of the rendering. If you're willing to use Bokeh's sister library HoloViews, it however has a both Bokeh and SVG backend. When rendered through that SVG backend, your browser will then have access to all the text elements.
To help evaluate plotting libraries to see if they're suitable for your purpose, what you're looking for is basically a SVG backend. Usually it's easy to find a list of supported backends in the documentation of each library.
Also note that "having all individual plot elements accessible to the browser" and "plotting a lot of data points" are conflicting goals. The HTML5 canvas backend works well for plotting lots of data (even more so with datashader) partly because it only exposes the final plot image to the browser. If you want to expose the details of your plot to the browser (e.g via the SVG backend), you should expect to see a performance hit at some point if your plots get bigger (more data) or otherwise more complex, compared to the HTML5 canvas backend.
There is no way to do this. Bokeh plots are not textual DOM elements, everything is rendered on an HTML raster canvas, which the browser only sees as an rectangular area of RGBA pixels.

How to combine two charts into the single PDF using ReportLab?

Question : I'm generating charts using ReportLab. Charts are generated properly but into different PDF. I want to combine them into a single existing pdf.
basic structure of code is
class BreakdownPieDrawing():
def firstChart():
#code for generating first Pie chart
def secondChart():
#code for generating second Pie chart
if __name__=="__main__":
drawing1 = BreakdownPieDrawing()
drawing1.firstChart()
drawing1.save(formats=['pdf'],outDir='.',fnRoot='first')
drawing2 = BreakdownPieDrawing()
drawing2.secondChart()
drawing2.save(formats=['pdf'],outDir='.',fnRoot='second')
for full code Snippets please refer http://www.reportlab.com/snippets/4/
This code produces two separate PDFs. How can i combine them into single PDF.
I tried this to code :
def makePdf(self,drawing):
doc = SimpleDocTemplate('hello.pdf')
doc.build(drawing)
and then after I'm passing "BreakdownPieDrawing" class's object into this method. But this approach is not working.
I'm new to reportLab and python so pardon me for such a ugly code.
So the question is how to add this charts into existing pdf. Any help would be greatly appreciated.
If you look closely at the code snippet you provided (disclaimer: I wrote ;-) ) specifically at line#33 you see
# adding a pie chart to the drawing
self._add(self,Pie(),name='pie',validate=None,desc=None)
That lines adds the Pie chart to the drawing, you will then need to add your second chart to the same drawing you use the _add method, again like the snippet does on line#46 for adding the legend. Your drawing will have the two charts and when you save it as PDF you should get them both.
Are these two charts actually full page? If so, you can just call for a page break between drawing the two. Otherwise you can just adjust the coordinates so that both will fit on the page.
Alternatively, if you are doing something more complicated and will end up using Platypus, it might make sense to create a custom Flowable to render them.

Categories