Logarithmic y axis with morris.js

房东的猫 提交于 2020-01-13 05:09:07

问题


I'm trying to get a logarithmic scale for the y-axis of a morris.js line chart.

http://www.oesmith.co.uk/morris.js/lines.html

I already tried playing with the yLabelFormat option, but it's not what I need. Any hint is appreciated.

If there is no way of doing this with morris.js, you can suggest another lightweight javascript library to make simple line charts with logarithmic scale.


回答1:


You can extend Morris and modify the transY function to do the logarithmic scale.

I also added the gridIntegers parameter to have only integers on the y-Axis.

Remove the code after the transY function if you want only the yLogScale.

Use the following snippet to view the result with yLogScale parameter set as true or false.

(function () {
    var $, MyMorris;

    MyMorris = window.MyMorris = {};
    $ = jQuery;

    MyMorris = Object.create(Morris);

    MyMorris.Grid.prototype.gridDefaults["yLogScale"] = false;
    MyMorris.Grid.prototype.gridDefaults["gridIntegers"] = false;

    MyMorris.Grid.prototype.transY = function (y) {
        if (!this.options.horizontal) {
            if (this.options.yLogScale) {
                return this.bottom - (this.height * Math.log((y + 1) - this.ymin) / Math.log(this.ymax / (this.ymin + 1)));
            } else {
                return this.bottom - (y - this.ymin) * this.dy;
            }
        } else {
            return this.left + (y - this.ymin) * this.dy;
        }
    };

    MyMorris.Grid.prototype.setData = function (data, redraw) {
        var e, idx, index, maxGoal, minGoal, ret, row, step, total, y, ykey, ymax, ymin, yval, _ref;
        if (redraw == null) {
            redraw = true;
        }
        this.options.data = data;
        if ((data == null) || data.length === 0) {
            this.data = [];
            this.raphael.clear();
            if (this.hover != null) {
                this.hover.hide();
            }
            return;
        }
        ymax = this.cumulative ? 0 : null;
        ymin = this.cumulative ? 0 : null;
        if (this.options.goals.length > 0) {
            minGoal = Math.min.apply(Math, this.options.goals);
            maxGoal = Math.max.apply(Math, this.options.goals);
            ymin = ymin != null ? Math.min(ymin, minGoal) : minGoal;
            ymax = ymax != null ? Math.max(ymax, maxGoal) : maxGoal;
        }
        this.data = (function () {
            var _i, _len, _results;
            _results = [];
            for (index = _i = 0, _len = data.length; _i < _len; index = ++_i) {
                row = data[index];
                ret = {
                    src: row
                };
                ret.label = row[this.options.xkey];
                if (this.options.parseTime) {
                    ret.x = Morris.parseDate(ret.label);
                    if (this.options.dateFormat) {
                        ret.label = this.options.dateFormat(ret.x);
                    } else if (typeof ret.label === 'number') {
                        ret.label = new Date(ret.label).toString();
                    }
                } else {
                    ret.x = index;
                    if (this.options.xLabelFormat) {
                        ret.label = this.options.xLabelFormat(ret);
                    }
                }
                total = 0;
                ret.y = (function () {
                    var _j, _len1, _ref, _results1;
                    _ref = this.options.ykeys;
                    _results1 = [];
                    for (idx = _j = 0, _len1 = _ref.length; _j < _len1; idx = ++_j) {
                        ykey = _ref[idx];
                        yval = row[ykey];
                        if (typeof yval === 'string') {
                            yval = parseFloat(yval);
                        }
                        if ((yval != null) && typeof yval !== 'number') {
                            yval = null;
                        }
                        if (yval != null) {
                            if (this.cumulative) {
                                total += yval;
                            } else {
                                if (ymax != null) {
                                    ymax = Math.max(yval, ymax);
                                    ymin = Math.min(yval, ymin);
                                } else {
                                    ymax = ymin = yval;
                                }
                            }
                        }
                        if (this.cumulative && (total != null)) {
                            ymax = Math.max(total, ymax);
                            ymin = Math.min(total, ymin);
                        }
                        _results1.push(yval);
                    }
                    return _results1;
                }).call(this);
                _results.push(ret);
            }
            return _results;
        }).call(this);
        if (this.options.parseTime) {
            this.data = this.data.sort(function (a, b) {
                return (a.x > b.x) - (b.x > a.x);
            });
        }
        this.xmin = this.data[0].x;
        this.xmax = this.data[this.data.length - 1].x;
        this.events = [];
        if (this.options.events.length > 0) {
            if (this.options.parseTime) {
                this.events = (function () {
                    var _i, _len, _ref, _results;
                    _ref = this.options.events;
                    _results = [];
                    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
                        e = _ref[_i];
                        _results.push(Morris.parseDate(e));
                    }
                    return _results;
                }).call(this);
            } else {
                this.events = this.options.events;
            }
            this.xmax = Math.max(this.xmax, Math.max.apply(Math, this.events));
            this.xmin = Math.min(this.xmin, Math.min.apply(Math, this.events));
        }
        if (this.xmin === this.xmax) {
            this.xmin -= 1;
            this.xmax += 1;
        }
        this.ymin = this.yboundary('min', ymin);
        this.ymax = this.yboundary('max', ymax);
        if (this.ymin === this.ymax) {
            if (ymin) {
                this.ymin -= 1;
            }
            this.ymax += 1;
        }
        if (((_ref = this.options.axes) === true || _ref === 'both' || _ref === 'y') || this.options.grid === true) {
            if (this.options.ymax === this.gridDefaults.ymax && this.options.ymin === this.gridDefaults.ymin) {
                this.grid = this.autoGridLines(this.ymin, this.ymax, this.options.numLines);
                this.ymin = Math.min(this.ymin, this.grid[0]);
                this.ymax = Math.max(this.ymax, this.grid[this.grid.length - 1]);
            } else {
                step = (this.ymax - this.ymin) / (this.options.numLines - 1);
                if (this.options.gridIntegers) {
                    step = Math.max(1, Math.round(step));
                }
                this.grid = (function () {
                    var _i, _ref1, _ref2, _results;
                    _results = [];
                    for (y = _i = _ref1 = this.ymin, _ref2 = this.ymax; step > 0 ? _i <= _ref2 : _i >= _ref2; y = _i += step) {
                        _results.push(y);
                    }
                    return _results;
                }).call(this);
            }
        }
        this.dirty = true;
        if (redraw) {
            return this.redraw();
        }
    };
}).call(this);

var data = [
    { y: '2016-01', a: 1, b: 5 },
    { y: '2016-02', a: 2,  b: 3 },
    { y: '2016-03', a: 2,  b: 2 },
    { y: '2016-04', a: 1,  b: 1000 },
    { y: '2016-05', a: 2,  b: 2 },
    { y: '2016-06', a: 3,  b: 3 },
    { y: '2016-07', a: 1, b: 2 }
  ];

var morrisArea =
Morris.Area({
    element: 'chart',
    data: data,
  xkey: 'y',
  ykeys: ['a', 'b'],
  labels: ['Label A', 'Label B'],
  fillOpacity: 0.6,
  hideHover: 'auto',
  resize: true,
  yLogScale: true,
  gridIntegers: true,
  pointFillColors: ['#ffffff'],
  pointStrokeColors: ['black'],
  lineColors: ['gray', 'blue'],
  gridIntegers: true,
  ymin: 0
});

$(".button").on("click", function() {
  $(".button").removeClass("on");
  $(this).addClass("on");
});

function setYLogScale(status) {
  morrisArea.options["yLogScale"] = status;
  morrisArea.setData(data);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css" rel="stylesheet" />
<style>
  body { font-family: Arial; }
  .button {
    padding: 3px 5px;
    border: 1px solid black;
    background-color: #eeeeee;
    display: inline-block;
    cursor: pointer;
  }
  .on { background-color: lightblue; }
</style>

<div class="button" onclick="setYLogScale(true);">yLogScale ON</div>
<div class="button" onclick="setYLogScale(false);">yLogScale OFF</div>
<div id="chart"></div>


来源:https://stackoverflow.com/questions/24328631/logarithmic-y-axis-with-morris-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!