1. 程式人生 > >(3)基於Echarts外掛的多維資料視覺化設計和實現

(3)基於Echarts外掛的多維資料視覺化設計和實現

說完了內部擴充套件和新增介面,接著就是外部的介面了。
外部的介面主要對原始資料進行一系列的計算、變換、包裝,然後放入option各個引數中。
createChart介面

/**
   * 通過Echarts的setOption介面建立echarts多維圖表
*/
createChart: function () {
    //optionData由外部介面計算出的配置項資料
    var optionData = this.optionData;
    var option = {
        color:this.colors,
        grid:optionData.gridData,
        tooltip: {
            trigger: 'item'
}, //圖例預設為垂直放置 legend: { show: true, orient: 'vertical', data: optionData.legendData, right: 0, top: 60, formatter: function (name) { return echarts.format.truncateText(name, 80, '14px Microsoft Yahei'
, '…'); }, tooltip:{ show: true } }, calculable: true, singleAxis: optionData.singleAxisData, xAxis:optionData.xAxisData, yAxis: optionData.yAxisData, series: optionData.seriesData }; if(optionData.formatter){ option.tooltip.formatter = optionData.formatter; } this
.chart.setOption(option); },

從上面程式碼中可以看到,多維圖表的構造和普通圖表並沒有本質上的區別,只是傳入的引數不同而已。
不知大家有木有發現,在上面程式碼中optionData是一個關鍵變數,各種賦值都跟它密切相關。

getChartOption介面: 而 optionData是從何處來的呢?在我的設計中getChartOption函式經過一系列的處理和計算,最終得到optionData所需的資料。getChartOption函式程式碼較多,其實還可以繼續劃分為幾個小函式,這樣程式碼看起來更優雅一些。

/**
 * 獲取圖表的option配置項 
*/
getChartOption: function () {
    var that = this;
    var state = that.properties.state;
    var measure = that.properties.measure;
    var dimension = that.properties.dimension;
    var dLen = dimension.length;
    var mLen = measure.length;
    var visualMLen = mLen === 0 ? 1 : mLen;
    var chart = this.chart;
    var color = this.colors;
    var finalData = that.finalData;
    // 求出圖例的資料
    var legendData = mLen > 0 && measure.map(function(item) {
            return item.alias;
        });
    // 獲取維度中連續的欄位
    var continuousKey = that.getContinueKey(dimension, mLen);
    // 該展示連續和離散圖表
    var isContinue = continuousKey.length > 0;
    // 將原始資料進行標準化,得到按維度分類的資料
    var categoryData = that.standarHigherData(finalData, measure, dimension);
    // 計算出各級維度label顯示需要的各種屬性資訊,如:label座標值、所佔區域寬度、分隔線座標值
    var percentData = that.calLabelProperty(categoryData.chartLabelData, continuousKey.length > 0);
    var chartData = categoryData.chartData;
    var peakValue = categoryData.peakValue;
    //圖表到左邊的距離
    var LEFT_DISTANCE = mLen === 0 ? 10 : 60;
    var sum = categoryData.chartLabelData[0] && categoryData.chartLabelData[0].sum;
    var showClassNum = categoryData.chartLabelData.length;
    //圖表grid到圖表最上面的距離
    var TOP_DISTANCE = 28;
    //圖表grid的x軸label所佔的高度
    var AXIS_LABEL_HEIGHT = 50;
    //圖表圖形顯示區域到圖表最右邊的距離
    var RIGHT_DISTANCE = 100;
    //圖表圖形實際顯示寬度
    var realChartWidth = this.getWidth() - LEFT_DISTANCE - RIGHT_DISTANCE;
    //圖表圖形實際顯示高度
    var realChartHeight = this.getHeight() - (showClassNum == 0 ? 14 : TOP_DISTANCE * showClassNum) - (visualMLen - 1 ) * 10 - AXIS_LABEL_HEIGHT;
    //圖表每一個grid所佔的寬度
    var perChartWidth = realChartWidth / (isContinue ? chartData.length : sum);
    var xAxisData = [], yAxisData = [], gridData = [], seriesData = [], singleAxisData = [];
    var xAxisObj, gridObj, yAxisObj, seriesObj, singleAxisObj;
    var perGridHeight = realChartHeight / visualMLen, gridWidth = 0;
    var gridIndex = 0, left = LEFT_DISTANCE;
    /*
     * 為了避免label數量眾多,而圖表所佔寬度不夠時導致地標籤重疊的情況發生,
     * 故需要對chartData和percentData的資料,結合realChartWidth和continuousKey進行二次計算
     * 以便圖表得到最佳的展示結果,此時會人為剔除一些label標籤,不會展示所有的label
    */
    var category = that.preprocessCategory(percentData, realChartWidth, continuousKey, chartData);
    var categoryIndex = category.categoryIndex;
    var disContinuousKey = that.getDisGroupItem(dLen, continuousKey);
    // 處理懸浮框的顯示格式
    var formatter = that.curry(that.processTooltipFormatter, dimension, measure, disContinuousKey);     
    //分別對每一個度量進行遍歷
    for (var j = 0; j < visualMLen; j++) {
        left = LEFT_DISTANCE;
        //對chartData圖表資料進行遍歷
        for (var i = 0, dataItem ; i < chartData.length; i++) {
             dataItem = chartData[i];
             //求出每一個分組的寬度大小
             gridWidth = isContinue ? perChartWidth : dataItem.count * perChartWidth;
             if (i >= 1) {
                 if (isContinue) {
                     left += perChartWidth;
                 } else {
                     left += chartData[i - 1].count * perChartWidth;
                 }
             }
             //grid物件的配置資訊
             gridObj = {
                 width: gridWidth,
                 height: perGridHeight,
                 left: left,
                 top: (showClassNum  == 0 ? 14 : TOP_DISTANCE * showClassNum) + (j * perGridHeight + ((j > 0) &&  j * 10))
             };
             //x軸物件的配置資訊
             xAxisObj = that.getXAxisOption({
                 type: dataItem.type,
                 mLen: mLen,
                 measureIndex: j,
                 axisPeak: dataItem.xAxisPeak,
                 realTimeFormat: dataItem.realTimeFormat,
                 timeFormat: dataItem.timeFormat,
                 axisLabel: dataItem.axisLabel,
                 categoryIndex: categoryIndex,
                 gridIndex: gridIndex,
                 gridWidth: gridWidth,
                 continueIndex: dataItem.continueIndex,                 
                 minInterval: dataItem.minInterval,
                 labelData: dataItem.axisLabelData,
                 index: i,
                 dimension:dimension
             });
             //y軸物件的配置資訊
             yAxisObj = that.getYAxisOption({
                 index: i,
                 mLen: mLen,
                 context:  that,
                 measure: measure,                  
                 peakValue: peakValue,
                 gridIndex: gridIndex,
                 measureIndex: j
             });
             //series物件的配置資訊
             seriesObj = that.getSeriesOption({
                 gridIndex: gridIndex,
                 measureIndex: j,
                 context:  that,
                 measure: measure,
                 xAxisType: dataItem.type,
                 xAxisKeyName: dataItem.xAxisKeyName,
                 xAxisKey: dataItem.xAxisKey,
                 state: state,                      
                 realTimeFormat: dataItem.realTimeFormat,
                 dateFormat: dataItem.dateFormat,
                 perChartWidth: perChartWidth,
                 barWidth: '20%',
                 color: color,
                 data: dataItem.data[j]
             });
             xAxisData.push(xAxisObj);
             yAxisData.push(yAxisObj);
             gridData.push(gridObj);
             seriesData.push(seriesObj);
             gridIndex++;
        }
    }
    var labelFormatWidth = [];
    //處理非座標軸上的label的配置資訊
    for (i = 0; i < percentData.length; i++) {
        labelFormatWidth[i] = realChartWidth / percentData[i].label.length - 10;
        labelFormatWidth[i] = labelFormatWidth[i] <= 26 ? 26 : labelFormatWidth[i];
        //獲取singleAxisObj軸物件的配置資訊
        singleAxisObj = that.getSingleAxisOption({
            index: i,
            mLen: mLen,
            realChartWidth: realChartWidth,
            realChartHeight: realChartHeight,
            distance: {
                topDistance: TOP_DISTANCE,
                rightDistance: RIGHT_DISTANCE,
                axisLabelHeight: AXIS_LABEL_HEIGHT,
                leftDistance: mLen === 0 ? 10 : LEFT_DISTANCE
            },
            labelFormatWidth: labelFormatWidth,
            percentData: percentData,
            labelData: category.category
        });
        singleAxisData.push(singleAxisObj);
        seriesObj = that.getSingSeriesOption({index: i});
        seriesData.push(seriesObj);
    }
    that.optionData = {
        xAxisData: xAxisData,
        yAxisData: yAxisData,
        gridData: gridData,
        formatter: formatter,
        legendData: legendData,
        singleAxisData: singleAxisData,
        seriesData: seriesData
    };
},  

getChartOption函式作為資料處理的總函式,是整個多維資料圖表外部介面的核心,對於其中一些重要的子函式,本文會一一進行講解。首先來看standarHigherData介面:
standarHigherData介面:該函式主要將原始的多維資料進行分解、變換、包裝。如圖1所示,為多維原始資料。如圖2所示,為處理後的資料。
這裡寫圖片描述

圖1 多維原始資料

這裡寫圖片描述
圖2 經過standarHigherData介面處理後的資料

從上面兩圖中,可以看出處理後的資料和原始資料之間差異性還是很大的,做了很多變換、分解、包裝。
該介面的具體原始碼如下所示:
/**
 * 用於規整高維資料,處理連續和離散情況下資料的內容和格式
 * @param {Array.<Array>} data: 需要分組的源資料
 * @param {Array.<Object>} measure: 包含度量資訊的陣列
 * @param {Array.<Object>} dimension: 包含維度資訊的陣列
*/
standarHigherData: function (data, measure, dimension) {
    var that = this, axisIndex;
    var continuousIndexs = [], groupedCategoryData = {};
    var dLen = dimension.length;
    var mLen = measure.length;
    var yAxisPeak = [], chartData = [], initChartData ;
    //獲取連續的序號
    continuousIndexs = this.getContinueKey(dimension, mLen);
    //是否有連續型資料
    var isContinue = continuousIndexs.length > 0;
    // 當存在兩個和以上的維度連續的情況下,需要對原始資料進行分組合計
    var groupData = this.groupByData(data, dLen, mLen, continuousIndexs);
    //只有一個維度連續或者沒有維度連續的情況
    if (continuousIndexs.length <= 1) {
        groupedCategoryData[dLen - 1] = {};
        groupedCategoryData[dLen - 1].data = that.getDimensionCategory(groupData, dLen, mLen, isContinue);
        (continuousIndexs.length && mLen) && (groupedCategoryData[dLen - 1].xAxisPeak = getDimensionPeak(groupedCategoryData[dLen - 1].data.chartData, dimension, dLen - 1, that));
    //多個維度連續
    } else {
        for (var i = 0; i < continuousIndexs.length; i++) {
            var continuousItem = continuousIndexs[i];
            groupedCategoryData[continuousItem] = {};
            groupedCategoryData[continuousItem].data = that.getDimensionCategory(groupData[continuousItem], dLen - continuousIndexs.length + 1, mLen, isContinue);
            groupedCategoryData[continuousItem].xAxisPeak = getDimensionPeak(groupedCategoryData[continuousItem].data.chartData, dimension, continuousItem, that);
            var curYAxisPeakData = groupedCategoryData[continuousItem].data.peakValue;
            if (i == 0) {
                yAxisPeak = curYAxisPeakData;
            } else {
                for (var j = 0; j < mLen; j++) {
                    if (curYAxisPeakData[j].min < yAxisPeak[j].min) {
                        yAxisPeak[j].min = curYAxisPeakData[j].min;
                    }
                    if (curYAxisPeakData[j].max > yAxisPeak[j].max) {
                        yAxisPeak[j].max = curYAxisPeakData[j].max;
                    }
                }
            }
        }
    }
    //一個連續維度或者無連續維度
    if (continuousIndexs.length <= 1) {
        initChartData = groupedCategoryData[dLen - 1].data.chartData;
        for (var i = 0; i < initChartData.length; i++) {
            addAxisDataItem(groupedCategoryData, dimension, chartData, dLen - 1, i, that);
        }
        groupedCategoryData[dLen - 1].data.chartData = chartData;
        axisIndex = dLen - 1;
    //多個維度連續
    } else {
        initChartData = groupedCategoryData[continuousIndexs[0]].data.chartData;
        for (var i = 0, index; i < initChartData.length; i++) {
            for (var j = 0; j < continuousIndexs.length; j++) {
                index = continuousIndexs[j];
                addAxisDataItem(groupedCategoryData, dimension, chartData, index, i, that);
            }
        }
        groupedCategoryData[continuousIndexs[0]].data.chartData = chartData;
        groupedCategoryData[continuousIndexs[0]].data.peakValue = yAxisPeak;
        axisIndex = continuousIndexs[0];
    }
    return groupedCategoryData[axisIndex].data;
    /**
     * 每個資料項新增軸資料
     * @param groupedCategoryData
     * @param dimension
     * @param chartData
     */
    function addAxisDataItem(groupedCategoryData, dimension, chartData, index, dataIndex, context) {
        var gridData = {};
        var xAxisData = {};
        var key = dimension[index];
        var mLen = context.properties.measure.length;
        context.updateAxis('xAxis', xAxisData, key, null, 50);
        gridData = groupedCategoryData[index].data.chartData[dataIndex];
        echarts.util.merge(gridData, xAxisData);
        // ?! 量詞對其後沒有緊接著":"的"mm"字串進行搜尋
        gridData.realTimeFormat = gridData.realTimeFormat && gridData.realTimeFormat.replace(/m{2}(?!:)/g, 'MM');
        mLen == 0 && (gridData.type = 'category');
        gridData.xAxisKeyName = key.alias;
        gridData.xAxisKey = key.key;
        gridData.continueIndex = index;
        gridData.xAxisPeak = groupedCategoryData[index].xAxisPeak || null;
        chartData.push(gridData);
    }
    /**
       * 當軸連續的情況下,求出維度的最大值和最小值
       * @param {Array} chartData:圖表x軸維度資料
       * @return {Object} 包含各個維度最大值和最小值的陣列
    */
    function getDimensionPeak(chartData, dimension, index, context) {
        var totalData = [];
        var xAxisData = {};
        var key = dimension[index];
        context.updateAxis('xAxis', xAxisData, key);
        dateFormat = key.timeFormat || key.colType;
        if (xAxisData.type == 'category') {
            return;
        } else if (xAxisData.type == 'time') {
            for (var i = 0; i < chartData.length; i++) {
                totalData = totalData.concat(chartData[i].axisLabelData.map(function (item) {
                    item = (item === null || item == '' || item == 'null') ? '1970-01-01 00:00:00' : context.processTimeItem(dateFormat, item);
                    return new Date(item).getTime();
                }));
            }
        } else {
            for (var i = 0; i < chartData.length; i++) {
                totalData = totalData.concat(chartData[i].axisLabelData.map(function(item) {
                    return ((item === null || item == '' || item == 'null') ? 0 : item);
                }));
            }
        }
        var min = Math.min.apply(Array, totalData);
        var max = Math.max.apply(Array, totalData);
        return {
            min: min,
            max: max
        };
    }
},

在standarHigherData介面,也有幾個重要的子函式,比如groupByData,主要是當連續的維度在兩個和以上的時候,對資料進行分組合計,在這個過程有新的資料生成。
groupByData介面原始碼如下:

/**
  將資料進行分組,以'\&%#@'分割資料
    @param {Array} data: 需要分組的源資料
    @param {Number} dLen: 維度的個數
    @param {Number} mLen: 度量的個數
    @param {Array} groupDimenIndex: 需要分組的維度序號:[0, 1, 2]
    @return {Array} groupData: 分組後的資料
*/
groupByData: function(data, dLen, mLen, groupDimenIndex) {
    var inGroupIndex = getDisGroupItem(dLen, groupDimenIndex);
    var SPLIT_STR = '\&%#@';
    var key;
    var map = {};
    var dataItem;
    var groupDataMap = {};

    if (groupDimenIndex.length < 2) {
        return data;
    }
    for (var i = 0; i < groupDimenIndex.length; i++) {
        for (var j = 0 ; j < data.length; j++) {
            dataItem = data[j];
            key = getItemKey(dataItem, dLen, groupDimenIndex[i], inGroupIndex, SPLIT_STR);
            if (map[key]) {
                map[key] = sumMeasureItem(map[key], dataItem.slice(dLen, dLen + mLen));
            } else {
                map[key] = dataItem.slice(dLen, dLen + mLen);
            }
        }
        groupDataMap[groupDimenIndex[i]] = map;
        map = {};
    }
    return setMapToArray(groupDataMap);
    /**
       map的資料轉為資料
       @param {Object} map
       @return 返回處理後的map
    */
    function setMapToArray(map) {
        var dimension = [];
        for (var prop in map) {
            if (map.hasOwnProperty(prop)) {
                for (var name in map[prop]) {
                    if (map[prop].hasOwnProperty(name)) {
                        dimension.push(name.split(SPLIT_STR).concat(map[prop][name]));
                    }
                }
                map[prop] = dimension;
                dimension = [];
            }
        }
        return map;
    }
    /**
     用於累加各個度量值
     @param {Array} curSum: 當前累加值
     @param {Array} addMeasure: 需要累加的度量值
        @return {Array} sum: 累加後的值
    */
    function sumMeasureItem(curSum, addMeasure) {
       var sum = [];
       for (var i = 0; i < curSum.length; i++) {
           sum.push(Number(curSum[i]) + Number(addMeasure[i]));
       }
       return sum;
    }
    /**
         獲取分組的key值
         @param {Array} item:分組的單條資料
         @param {Number} groupDimenValue:分組欄位的序號
         @param {Array} inGroupIndex:無需分組的序號
         @return {String} key: 分組的key值
    */
    function getItemKey(item, dLen, groupDimenValue, inGroupIndex, SPLIT_STR) {
        var key ;
        var keyIndex = inGroupIndex.concat([groupDimenValue]);
        for (var i = 0; i < dLen; i++) {
            if (keyIndex.indexOf(i) > -1) {
               key = key == null ? item[i] : (key + SPLIT_STR + item[i]);
            }
        }
        return key;
    }
    /**
       獲取無需分組的欄位序號
       @param {Number} dLen: 維度的個數
       @param {Array} groupDimenIndex: 需要分組的維度序號:[0, 1, 2]
       @return {Array} disGroupIndex: 無需分組的序號
    */
    function getDisGroupItem(dLen, groupDimenIndex) {
        var disGroupIndex = [];
        for (var i = 0; i < dLen; i++) {
            if (groupDimenIndex.indexOf(i) == -1) {
                disGroupIndex.push(i);
            }
        }
        return disGroupIndex;
    }
},

getDimensionPeak子函式,主要是當圖表處於連續的情況下,求出各個連續維度的維度值的最大值和最小值,這樣在各個分組中,才能對比連續性。

接著我們再來看preprocessCategory介面,
preprocessCategory介面:該介面主要對standarHigherData和calLabelProperty處理後的資料進行加工,篩選出在圖表上不會互相重疊的標籤label,最終經過這樣篩選出的資料,才能顯示在圖表上。

/**
   * 根據圖表寬度篩選各個維度上可以容納的標籤和標籤顯示所需要的屬性資訊
   * @param {Array} data: 標籤資料
   * @param {Number} realChartWidth: 圖表寬度
   * @param {Array} continuousKey:連續維度資訊陣列
   * @return {Object} 包含各個維度要顯示的分組資訊和座標軸上顯示的label內容
*/
preprocessCategory: function(data, realChartWidth, continuousKey, chartData) {
    var percentData = echarts.util.clone(data);
    var category = [];
    var width = 0;
    var percent, label, categoryItem, area;
    var lastLabelIndex;
    var interval = 1, classNum = percentData.length;
    var categoryIndex = [];
    var index = classNum - 1;
    var length = continuousKey.length;
    for(var i = 0; i < percentData.length; i++) {
        category[i] = {};
        percent = category[i].percent = [];
        label = category[i].label = [];
        area = category[i].area = [];
        categoryItem = percentData[i];
        for(var j = 0; j < categoryItem.percent.length; j++) {
            //前後兩個標籤是否重疊
            if (j == 0 || calLabelIndex(realChartWidth, categoryItem.percent, j, lastLabelIndex)) {
                percent.push(categoryItem.percent[j]);
                label.push(categoryItem.label[j]);
                area.push(categoryItem.area[j]);
                lastLabelIndex = j;
                //與座標軸分類一致的類別才放入陣列
                if (i == index) {
                   categoryIndex.push(j);
                }
            }
        }
    }
    //如果座標軸上連續的維度key個數大於1
    if (length >= 2) {
        categoryIndex = calContinueAxisLabelIndex(chartData, length, realChartWidth);
    }
    //category是最終篩選出的分類資料,categoryIndex則是最靠近座標軸的維度資料序號值
    return {category: category, categoryIndex: categoryIndex};
    /**
       計算前後兩個label是否重疊
    */
    function calLabelIndex(realChartWidth, data, j, lastLabelIndex) {
        if (Math.round(realChartWidth * (data[j] - data[lastLabelIndex])) >= 26) {
          return true;
        }
        return false;
    }
    /**
     * 計算1個以上連續維度時,座標軸的label顯示情況
     * @param {Array} data :與座標軸上最接近的維度標籤資料
     * @param {Number} length: 連續維度的個數
         */
    function calContinueAxisLabelIndex(data, length, realChartWidth) {
        var categoryIndex = [];
        var chartBit = [];
              //計算出每一個座標系的比率
        for (var i = 0, len = data.length; i < len; i++) {
            chartBit[i] = (i + 1) / len;
        }
        for(var j = 0; j < data.length; j++) {
            //前後兩個標籤是否重疊
            if (j == 0 || calLabelIndex(realChartWidth, chartBit, j, lastLabelIndex)) {
                lastLabelIndex = j;
                categoryIndex.push(j);
            }
        }
        return categoryIndex;
    }
},

processTooltipFormatter介面:該介面主要設定懸浮框的顯示格式和內容,程式碼如下所示

        /**
           * 處理懸浮框顯示的格式
           * @param {Array.<Object>} dimension: 包含維度資訊的陣列
           * @param {Array.<Object>} measure: 包含度量資訊的陣列
           * @param {Array} disContinuousKey:離散欄位陣列
           * @param {Object} params: echarts內部引數
        */
        processTooltipFormatter: function(dimension, measure, disContinuousKey, params) {
            var data = params.data;
            var len = data.length;
            var color = params.color;
            var formatter = '';
            var continueLen = dimension.length - disContinuousKey.length;
            var filterDimension = [];
            var timeFormat = params.timeFormat;
            var aliasIndex = 0;
            if (continueLen == 0) {
                //無連續欄位
                filterDimension = dimension.filter(function (item, index) {
                    return index != (dimension.length -1)
                });
            } else {
                //有連續欄位,並從dimension中刪除,並得到新陣列
                filterDimension = dimension.slice(0, disContinuousKey.length);
            }
            while (len - 2) {
                formatter += getFormatter(color, filterDimension[aliasIndex].alias, data[len - 1]);
                len -- ;
                aliasIndex ++ ;
            }
            formatter += getFormatter(color, params.xAxisKeyName, timeFormat ? new Date(data[0]).Format(timeFormat) : data[0]);
            measure.length > 0 && (formatter += getFormatter(color, measure[params.measureIndex].alias, data[1]));            
            return formatter;
            /**
               獲取資料的html字串
            */
            function getFormatter(color, name, value) {
                 return  ('<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:'
                           + color + '"></span>'+ name +':' + value + '</br>');
            }
        },

以上就是實現過程中的主要介面的介紹和闡釋,還有一些小的功能和介面,由於比較簡單,所以就沒有介紹。還有本文將連續性圖表和離散性圖表分別進行了設計,但是在圖表的實現過程中,由於兩者有太多的相同處理步驟和方法,只是在一些細微處有一些差別。故為了提高程式碼的可複用性,在實現過程中,多維離散和連續圖表的實現是放在一起的。

本人已將整個實現原始碼進行了封裝,只要按文中的要求傳入data、dimension、measure三個引數即可構造出圖表。

如果你注意到一個不準確或似乎不太正確的地方,請讓我知道。謝謝!

相關推薦

3基於Echarts外掛資料視覺設計實現

說完了內部擴充套件和新增介面,接著就是外部的介面了。 外部的介面主要對原始資料進行一系列的計算、變換、包裝,然後放入option各個引數中。 createChart介面: /** * 通過Echarts的setOption介面建立echarts多

資料視覺echart,plotly,matlab

1.前沿 資料視覺化是資料描述的學科,資料視覺化有利於我們更好的展示資料、分析資料等等。 不同維數資料展示 一維資料(玫瑰圖) 二維資料 三維資料 1.雲圖 [X, Y, Z] = peaks; contour

資料進階:22個免費的資料視覺分析工具推薦

22個免費的資料視覺化和分析工具推薦   本文總結推薦22個免費的資料視覺化和分析工具。列表如下: 資料清理(Data cleaning)   當你分析和視覺化資料前,常需要“清理”工作。比如一些輸入性列表“New York City” ,同時其他人會

Shiro許可權管理框架:Shiro中許可權過濾器的初始流程實現原理

本篇是Shiro系列第三篇,Shiro中的過濾器初始化流程和實現原理。Shiro基於URL的許可權控制是通過Filter實現的,本篇從我們注入的ShiroFilterFactoryBean開始入手,翻看原始碼追尋Shiro中的過濾器的實現原理。 初始化流程 ShiroFilterFactoryBean實現

極簡檢視幾何3基於基本矩陣計算攝像機矩陣

MVG: p256 假設F為基本矩陣,S為任意反對稱矩陣,則可以將一對攝像機矩陣定義為: 其中e’為極點, 因為只有在如下條件滿足時,P’的秩為3, 因此S可以表示為極點的反對稱矩陣的形式 進而得到如下求解公式:

運維文檔分享3:V7000存儲運使用手冊

用戶 mar 可用 輸入 指數 基本 raid級別 系統 1.5 前言:最近整理電腦,發現之前寫的幾篇生產上的運維測試文檔,特來分享。一、 IBM Storwize V7000簡介 IBM Storwize V7000 適用於中端市場,它通過內置的自動精簡配置、

jquery知識點總結3---動畫效果+外掛機制

動畫效果 在一定的時間內, 不斷改變元素樣式 slideDown()/slideUp()/slideToggle() fadeOut()/fadeIn()/fadeToggle() show()/

敏捷測試3--基於story的敏捷基礎知識

基於story的敏捷基礎知識----story編寫 為什麼使用Story? 軟體行業40年多來,需求分析技術已經很成熟了,但是MRD驅動的過程不堪重負。因為往往MRD編寫會佔去很多時間,MRD評審又會佔去大量時間,編碼完成過後提測,壓力又全部傾注在QA身上,往往臨計劃上線時

袁芳的學習筆記3基於Predix的微服務

作者:袁芳,北京華瑞特資訊科技有限公司 GE Predix支援微服務,本次通過微服務示例工程,瞭解如何構建、部署、擴充套件微服務。官網有兩個github工程,一個使用Apache CXF執行JAX-RS 2.0標準Java申明@GET,@PUT, @POST, @D

Masonry適配——3UILable如何設定行顯示

UILabel在使用過程中,一個重要的特性是可以進行多行顯示,或者是自定義顯示行數。同時呢,在設定多行顯示的過程中,還可以計算出label所需要的高度。 但不管是使用frame,還是使用masonr

Python推薦演算法案例3——基於協同推薦的電影推薦

    上一節是根據物品item的描述屬性進行基於內容的推薦基於內容的電影推薦,本節中還是以電影推薦為例,講解基於內容的協同推薦演算法。    python程式碼如下import pandas as pd useritemdata=pd.read_csv('C:/Users/

PCL庫學習3----基於平面模型的點雲分割地面點雲分割Plane Model Segmentation

執行環境: VS2013,PCL1.8.0 程式碼參考:        最近做的專案需要對採集到的點雲場景進行去除地面的操作。在參考了CSDN博主:有夢想的田園犬對於PCL官方几種例程中的點雲分割方法的實驗後,考慮到系統的實時性要求,選擇基於平面模型的地面點雲去噪方

Cordova外掛開發3- 將Cordova外掛釋出到npm

本篇文章講述的是如何將自己開發的cordova外掛釋出到npm,具體內容包含以下三個方面: 1,將外掛上傳到github; 2,將外掛釋出到npm; 3,將npm上的外掛與github上同步; 詳

系統基於封裝/抽象/型的簡單的汽車租賃系統

package day803; //汽車總類 public abstract class MotoVehicle { private int day; private String Brand;

【JavaScript】Array 物件[並列陣列、陣列、陣列字串相互轉換]

  使用陣列儲存資料,常常允許用一個指令碼查詢陣列中是否有某一個值(可能驗證使用者輸入到文字框中的資料是否是可接受的)。另外,在查詢匹配的項時,指令碼可以在另一個數組中查詢一些相關的資訊。完成這個任務的 一種方式是使用兩個或多個並行陣列 另一種方式是模擬多維

第八章 3 基於Listcheck適配器的訪問控制

black 輸入參數 rule 訪問 參數 pro tina emp stc denier適配器訪問控制比較死板。Listchecker的適配器更加靈活。 定義handler: apiVersion: config.istio.io/v1alpha2 kind:

基於C#的socket編程的TCP異步實現

ont .text 相關 llb 對象創建 length ethos dex eof 一、摘要   本篇博文闡述基於TCP通信協議的異步實現。 二、實驗平臺   Visual Studio 2010 三、異步通信實現原理及常用方法 3.1 建立連接    在同步模式中,

藍的成長記——追逐DBA1:奔波於路上,挺進山東 藍的成長記——追逐DBA(3):古董上操作,資料匯入匯出成了問題 藍的成長記——追逐DBA8:重拾SP報告,回憶oracle的STATSPACK實驗 藍的成長記— —追逐DBA9:國慶漸去,追逐DBA,新規劃,新啟程

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

什麼是機房三3D監控系統,什麼是機房視覺動力環境監控系統?

隨著計算機技術的迅速發展,數字交換技術的日新月異,計算機通訊已經深入到社會生活並對社會經濟的發展起著決定性的作用,而在這其中計算機機房資料中心作為載體更是整體生態鏈中的重中之重。如果沒有統一的監控系統進行管理,主要是依靠值班人員的定時巡檢來進行系統監控,由於值班

深度學習tensorflow實戰筆記3VGG-16訓練自己的資料並測試儲存模型

    前面的部落格介紹瞭如何把影象資料轉換成tfrecords格式並讀取,本篇部落格介紹如何用自己的tfrecords格式的資料訓練CNN模型,採用的模型是VGG-16。現有的教程都是在mnist或者cifar-10資料集上做的訓練,如何用自己的資料集進行訓練相關的資料比較