设为首页 收藏本站
查看: 1072|回复: 0

[经验分享] Redis源码分析(五)--- sparkline微线图

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-10-11 08:38:07 | 显示全部楼层 |阅读模式
       sparkline这个单词,我第一次看的时候,也不知道这什么意思啊,以前根本没听过啊,但是这真真实实的出现在了redis的代码中了,刚刚开始以为这也是属于普通的队列嘛,就把他分在了struct包里了。好来分析完了,与原本我所想的差太大了。sparkline英文中的意思“微线图”,这么说吧,类似于折线图,由一个一个信息点构成。所以看到这个意思,你或许就明白了sparkline.c是干什么用的了吧,就是画图用的。我们看看这个画图的内部结构是什么,画图需要的元素是哪些:



    /* sparkline.h -- ASCII Sparklines header file
     *
     * ---------------------------------------------------------------------------
     *
     * Copyright(C) 2011-2014 Salvatore Sanfilippo <antirez@gmail.com>
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are met:
     *
     *   * Redistributions of source code must retain the above copyright notice,
     *     this list of conditions and the following disclaimer.
     *   * Redistributions in binary form must reproduce the above copyright
     *     notice, this list of conditions and the following disclaimer in the
     *     documentation and/or other materials provided with the distribution.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     * POSSIBILITY OF SUCH DAMAGE.
     */  
      
    #ifndef __SPARKLINE_H  
    #define __SPARKLINE_H  
      
    /* sparkline是一类信息体积小和数据密度高的图表。目前它被用作一些测量,
     *相关的变化的信息呈现的方式,如平均温度,股市交投活跃。sparkline常常以一组多条的形式出现在柱状图,折线图当中。
     *可以理解为一个图线信息 */  
    /* A sequence is represented of many "samples" */  
    /* 可以理解为图像上的一个信息点,有文字,有值的大小 */  
    struct sample {  
        double value;  
        char *label;  
    };  
      
    /* 图线信息结构体,包括n个元素点,可以据此描述出图,绘图的可不是直接按点和值直接绘制的 */  
    struct sequence {  
        //当前元素点个数  
        int length;  
        //总共的文字个数,有些点没有label描述,为NULL  
        int labels;  
        //元素点列表  
        struct sample *samples;  
        //元素中的最大值,最小值  
        double min, max;  
    };  
      
    /* 定义了一些渲染图时候一些属性操作设置 */  
    #define SPARKLINE_NO_FLAGS 0  
    #define SPARKLINE_FILL 1      /* Fill the area under the curve. */  
    #define SPARKLINE_LOG_SCALE 2 /* Use logarithmic scale. */  
      
    struct sequence *createSparklineSequence(void);  //创建图线序列结构体  
    void sparklineSequenceAddSample(struct sequence *seq, double value, char *label); //在图线序列中添加一个信息点  
    void freeSparklineSequence(struct sequence *seq);   //释放图线序列  
    sds sparklineRenderRange(sds output, struct sequence *seq, int rows, int offset, int len, int flags); //渲染图线序列为一个图,其实就是得到一个字符串组成的图  
    sds sparklineRender(sds output, struct sequence *seq, int columns, int rows, int flags); //方法同上,只是少可一个偏移量  
      
    #endif /* __SPARKLINE_H */  


我们看到上面的sample结构体其实“信息点”元素的意思了,里面很简单,一个文字label,一个value值,简洁明了,然后sequence就自然是图线了,里面就定义了元素点列表了,里面还有线的长度,和最大值,最小值,信息还挺全面的线。后序的画图操作都是根据这个图线序列结构体操作的。结构体一点都不复杂。但是画图的实现一点都不简单,如何根据给定的一些点信息画出一个类似折线的图线呢,可别忘了,这是要在命令行窗口的图线哦,所以不会像高级语言中的GUI的操作那样很方便,我们看看redis代码中是怎么写的。



    /* sparkline.c -- ASCII Sparklines  
     * This code is modified from http://github.com/antirez/aspark and adapted  
     * in order to return SDS strings instead of outputting directly to  
     * the terminal.  
     *  
     * ---------------------------------------------------------------------------  


在sparkline.c中的注释声明,此代码修改自 http://github.com/antirez/aspark,原来是开源的代码实现,但是一开始真的不知道还有这么个叫aspark的东西,都跟BigData里的spark搞混了,然后我点击此地址,官方解释来了:



    aspark is a C program to display ASCII Sparklines.  
    It is completely useless in 2011.  


不错,意思就是说aspark就是用来在C程序上显示图线效果的。后来,我看了下,的确代码差不多,redis的代码在上面加了自己的东西,稍稍修改,aspark的图线展现有几种形式,第一种,最简单的展示:

$ ./aspark 1,2,3,4,10,7,6,5
    `-_
__-`   `

第二张把行数扩展为更多行,展示更多的数据,上面的这个为2行展示,数据多的时候,调节行数,默认输出2行展示

$ ./aspark 1,2,3,4,5,6,7,8,9,10,10,8,5,3,1 --rows 4
       _-``_   
     _`        
   -`       `  
_-`          `_


当然可以更加可视化,在空白处填充字符,看起来更舒服:

$ ./aspark 1,2,3,4,5,6,7,8,9,10,10,8,5,3,1 --rows 4 --fill
       _o##_   
     _#|||||   
   o#|||||||#  
_o#||||||||||#_

用了"|"符号,很有想象力的哦,最最关键的我们看如何实现这样的效果呢,核心代码如下:



    /* Render part of a sequence, so that render_sequence() call call this function
     * with differnent parts in order to create the full output without overflowing
     * the current terminal columns. */  
    /* 渲染出这个图线信息 */  
    sds sparklineRenderRange(sds output, struct sequence *seq, int rows, int offset, int len, int flags) {  
        int j;  
        double relmax = seq->max - seq->min;  
        int steps = charset_len*rows;  
        int row = 0;  
        char *chars = zmalloc(len);  
        int loop = 1;  
        int opt_fill = flags & SPARKLINE_FILL;  
        int opt_log = flags & SPARKLINE_LOG_SCALE;  
      
        if (opt_log) {  
            relmax = log(relmax+1);  
        } else if (relmax == 0) {  
            relmax = 1;  
        }  
      
        while(loop) {  
            loop = 0;  
            memset(chars,' ',len);  
            for (j = 0; j < len; j++) {  
                struct sample *s = &seq->samples[j+offset];  
                //value派上用处了  
                double relval = s->value - seq->min;  
                int step;  
      
                if (opt_log) relval = log(relval+1);  
                //最后会算出相关的step  
                step = (int) (relval*steps)/relmax;  
                if (step < 0) step = 0;  
                if (step >= steps) step = steps-1;  
      
                if (row < rows) {  
                    /* Print the character needed to create the sparkline */  
                    /* step控制输出的字符是哪一个 */  
                    int charidx = step-((rows-row-1)*charset_len);  
                    loop = 1;  
                    if (charidx >= 0 && charidx < charset_len) {  
                        chars[j] = opt_fill ? charset_fill[charidx] :  
                                              charset[charidx];  
                    } else if(opt_fill && charidx >= charset_len) {  
                        //用"|"填充内容,更加可视化  
                        chars[j] = '|';  
                    }  
                } else {  
                    /* Labels spacing */  
                    if (seq->labels && row-rows < label_margin_top) {  
                        loop = 1;  
                        break;  
                    }  
                    /* Print the label if needed. */  
                    if (s->label) {  
                        int label_len = strlen(s->label);  
                        int label_char = row - rows - label_margin_top;  
      
                        if (label_len > label_char) {  
                            loop = 1;  
                            chars[j] = s->label[label_char];  
                        }  
                    }  
                }  
            }  
            if (loop) {  
                row++;  
                output = sdscatlen(output,chars,len);  
                output = sdscatlen(output,"\n",1);  
            }  
        }  
        zfree(chars);  
        return output;  
    }  


由于本人能力有限,有点不太懂里面的具体细节,大概看了下,把变量用到的地方稍稍看了下,上面的代码都是非常优秀的代码,值得我们学习,今天至少让我知道了什么叫sparkline叫什么 了,哈哈。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-25792-1-1.html 上篇帖子: Redis源码分析(四)-- sds字符串 下篇帖子: redis安装和配置
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表