以前にもpythonでPCAを実施するスクリプトを書いてみていたが、webアプリ版を作ってみた。まずは低機能にとりあえず数値だけのcsvファイルを投げるとプロットを描かせるだけのものから
こんな感じ。
Flaskのviewsはこんなふうで。
/flask_root_folder/app/views/stat.py
# PCA, MDS, tSNEのプロットを作成する from functools import wraps from flask import request, redirect, url_for, render_template, flash, Blueprint, session, g, send_file, current_app, Response from flask_wtf import FlaskForm from wtforms import SubmitField, SelectField from werkzeug.utils import secure_filename import csv, os, shutil, subprocess, sys, re, time import numpy as np from matplotlib import pyplot as plt from sklearn.decomposition import PCA from sklearn.manifold import MDS, TSNE import matplotlib import matplotlib.pyplot as plt app = Blueprint('stat', __name__) ALLOWED_EXTENSIONS = set(['txt', 'csv']) #選択できる入力ファイルの拡張子 def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS class StatForm(FlaskForm): stat_type = SelectField('statistics type', choices=[('PCA', 'PCA'), ('MDS', 'MDS'), ('tSNE', 'tSNE')]) submit = SubmitField('Submit') @app.route('/stat', methods=['GET', 'POST']) def stat_index(): user = g.user.name form=StatForm() dir = "./user/" + user + "/stat" if os.path.exists(dir): shutil.rmtree(dir) if not os.path.exists(dir): os.makedirs(dir) input = dir + "/input.txt" output = dir + "/output.txt" #ファイルをアップロードして入力する if request.method == 'POST': if 'file' not in request.files: flash('No file part') return redirect(request.url) #ファイルが許可された形式でないとエラーを返す file = request.files['file'] if file.filename == '': flash('No selected file') return redirect(request.url) #ファイルが選択されていないとエラーを返す if file and allowed_file(file.filename): file.save(input) #ファイルをinputに保存する npArray = np.loadtxt(input, delimiter = ",") X = np.array(npArray) stat_fig = dir + "/stat_" + str(time.time()) + ".png" if form.stat_type.data == "PCA": pca = PCA() pca.fit(X) transformed = pca.fit_transform(X) plt.figure() plt.scatter(transformed[:, 0], transformed[:, 1]) plt.title('principal component') plt.xlabel('pc1') plt.ylabel('pc2') stat_result = pca.explained_variance_ratio_ plt.savefig(stat_fig) img_url = "../../static/" + stat_fig # flask_root_folder/app/staticにflask_root_folder/userのリンクを張ってある return render_template('/tools/stat.html', stat_result=stat_result, form=form, img_url=img_url) if form.stat_type.data == "MDS": mds = MDS(n_jobs=4) mds.fit(X) transformed = mds.fit_transform(X) plt.figure() plt.scatter(transformed[:, 0], transformed[:, 1]) plt.title('Multidimensional scaling') plt.savefig(stat_fig) img_url = "../../static/" + stat_fig return render_template('/tools/stat.html', form=form, img_url=img_url) if form.stat_type.data == "tSNE": tsne = TSNE() tsne.fit(X) transformed = tsne.fit_transform(X) plt.figure() plt.scatter(transformed[:, 0], transformed[:, 1]) plt.title('t-distributed Stochastic Neighbor embedding') plt.savefig(stat_fig) img_url = "../../static/" + stat_fig return render_template('/tools/stat.html', form=form, img_url=img_url) return render_template('/tools/stat.html', form=form)
template
flask_root_folder/app/templates/tools/stat.html
{% extends "base.html" %} {% import "bootstrap/wtf.html" as wtf %} {% block title %}Statistics_tool{% endblock %} {% block head %} {{ super() }} {% endblock %} {% block scripts %} {{ super() }} {% endblock %} {% block page_top %} <h2>Statistics tool</h2> <div class="row"> <form class="form form-group form-group-sm" method=post enctype=multipart/form-data> <div class="col-xs-1"> </div> <div class="col-xs-10"> <br> <b>Upload csv file</b><br> <input type=file name=file> <br> <b>statistics type</b><br> {{ form.stat_type }}<br><br> <b>start statistics</b><br> <input class='btn btn-primary' type=submit value=Submit> {% if img_url %} <p><img src="{{ img_url }}"></p> {% endif %} <br><br> {{ stat_result|safe }}<br> {% for message in get_flashed_messages() %} <div class="alert alert-success">{{ message }}</div> {% endfor %} <br><br> </div> </form> </div> <div class="col-xs-1"> </div> {% endblock %} {% block left %} {% endblock %} {% block right %} {% endblock %} {% block page_bottom %} {% endblock %}