This is my first question here so please tell me if I missed out on something ;)
I'm building a website that will run some python code to solve a specific problem and show the results as numbers and a plot (all on the same page). In order to play with the parameters and visualize them before running the python code, I first need to send some form data from html to flask, so I figured I could do this through ajax - as I have done before to plot the results with standard parameters, based on the mpld3 example.
First, the html/form side (look for the comments):
<div class="row">
<div class="col-md-8">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Context Plots</h3>
</div>
<div class="panel-body overflow">
<div calss="loading-div" id="context_loading_div">
<div class="loading-tag">
<i class="fa fa-cog fa-spin"></i>
</div>
</div>
<div class="plot" id="context_plot_container"></div>
<!-- ### plot script here ### -->
<script src="{{ url_for('static', filename='js/solver_context.js') }}" type="text/javascript">
</script>
</div>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Context Parameters</h3>
</div>
<div class="panel-body">
<form action="" method="post" class="form-horizontal">
<div class="form-group">
<label for="buy_upper" class="col-sm-6 control-label" title="Utility buying price low tariff">Buying high [CHF]</label>
<div class="col-sm-6 input-group">
<span class="input-group-addon"><i class="fa fa-usd"></i></span>
<--! ### form element to fetch data from here ### -->
<--! the jinja templating stuff here works fine -->
<input type="range" name="buy_upper" class="form-control" id="buy_upper" min="0.05" max="1.0" step="0.01" value={% if reqMeth == 'POST' %}{{ request.form['buy_upper'] }} {% else %}"0.22"{% endif %} />
</div>
<--! some more form elements -->
</div>
</form>
</div>
</div>
</div>
</div>
Second, the javascript/ajax side:
$(window).load(function() {
$("#context_plot_container").hide();
$("#context_loading_div").show();
var buy_upper = document.getElementById("buy_upper").value;
var buy_lower = document.getElementById("buy_lower").value;
var sell_upper = document.getElementById("sell_upper").value;
var sell_lower = document.getElementById("sell_lower").value;
var qu = {"buy_upper": buy_upper, "buy_lower": buy_lower, "sell_upper": sell_upper, "sell_lower": sell_lower};
$.ajax({
type: "POST",
async: true,
contentType: "application/json; charset=utf-8",
url: "/context_plot",
data: JSON.stringify(qu),
success: function (data) {
var graph = $("#context_plot_container");
graph.html(data);
$("#context_plot_container").show();
$("#context_loading_div").hide();
},
dataType: "html"
});
});
This script should run after pressing a refresh button, but for now I'm loading it at the same time as the rest of the page. As I'm new to anything that's javascript/jquery/ajax I've more or less just copied the mpld3 example mentioned above.
Lastly, the python/flask side:
## plot routes
@app.route('/context_plot', methods=['GET', 'POST'])
def context_plot():
import numpy as np
plt.close(); # (opened above - works fine in the results plot)
# check params
# try:
buy_upper = float(request.args.get('buy_upper'));
buy_lower = float(request.args.get('buy_lower'));
sell_upper = -float(request.args.get('sell_upper'));
sell_lower = -float(request.args.get('sell_lower'));
# except:
# buy_lower = 0.19;
# buy_upper = 0.29;
# sell_lower = -0.09;
# sell_upper = -0.09;
# data
up = np.array([buy_lower] * 28 + [buy_upper] * 52 + [buy_lower] * 16);
urp = np.array([sell_lower] * 28 + [sell_upper] * 52 + [sell_lower] * 16);
# time vector
t = np.arange(0, len(up) - 1, 1 / 96.0)[:len(up)];
# figure
fig, (ax1, ax2) = plt.subplots(2, 1, figsize = (9, 6), sharex = 'col');
# subplot 1
ax1.grid(True, alpha = 0.5);
ax1.set_ylabel('costs [CHF/kWh]');
ax1.set_title('Utility profiles');
ax1.plot(t, up, t, urp, 'k');
ax1.margins(y = 0.1);
leg = ax1.legend(['buying', 'selling'], loc = 'upper left', framealpha = 0);
leg.set_title(''); # workaround for "None" at the bottom left
# subplot 2
ax2.grid(True, alpha = 0.5);
ax2.plot(t, urp);
ax2.margins(y = 0.1);
plugins.connect(fig, plugins.MousePosition(fontsize=12));
return mpld3.fig_to_html(fig); # (works fine in the results plot)
Now when I try to run everything, the figure doesn't show up. And when I look at firefox's network inspection tool ('Response' part) I find Werkzeugs's debugger saying:
File "X:\...\opt.py", line 84, in context_plot
sell_upper = -1 * request.args.get('sell_upper');
TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'
(From here)
So I'm interpreting that there is no 'sell_upper' in the query string. Then again I look at firefox's network inspection tool ('Params' part) and I see:
{"buy_upper":"0.99","buy_lower":"0.18","sell_upper":"0.27","sell_lower":"0.16"}
I also tried fiddling around with the way the parameters are passed by using qu
instead of JSON.stringify(qu)
or taking quotes away and so on... and I just don't seem to get it right.
So I guess the problem is that either the query string is still malformed, or the request.args.get() doesn't work as expected, when calling the route through ajax... or something else entirely -.-