Flask Application#
You can use pyvista
in to make a flask application to display both static
and dynamic plots. See the following examples as well as the source at Flask
Example.
Dynamic Example#

Example Dynamic Flask Webpage#
Python Application app.py
#
"""Simple flask app to display dynamic threejs generated from pyvista.
Expected paths:
dynamic_ex/
└── app.py
templates/
└── index.html
"""
import os
from flask import Flask, render_template, request
import numpy as np
import pyvista
from pyvista import examples
static_image_path = os.path.join('static', 'images')
if not os.path.isdir(static_image_path):
os.makedirs(static_image_path)
app = Flask(__name__)
@app.route("/")
def index():
return render_template('index.html')
@app.route("/getimage")
def get_img():
"""Generate a screenshot of a simple pyvista mesh.
Returns
-------
str
Local path within the static directory of the image.
"""
# get the user selected mesh option
meshtype = request.args.get('meshtype')
color = request.args.get('color')
style = request.args.get('style')
print(f"'{style}'")
# bool types
show_edges = request.args.get('show_edges') == 'true'
lighting = request.args.get('lighting') == 'true'
pbr = request.args.get('pbr') == 'true'
anti_aliasing = request.args.get('anti_aliasing') == 'true'
if meshtype == 'Sphere':
mesh = pyvista.Sphere()
elif meshtype == 'Cube':
mesh = pyvista.Cube()
elif meshtype == 'Bohemian Dome':
mesh = pyvista.ParametricBohemianDome()
elif meshtype == 'Cylinder':
mesh = pyvista.Cylinder()
elif meshtype == 'Vectors':
n_points = 20
points = np.random.random((n_points, 3))
poly = pyvista.PolyData(points)
poly['direction'] = np.random.random((n_points, 3))
poly['direction'] -= poly['direction'].mean(axis=0) # normalize
mesh = poly.glyph(geom=pyvista.Arrow(), orient=True, scale=True, factor=0.2)
# reset color as we will want to see the colors of the arrows
color = None
elif meshtype == 'Queen Nefertiti':
mesh = examples.download_nefertiti()
elif meshtype == 'Lidar':
mesh = examples.download_lidar()
else:
# invalid entry
raise ValueError('Invalid Option')
# generate screenshot
filename = 'mesh.html'
filepath = os.path.join(static_image_path, filename)
# create a plotter and add the mesh to it
pl = pyvista.Plotter(window_size=(600, 600))
pl.add_mesh(
mesh,
style=style,
lighting=lighting,
pbr=pbr,
metallic=0.8,
split_sharp_edges=True,
show_edges=show_edges,
color=color,
)
if anti_aliasing:
pl.enable_anti_aliasing()
pl.background_color = 'white'
pl.export_html(filepath)
return os.path.join('images', filename)
if __name__ == '__main__':
app.run()
Ajax Template index.html
#
This template should be within the templates
directory in the same
path as app.py
.
This template returns the meshtype
parameter back to the
get_img
method in the flask app, which is used to select the type
of mesh to be plotted.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<fieldset>
<select style="background-color: #ffffa0" name="meshtype", id="meshtype" onchange="getState(this.value)">
<option>Select Mesh Type</option>
<option>Sphere</option>
<option>Cube</option>
<option>Bohemian Dome</option>
<option>Cylinder</option>
<option>Vectors</option>
<option disabled="true" value="divider">-------------</option>
<option>Queen Nefertiti</option>
</select>
<div class="item">
<input type="checkbox" id="show_edges">
<label for="show_edges">Show Edges</label>
</div>
<div class="item">
<input type="checkbox" id="lighting" checked>
<label for="lighting">Lighting</label>
</div>
<div class="item">
<input type="checkbox" id="pbr" checked>
<label for="pbr">Physically Based Rendering</label>
</div>
<div class="item">
<input type="checkbox" id="anti_aliasing" checked>
<label for="anti_aliasing">Anti-Aliasing</label>
</div>
<label for="colorpicker">Color Picker:</label>
<input type="color" id="colorpicker" value="#a4b2ba">
<div>
Style:
<input type="radio" class="style" name="style" value="points" /> Points
<input type="radio" class="style" name="style" value="wireframe" /> Wireframe
<input type="radio" class="style" name="style" value="surface" checked/> Surface
</div>
<br>
<button type='button' id ='retrieve'>Plot</button>
</fieldset>
<iframe src="" height="600" width="600" title="PyVista" id="myimg" frameBorder="0" allowtransparency=yes scrolling=no>
<p>Your browser does not support iframes.</p>
</iframe>
</body>
<script>
$(document).ready(function() {
$('#retrieve').click(function(){
$.ajax({
url: "{{ url_for ('get_img') }}",
type: "GET",
data: {
meshtype: $('#meshtype option:selected').val(),
show_edges: ($("#show_edges").is(":checked")),
lighting: ($("#lighting").is(":checked")),
pbr: ($("#pbr").is(":checked")),
color: $('#colorpicker').val(),
style: $(".style:checked").val(),
anti_aliasing: ($("#anti_aliasing").is(":checked")),
},
success: function(response) {
$("#myimg").attr('src', '/static/' + response);
},
error: function(xhr) {
alert("Please select a mesh type from the drop down menu.");
}
});
});
});
</script>
</html>
Static Example#

Example Static Flask Webpage#
Python Application app.py
#
"""Simple flask app to display static images generated from pyvista.
Expected paths:
static_ex/
└── app.py
templates/
└── index.html
"""
import os
from flask import Flask, escape, render_template, request
import pyvista
static_image_path = os.path.join('static', 'images')
if not os.path.isdir(static_image_path):
os.makedirs(static_image_path)
app = Flask(__name__)
@app.route("/")
def index():
return render_template('index.html')
@app.route("/getimage")
def get_img():
"""Generate a screenshot of a simple pyvista mesh.
Returns
-------
str
Local path within the static directory of the image.
"""
# get the user selected mesh option
meshtype = request.args.get('meshtype')
if meshtype == 'Sphere':
mesh = pyvista.Sphere()
elif meshtype == 'Cube':
mesh = pyvista.Cube()
elif meshtype == 'Bohemian Dome':
mesh = pyvista.ParametricBohemianDome()
elif meshtype == 'Cylinder':
mesh = pyvista.Cylinder()
else:
# invalid entry
raise ValueError('Invalid Option')
# generate screenshot
filename = f'{meshtype}.png'
filepath = os.path.join(static_image_path, escape(filename))
mesh.plot(off_screen=True, window_size=(300, 300), screenshot=filepath)
return os.path.join('images', filename)
if __name__ == '__main__':
app.run()
Ajax Template index.html
#
This template should be within the templates
directory in the same
path as app.py
.
This template returns the meshtype
parameter back to the
get_img
method in the flask app, which is used to select the type
of mesh to be plotted.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<select style="background-color: #ffffa0" name="country", id="meshtype" onchange="getState(this.value)">
<option>Select Mesh Type</option>
<option>Sphere</option>
<option>Cube</option>
<option>Bohemian Dome</option>
<option>Cylinder</option>
</select>
<button type='button' id ='retrieve'>Plot</button>
<img src="" id="myimg" />
</body>
<script>
$(document).ready(function() {
$('#retrieve').click(function(){
$.ajax({
url: "{{ url_for ('get_img') }}",
type: "GET",
data: {
meshtype: $('#meshtype option:selected').val()
},
success: function(response) {
$("#myimg").attr('src', '/static/' + response);
},
error: function(xhr) {
alert("Please select a mesh type from the drop down menu.");
}
});
});
});
</script>
</html>