add MyShow

master
xianhu 2017-01-18 14:53:41 +08:00
parent 79c789df53
commit 3bb4f7b877
12 changed files with 527 additions and 0 deletions

View File

@ -0,0 +1,38 @@
# _*_ coding: utf-8 _*_
import pymysql
con = pymysql.connect(host="xxxx", user="root", passwd="xxxx", db="xxxx", charset="utf8")
cursor = con.cursor()
con.autocommit(1)
def get_all_topics():
cursor.execute("select distinct t_topic_id, t_topic_name from t_zhihutopics where t_topic_haschildren = 1;")
return [item for item in cursor.fetchall() if item[0].strip()]
def get_topic_data(topic_id, topic_name):
data_dict = {
"type": "force",
"nodes": [
{"id": topic_id, "name": topic_name, "level": 0}
],
"links": []
}
nodes_set = set([topic_id])
dai_ids = set([topic_id])
while dai_ids:
cursor.execute("select * from t_zhihutopics where t_topic_parentid = %s;", [dai_ids.pop()])
for item in cursor.fetchall():
_, t_id, t_name, t_pid, t_haschild, _ = item
if t_id not in nodes_set:
nodes_set.add(t_id)
data_dict["nodes"].append({"id": t_id, "name": t_name, "level": 1 if t_pid == topic_id else 2})
data_dict["links"].append({"source": t_pid, "target": t_id})
if t_haschild == 1:
dai_ids.add(t_id)
return data_dict

100
MyShow/MyShow.py 100644
View File

@ -0,0 +1,100 @@
# _*_ coding: utf-8 _*_
import logging
import GetData_zhihu
# flask
from flask import Flask, session, request
from flask import render_template, flash, redirect, url_for, jsonify
# flask extends
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import Length, Email
# application
app = Flask(__name__)
app.config["SECRET_KEY"] = "hard to guess string"
# manager and bootstrap
bootstrap = Bootstrap(app=app)
# global data
zhihu_all_topics = GetData_zhihu.get_all_topics()
zhihu_all_topics_key = {}
zhihu_init_topics = GetData_zhihu.get_topic_data(topic_id="19559424", topic_name="数据分析")
# form class
class UserForm(FlaskForm):
name = StringField("name", validators=[Email(message="邮箱格式不正确!")])
password = PasswordField("password", validators=[Length(min=6, message="密码长度至少6位")])
submit = SubmitField("提 交")
@app.route("/", methods=["GET", "POST"])
def temp():
return redirect(url_for("index"))
@app.route("/index/", methods=["GET", "POST"])
def index():
user_form = UserForm()
if request.method == "POST":
if user_form.validate_on_submit():
session["username"] = user_form.name.data
else:
flash(user_form.errors["name"][0] if "name" in user_form.errors else user_form.errors["password"][0])
else:
if request.args.get("action") == "login_out":
flash("您已成功退出系统!")
session["username"] = None
return redirect(url_for("index"))
elif request.args.get("action") == "overview":
session["page_type"] = "overview"
return redirect(url_for("index"))
elif request.args.get("action") == "zhihu_topics":
session["page_type"] = "zhihu_topics"
return redirect(url_for("index"))
return render_template("index.html", name=session.get("username"), page_type=session.get("page_type", "overview"), form=user_form)
@app.route("/zhihu_get_topics_list/", methods=["post"])
def zhihu_get_topics_list():
key = request.form.get("key")
result = {"success": 1, "data": []}
if key:
if key in zhihu_all_topics_key:
result = zhihu_all_topics_key[key]
else:
for item in zhihu_all_topics:
if item[1].find(key) >= 0:
result["data"].append({"id": item[0], "name": item[1]})
if len(result["data"]) > 0:
result["success"] = 1
zhihu_all_topics_key[key] = result
logging.debug("all_topics_key increase: %s", len(zhihu_all_topics_key))
return jsonify(result)
@app.route("/zhihu_get_topics_data/", methods=["post"])
def zhihu_get_topics_data():
if request.form["id"] == "19554449":
result = zhihu_init_topics
else:
result = GetData_zhihu.get_topic_data(request.form["id"], request.form["name"])
return jsonify(result)
@app.errorhandler(404)
def page_not_found(excep):
return render_template("error.html", error=excep, name=session.get("username")), 404
# main process
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s\t%(levelname)s\t%(message)s")
logging.debug("app url_map: %s", app.url_map)
app.run()

View File

@ -0,0 +1,105 @@
/*
* Base structure
*/
/* Move down content because we have a fixed navbar that is 50px tall */
body {
padding-top: 50px;
}
/*
* Global add-ons
*/
.sub-header {
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
/*
* Top navigation
* Hide default border to remove 1px line.
*/
.navbar-fixed-top {
border: 0;
}
/*
* Sidebar
*/
/* Hide for mobile, show later */
.sidebar {
display: none;
}
@media (min-width: 768px) {
.sidebar {
position: fixed;
top: 51px;
bottom: 0;
left: 0;
z-index: 1000;
display: block;
padding: 20px;
overflow-x: hidden;
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
background-color: #f5f5f5;
border-right: 1px solid #eee;
}
}
/* Sidebar navigation */
.nav-sidebar {
margin-right: -21px; /* 20px padding + 1px border */
margin-bottom: 20px;
margin-left: -20px;
}
.nav-sidebar > li > a {
padding-right: 20px;
padding-left: 20px;
}
.nav-sidebar > .active > a,
.nav-sidebar > .active > a:hover,
.nav-sidebar > .active > a:focus {
color: #fff;
background-color: #428bca;
}
/*
* Main content
*/
.main {
padding: 20px;
}
@media (min-width: 768px) {
.main {
padding-right: 40px;
padding-left: 40px;
}
}
.main .page-header {
margin-top: 0;
}
/*
* Placeholder dashboard ideas
*/
.placeholders {
margin-bottom: 30px;
text-align: center;
}
.placeholders h4 {
margin-bottom: 0;
}
.placeholder {
margin-bottom: 20px;
}
.placeholder img {
display: inline-block;
border-radius: 50%;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

35
MyShow/static/js/echarts.min.js vendored 100644

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,60 @@
{% extends "bootstrap/base.html" %}
{% block title %}MyShow{% endblock %}
{% block head %}
{{ super() }}
<meta charset="utf-8">
<!-- Icon -->
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<!-- Custom styles for this template -->
<link href="{{ url_for('static', filename='css/dashboard.css') }}" rel="stylesheet">
<!-- Loading Js Files -->
<script src="{{ url_for('static', filename='js/jquery-3.0.0.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/echarts.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/bootstrap-typeahead.min.js') }}"></script>
{% endblock %}
{% block navbar %}
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="nav navbar-header navbar-left">
<a class="navbar-brand" href="/">数据展示</a>
</div>
<div id="navbar" class="nav navbar-nav navbar-right" style="margin-right: 10px">
{% if name %}
<div class="btn-group navbar-btn navbar-right">
<button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown">
{{ name }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" id="login_out_menu">
<li><a href="/index/?action=login_out">退出登录</a></li>
</ul>
</div>
{% elif form %}
<form class="navbar-form navbar-right" role="form" method="post">
{{ form.csrf_token }}
<div class="form-group">
{{ form.name(placeholder="Email...", class="form-control") }}
</div>
<div class="form-group">
{{ form.password(placeholder="Password...", class="form-control") }}
</div>
{{ form.submit(class="btn btn-primary") }}
</form>
{% endif %}
</div>
</div>
</nav>
{% endblock %}
{% block content %}
<div class="container">
{% block page_content %}
{% endblock %}
</div>
{% endblock %}

View File

@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block title %}数据展示 - Error{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>{{ error }}</h1>
</div>
{% endblock %}

View File

@ -0,0 +1,165 @@
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block head %}
{{ super() }}
<script type="text/javascript">
var zhihu_topics = function () {
var zhi_graph = echarts.init(document.getElementById("show_data_zhihu"));
zhi_graph.showLoading();
var set_zhi_graph = function (data) {
zhi_graph.hideLoading();
var categories = [];
for (var i = 0; i < 3; i++) {
categories[i] = {
name: "级别" + (i + 1)
}
}
data.nodes.forEach(function (node) {
node.symbolSize = 10;
node.label = {
normal: {
show: true,
position: 'right'
}
};
node.draggable = true;
node.category = node.level
});
data.links.forEach(function (link) {
link.label = {
normal: {
show: false
}
}
});
var option = {
title: {
text: '知乎话题关系图',
subtext: '展示知乎话题之间的关系',
top: 'top',
left: 'left'
},
legend: [{
data: categories.map(function (a) {
return a.name;
})
}],
animation: false,
series: [
{
type: 'graph',
layout: data.type,
data: data.nodes,
links: data.links,
categories: categories,
roam: true,
force: {
repulsion: 100
}
}
]
};
zhi_graph.setOption(option);
};
$.post("/zhihu_get_topics_data/", {id: "19554449", name: "数据"}, set_zhi_graph);
var subjects = [
{ id: 1, name: '北京' },
{ id: 2, name: '南京' },
{ id: 3, name: '广州' },
{ id: 4, name: '深圳' }
];
$('#zhihusearch').typeahead({
source: function (query, process) {
$.post("/zhihu_get_topics_list/", {key: query}, function (e) {
if (e.success) {
process(e.data);
}
});
}, {#source: subjects,#}
items: 20,
minLength: 1,
updater: function (item) {
return item;
},
displayText: function (item) {
return ":" + item["name"];
},
afterSelect: function (item) {
$.ajax({
type: "post",
async: true,
url: "/zhihu_get_topics_data/",
data: item,
dataType: "json",
beforeSend: function (xhr) {
zhi_graph.showLoading();
return true
},
success: function (result) {
if (result) {
set_zhi_graph(result)
}
},
error: function (error) {
alert("请求数据失败!");
zhi_graph.hideLoading();
}
});
}
});
};
</script>
{% endblock %}
{% block page_content %}
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li class={% if page_type == "overview" %} "active" {% else %} "" {% endif %} >
<a href="/index/?action=overview">概 述</a>
</li>
<li class={% if page_type == "zhihu_topics" %} "active" {% else %} "" {% endif %} >
<a href="/index/?action=zhihu_topics">知乎话题关系</a>
</li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main" style="padding-left: 20px; padding-right: 20px">
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert">&times;</button>
{{ message }}
</div>
{% endfor %}
{% if page_type == "overview" %}
<h2>数据展示,点击左边菜单栏即可查看各类数据展示页面</h2>
{% elif page_type == "zhihu_topics" %}
<div class="nav navbar-nav navbar-right">
<input type="text" class="form-control" id="zhihusearch" data-provide="typeahead" placeholder="Search Topic...">
</div>
<div id="show_data_zhihu" style="width: 900px; height:600px;"></div>
<script type="text/javascript">
zhihu_topics();
</script>
{% endif %}
</div>
</div>
{% endblock %}
{% block scripts %}
<script type="text/javascript">
</script>
{% endblock %}

View File

@ -41,6 +41,10 @@
### python_restful_api.py: RESTful API进阶: 连接数据库、添加参数、Token认证、返回代码说明等
### python_context.py: With语句和上下文管理器ContextManager
### python_flask.py: Flask相关说明
### MyShow: 玩点好玩的--知乎全部话题关系可视化Docker+Flask+Bootstrap+echarts+uWSGI+Nginx
===================================================================================================
### 您可以fork该项目, 并在修改后提交Pull request