I am using Bokeh to vizualize scientific data for a while and I fail to customize my layout as I wish.
from bokeh.plotting import figure
from bokeh.io import show
from bokeh.layouts import row
from bokeh.models.widgets import Button
tools_to_show = 'hover, box_zoom, save, reset, pan'
p = figure(tools=tools_to_show, output_backend = "webgl")
p.line([1, 2, 3, 4], [9, 5, 7, 6])
b_valid = Button(label="valid")
my_plot = row(p, b_valid, sizing_mode="stretch_both")
show(my_plot)
I have a plot area and a controls area. The controls area should be smaller, maybe 1/3 of available width to let the plot with a bigger area (2/3 of available width).
I'm using sizing_mode = "stretch_both" to be sure to use all available space in screen.
I need to keep using the bokeh server (bokeh serve myapp.py) to get python callback working, so the embbeded solution suggested here is not working for me.
Maybe there is a way with serving directory with bokeh command because there is a template mechanism, but I can't figure how to get seperate div for plot and controls.
Have you any (simple) idea ?
Edit : it seems that it's not a feature currently available on bokeh. A promising solution is to be able to place components embedded in template using bokeh server : amilestone is scheduled
I would say that we are backing away from the built-in layout system for more than very simple things. PR #7708 was just merged an will be in the upcoming 0.13.0 release. When 0.13.0 is available, you can embed individual document roots separately in temlates, e.g. if you define five plots in a Bokeh server app:
curdoc().add_root(p0)
curdoc().add_root(p1)
curdoc().add_root(p2)
curdoc().add_root(p3)
curdoc().add_root(p4)
They can all be placed in responsive Bootstrap layouts:
<div class="row">
<div class="col-sm-8">
{{ embed(doc.roots[0]) }}
<br>
</div>
<div class="col-sm-4">
{{ embed(doc.roots[1]) }}
<br>
</div>
</div>
<div class="row">
<div class="col-sm-4">
{{ embed(doc.roots[2]) }}
<br>
</div>
<div class="col-sm-4">
{{ embed(doc.roots[3]) }}
<br>
</div>
<div class="col-sm-4">
{{ embed(doc.roots[4]) }}
<br>
</div>
</div>
Related
Actually I am creating a Basic E-Commerce Flask Application.
Data of the price, discount and everything is provided from content.json file to the function in python from where it goes to home.html file such that each product's data is represented in specific boxes.
It currently looks like this..
I just added random data here for reference...
Here I want all the boxes to be placed in a grid of 2 or 3 columns depending upon the width of the screen.
I have placed all the boxes generated from the jinja for loop in the boxes class.
<div class="boxes">
{% for item in data %}
<div class="card bg-dark text-white" style="width: 23rem;">
<div class="card-body">
<h5 class="card-title">{{item}}</h5>
<h6 class="card-subtitle mb-2 text-muted">Category: {{item.split(" ")[len(item.split(" "))-1]}}s</h6>
<p class="card-text" id="cut">Actual Price: {{data[item].price}} Rupees</p>
<p class="card-text">New Price: {{round(((100-data[item].discount)/100)*data[item].price)}} Rupees</p>
<p class="card-text">Discount: {{data[item].discount}}%</p>
<p class="card-text">Ratings: {{ data[item].rating }}⭐</p>
Buy Now
Product Details
</div>
</div>
</div>
but, when I applied grid properties and styles in 'boxes' class it seems to work only on the first box like the margin etc, and not in the other boxes.
Like this:
see here it's only applied to first box
I think it's because of the dynamic data generated due to jinja for loop that's causing this issue, and I don't know how to solve this.
the style for 'boxes' class:
.boxes {
display: grid;
grid-template-columns: auto auto auto;
grid-gap: 10px;
padding: 10px;
}
So yeah the main problem is how to apply this grid to all the boxes present in the boxes class
I am using wtforms as part of a Python + Flask project. There are some cases where I want multiple fields of a form to appear on the same line on the webpage. With SelectField, this works as expected. However, when I use IntegerField, it seems to automatically create a new line after the field is displayed, and I get have more than one on a line.
The Form:
class PremiumMandatory(FlaskForm):
match_dol = IntegerField('Dollar')
match_per = IntegerField('Percent')
The .html
{{form.match_dol.label}}
${{form.match_dol(size=3)}}
 
{{form.match_per(size=3)}}%
{% for error in form.match_per.errors %}
Using the above, the two fields also appear on different lines on the webpage. Ho do I keep then on the same line?
This is an entirely HTML/CSS problem. There are many ways to put multiple fields of a form on the same line, for example, you could use Bootstrap's grid system, which is very easy to use.
Another simple way is:
<form>
<div style="display: table;">
<div style="display: table-row;">
<div style="display: table-cell;">
{{ form.match_dol.label }}
{{ form.match_dol(size=3) }}
</div>
<div style="display: table-cell;">
{{ form.match_per.label }}
{{ form.match_per(size=3) }}
</div>
</div>
<div style="display: table-row;">
...
</div>
</div>
</form>
I created some plots with bokeh and exported them as html files. I now try to add these plots in a django template. The first plot works just fine, but if I want to add a second one it is not displayed.
Here i have the python file that creates the bokeh html:
from bokeh.plotting import figure, output_file, show
output_file("test2.html",title="test2")
p = figure(plot_width=400, plot_height=400)
p.circle([1, 5, 7, 2, 5], [6, 7, 2, 5, 5], size=20, color="navy", alpha=0.5)
show(p)
This is the second plot, the first one is saved as test.html, the title is test and some of the point coordinates are different.
And here is my django template:
{% extends "MainPage/PageBase.html" %}
{% block content %}
<div class="container">
<div class="card">
<div class="card-header">
<font size="3">plot1</font>
</div>
<div class="card-body">
<blockquote class="blockquote mb-0">
<p><div class="basic">
{% include "GPanalysis\WorkingData\test.html" %}
</div></p>
</blockquote>
</div>
</div>
<div class="card">
<div class="card-header">
<font size="3">plot2</font>
</div>
<div class="card-body">
<blockquote class="blockquote mb-0">
<p><div class="basic">
{% include "GPanalysis\WorkingData\test2.html" %}
</div></p>
</blockquote>
</div>
</div>
</div>
{% endblock %}
In the first box appears a graph but the second one is empty.
I switched the position of two plots, but only the one that comes first in the html script will be displayed. If I try to call the same graph twice, it will be plotted twice but the second one is directly below the first one and not at the location it should be according to the html script.
I am not sure if this is an error i have somewhere or if what I am trying is simply not possible. I am aware, that there are other possibilities to get multiple bokeh plots in one template, but this one would be the easyest for my situation as i have to generate the html files anyway.
Thanks for any helpful answer.
Don't do this. Bokeh file output is not designed or intended to be embedded this way, and there is no expectation that it should work well or at all:
File output generates full HTML files with their own <head>, by doing this you are 100% guaranteed to generate malformed HTML
Bokeh objects from different files will probably end up stomping on each other, because file output is not intended to be used this way.
There are APIs sepcifically purposed for Embedding Plots and Apps and those should be used.
I am trying to show graphs made in plotly on a webpage served by flask.
The way it is set up now, they both display on the same page, one on top of the other. I want to show them individually on different pages.
The solution I found for plotly displays all of the graphs made, and I'm not sure how to get individual graphs
My flask/python
graphs = [
dict(
data=[thetaGraph, deltaGraph, alphaGraph, betaGraph,gammaGraph ],
layout=dict(
title='Brain Data'
)
),
dict(
data=[xGraph,yGraph,zGraph],
layout=dict(
title='Accelerometer Data'
)
),
]
ids = ['graph-{}'.format(i) for i, _ in enumerate(graphs)]
graphJSON = json.dumps(graphs, cls=plotly.utils.PlotlyJSONEncoder)
return render_template('index.html', title='Home',ids=ids, graphJSON=graphJSON)
And then the webpage
<div class="container">
<div class="row">
<!-- LEFT SIDE -->
<div class="col-6">
{% for id in ids %}
<div id="{{id}}"></div>
{% endfor %}
</div>
</div>
</div>
<footer>
<script type="text/javascript">
var graphs = {{graphJSON | safe}};
var ids = {{ids | safe}};
for(var i in graphs) {
Plotly.plot(ids[i], // the ID of the div, created above
graphs[i].data,
graphs[i].layout || {});
}
</script>
</footer>
Im unsure how to get just the first graph in that html, and then the second graph elsewhere on the page. Ive tried using {% for id in range(0,1) %} just to get the first element, or just putting <div id="{{ids[0]}}"></div>
but I get 'ids' in undefined
When printing out ids i get ['graph-0', 'graph-1'] which means that this is a list and I should be able to index it, but apparently that is not a thing with flask. I'm sure there is some strange way that flask needs it similarly to it's ways of reading from 2D arrays
I was able to figure out a way to complete my task, but it does not involve indexing arrays. Since the javascript creates usable id's I am able to show individual graphs by simple referencing them
Replacing
<div class="col-6">
{% for id in ids %}
<div id="{{id}}"></div>
{% endfor %}
</div>
With
<div class="col-6">
<div id="graph-0"></div>
</div>
Gave me the outcome I was looking for
The problem looks simple but everywhere I search it I get results for uploading a file, whereas my use case is, that based on a few params, I in my Handler decide the relevant file and upload it as a link in my View. I am using tornado for this. e.g :
<div class="form-group"> <!-- Date input -->
<label for="actDateFrom" class="control-label">Date</label>
<input ng-model="data.actDateFrom" class="form-control" name="actDateFrom" placeholder="MM/DD/YYY" type="text"/>
</div>
<div class="form-group"> <!-- Date input -->
<label for="actDateTo" class="control-label">Date</label>
<input ng-model="data.actDateTo" class="form-control" name="actDateTo" placeholder="MM/DD/YYY" type="text"/>
</div>
<div class="form-group"> <!-- Submit button -->
<button type="submit" class="btn btn-default" data-ng-disabled="form.$invalid" data-ng-click="sendActRequest()" >Go Fetch !</button>
</div>
Based on the inputs above, I have a handler, that should basically filter a csv file and get that file showing up as a link .
All I am stuck at is the code for uploading that subset file as a link in my view, I can manage the rest. Please not that the file is lying somewhere on the server itself.
Thanks in Advance!
Lol that was so easy, I think the funda is that only a static file can be served, I just put it in my some web/static/files path which is visible to the server and posted a href link to it, something like below:
<div>
Activations Logs for the time period.
</div>
Please dont downvote, actually I am new to Web Dev :P Thanks !