Embedding multiple bokeh HTML plots into flask - html

I've searched for the past 3 hours on the bokeh website and stack overflow but none of it is really what i was looking for.
I've generated my plots already, and have them in html files. All i want to do is embed the plots into my dashboard in a multi grid like formation in the white area in the pic below. However, adding just 2 plots cause them to overlay and be really weird.
I used the {{ include }} method to include the graphs this way:
Anyone can give me pointers on how to align them well? Ideally i want 6 small plots in that space. I didnt want to regenerate the plots everytime i loaded the dashboard so i didnt want the embed way.
Please help :( Thank you so much!
EDIT: following big's suggestion, using responsive = True works, but i am unable to control the css styling and the sizes of the charts. I suspect its to do with using the include tag. can anyone help? :)

Why you dont try to make it with the horizontal layout
horizontal-layout
Whith your way ( {% include %} ), i don't find a solution so probably sou must use the standart flask way. Python file:
#Your imports
from flask import Flask, render_template
from bokeh.embed import components
from bokeh.plotting import figure
#app.route('/')
def homepage():
title = 'home'
from bokeh.plotting import figure
#First Plot
p = figure(plot_width=400, plot_height=400, responsive = True)
p.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)
#Second Plot
p2 = figure(plot_width=400, plot_height=400,responsive = True)
p2.square([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="olive", alpha=0.5)
script, div = components(p)
script2, div2 = components(p)
return render_template('index.html', title = title, script = script,
div = div, script2 = script2, div2 = div2)
Your HTML file:
<!DOCTYPE html>
<html lang="en">
<head>
<link
href="http://cdn.bokeh.org/bokeh/release/bokeh-0.11.1.min.css"
rel="stylesheet" type="text/css">
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-0.11.1.min.js"></script>
<meta charset="UTF-8">
<title>{{title}}</title>
</head>
<body>
<div style="width: 20%; display: inline-block;">
{{ div | safe }}
{{ script | safe }}
</div>
<div style="width: 20%; display: inline-block;">
{{ div2 | safe }}
{{ script2 | safe }}
</div>
</body>
</html>
And one other tip is to make a python file like my_plots.py
and add your plots there, and then import to you main.py it will make your code cleaner. (i dont know 100% if this will impact your speed, but i don't seen any isues until now ) For example.
my_plots.py:
from bokeh.plotting import figure
def first_plot():
p = figure(plot_width=400, plot_height=400, responsive = True)
p.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)
return p
def second_plot():
p2 = figure(plot_width=400, plot_height=400, responsive = True)
p2.square([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="olive", alpha=0.5)
return p2
main.py:
#app.route('/')
def homepage():
title = 'home'
#First Plot
from my_plots import first_plot
p = first_plot()
#Second Plot
from my_plots import second_plot
p2 = second_plot()
script, div = components(p)
script2, div2 = components(p)
return render_template('index.html', title = title, script = script,
div = div, script2 = script2, div2 = div2)
Hope i was helpful, Good Luck!

Updating Leo's answer as it is for the deprecated version of Bokeh.
Bokeh v3.0.1
Flask v2.2.2
Flask App
from flask import Flask, render_template
from bokeh.embed import components
from bokeh.plotting import figure
app = Flask(__name__)
#app.route('/')
def homepage():
title = 'home'
from bokeh.plotting import figure
### First Plot ###
p1 = figure(height = 400, sizing_mode = "stretch_width")
p1.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)
### Second Plot ###
p2 = figure(height = 400, sizing_mode = "stretch_width")
p2.square([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="olive", alpha=0.5)
script1, div1 = components(p1)
script2, div2 = components(p2)
return render_template(
'index.html',
title = title,
script = script1,
div = div1,
script2 = script2,
div2 = div2
)
if __name__ == '__main__':
app.run(debug=True)
HTML Template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bokeh/3.0.1/bokeh.min.js"
integrity="sha512-p7EUyPmeDeOwHiu7fIZNboAcQLxei3sWtXoHoShWWiPNUSRng/Xs5JPcaFPRa4dKy9IuHjyIQuLE4caGCwuewA=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<title>Bokeh Charts</title>
</head>
<body>
<div style="width: 40%; display: inline-block;">
{{ div1 | safe }}
{{ script1 | safe }}
</div>
<div style="width: 40%; display: inline-block;">
{{ div2 | safe }}
{{ script2 | safe }}
</div>
</body>
</html>

Related

how to integrate python with html using jinja

Here I am using jinja template to integrate python with html. Backend code has been written to fetch images one after another from folder and count the number of objects in an image and display it on front end.There is one container for live image, another container for preview image and the total count box it should display on dashboard.
mian.py
app=Flask(__name__)
#app.route('/')
def welcome():
return render_template("index.html")
#app.route('/')
def count(photo):
image = cv2.imread(f"C:/Users/suhas/Documents/New folder/templates/static/photos/{photo}")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
plt.imshow(gray, cmap='gray')
#plt.show()
blur = cv2.GaussianBlur(gray, (11, 11), 0)
plt.imshow(blur, cmap='gray')
plt.show()
canny = cv2.Canny(blur, 25, 205, 2)
plt.imshow(canny, cmap='gray')
dilated = cv2.dilate(canny, (1, 1), iterations=2)
plt.imshow(dilated, cmap='gray')
(cnt, hierarchy) = cv2.findContours(
dilated.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
cv2.drawContours(rgb, cnt, -1, (0, 255, 0), 2)
bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
imS = cv2.resize(rgb, (540, 340))
text = "Total count:"+str(len(cnt))
# font
font = cv2.FONT_HERSHEY_SIMPLEX
# org
org = (220, 325)
# fontScale
fontScale = 1
# Red color in BGR
color = (0, 0, 255)
# Line thickness of 2 px
thickness = 2
# Using cv2.putText() method
imag = cv2.putText(imS, text, org, font, fontScale,
color, thickness, cv2.LINE_AA, False)
cv2.imshow('output', imag)
img=print(f"Total numbe:{photo}", len(cnt))
cv2.waitKey(1)
time.sleep(10)
cv2.destroyAllWindows()
cnt = 0
# return 1
while 1:
photo=os.listdir("C:/Users/suhas/Documents/New folder/templates/static/photos/")
# if len(photo)==0:
# break
for i in photo:
count(i)
shutil.move("C:/Users/suhas/Documents/New folder/templates/static/photos/%s"%(i),"C:/Users/suhas/Documents/New folder/templates/static/move")
print("------")
time.sleep(10)
return render_template("index.html",live='photo',preview='img',TotalCount='text')
if __name__=="__main__":
app.run()
HTML
</div>
<div class="videoSection">
<div class="liveVideoContainer">
<h3>Live</h3>
{% for img in live %}
<img src=" {{url_for('static',filename= img )}} " width="80" height="142">
{% endfor %}
<div class="previewVideoContainer">
<h3>Preview</h3>
<img src="{{url_for('static',filename= preview)}} " width="80" height="142">
' </div>
<footer>
<div class="count">
<h3>{{Totalcount}}</h3>
</div>
</footer>
</div>

Formatting issue with HTML template for r Shiny output table

I'll preface this by saying that I used to decent at HTML a couple of decades ago but I think I missed the connection with R. I'm trying to display some text and pass some variables. That is working great (I modified some basic code). However, I'm unable to change the format as everything is showing in one column instead of several. I tried a few things in vain. I have a feeling it's really basic but any help would be greatly appreciated.
Here is the HTML file :
<div class="aimm-score-table">
<ul class="aimm-score-row">
<li>Potential Score</li><li>Likelihood factor</li><li>Score</li>
</ul>
<ul class="aimm-score-row">
<li id="{{ ns('aimm_score_potential_score') }}"></li>
<li>--</li>
<li id="{{ ns('aimm_score_likelihood_factor') }}"></li>
<li>=</li>
<li id="{{ ns('aimm_score_score') }}"></li>
</ul>
<ul class="aimm-score-row">
<li>Rating</li>
<li id="{{ ns('aimm_score_rating') }}"></li>
</ul>
</div>
This is what I get :
This is what I want :
Here is a way. Of course you will have to change the CSS if you want other borders, etc.
library(htmltools)
tbl <- withTags(
table(
tbody(
tr(
td(colspan = 3, class="col3", "Potential"),
td(colspan = 3, class="col3", "Likelihood"),
td(colspan = 3, class="col3", "Ex-Ante")
),
tr(
td(),
td("88"),
td(colspan = 2, class="col2", "-"),
td("17"),
td(colspan = 2, class="col2", "="),
td("61"),
td()
),
tr(
td(colspan = 3, class="col3"),
td(colspan = 3, class="col3"),
td(colspan = 3, class="col3", "Good")
)
)
)
)
browsable(
tagList(
tags$style(
HTML(
"table {width: 400px; table-layout: fixed}",
"table, td {border: 1px solid black}",
"td {text-align: center}",
"td.col3 {width: calc(100% / 3)",
"td.col2 {width: calc(100% * 2 / 9)",
"td {width: calc(100% / 9)"
)
),
tbl
)
)
Stéphane Laurent many thanks, I integrated your code to my html template and this works like a charm.
#YBS I'm not familiar with the use of htmltable but I had to find a way to recycle variables stored under a www/ folder that are called from my ui :
htmlTemplate(
filename = "www/html/aimm_score_table.html",
ns = ns
),
and use an html table seemed the only way, I'm not used to combining different types of codes and storing stephanes as a template was the most straightforward. Thank you both!

Django 1.11 How to display template variable from within HTML saved in model for CMS Site

Within a template, I need to render a {{ variable }} from HTML content saved in a model instance.
Below are the stripped down parts of the code.
page.html
{% load static %}
<html>
<head>
<styles, links, etc.>
<title>{{ object.title }}</title>
</head>
<body>
<div>{{ object.html_content }}</div>
</body>
</html>
Model
class Page(models.Model):
title = models.CharField(max_length=30)
html_content = models.TextField()
GlobalMixin
# Used site wide for Global information.
class GlobalMixin(object):
def get_context_data(self, *args, **kwargs):
context = super(GlobalMixin, self).get_context_data(*args, **kwargs)
context['variable'] = "A Global piece of information"
return context
View
from .mixins import GlobalMixin
from .models import Page
PageView(GlobalMixin, generic.DetailView):
model = Page
template_name = "my_app/page.html"
def get_context_data(self, *args, **kwargs):
context = super(PageView, self).get_context_data(*args, **kwargs)
return context
Admin & HTML Content Field
I then enter admin, add new Page, enter my HTML content into html_content Field "Html Content" as per the following example.
<p>This is {{ variable }} that I need to display within my rendered page!</p>
Then SAVE.
BROWSER RESULTS
This is {{ variable }} that I need to display within my loaded page!
I know there is Django Flat Pages, but it doesn't look like it works for me as I require Global variables in my templates that flat pages doesn't offer.
The template is being rendered directly with the models content without looking at it.
I think I need to process the html_content field in the view and then add the required context variables to the context returned or save a temporary template file, append the html_content into the file, then render it.
How do I do make this work?
Is there a Django packaged interface that I can use to process the template from within my view?
I worked it out. Here's the code if anyone else comes across this or has a better way, please share.
Change View type to TemplateView, use slug in url to get model instance, use django.template.engines to convert the string to a template object then render the template object and return it in the context.
page.html
{% load static %}
<html>
<head>
<styles, links, etc.>
<title>{{ object.title }}</title>
</head>
<body>
<!-- <div>{{ object.html_content }}</div> -->
<div>{{ html_content }}</div>
</body>
</html>
views.py
from django.views.generic.base import TemplateView
from .mixins import GlobalMixin
from .models import Page
# NEW
from django.shortcuts import get_object_or_404
from django.template import engines
PageView(GlobalMixin, TemplateView): # generic.DetailView
# model = Page
template_name = "my_app/page.html"
def get_context_data(self, *args, **kwargs):
context = super(PageView, self).get_context_data(*args, **kwargs)
# NEW
context['object'] = get_object_or_404(Page, slug=self.kwargs['slug'])
t = engines['django'].from_string(context['object'].html_content)
context['html_content'] = t.render(context=context, request=None)
return context
I thought you could use custom filter like below.
file path
yourapp/templatetags/__init__.py
yourapp/templatetags/filters.py
filters.py
from django import template
import re
register = template.Library()
#register.filter(name="change_global_variable")
def change_global_variable(value):
return re.sub(r'\{\{(.*)\}\}', 'A global piece', value)
template
{% load static %}
{% load filters %} //filters.py//
<html>
<head>
<styles, links, etc.>
<title>{{ object.title }}</title>
</head>
<body>
<div>{{ object.html_content | change_global_variable}}</div>
</body>
</html>

How to adjust height and formatting of rows in Bokeh DataTable

I'm trying to adjust the font-size of the title and cells and pop-up message of a bokeh DataTable.
When doing so using the HTMLTamplateFormatter I can get the font-size to increase, however, I do not know how to increase the height of a row.
Also I have no clue how to adjust the formatting/height of the top/title cell of the column.
I was able to make the title bold using the information provided at this issue. Is there a similar piece of code I could use to increase the font-size.
When hovering a cell I want to show some information, I would also like to format this, is that possible? And if so how?
This is a minimal example of what I currently have:
import pandas
from bokeh.models import (ColumnDataSource, TableColumn, DataTable)
from bokeh.models.widgets import HTMLTemplateFormatter
from bokeh.io import show
data = pandas.DataFrame({"x": [1, 2, 3, 4],
"y": [200, 3, 4, 5]})
source = ColumnDataSource(data=data)
columns = []
# column 1 with bold title: x and 200% font-size
template200 = """
<div title="<%= x %>" style="font-size: 200%">
<%= value %>
</div>
"""
htmltemplateformatter200 = HTMLTemplateFormatter(template=template200)
col = "x"
title = "<b>%s</b>" % col
columns.append(TableColumn(field=col, title=title,
width=50, editor=None,
formatter=htmltemplateformatter200))
# column 2 with normal title: y and 400% font-size
template400 = """
<div title="<%= x %>" style="font-size: 400%">
<%= value %>
</div>
"""
htmltemplateformatter400 = HTMLTemplateFormatter(template=template400)
col = "y"
columns.append(TableColumn(field=col, title=col,
width=50, editor=None,
formatter=htmltemplateformatter400))
data_table = DataTable(source=source, columns=columns, row_headers=False,
sortable=False)
show(data_table)
This code will make the text in the table cell bigger. However, when I change the size to 400% the text is larger than the height of the row can visualize.
Could anyone help me with this?
Cheers,
Dave
First edit:
To show what I want to be able to do:
In my case I think I would only need a single row height since I want all the font-sizes to be the same.
Second edit:
After the reply of Okonomiyaki I looked at my code again and came up with the following solution:
main.py:
import pandas
from bokeh.models import (ColumnDataSource, TableColumn, DataTable)
from bokeh.models.widgets import HTMLTemplateFormatter
from bokeh.io import curdoc
data = pandas.DataFrame({"x": [1, 2, 3, 4],
"y": [200, 3, 4, 5]})
source = ColumnDataSource(data=data)
columns = []
# column 1 with bold title: x and 20px font-size
template200 = """
<div title="<%= x %>" style="font-size: 20px;">
<%= value %>
</div>
"""
htmltemplateformatter200 = HTMLTemplateFormatter(template=template200)
col = "x"
title = "<b>%s</b>" % col
columns.append(TableColumn(field=col, title=title,
width=50, editor=None,
formatter=htmltemplateformatter200))
# column 2 with bold title: y and 20px font-size
template400 = """
<div title="<%= y %>" style="font-size: 20px;">
<%= value %>
</div>
"""
htmltemplateformatter400 = HTMLTemplateFormatter(template=template400)
col = "y"
columns.append(TableColumn(field=col, title=col,
width=50, editor=None,
formatter=htmltemplateformatter400))
data_table = DataTable(source=source, columns=columns, row_headers=False,
sortable=False, height=1000, fit_columns=True)
curdoc().add_root(data_table)
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function() {
$( document ).tooltip();
});
</script>
<meta charset="utf-8">
{{ bokeh_css }}
{{ bokeh_js }}
<style>
{% include 'jquery-ui.css' %}
{% include 'styles.css' %}
</style>
</head>
<body>
<div class="content">
{{ plot_div|indent(8) }}
</div>
{{ plot_script|indent(8) }}
</body>
</html>
styles.css:
.ui-tooltip {
padding: 8px;
position: absolute;
z-index: 9999;
max-width: 500px;
-webkit-box-shadow: 0 0 5px #aaa;
box-shadow: 0 0 5px #aaa;
opacity: 1;
font-size: 20px;
}
So few things, it turns out it is not possible to have variable row heights with a data_table. This is a restriction set by the underlying Js library - Slick Grid.
https://groups.google.com/a/continuum.io/forum/#!topic/bokeh/cg01WWfpdhw
Some discussion relevant to bokeh here.
You can however easily have variable styles on each row, and this can be set within python. Having the text/styles change is easier done with an external css sheet - although could be done within the HTML formatter, but quite messily.
Create the following app structure: (to run in command prompt type bokeh serve --show myapp)
myapp
|
+---main.py
|---templates
+---index.html
+---styles.css
main.py (contained within myapp directory) :
import pandas
from bokeh.models import (ColumnDataSource, TableColumn, DataTable)
from bokeh.models.widgets import HTMLTemplateFormatter
from bokeh.io import show, curdoc
x0 = [1,"8px", "red", "bold", "hover 1"]
x1 = [2,"10px", "blue", "italic", "hover 2"]
x2 = [3,"12px", "green", "bold", "hover 3"]
x3 = [4,"14px", "orange", "strong", "hover 4"]
x = [x0,x1,x2,x3]
data = pandas.DataFrame({"x": x,
"y": [200, 3, 4, 5]})
source = ColumnDataSource(data=data)
columns = []
# now in the formatter value[0] = original x value
# value[1] = desired font size
# value[2] = desired font color
# value[3] = desired font style
# value[4] = text to display on hover
# you could feed in any styles you want, or do it externally via css + js
template200 = """
<div title="<%= x %>" style="font-size: <%= value[1]%> ;
color: <%=value[2]%>; font-weight:<%=value[3] %>;" >
<div class = "parent_div">
<span class="nonhover"> <%= value[0] %> </span>
<span class= "cell_hover"><%= value[4]%></span> </div>
</div>
"""
htmltemplateformatter200 = HTMLTemplateFormatter(template=template200)
col = "x"
title = "<b>%s</b>" % col
columns.append(TableColumn(field=col, title=title,
width=50, editor=None,
formatter=htmltemplateformatter200))
# column 2 with normal title: y and 400% font-size
template400 = """
<div title="<%= x %>" style="font-size: 20px;">
<%= value %>
</div>
"""
htmltemplateformatter400 = HTMLTemplateFormatter(template=template400)
col = "y"
columns.append(TableColumn(field=col, title=col,
width=50, editor=None,
formatter=htmltemplateformatter400))
data_table = DataTable(source=source, columns=columns, row_headers=False,
sortable=False,height = 1000, fit_columns=True)
curdoc().add_root(data_table)
styles.css (contained within directory templates)
Basically you have two spans within a div. When you hover over them, one has the display property set to none - therefore not visible. The other span which is previously not visible then has its display set to inline, becoming visible. You can change the style of the hover over text through this.
Also note because both of the spans are contained within the very outer div which has the styles set through python, both the hover and default text have the same css style properties.
.nonhover{
display: inline;
}
.cell_hover{
display: none;
background: yellow;
}
.parent_div:hover .nonhover{
display: none;
}
.parent_div:hover .cell_hover{
display: inline;
background: yellow;
}
index.html (contained within directory templates)
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/0.10.0/lodash.min.js"></script>
<meta charset="utf-8">
{{ bokeh_css }}
{{ bokeh_js }}
<style>
{% include 'styles.css' %}
</style>
</head>
<body>
<div class="content">
{{ plot_div|indent(8) }}
</div>
{{ plot_script|indent(8) }}
</body>
</html>
Hope that still helps.

how to use webbrowser to open the link when it is clicked in wxPython frame

I am writing a small app using wxPython. I have already save my data into a HTML string. I use the wx.html2.webview to display my HTMl.
And here is my code being simplified:
class MyBrowser(wx.Dialog):
def __init__(self, *args, **kwds):
wx.Dialog.__init__(self, *args, **kwds)
sizer = wx.BoxSizer(wx.VERTICAL)
self.browser = wx.html2.WebView.New(self)
sizer.Add(self.browser, 1, wx.EXPAND, 10)
self.SetSizer(sizer)
self.SetSize((800, 700))
if __name__ == '__main__':
app = wx.App()
dialog = MyBrowser(None, -1)
dialog.browser.SetPage(HTMLstring,"")
dialog.Show()
app.MainLoop()
there are images and links in my HTML string. I have successfully display my HTML string. But my question is :I hope the default webbrowser can open the links when I click on it.
So what should I do. Could someone please provide a link to such an example or (better still), post a short snippet here that shows how to do it?
By the way, I used the wx.HTMLwindow before I found it could not display my HTML string in the right way.
Here is my HTMLstring being simplified:
<html>
<head>
<style type="text/css">
div#container{background-color:#F0F8FF;width:700px}
div#content {height:200px;width:400px;float:left;word-break: break-all;}
div#predict{width:700px;}
.box {height:200px;width:300px;overflow:hidden;background-repeat: no-repeat;background-position:center center;float:left;}
img{margin-top: -50px;}
a:link{ text-decoration:none;}
</style>
</head>
<body>
<br>
<hr />
<p>SCCA Predicted:</p>
<div>
Eye discharge 1.0, Sensation of foreign body 0.99901248481,
</div>
</body></html>
There isn't a good way to do this. You can use webview's EVT_WEBVIEW_NAVIGATING event. However as the documentation notes, if there are multiple frames on the web page, then this event will get fired multiple times. If you want to go that route and try it out, then I would recommend using Python's webbrowser module to open your default browser.
Here's a quick demo:
import webbrowser
import wx
import wx.html2
class MyBrowser(wx.Dialog):
def __init__(self, *args, **kwds):
wx.Dialog.__init__(self, *args, **kwds)
sizer = wx.BoxSizer(wx.VERTICAL)
self.browser = wx.html2.WebView.New(self)
self.browser.Bind(wx.html2.EVT_WEBVIEW_NAVIGATING, self.onNav)
self.browser.Bind(wx.html2.EVT_WEBVIEW_NEWWINDOW, self.onNewWindow)
sizer.Add(self.browser, 1, wx.EXPAND, 10)
self.SetSizer(sizer)
self.SetSize((700, 700))
def onNav(self, event):
print "onNav called"
url = event.GetURL()
print url
webbrowser.open(url)
def onNewWindow(self, event):
print "onNewWindow called"
url = event.GetURL()
print url
webbrowser.open(url)
if __name__ == '__main__':
html = """<html>
<head>
<style type="text/css">
div#container{background-color:#F0F8FF;width:700px}
div#content {height:200px;width:400px;float:left;word-break: break-all;}
div#predict{width:700px;}
.box {height:200px;width:300px;overflow:hidden;background-repeat: no-repeat;background-position:center center;float:left;}
img{margin-top: -50px;}
a:link{ text-decoration:none;}
</style>
</head>
<body>
<br>
<hr />
<p>SCCA Predicted:</p>
<div>
<a href="http://sideeffects.embl.de/se/C0423006" >Eye discharge 1.0, </a><a href="http://sideeffects.embl.de/se/C0423602" >Sensation of foreign body 0.99901248481, </a>
</div>
</body></html>
"""
app = wx.App()
dialog = MyBrowser(None, -1)
dialog.browser.SetPage(html, '')
dialog.Show()
app.MainLoop()
I use the desktop module for that, edited using Mike's example but using desktop module instead of webbrowser.
import wx
import wx.html2
import desktop
html = """
<html>
<head>
<style type="text/css">
div#container{background-color:#F0F8FF;width:700px}
div#content {height:200px;width:400px;float:left;word-break: break-all;}
div#predict{width:700px;}
.box {height:200px;width:300px;overflow:hidden;background-repeat: no-repeat;background-position:center center;float:left;}
img{margin-top: -50px;}
a:link{ text-decoration:none;}
</style>
</head>
<body>
<br>
<hr />
<p>SCCA Predicted:</p>
<div>
<a href="http://sideeffects.embl.de/se/C0423006" >Eye discharge 1.0, </a><a href="http://sideeffects.embl.de/se/C0423602" >Sensation of foreign body 0.99901248481, </a>
</div>
</body></html>
"""
class MyBrowser(wx.Dialog):
def __init__(self, *args, **kwds):
wx.Dialog.__init__(self, *args, **kwds)
sizer = wx.BoxSizer(wx.VERTICAL)
self.browser = wx.html2.WebView.New(self)
self.browser.Bind(wx.html2.EVT_WEBVIEW_NAVIGATING, self.onNav)
sizer.Add(self.browser, 1, wx.EXPAND, 10)
self.SetSizer(sizer)
self.SetSize((700, 700))
def onNav(self, event):
print "onNav called"
url = event.GetURL()
print url
self.openExternal(url)
def openExternal(self, url, doclear=False):
"""
Open an external file with desktop module.
:param `url`: the file url to open in external program
:param `doclear`: clear InfoBar message
"""
wx.BeginBusyCursor()
try:
desktop.open(url.strip())
except OSError:
text = (_(u'Your default browser could not be opened, \
or the external program was not found or no \
external program is defined for this file.'))
wx.EndBusyCursor()
if __name__ == '__main__':
app = wx.App()
with MyBrowser(None, -1) as dlg:
dlg.browser.SetPage(html, '')
dlg.ShowModal()
app.MainLoop()
I also use 'with' to create the dialog, this ensures that it is getting destroyed when one with done with it.
https://pypi.python.org/pypi/desktop
If you need it on Py3 I made some changes which you can get here:
https://bitbucket.org/wbruhin/desktop