I'm currently learning d3.js for visualization, using Flask as the python backend, and following this example of showing two simple charts with different datasets on the same page.
I'm attempting the following modification: instead of using CSVs, I'd like to pass a json file from a python backend (the example just reads in data from two csv files). How might I pass 2 json datasets over? I can pass one as follows:
Python backend
import flask...
app = flask.Flask(__name__)
#app.route("/")
def index():
return flask.render_template("index.html")
#app.route("/data")
def data():
x = [1, 2, 3, 4, 5]
y = [1, 2, 3, 4, 5]
js = [{"x":x[i], "y":y[i]} for i in range(len(x))]
return json.dumps(js)
index.html
<script>
d3.json("/data", function(data) ...)
</script>
I've tried writing another python function, like def data_bar to return a separate json dataset, but that couldn't be read. In theory, I could pass both data sets in one json dataset, like:
x = [1,2,3,4,5]
y = [1,2,3,4,5]
x1 = [10,20,30]
y1 = [40,50,60]
But this encounters problems if the domains of the first set (x and y) and the second set (x1 and y1) aren't the same. e.g. the first set could be "student_name" and "grade", the second set could be "class_name" and "average_grade".
render with one data set passed in:
return render_template("result.html",resultVarInHtml = myData)
render with multiple data set passed in:
return render_template("result.html",resultVarInHtml = myData, resultVarInHtml2 = myData2)
Now when I load result.html
I can use this code to show my data (assuming a key value dictionary object, but you get the point)
results.html
<!doctype html>
<html>
<body>
<p>First Data Set</p>
<table border = 1>
{% for key, value in resultVarInHtml.iteritems() %}
<tr>
<th> {{ key }} </th>
<td> {{ value }} </td>
</tr>
{% endfor %}
</table>
<p>2nd Data Set</p>
<table border = 1>
{% for key, value in resultVarInHtml2.iteritems() %}
<tr>
<th> {{ key }} </th>
<td> {{ value }} </td>
</tr>
{% endfor %}
</table>
</body>
</html>
And you will get a proper table, mate.
Related
In my angular app i display JSON data in a table with pagination using ngx-pagination i want to export my table in pdf format I used a couple of npm packages that take a screenshot off the HTML page and convert it to a pdf to export, the only problem is not all the data is being displayed because of the pagination and number of items per page, is there a work around this?
Here is the code I used :
<table
class="
table
is-hoverable is-striped is-fullwidth
content-table
#userTable
"
id="htmlData"
>
<thead>
<tr>
<th>{{ "DataSource.RecordID" | translate }}</th>
<th colspan="6">{{ "DataSource.Details" | translate }}</th>
</tr>
</thead>
<tbody>
<tr
*ngFor="
let row of FilteredMatchTransactions
| paginate: { itemsPerPage: itemsPerPage, currentPage: p };
let i = index
"
>
<td>
{{ "DataSource.SessionID" | translate }} :
{{ row.SESSION_ID }}
</td>
<td>
{{ "DataSource.ExternalStan" | translate }} :
{{ row.EXTERNAL_STAN }}
</td>
<td>
PAN :
{{ row.CARD_NUMBER }}
</td>
<td>
{{ "DataSource.Amount" | translate }} :
{{ row.TRANSACTION_AMOUNT.split(" ")[0] }}
</td>
<td>
{{ "DataSource.Currency" | translate }} :
{{ row.TRANSACTION_AMOUNT.split(" ")[1] }}
</td>
<td>
Terminal :
{{ row.TERMINAL_ID }}
</td>
<td>
{{ "DataSource.TransactionDate" | translate }} :
{{ row.TRANSACTION_DATE }}
</td>
</tr>
</tbody>
</table>
ts :
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
....
....
public downloadPDF(): void {
let DATA = document.getElementById('htmlData');
console.log(DATA);
html2canvas(DATA).then((canvas) => {
let fileWidth = 208;
let fileHeight = (canvas.height * fileWidth) / canvas.width;
const FILEURI = canvas.toDataURL('image/png');
let PDF = new jsPDF('p', 'mm', 'a4');
let position = 0;
PDF.addImage(FILEURI, 'PNG', 0, position, fileWidth, fileHeight);
PDF.save('angular-demo.pdf');
});
}
my idea is about to use a temporary created table DOM element instead of using angular active table (situated in the view), this is an overview of the idea:
// I suppose that this jsonApiData is an array got from API which you used it in DataSource and containing all data without pagination, so you should be sure that you already loaded all data from the API before performing any data manipulation or consumption:
private jsonApiData;
public downloadPDF(): void {
/*let table = document.getElementById('htmlData');*/
// refer to getTemporaryTableDom method below
let table = this.getTemporaryTableDom(this.jsonApiData);
html2canvas(table).then((canvas) => {
...
...
// Important: after finishing your save, remove the temporary table DOM from the memory
table.remove(); ==> to free up your memory.
});
}
...
...
/** this method will create a temporary table dom,
* and fill it with your api data.
**/
private getTemporaryTableDom(jsonData){
let t = document.createElement('table');
// fill your DOM Html table with your api data
for(let [index,obj] of Object.entries(jsonData)){
let newInsertedRow = t.insertRow(index);
// to insert cells and its values you can also use loop, i will let you free to chose
c = newInsertedRow.insertCell(0); // example SessionID
c.innerHTML = obj.SessionId; // SessionID value
c = r.insertCell(1); // example: ExternalStan
c.innerHTML = obj.ExternalStan; // ExternalStan value
...
...
}
return t; // to return the DOM TAble html element
}
This is just an idea to make sure you are using static data so that you will be able to control it without any problem, because using the angular view Doms can make things more difficult to manage because they are based on many concepts like ChangeDetection, component lifecycle, etc..
for more table dom manipulation details, you can refer to these ressources:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableElement
https://stackoverflow.com/a/2324826/8678900
I developed a web project where I can upload two files and django server execute a function to return the lines that don't match with other in a pandas dataframe which is renderized in a html template. Is returned a two columns table, file1 and file2. I would like to have another column with the text and text difference 'highlighted'. I have no knowledge about javascript programing, but I don't know how to apply the function on each table row.
My views.py
def index(request):
form = UploadFileForm(request.POST, request.FILES)
if request.method == 'POST':
if form.is_valid():
check = CheckFiles(form.cleaned_data["arquivo1"], form.cleaned_data["arquivo2"]).verifica_tamanho()
if type(check) == str:
return HttpResponse('The file are the same!')
#return HttpResponse(check.to_html())
return render(request, 'index2.html', {'check': check})
else:
print('Invalid Form!')
return render(request, 'index.html', {'form': form})
and in my index2.html:
<table class="table" border="1px">
<thead class="thead-dark">
<tr>
<th scope="col">Original File</th>
<th scope="col">Secondary File</th>
</tr>
</thead>
<tr>
{% for _, record in check.iterrows %}
<tr>
{% for value in record %}
<td>{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
</tr>
</table>
and the highlight javascript function is:
highlight($("#new"), $("#old"));
function highlight(newElem, oldElem){
var oldText = oldElem.text(),
text = '';
newElem.text().split('').forEach(function(val, i){
if (val != oldText.charAt(i))
text += "<span class='highlight'>"+val+"</span>";
else
text += val;
});
newElem.html(text);
}
.highlight {background-color: #B4D5FF}
So, I need some help to understand how to apply this javascript function on each table row.
Thank you, have a nice day.
I can see you also use jquery so:
$(.table tr).each(function(index){
$(this).addClass("highlight");
});
that way you can apply highlight to every row.
It seems like your current highlight function "highlights" chars that have changed in the string but I have no idea what it has to do with rows... What is $("#new") ... what is $("#old")...
**UPDATE **
$("table tr").each(function(index){
a = $(this).find("td");
first_td = a.eq(0);
second_td = a.eq(1);
highlight(second_td, first_td);
});
I am using flask.
I pass 4 different lists into the HTML file, loop through them and put their value in the table
{% for (s_pid, s_name, s_cpu_percent, s_memory_percent) in zip(pid, name, cpu_percent, memory_percent)%}
<tr>
<td id="task-pid">{{s_pid}}</td>
<td id="task-name">{{s_name}}</td>
<td id="task-cpu-percent">{{s_cpu_percent}}</td>
<td id="task-memory-percent">{{s_memory_percent}}</td>
</tr>
{% endfor %}
It looks great and I can see every value in the table clearly
I need to update these values every 5 seconds and for that, I am using jquery (using ajax just to get the updated value and put in the values below e.g var task_status_cpu_percent = data["task status cpu percent"];(list))
for(var i = 0; i< task_status_pid.length; i++){
$("#task-pid").text(task_status_pid[i]);
$("#task-memory-percent").text(task_status_memory_percent[i]);
$("#task-name").text(task_status_name[i]);
$("#task-cpu-percent").text(task_status_cpu_percent[i]);
}
task_status_pid is a list, in fact, all of the task_status are lists in the same length but when the jquery code accrues it doesn't do anything! I tried using replaceWith and that didn't go well
what happened is that all the values were on the first tab.
what do I need to do in order to go through all of the values in task-pd task-name etc' like it is on the loop ({% for (s_pid, s_name, s_cpu_percent, s_memory_percent) in zip(pid, name, cpu_percent, memory_percent)%})
You need to use class or add a counter to the ID. IDs MUST be unique
So EITHER
{% set count = namespace(value=0) %}
{% for (s_pid, s_name, s_cpu_percent, s_memory_percent) in zip(pid, name, cpu_percent, memory_percent)%}
<tr>
<td id="task-pid{{count.value}}">{{s_pid}}</td>
<td id="task-name{{count.value}}">{{s_name}}</td>
<td id="task-cpu-percent{{count.value}}">{{s_cpu_percent}}</td>
<td id="task-memory-percent{{count.value}}">{{s_memory_percent}}</td>
</tr>
{% set count.value = count.value + 1 %}
{% endfor %}
and then
$("#task-pid"+i).text(task_status_pid[i]);
OR (recommended)
const $tasks = $(".task-pid");
for(var i = 0; i< task_status_pid.length; i++){
$tasks.eq(i).text(task_status_pid[i]);
....
}
using <td class="task-pid" etc
I am trying to populate a table in django template, but I want to compare cell values, one of them is javascript variable and another is django template variable. Is it possible to compare them without converting django variables to javascript variables? or is there a quick work around?
{% for x in price_data %}
<script>
counter++
var VALUE =document.getElementById("price_table").rows[0].cells.item(counter).innerHTML;
</script>
{% if x.room_scan == i and x.checkin == VALUE %}
I want to check if x.checkin is equals to VALUE.
Thanks.
You can do something like this. Code I used to create the table (as I don't have original table)
<table id="price_table">
<tr>
{% for x in range %}
<td>{{ x }}</td>
{% endfor %}
</tr>
</table>
I passed these variables to view
{
'range': range(1,5),
'x_room_scan': 2
}
and inside the template (I reduced the code a bit to simplify it)
<script>
var counter = 0;
{% for x in range %}
counter++;
var value =document.getElementById("price_table").rows[0].cells.item(counter).innerHTML;
if({{ x_room_scan }} == value) {
console.log(value);
}
{% endfor %}
</script>
I am implementing a table using vuejs + django.
When I am declaring row and column statically, it is working. but when I am taking the value from django, it is not working anymore, though it is printing correct value.
My HTML code looks like
{% verbatim %}
<div class="col-9">
<label><h4>Position</h4></label> col: {{tableCols}} : row: {{tableRows}} (here it is printing correct value)
<table>
<tr v-for="row in tableRows">
<td v-for="col in tableCols"
v-bind:class="{selected: selectedData === counter(row,col)}"
v-on:mousedown="mouseDown(counter(row,col))"
v-on:mouseover="mouseOver(counter(row,col))"
v-on:mouseup="mouseUp"
>
{{rowName[row-1]}}:{{col}}:{{counter(row,col)}}
</td>
</tr>
</table>
</div>
<input type="hidden" name="containerIDs" v-model="selectedData">
{% endverbatim %}
and vuejs code looks like
new Vue({
el: '#testtube',
data: {
tableCols : "{{testtubeplate.number_of_columns}}", // 12,
tableRows : "{{testtubeplate.number_of_rows}}", //8,
rowName: RowName,
selectedData: [],
cellNo: 0,
isMouseDown:false
},
methods: {
...
in HTML I have printed col: {{tableCols}} : row: {{tableRows}}, which is printing right value, but only 1 row and 2 column is creating instead of 12 and 8.
But if I put 12, 8 statically it is working. (pic attached)
Any suggestions?
Got the solution,
I have to convert to value into integer.
So need to change vuejs code as
tableCols : parseInt("{{testtubeplate.number_of_columns}}"), // 12,
tableRows : parseInt("{{testtubeplate.number_of_rows}}"), //8,