看到小芮介绍了pygal文章后, http://rfyiamcool.blog.51cto.com/1030776/1378400, 我一直搞数据工作, 所以对于这种数据的展现很有兴趣. 做了点研究, 记录如下:

=================
pygal的特点
=================
Web中显示chart, 现在的主流做法是使用javascript chart包, 比如highcharts和ECharts, 交互性很好. 另外还有server端生成图片, 然后在浏览器端加载图片, 显然交互性差了很多.

这里介绍第3种做法, 使用 pygal(一个 python 包)在web server 端生成svg矢量图(其实是xml格式), 然后在flask中, 我们可将svg图和普通jinja2参数一样传到html模板中, 最后 web 浏览器就得到图文并茂的结果了.

还有一个方法其实更好, 将svg以文件形式保存下来, 然后在以iframe方式将svg文件引入. 好处是,  iframe有滚动条, 浏览大的svg就不吃力了. 代码如下,

<div class="center"><iframe scrolling="no" frameborder="0" src="../../da/dcb/classmodule__inherit__graph.svg" width="3944" height="832"><p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p></iframe></div>

和 highcharts 等js chart包相比, pygal优势有:
1. 使用highcharts, server端除了一般的endpoint接口外, 还需要写一套api接口, 来返回json格式数据. 使用pygal, 只需要实现普通的endpoint接口.
2. 使用pygal, 使用的数据格式是python原生的tuple和list.
3. 避免了写javascript 代码.

当然, pygal的缺点也很明显:
1. 浏览器兼容性还不是很好, 尤其IE,  IE 9以下干脆不支持svg
2. 交互性还不够丰富

=================
经验总结:
=================
1. svg对象应该直接输出到html的figure标签之下, 而不是在figure/embed属性中
2. svg对象在输出时, 应该加上jinja2的 safe 这个filter
3. view 函数返回的response, 不能设置Content-Type='image/svg+xml'
4. chart.disable_xml_declaration应该设置为True
5. 在server端创建chart对象后, 可以紧接着为chart指定js属性, 来加载本地的svg.jquery.js和pygal-tooltips.js 文件. 如果不指定这个属性, 默认将从 http://kozea.github.com/pygal.js 下载js, 速度较慢. 当然在html端, 仍须再次声明加载这两个js文件.
6. 如果对每个serial的颜色有特别的要求, 可以为chart定制一个style,在sytle中指定serial 的颜色序列.    pygal的style.py其实已经预定义了14种style, 也叫theme, 可以作为参考.
from pygal.style import Style
custom_style=Style(colors=(
                       '#b6e354'  #green   
                       ,'#fd971f' #yellow       
                       ,'#DC3912' #red                
                ))
chart = pygal.Line(legend_at_bottom=True,style=custom_style) ;    
7. 可以为chart指定height和width, 但是值不能太小(比如50), 太小了将导致pygal进入死循环, 最终报MemoryError内存不足错误.
8. 一般不需要为chart 指定width, 它自动会撑满上层html容器. 如果需要显示很宽幅度的图, 可以将 chart 的width/height设置的大一些, 比如2000, 这时相当于将图像做了zoom out, 图像上的字体会变小的.
    chart.width=2000
    chart.height=400
9. 接前一点, 如果你还不想让字体变小, 应该将chart放在一个带滚动条的div中, div上可以加上滚动条(比如width为940).  
   同时, 为svg xml节点增加 width 属性(这个width相当于canvas的width), 设置它稍微大于chart的width(chart为2000, svg width为2100), 这样的效果即是1:1输出, 没有缩放.
   演示: http://www.w3schools.com/svg/tryit.asp?filename=trysvg_rect
   
   当前的pygal没有办法做到这个, 等我有空的时候, fork一下pygal项目, 增加这个feature, 即为pygal的chart对象增加一个svg_width和svg_height属性, 在做render时, 直接为svg xml的svg node加上 <svg  style="width:2100px" > 这样的属性.  
   
   在pygal支持这个功能之前, 我们还是有2个办法为svg增加width属性:
   
   第1个方法是, 增加一个css文件, 在里面为svg 设置style, 然后在html中引用这个css文件, 这个方法仅仅适合于html有一个svg对象, 或者有多个svg, 但size都一样的情形.
    =======large_svg.css file
    svg{
      width:2100px;
    }

=======html 文件部分内容
    <link rel="stylesheet" href="/static/css/large_svg.css" >  
    <div id="svg_scrollable_div" style="width:940px;overflow-x:auto;overflow-y:hidden;">
            <figure>
              <!-- the following safe filter is must -->
             {{svg_xml|safe}}  
            </figure>
    </div>    
    
    第2个方法是, 在chart做完render之后, 直接修改svg的xml字符串,为 svg xml节点增加  style="width:2100px"  属性. 这个方法的适应性很好.
    svg_xml = chart.render()
    svg_xml='<svg  style="width:2100px" '+svg_xml[4:]

=================
示例
=================
本示例演示了, 如何将svg以jinja2参数的形式传递到html中.

#--------------------------------------
# flask view 函数
#--------------------------------------

@mod.route("/svg")
def raw_svgs():
    chart = pygal.Line(legend_at_bottom=True,legend_box_size=18)
    
    ##--------------------------------------
    ##Declare the location of svg.jquery.js and pygal-tooltips.js in server side.
    ##--------------------------------------
    #It must be declare in server side, not html file
    #if not declare in server, by default it will load the two js files located in http://kozea.github.com/pygal.js. And it will slow down the page loading
    
    #1, It works, load local js files
    SITE_ROOT = os.path.realpath(os.path.dirname(__file__))
    chart.js = [os.path.join(SITE_ROOT, "static/js/", "svg.jquery.js"),
                os.path.join(SITE_ROOT, "static/js/", "pygal-tooltips.js")]
        
    #2.a, It Works, but it is ugly because it use local absolute http url  
    #chart.js =['http://127.0.0.1:5000/static/js/svg.jquery.js',
    #     'http://127.0.0.1:5000/static/js/pygal-tooltips.js']
    
    #2.b, works, use local CDN absolute http url  
    #chart.js =['http://another_server/pygal-tooltips.js',
    #     'http://another_server/svg.jquery.js']            
       
    #3, Does not work, error raised at visiting, IOError: [Errno 2] No such file     
    #chart.js = [url_for('static', filename='js/svg.jquery.js'),
    #            url_for('static', filename='js/pygal-tooltips.js')]  
        
    
    #disable xml root node     
    chart.disable_xml_declaration = True      
    chart.title = 'Browser usage evolution (in %)'
    chart.x_labels = map(str, range(2002, 2013))
    chart.add('Firefox', [None, None, 0, 16.6,   25,   31, 36.4, 45.5, 46.3, 42.8, 37.1])
    chart.add('Chrome',  [None, None, None, None, None, None,    0,  3.9, 10.8, 23.8, 35.3])
    chart.add('IE',      [85.8, 84.6, 84.7, 74.5,66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1])
    chart.add('Others',  [14.2, 15.4, 15.3, 8.9, 9, 10.4,  8.9,  5.8,  6.7,  6.8,  7.5])
    
    svg_xml = chart.render()
    
    response=make_response(render_template('test_svg.html', title="Hello pygal" , svg_xml=svg_xml))
    #response.headers['Content-Type']='image/svg+xml' 不能设置Content-Type为svg模式
    return response

#--------------------------------------
# test_svg.html 文件         
#--------------------------------------
<!DOCTYPE html>
<html>
  <head>
    <title>{{title}}</title>
    <!-- 这里也要说明要加载svg.jquery.js和pygal-tooltips.js, 否则不显示tooltips -->
    <script type="text/javascript" src="/static/js/svg.jquery.js"></script>
    <script type="text/javascript" src="/static/js/pygal-tooltips.js"></script>     
   </head>
  <body>
        <figure>
          <!-- the following safe filter is must -->
         {{svg_xml|safe}}  
        </figure>
  </body>
</html>

使用pygal 做chart图的经验分享的更多相关文章

  1. Kittenblock画笔基础,移动留下痕迹的蝴蝶,图形化编程经验分享

    Kittenblock画笔基础,移动留下痕迹的蝴蝶,图形化编程经验分享 跟很多学生聊过,很多学生不是不努力,只是找不到感觉.有一点不可否认,同样在一个教室上课,同样是一个老师讲授,学习效果迥然不同.关 ...

  2. 经验分享:Essay写作遇到困难请你这样做

    很多留学生在essay写作中可能会遇到很多困难,要么是essay写作内容出现问题,又或者是对于essay写作格式的不了解,导致自己无法顺利完成essay.今天小编就收集了几位留学生的写作经验分享,希望 ...

  3. Splunk大数据分析经验分享

    转自:http://www.freebuf.com/articles/database/123006.html Splunk大数据分析经验分享:从入门到夺门而逃 Porsche 2016-12-19 ...

  4. (转)CMOS Sensor的调试经验分享

    CMOS Sensor的调试经验分享 我这里要介绍的就是CMOS摄像头的一些调试经验. 首先,要认识CMOS摄像头的结构.我们通常拿到的是集成封装好的模组,一般由三个部分组成:镜头.感应器和图像信号处 ...

  5. Android内存优化解决 资料和总结的经验分享

    在前公司做一个图片处理的应用时, 项目交付的时候,客户的手机在运行应用的时候,一直在崩溃,而这个异常就是OutOfMemory的错误,简称为OOM, 搞得我们也是极其的崩溃,最后 ,我们是通过网上搜集 ...

  6. CMOS Sensor的调试经验分享

    转自:http://bbs.52rd.com/forum.php?mod=viewthread&tid=276351 CMOS Sensor的调试经验分享 我这里要介绍的就是CMOS摄像头的一 ...

  7. 漏洞经验分享丨Java审计之XXE(下)

    上篇内容我们介绍了XXE的基础概念和审计函数的相关内容,今天我们将继续分享Blind XXE与OOB-XXE的知识点以及XXE防御方法,希望对大家的学习有所帮助! 上期回顾  ◀漏洞经验分享丨Java ...

  8. 我的秋招经验分享(已拿BAT头条网易滴滴)

    微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...

  9. CMOS Sensor的调试经验分享【转】

    转自:https://blog.csdn.net/yapingmcu/article/details/37817727 转自:http://bbs.52rd.com/forum.php?mod=vie ...

随机推荐

  1. XCode显示iOS Simulators时不显示系统版本号并出现Identifier(UUID)

    如果出现如下的显示问题,说明你添加了多个相同系统版本的iOS Simulators: 打开Windows->Devices,查看已经出现了相同版本的模拟器: 那么我们删除一些相同的模拟器,即可解 ...

  2. Oracle数据库查看当前数据库版本的方法

    常用的有三种方法:   方法一:v$version SQL> select * from v$version; BANNER ---------------------------------- ...

  3. Linux 开机 logo 修改

    从内核被解压到文件系统被挂载,我们看到的经典画面是一个小企鹅.如果嫌小企鹅枯燥,我们可以把它换掉. 1. 准备图片 这里需要的是 ppm 图片,所以,我们需要把常见格式给转换为 .ppm 才能使用.c ...

  4. hihocoder #1112 树上的好路径

    时间限制:1000ms单点时限:1000ms内存限制:256MB 描述 现在有一棵有N个带权顶点的树,顶点编号为1,2,...,N.我们定义一条路径的次小(最小)权为它经过的所有顶点(包括起点和终点) ...

  5. CloseHandle(IntPtr handle)抛异常

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static ext ...

  6. POJ - 1511 Invitation Cards(Dijkstra变形题)

    题意: 给定一个有向图,求从源点到其他各点的往返最短路径和.且这个图有一个性质:任何一个环都会经过源点. 图中的节点个数范围:0-100w; 分析: 我们先可以利用Dijkstra算法求解从源点到其余 ...

  7. 【Alpha阶段】第六次Scrum例会

    会议信息 时间:2016.10.27 21:30 时长:30min 地点:大运村1号公寓5楼楼道 类型:日常Scrum会议 个人任务报告 姓名 今日已完成Issue 明日计划Issue 工作困难 今日 ...

  8. SQLite的WAL机制

    标注:本文部分有黏贴这里的资料,另外还加了一些自己的笔记 使用CoreData或者SQLite3的时候,我们创建的数据库, 在存储的文件夹中有三个文件:分别为:**.sqlite  **.sqlite ...

  9. 强大的css3

    强大的css3 我们知道,这几年来智能手机的高速发展使得人们使用移动端上网的时间和人数已经超过了PC端.例如在2015年,就中国电商而言,各电商平台在移动端持续发力,移动端购物占比不断攀升,双11期间 ...

  10. python redis使用心得

    发布与订阅 连接池代码 redis_conn.py import redis REDIS_CONN = { 'HOST': '192.168.1.11', 'PORT': '6378', 'DB': ...