-
|
I have a Python Quart app as shown below. from quart import Quart, render_template
app = Quart(__name__)
@app.get("/")
async def root():
return await render_template("index.html")
@app.get("/newchart")
async def new_chart():
data = [2, 8, 13, 15, 9, 14]
return await render_template("chart.html", data=data)
app.run(debug=True)The content of the <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Example Chart</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<h1>Example Chart</h1>
<button hx-get="/newchart" hx-target="#chart">New Chart</button>
<br>
<div id="chart"></div>
</body>
</html>The content of the <div style="max-width: 700px">
<canvas id="myChart"></canvas>
</div>
<script>
const ctx = document.getElementById("myChart");
new Chart(ctx, {
type: "bar",
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
label: "# of Votes",
data: {{ data }}
borderWidth: 1,
},
],
},
options: {
scales: {
y: {
beginAtZero: true,
},
},
},
});
</script>My goal is to use data generated in the Python code and graph it using Chart.js. But in my example the chart does not appear on the web page when I click the button. Does anyone know how I can accomplish this? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 7 replies
-
|
You have a syntax error: data: {{ data }}It should be: data: {{ data }},Overall it's probably better to get the chart options as JSON from a separate endpoint. The Python server will be able to format its syntax correctly. |
Beta Was this translation helpful? Give feedback.
-
|
Here is my latest attempt which mostly works. The Python code and HTML templates are shown below along with a video of the example. The chart works fine when it is first created, but when the data is updated, the new chart will slowly appear. This seems to randomly occur so does anyone know why this happens? Is there a better way to update or create the chart using the HTML template? app.pyfrom quart import Quart, render_template, request
app = Quart(__name__)
@app.get("/")
async def root():
return await render_template("index.html")
@app.post("/results")
async def results():
form = await request.form
nums = form["numbers"]
nums = [int(n) for n in nums.split(",")]
return await render_template("results.html", numbers=nums)
app.run(debug=True)templates/index.html<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Example</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script>
</head>
<body>
<h1>Example</h1>
<p>Enter some numbers in the form.</p>
<form hx-post="/results" hx-target="#results">
<input type="text" name="numbers" value="1, 12, 3, 4, 5, 6" />
<button type="submit">Submit Numbers</button>
</form>
<div id="results"></div>
</body>
</html>templates/results.html<p>Numbers are: {{ numbers }}</p>
<div id="resultsjs"></div>
<div style="max-height: 480px; max-width: 700px">
<canvas id="myChart"></canvas>
</div>
<script>
function createChart(nums) {
// Show numbers in div to make sure this template works
const resultsJsDiv = document.getElementById("resultsjs");
resultsJsDiv.innerHTML = `<p>Numbers JS are: ${nums}</p>`;
// Show numbers in chart
const ctx = document.getElementById("myChart");
new Chart(ctx, {
type: "bar",
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
label: "# of Votes",
data: nums,
borderWidth: 1,
},
],
},
options: {
animation: false,
scales: {
y: {
beginAtZero: true,
},
},
},
});
}
createChart({{ numbers | tojson }});
</script>DemoHere is a demo of running the code on macOS 15.7 in Safari 26.1. Notice the chart will slowly appear when it is updated. This doesn't occur all the time. I want the updated chart to just appear like it does when it is first created; not slowly appear. Screen.Recording.2025-12-10.at.8.14.42.AM.mov |
Beta Was this translation helpful? Give feedback.
-
|
This example uses HTML data attributes to pass the labels and values to the chart with the app.pyHere is the Python code that returns the results template along with data values that are eventually used by the chart. from quart import Quart, render_template, request
app = Quart(__name__)
@app.get("/")
async def root():
return await render_template("index.html")
@app.post("/results")
async def results():
form = await request.form
nums = form["numbers"]
y = [float(n) for n in nums.split(",")]
x = list(range(1, len(y) + 1))
data = {"x": x, "y": y}
return await render_template("results.html", data=data)
app.run(debug=True)index.htmlHere is the main HTML page which uses htmx for the form submission and targets the <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Example Chart</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script>
</head>
<body>
<main class="container">
<h1>Example Chart</h1>
<p>Enter some numbers then submit the form.</p>
<form hx-post="/results" hx-target="#results">
<input type="text" name="numbers" class="form-control mb-3" value="1, 12.4, 3, 4, 5.1, 6" />
<button type="submit" class="btn btn-primary mb-3">Submit Numbers</button>
</form>
<div id="results">
<p>X values are: 0</p>
<p>Y values are: 0</p>
<div id="retain" style="max-height: 480px; max-width: 600px">
<canvas id="myChart" hx-preserve></canvas>
</div>
</div>
</main>
<script src="{{ url_for('static', filename='linechart.js') }}"></script>
</body>
</html>results.htmlHere is the HTML template used for the results response. Notice the data attributes on the div for providing the labels and values to the JavaScript code which creates the chart. <p>X values are: {{ data['x'] }}</p>
<p>Y values are: {{ data['y'] }}</p>
<div
id="retain"
style="max-height: 480px; max-width: 600px"
data-labels="{{ data['x'] | tojson }}"
data-values="{{ data['y'] | tojson }}"
>
<canvas id="myChart" hx-preserve></canvas>
</div>linechart.jsLastly, here is the JavaScript file that handles creating the chart and updating it if it already exists. The let chart = null;
function createChart(labels, values) {
if (chart) {
chart.data.labels = labels;
chart.data.datasets[0].data = values;
chart.update();
return;
}
const ctx = document.getElementById("myChart");
chart = new Chart(ctx, {
type: "line",
data: {
labels: labels,
datasets: [
{
label: "# of Items",
data: values,
},
],
},
});
}
htmx.on("htmx:afterSwap", (evt) => {
const div = document.getElementById("retain");
const labels = JSON.parse(div.dataset.labels);
const values = JSON.parse(div.dataset.values);
createChart(labels, values);
}); |
Beta Was this translation helpful? Give feedback.
This example uses HTML data attributes to pass the labels and values to the chart with the
htmx:afterSwapevent. Thehx-preserveattribute keeps the canvas from being replaced by the HTML response.app.py
Here is the Python code that returns the results template along with data values that are eventually used by the chart.