Displaying Image as a result of operations with Flask and AJAX - javascript

I'm currently working on a project, in which an explainable AI library for CNN image recognition (https://github.com/albermax/innvestigate) is meant to be implemented in a web-service. Now, I found a good looking template, which involved general image recognition back- & frontend, based on Flask (https://github.com/OkanKY/keras-flask-webapp).
I managed to implement the library, but do not manage to display the resulting plot-image on the web-service. This is what I tried:
Python/Flask Code:
#app.route('/predictResNet50', methods=['GET', 'POST'])
def predictResNet50():
if request.method == 'POST':
file_path = get_file_path_and_save(request)
...
plt.savefig(file_path[:-4] + explainer + "Plot.jpg")
fullPlotFilename = file_path[:-4] + explainer + "Plot.jpg"
...
return fullPlotFilename
By that, the plot image is perfectly stored in the static/images library. The corresponding JavaScript code, which invokes the API, looks like this:
$.ajax({
type: 'POST',
url: '/predictResNet50',
data: form_data,
contentType: false,
cache: false,
processData: false,
async: true,
success: function (data) {
// Get and display the result
$('.loaderResNet50').hide();
// $('#resultResNet50').fadeIn(600);
// $('#resultResNet50').text(' Result: ' + data1);
$('#plotResNet50').show();
$('#plotResNet50').html('<img src="' + data + '">');
console.log('ResNet50 Success!');
},
});
Before the modifications, the result of the prediction was displayed (out-commented part). Now, the plot image is supposed to be displayed. Ideally, the result plus the prediction would be the goal, but for now, the plot would be sufficient. But this does not work for some reason. The correct value is returned to the API call in JS, but only the image adress, not the actual image is presented.
HTML Script:
<div id="plotResNet50">
</div>
Could somebody tell me, what I'm missing? Since I'm not too experienced with JQuery, help would be greatly appreciated!!
Link to the current GitLab Repo can be provided, if the stated information is not sufficient.

The function html() is not the appropriate function to be used if you intend to add an element to HTML using JQuery.
Instead use:
$('#plotResNet50').prepend('<img src="' + data + '">')

Related

Javascript Flask URL_for improper redirect

I know there are already several questions about the best way to do a Flask URL_for through Javascript, but I can't get it to work for me. I am new to Front End development so go easy on me here. I have tried multiple ways, and each way returns an error or a different problem.
I have a Bootstrap dropdown menu that when clicked on, should return a report to the user. I thought I had it solved earlier because I can get it to return the report if I do it this way:
$('.dropdown-item').on('click', function (event) {
branch = $(this).attr('branch');
selected_date = selected_date;
window.location.href = route_summ/branch/selected_date
The problem is then that it adds the route_summ in front of every other file, including javascript, css, etc files, so none of those can be found any longer. If instead I do:
window.location.href = "{{url_for('route_summ', branch=branch, selected_date = selected_date)}}"
As I have seen in other posts people suggest, it doesn't look at any of the variables and instead just tries going to route_summ//.
Some posts talk about using an $.ajax call, so I have done it this way:
$.ajax({
type: 'GET',
url: "/route_summ/" + $(this).attr('branch') + '/' + selected_date,
data: {
branch: $(this).attr('branch')
},
method: 'GET',
success: function(response) {
console.log('Success');
window.location.href = "{{url_for('route_summ', branch = branch, selected_date = selected_date)}}"
}
});
But that doesn't work either. It establishes a call and returns "Success", but it doesn't redirect to the site. If I were to just go to the site, it works, but I can't get it to link to it without screwing up the other dependent links on it. Can anyone please help me? I'm at my wit's end here.
Okay I figured it out. My first solution would've worked, but I needed to put a "url_for" in my tags. I'm going to leave this up in case any other novices run into this problem.

Jquery datatable: add rows from database in a loop

I have a page that makes an Ajax call to a database on page load. It returns a list of companies that the user is following and then iterates the list trough and does another Ajax call to each company, to get some statistics about them. The statistics are then added to a Datatable which is being drawn quite a few times:
var table = $("#example").DataTable();
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "../json/stats.aspx?t=followed-companies",
dataType: "json",
success: function (data) {
for (i = 0; i < Object.keys(data).length; i++) {
$.ajax({
type: "POST",
async: true,
contentType: "application/json; charset=utf-8",
url: "../json/stats.aspx?t=company-stats" + "&n=" + data[i]
}).done(function (dataSecondary) {
var stringtest = "<tr><td>" + dataSecondary.Stats1 + "</td>" +
"<td>" + dataSecondary.Stats2 + "</td>" +
"<td>" + dataSecondary.Stats3 + "</td>" +
"<td>" + '<button type="button" id="delete" class="btn btn-danger btn-xs dt-delete">' + "Delete" + "</td></tr>";
table.row.add($(stringtest)).draw();
});
}
},
error: function (xhr) {
console.log('error', xhr);
}
});
I do not have much experience in programming, but I do know that this takes ages to load and so has a very poor performance.
Main question is, can I use the table.draw(); after I have added the rows in that loop? I guess that could save some time. I tried to draw the table after the loop is finished but the table said that there is no data to show.
Second question, is this bad practise (mainly those nested Ajax calls with loops and SQL queries), and should I try to unify as many SQL queries as possible?
JSFiddle example - Get Post Data using ajax and display in .dataTable()
Main question is, can I use the table.draw(); after I have added the rows in that loop?
Yes you can. If you look at the docs of datatables you'll see that the draw() function is made for that.
When you perform an action such as adding or deleting a row, changing
the sorting, filtering or paging characteristics of the table you'll
want DataTables to update the display to reflect these changes. This
function is provided for that purpose.
Second question, is this bad practise (mainly those nested Ajax calls with loops and SQL queries), and should I try to unify as many SQL queries as possible?
Yes it's bad practice to have many calls going to your backend. If you have control over the backend, you should aim to optimise it. For example: When you supply a list of companies, it will return the stats for all those companies specified.
Currently it will especially be a bad experience for those with a slow internet connection e.g. mobile users.
Also, this solution doesn't scale well. Imagine your website taking off and 100s of individuals are using it simultaneously. That means 100 * amount-of-followed-companies calls, while with the suggested it would be 100 calls to the backend for fetching the same data.
Have you also considered the possibility to generate a table using ajax sourced data.
UPDATE:
As for the draw() function that is not working. According to the docs, you provide the data structure without actually building the table with html yourself. Use the data returned instead where columnNameX is the name of the columns you specified. Give this a try in your .done().
var data = {
columnName1: dataSecondary.Stats1
columnName2: dataSecondary.Stats2
columnName3: dataSecondary.Stats3
}
table.row.add(data).draw();
As for generating the button. I haven't worked with them before but you can find more about them here.

Ajax not getting most recent version of JSON file

I'm rather new to terminology and coding in general, but I've tried to trim down my code, though it may still have redundancies. Thanks in advance for your understanding.
I'm using an ajax and php script to write some data to a file on the server called data.json. The script works fine, and opening the json file shows that it's indeed updated with the data. The json file simply contains an array of objects.
Here's the code that does this:
function writeData() {
$.ajax({
type : "POST",
url : "save.php",
async : true,
data : {
json : JSON.stringify(dataToWrite)
}
});
document.getElementById('success-box').innerHTML = "Data successfully written.";
};
...and the PHP:
<?php
$json = $_POST['json'];
$file = fopen('data.json','w+');
fwrite($file, $json);
fclose($file);
?>
The problem I'm having is this: The user can navigate to a separate HTML page, and can click a button to view the data in the json file in a nicely-formated way. This is done via another ajax script that reads the data. This latter ajax script doesn't seem to be able to "see" the newly updated json file. It instead loads the old version of the file, before it was updated with the first ajax script. I'm sure that this second ajax script is run after the above writeData() is finished, because it's actually on a separate HTML page entirely, which is loaded later, after the user clicks a button.
Here's the second ajax script that reads the data from the data.json file (it's on another, separate HTML page):
$.ajax({
type : "GET",
url : "http://eslquiz.net/ell_errors/data.json",
async : true,
dataType : 'json',
success : function(response) {
data = response;
document.getElementById('main').innerHTML = `
<div id='top-stuff'>
<button onClick='viewData()'>Reset Filter</button>
<button onclick="print2()">Print Worksheet</button>
</div>
<br>
<div id='left-column' class='column'></div>
<div id='right-column' class='column'></div>
`;
leftColumn = document.getElementById('left-column');
rightColumn = document.getElementById('right-column');
leftColumn.innerHTML = "<b>Sentences:</b> <br><br>";
rightColumn.innerHTML = "<b>Errors:</b> <br><br>";
//add the sentences and their errorTypes:
for (i=0; i<data.length; i++) {
var senBox = document.createElement('div');
senBox.className = 'box';
senBox.setAttribute('id', 'sen' + i)
senBox.innerHTML += data[i].text;
var errBox = document.createElement('div');
errBox.className = 'box';
errBox.setAttribute('id', 'err' + i)
errBox.innerHTML += data[i].errorType;
leftColumn.appendChild(senBox);
rightColumn.appendChild(errBox);
}
}
});
All of these files are hosted in the same directory on One.com.
The strange thing is that when I manually open the data.json file and edit its contents in any way (by deleting everything, for example), the next time the ajax call is made, it reads the version I just manually updated. This makes me think it might be something to do with the One.com server refreshing itself?
I tried adjusting the ajax between synchronous/asynchronous, and using cache: false, but these don't seem to affect anything.
I've searched around, and can't seem to find out what's going on here. Thanks for any guidance you could provide.
Thanks. I ended up using the following:
jQuery.ajaxSetup({
cache: false
});
I tried using this before, but for some reason it didn't work, not sure why. But it's working now! Thanks.
first, GET method can be cached by the browser.
second, Make sure the response is a json type
$.ajax({
type : "GET",
url : "http://eslquiz.net/ell_errors/data.json?rand_v=" + Matn.random(), // add a random try again
async : true,
dataType : 'json',
success : function(response) {
// Make sure the response is a json type
// console.log(typeof(response));
// console.log(typeof(JSON.parse(response)));
data = response;
// ...

Wikipedia API search -- Retrieve same index of each array with forEach?

I'm working on a project for freeCodeCamp and I've been stuck on this part all day. I'm pulling data from the Wikipedia API and I'm able to work with it, yet I'm not sure how the syntax should look for what I'm trying to achieve. Here is a link to an example of the data I'm working with. Wikipedia API Search.
Now, in my HTML I have a bootstrap modal that appears after the user inputs something into a form, with a listed group inside with the returned data from the search.
This is the code I have so far.
$(document).ready(function () {
$('#searchForm').on('submit', function(e) {
e.preventDefault();
$('#wikiSearch').modal('show');
var usersearch = document.getElementById('userinput').value;
var apiURL = "https://en.wikipedia.org/w/api.php?
action=opensearch&search="
+ usersearch + "&format=json&callback=?";
$.ajax({
url: apiURL,
contentType: "application/json; charset=utf-8",
dataType: 'json',
type: 'GET',
success: function (data) {
data[1].forEach(function(item) {
$('#results').append("<tr><td><a href='#'>"+item+"</a></td></tr>")
});
data[2].forEach(function(item) {
$('#brief').append("<tr><td>"+item+"</td></tr>")
})
}
});
});
});
For each group in my modal of my HTML I want to display 1 result from the search. I figured I would be able to use a nested forEach but it's not returning the results I wanted. I've tried using map, and also tried creating a long nested for loop and feel like I might be doing more harm than good when it comes to learning since I'm only getting confused now lol. Thanks for any input.
To show the first row from the search results use the first key of the nested array:
$('#results').append("<tr><td><a href='#'>" + data[1][0] + "</a></td></tr>")
$('#brief').append("<tr><td>" + data[2][0] + "</td></tr>")
Don't forget to add a check for the possible undefined value inside the data array.

How do I get the counter of a google plus +1 button?

I have added a google +1 button to a website, but I want to get it's counter so i can do some math over it. is it possible to enter the iframe created by the standard method of creating the +1 button or do I need to make some adjustment?
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
<g:plusone></g:plusone>
I've tried this link:1 , but this is not very accurate
If you can access curl/file_get_contents/readfile/wget or some way to fetch an external URL, this is quite simple.
Load the following URL: https://plusone.google.com/_/+1/fastbutton?url=URLENCODED_URI (UPDATED URL, see note below *)
URLENCODED_URI is the site you wish to know the number of +1's for, e.g. http://www.google.com (http%3A%2F%2Fwww.google.com)
For example, fetch the URI https://plusone.google.com/_/+1/fastbutton?url=http://www.google.com/ (UPDATED URI) and locate the first occurance of window.__SSR = {'c': 32414.0 ,'si'. Preferably use regexp for this, but I'll leave the implementation to you and your chosen programming language (server side or client side).
The float number following 'c' is the number of +1's the site have. For google.com this is 32,414. Don't worry about the float, you can safely convert it to an integer.
* UPDATE: The URL has been updated as the old URL started to 404. Remember, this is expected as this is an unofficial method. There exist no official method (yet).
Could you use a callback function to grab the value of the div that displays the count?
function count() {
var count = $('#aggregateCount').html();
}
<g:plusone callback="count()"></g:plusone>
I'm basing this off the bubble annotation button, I haven't tested it but something like this should work.
A pure client-side solution that works for me to get the Google Plus counter is as follows. It does not need an API key.
var url = "http://www.yoursite-to-be-counted.com";
var data = {
"method":"pos.plusones.get",
"id": url,
"params":{
"nolog":true,
"id": url,
"source":"widget",
"userId":"#viewer",
"groupId":"#self"
},
"jsonrpc":"2.0",
"key":"p",
"apiVersion":"v1"
};
$.ajax({
type: "POST",
url: "https://clients6.google.com/rpc",
processData: true,
contentType: 'application/json',
data: JSON.stringify(data),
success: function(r){
setCount($(".google-plus-count"), r.result.metadata.globalCounts.count);
}
});
var setCount = function($item, count) {
if (count) {
$item.text(count);
}
};
Then I have some html with
<div class="google-plus-count"></div>
Credits here goes to this answer.

Categories