我正在嘗試重現這個專案,該專案由一個帶有 Flask 后端組件的應用程式和一個使用 vue-js 的前端組成。后端如下:
from flask import Flask, request, jsonify
from flask_cors import CORS
import pandas as pd
app = Flask(__name__)
CORS(app)
@app.route('/')
def hello():
offset = request.args.get('offset', default = 1, type = int)
limit = request.args.get('limit', default = 1, type = int)
df = pd.read_csv('test_data.csv', skiprows=range(1, offset 1), nrows=limit, parse_dates=['X'])
cols = [col for col in df.columns if col.startswith('Y')]
configs = {
'Y1': {'color': '#483D8B', 'col_name': 'name_Y1'},
'Y2': {'color': '#f87979', 'col_name': 'name_Y2'},
'Y3': {'color': '#00BFFF', 'col_name': 'name_Y3'},
}
datasets = []
for k, c in enumerate(cols):
datasets.append({
'label': configs[c]['col_name'],
'borderColor': configs[c]['color'],
'backgroundColor': configs[c]['color'],
'borderWidth': 2,
'pointBorderColor': '#000000',
'lineTension': k*0.23, # line curve
'pointRadius': 2,
'pointBorderWidth': 1,
'fill': False,
'data': df[c].tolist()
})
chart = {
'labels': df['X'].dt.strftime('%H:%M:%S').tolist(),
'datasets': datasets
}
return jsonify({'chart_data': chart})
app.run()
使用以下腳本生成 csv 檔案:
import pandas as pd
from datetime import datetime, timedelta
import random
now = datetime.now()
configs = {
'Y1': (0, 250),
'Y2': (0, 500),
'Y3': (0, 750),
}
df_num_rows = 10000
y_vals = {i: [random.randint(*configs[i]) for j in range(df_num_rows)] for i in configs}
df = pd.DataFrame({
'X': ['{:%Y-%m-%d %H:%M:%S}'.format(now timedelta(seconds=i)) for i in range(df_num_rows)],
**y_vals # ex: {**{'a': [1, 2, 3], 'b': [4, 5, 6]}}
})
df.to_csv('test_data.csv', index=False)y_vals = {i: [random.randint(*configs[i]) for j in range(df_num_rows)] for i in configs}
html檔案是:
<div id="app">
<div style="width: 600px; height: 300px;margin: 0 auto;">
<line-chart v-bind:chart-data="chartData"></line-chart>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue-chartjs.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-resource.min.js"></script>
<script>
Vue.component('line-chart', {
extends: VueChartJs.Line,
//mixins: [VueChartJs.mixins.reactiveProp],
props: ['chartData'],
data: function() {
return {
options: {
tooltips: {
mode: 'index', // so all three tooltips appear
intersect: false, // so don't need to be precise with the cursor on the point
},
scales: {
xAxes: [{ // configs for our X axis
display: true,
scaleLabel: {
display: true,
labelString: 'Time'
}
}],
yAxes: [{ // configs for our Yaxis
display: true,
scaleLabel: {
display: true,
labelString: 'Value'
}
}]
},
responsive: true,
maintainAspectRatio: false,
}
}
},
watch: { // this will be our flag for update
'chartData.update_flag': function(new_val, old_val) {
this.$data._chart.update();
}
},
mounted() {
this.renderChart(this.chartData, this.options); // Initialize and render the chart
}
})
var vm = new Vue({
el: '#app',
data() {
return {
chartData: {
'update_flag': 0, // our flag for update
'labels': [], // our labels
'datasets': [] // our datasets
},
}
},
methods: {
fillData(limit, offset) {
Vue.http.get('http://127.0.0.1:5000/?limit=' limit '&offset=' offset).then(res => {
if (offset === 0) { // if first request let's receive 20 rows of data/labels
this.chartData.labels = res.body.chart_data.labels;
this.chartData.datasets = res.body.chart_data.datasets;
} else {
this.chartData.labels.splice(0, limit); // remove the first label
this.chartData.labels.push(...res.body.chart_data.labels); // like python unpack
for (var i = 0; i < res.body.chart_data.datasets.length; i ) {
this.chartData.datasets[i].data.splice(0, limit);
this.chartData.datasets[i].data.push(...res.body.chart_data.datasets[i].data);
}
}
this.chartData.update_flag ^= 1;
}, err => {
console.log(err);
}).then(() => { // this will happen always
setTimeout(this.fillData, 1000, 1, offset limit); // preparing next request
});
}
},
created() {
this.fillData(20, 0); // let's ask for the first 20 rows
},
})
</script>
當我啟動應用程式并通過網路瀏覽器(端點:localhost:5000?limit=100&offset=100例如)執行 GET 請求時,網頁顯示與 json 對應的字串,即,它沒有呈現 html 頁面,因為,我認為,它不知道它必須呈現檔案index.html。盡管如此,前端正在接收一些資料。
如果我將代碼更改為return flask.render_template('client.html', chart_data=jsonify({'chart_data': chart},在前端我注意到它的this.chartData.labels長度為 0,就好像前端沒有正確接收資料一樣,對于this.chartData.datasets.
如何在這樣的應用程式中正確呈現 html 檔案?
uj5u.com熱心網友回復:
您應該在燒瓶中有兩個函式 - 具有兩個不同的 URL。
帶有 url 的第一個函式/應該只發送模板 - 而這個沒有limit=100&offset=100你的URL應該在瀏覽器中加載。
帶有 url 的第二個函式,即。/get_data應該發送 JSON 資料 - 并且Vue.http.get()應該limit=100&offset=100像這樣使用它/get_data?limit=100&offset=100
如果你想用單個 url 來做,那么你應該使用 someif/else來檢測頁面是否被瀏覽器加載并發送HTML- 或通過Vue并發送JSON。也許您可以使用一些帶有您期望回應的資訊的 HTTP 標頭JSON。Accept: application/json
具有兩個功能的完整作業代碼
from flask import Flask, request, jsonify, render_template_string
from flask_cors import CORS
import pandas as pd
app = Flask(__name__)
CORS(app)
def generate_data():
import pandas as pd
from datetime import datetime, timedelta
import random
now = datetime.now()
configs = {
'Y1': (0, 250),
'Y2': (0, 500),
'Y3': (0, 750),
}
df_num_rows = 10000
y_vals = {i: [random.randint(*configs[i]) for j in range(df_num_rows)] for i in configs}
df = pd.DataFrame({
'X': ['{:%Y-%m-%d %H:%M:%S}'.format(now timedelta(seconds=i)) for i in range(df_num_rows)],
**y_vals # ex: {**{'a': [1, 2, 3], 'b': [4, 5, 6]}}
})
df.to_csv('test_data.csv', index=False)
#y_vals = {i: [random.randint(*configs[i]) for j in range(df_num_rows)] for i in configs}
# ------
@app.route('/')
def index():
return render_template_string('''
<div id="app">
<div style="width: 600px; height: 300px;margin: 0 auto;">
<line-chart v-bind:chart-data="chartData"></line-chart>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue-chartjs.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-resource.min.js"></script>
<script>
Vue.component('line-chart', {
extends: VueChartJs.Line,
//mixins: [VueChartJs.mixins.reactiveProp],
props: ['chartData'],
data: function() {
return {
options: {
tooltips: {
mode: 'index', // so all three tooltips appear
intersect: false, // so don't need to be precise with the cursor on the point
},
scales: {
xAxes: [{ // configs for our X axis
display: true,
scaleLabel: {
display: true,
labelString: 'Time'
}
}],
yAxes: [{ // configs for our Yaxis
display: true,
scaleLabel: {
display: true,
labelString: 'Value'
}
}]
},
responsive: true,
maintainAspectRatio: false,
}
}
},
watch: { // this will be our flag for update
'chartData.update_flag': function(new_val, old_val) {
this.$data._chart.update();
}
},
mounted() {
this.renderChart(this.chartData, this.options); // Initialize and render the chart
}
})
var vm = new Vue({
el: '#app',
data() {
return {
chartData: {
'update_flag': 0, // our flag for update
'labels': [], // our labels
'datasets': [] // our datasets
},
}
},
methods: {
fillData(limit, offset) {
Vue.http.get('http://localhost:5000/get_data?limit=' limit '&offset=' offset).then(res => {
if (offset === 0) { // if first request let's receive 20 rows of data/labels
this.chartData.labels = res.body.chart_data.labels;
this.chartData.datasets = res.body.chart_data.datasets;
} else {
this.chartData.labels.splice(0, limit); // remove the first label
this.chartData.labels.push(...res.body.chart_data.labels); // like python unpack
for (var i = 0; i < res.body.chart_data.datasets.length; i ) {
this.chartData.datasets[i].data.splice(0, limit);
this.chartData.datasets[i].data.push(...res.body.chart_data.datasets[i].data);
}
}
this.chartData.update_flag ^= 1;
}, err => {
console.log(err);
}).then(() => { // this will happen always
setTimeout(this.fillData, 1000, 1, offset limit); // preparing next request
});
}
},
created() {
this.fillData(20, 0); // let's ask for the first 20 rows
},
})
</script>
''')
@app.route('/get_data')
def get_data():
offset = request.args.get('offset', default = 1, type = int)
limit = request.args.get('limit', default = 1, type = int)
df = pd.read_csv('test_data.csv', skiprows=range(1, offset 1), nrows=limit, parse_dates=['X'])
cols = [col for col in df.columns if col.startswith('Y')]
configs = {
'Y1': {'color': '#483D8B', 'col_name': 'name_Y1'},
'Y2': {'color': '#f87979', 'col_name': 'name_Y2'},
'Y3': {'color': '#00BFFF', 'col_name': 'name_Y3'},
}
datasets = []
for k, c in enumerate(cols):
datasets.append({
'label': configs[c]['col_name'],
'borderColor': configs[c]['color'],
'backgroundColor': configs[c]['color'],
'borderWidth': 2,
'pointBorderColor': '#000000',
'lineTension': k*0.23, # line curve
'pointRadius': 2,
'pointBorderWidth': 1,
'fill': False,
'data': df[c].tolist()
})
chart = {
'labels': df['X'].dt.strftime('%H:%M:%S').tolist(),
'datasets': datasets
}
return jsonify({'chart_data': chart})
if __name__ == '__main__':
generate_data()
app.run()
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/338427.html
