kuroの覚え書き

96の個人的覚え書き

PCAやMDS plotをpythonで行うWEBアプリ(ver1)

以前にもpythonでPCAを実施するスクリプトを書いてみていたが、webアプリ版を作ってみた。まずは低機能にとりあえず数値だけのcsvファイルを投げるとプロットを描かせるだけのものから

f:id:k-kuro:20191230183032p:plain
PCA by Python

こんな感じ。

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)
        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 %}