A 2D/3D heatmap of the forest cover dataset (100K sample).
Click and drag to zoom. Single click to zoom out.
A 2D/3D heatmap of the forest cover dataset (100K sample).
Click and drag to zoom. Single click to zoom out.
{"all_fields": true, "category": 6, "cluster": null, "cluster_status": false, "code": 200, "columns": 15, "correlations": {}, "created": "2016-03-07T23:55:58.516000", "credits": 0.0, "dataset_origin_status": true, "description": "A tidied up version of [UCI's forest cover dataset](https://archive.ics.uci.edu/ml/datasets/Covertype).", "download": {"code": 0, "excluded_input_fields": [], "header": true, "input_fields": [], "message": "", "preview": [], "separator": ","}, "excluded_fields": [], "field_types": {"categorical": 4, "datetime": 0, "effective_fields": 15, "items": 0, "numeric": 11, "preferred": 15, "text": 0, "total": 15}, "fields": {"000000": {"column_number": 0, "datatype": "int16", "name": "Elevation", "optype": "numeric", "order": 0, "preferred": true, "summary": {"bins": [[1893.72789, 147], [1964.26136, 1144], [2029.44693, 1517], [2085.85576, 2579], [2147.47206, 3525], [2201.08315, 2225], [2249.72827, 3923], [2322.43247, 9129], [2383.70512, 4395], [2431.16074, 7366], [2494.11672, 9047], [2568.16672, 20645], [2636.44147, 16778], [2699.54694, 24275], [2776.40066, 44566], [2851.52281, 36174], [2917.1172, 55803], [2981.54578, 65481], [3043.12585, 52243], [3099.2039, 42604], [3152.21453, 45626], [3207.59075, 48372], [3267.04266, 42264], [3319.28805, 12911], [3366.90042, 16529], [3423.69539, 7764], [3497.76232, 2617], [3588.3429, 662], [3659.32468, 231], [3718.4292, 226], [3776.08333, 84], [3827.44375, 160]], "kurtosis": 0.74923, "maximum": 3858, "mean": 2959.3653, "median": 2995.6424, "minimum": 1859, "missing_count": 0, "population": 581012, "skewness": -0.81759, "splits": [2308.57095, 2463.51629, 2566.15537, 2631.81872, 2690.78914, 2734.39545, 2772.78879, 2809.14953, 2841.8178, 2871.80138, 2897.89048, 2921.2394, 2941.31235, 2960.03261, 2977.43014, 2995.6424, 3014.51473, 3033.9162, 3054.11603, 3075.61137, 3097.97319, 3120.23765, 3141.6344, 3163.41173, 3185.20992, 3205.68212, 3227.98408, 3251.49286, 3278.28962, 3315.27451, 3372.88786], "standard_deviation": 279.98473, "sum": 1719426752, "sum_squares": 5133958162274, "variance": 78391.45141}}, "000001": {"column_number": 1, "datatype": "int16", "name": "Aspect", "optype": "numeric", "order": 1, "preferred": true, "summary": {"bins": [[5.07302, 27471], [14.63572, 15853], [23.89765, 29203], [33.49116, 18896], [45.49191, 42315], [61.58006, 39525], [74.85213, 24765], [86.34731, 27278], [97.94504, 22161], [106.56442, 12528], [115.70348, 21277], [126.72546, 17480], [139.82429, 23755], [153.7447, 14865], [165.27736, 13120], [177.00684, 13884], [189.05358, 12374], [199.99883, 10284], [210.26072, 10168], [218.79135, 5689], [228.24045, 10555], [239.69572, 8903], [253.07079, 13887], [267.20597, 11599], [278.69297, 11152], [287.07845, 6692], [296.42806, 15012], [307.42323, 14087], [319.92957, 26097], [330.92591, 12471], [340.39962, 22887], [352.74034, 24779]], "kurtosis": -1.22024, "maximum": 360, "mean": 155.65681, "median": 126.96597, "minimum": 0, "missing_count": 0, "population": 581012, "skewness": 0.40263, "splits": [7.13381, 15.00805, 22.35331, 29.55958, 37.07271, 44.15876, 51.17557, 58.34934, 65.50684, 73.07565, 81.05558, 89.20471, 97.82515, 106.79095, 116.68768, 126.96597, 138.32549, 151.27732, 166.14369, 182.10008, 199.46037, 218.15614, 239.35709, 260.51609, 279.1578, 295.62909, 309.10792, 320.46675, 330.63864, 340.45363, 349.85836], "standard_deviation": 111.91372, "sum": 90438473, "sum_squares": 21354341379, "variance": 12524.68095}}, "000002": {"column_number": 2, "datatype": "int8", "name": "Slope", "optype": "numeric", "order": 2, "preferred": true, "summary": {"bins": [[0.84871, 4336], [2.60064, 19346], [4.5601, 37154], [6.51858, 50899], [8.51543, 62179], [10.50009, 67636], [12.49392, 65636], [14.49028, 59409], [16.46701, 49796], [18.47388, 40149], [20.46379, 31051], [22.45716, 24998], [24.46432, 19340], [26.45551, 14858], [28.45711, 10899], [30.45643, 8010], [32.45603, 5879], [34.45071, 3987], [36.43951, 2455], [38.41956, 1442], [40.41341, 716], [42.41667, 348], [44.45327, 214], [46.42373, 118], [48.50746, 67], [50.425, 40], [52.4, 15], [54.42857, 7], [56.63636, 11], [58.75, 4], [61.22222, 9], [65, 4]], "kurtosis": 0.58118, "maximum": 66, "mean": 14.1037, "median": 12.98549, "minimum": 0, "missing_count": 0, "population": 581012, "skewness": 0.78927, "splits": [2.98587, 4.23348, 5.06326, 5.97301, 6.70306, 7.38368, 8.00983, 8.60095, 9.17143, 9.72434, 10.26329, 10.80018, 11.33801, 11.88074, 12.42943, 12.98549, 13.55573, 14.14877, 14.75892, 15.3878, 16.05382, 16.77491, 17.56682, 18.42592, 19.37064, 20.44632, 21.6972, 23.133, 24.90088, 27.19381, 30.72998], "standard_deviation": 7.48824, "sum": 8194421, "sum_squares": 148151159, "variance": 56.07377}}, "000003": {"column_number": 3, "datatype": "int16", "name": "Dist. to water", "optype": "numeric", "order": 3, "preferred": true, "summary": {"bins": [[0, 24603], [33.60275, 48786], [76.15621, 68509], [120.52176, 48442], [152.88296, 31708], [193.86468, 69493], [242.94146, 40228], [287.7634, 49776], [342.12796, 45365], [391.09932, 26279], [436.26437, 28086], [481.85136, 18609], [523.84539, 17412], [565.19197, 12653], [598.36251, 6957], [629.93955, 8850], [665.99983, 5889], [706.49138, 7717], [752.84921, 4556], [797.20886, 4807], [843.46958, 2860], [892.23636, 3080], [952.78796, 2259], [1006.22823, 1183], [1046.89186, 786], [1090.58547, 895], [1137.53499, 443], [1186.46565, 393], [1242.10345, 232], [1288.05319, 94], [1338.08929, 56], [1387.5, 6]], "kurtosis": 1.36616, "maximum": 1397, "mean": 269.42822, "median": 223.76708, "minimum": 0, "missing_count": 0, "population": 581012, "skewness": 1.14043, "splits": [7.23198, 24.21746, 36.9686, 49.08615, 63.24008, 77.11915, 90.59071, 103.70782, 120.10715, 132.42384, 147.39668, 161.61917, 176.61472, 191.07923, 207.08617, 223.76708, 239.46378, 257.53281, 275.34884, 294.35704, 313.1634, 335.44147, 359.18612, 384.81684, 414.03451, 444.69465, 482.25019, 523.47888, 574.17102, 645.77901, 762.0946], "standard_deviation": 212.54936, "sum": 156541027, "sum_squares": 68425036479, "variance": 45177.22856}}, "000004": {"column_number": 4, "datatype": "int16", "name": "Depth to water", "optype": "numeric", "order": 4, "preferred": true, "summary": {"bins": [[-152.7451, 51], [-127.01056, 284], [-106.20725, 386], [-83.83267, 1004], [-56.86091, 3530], [-37.17141, 4072], [-15.24868, 21566], [5.47148, 191834], [29.4156, 129270], [58.44902, 104217], [88.44529, 43057], [111.02308, 24135], [130.02628, 13775], [148.76029, 11760], [169.38392, 9778], [189.17842, 6709], [208.54092, 5267], [233.74102, 4676], [265.0219, 2192], [291.99611, 1286], [320.28372, 1001], [349.26471, 476], [373.54122, 279], [395.60355, 169], [416.74684, 79], [453.5, 24], [484.54545, 22], [508.10526, 19], [526.4375, 16], [546.44444, 27], [568.56522, 23], [590.17857, 28]], "kurtosis": 5.25024, "maximum": 601, "mean": 46.41886, "median": 30.18289, "minimum": -173, "missing_count": 0, "population": 581012, "skewness": 1.79025, "splits": [-16.60401, -6.40385, -3.0845, -0.65204, 1.36731, 3.34202, 5.35627, 7.41252, 9.51351, 11.70481, 14.16116, 16.81577, 19.72614, 22.99559, 26.64398, 30.18289, 33.62161, 37.02686, 40.86451, 45.52104, 50.87318, 56.28066, 62.54854, 69.03746, 76.46237, 85.00437, 95.28831, 108.26098, 126.35649, 151.52346, 191.20669], "standard_deviation": 58.29523, "sum": 26969912, "sum_squares": 3226381898, "variance": 3398.33403}}, "000005": {"column_number": 5, "datatype": "int16", "name": "Dist. to road", "optype": "numeric", "order": 5, "preferred": true, "summary": {"bins": [[207.74011, 22775], [423.39541, 24395], [621.25318, 32100], [819.55874, 30991], [1014.34678, 36946], [1226.29372, 41345], [1438.9781, 34655], [1679.8144, 43793], [1944.32759, 32535], [2123.55849, 15662], [2294.40133, 27182], [2512.92487, 23973], [2751.2876, 26860], [3003.7982, 24608], [3215.7437, 16555], [3416.13088, 16687], [3616.64762, 12112], [3819.7648, 13193], [4037.24157, 12932], [4308.65726, 18755], [4591.21535, 11609], [4838.70026, 10189], [5037.31507, 6297], [5247.28303, 11730], [5494.07351, 9183], [5711.53542, 8978], [5929.32201, 7804], [6147.22624, 3978], [6344.50462, 1732], [6582.22718, 964], [6822.28392, 398], [7013.21875, 96]], "kurtosis": -0.38372, "maximum": 7117, "mean": 2350.14661, "median": 1997.55037, "minimum": 0, "missing_count": 0, "population": 581012, "skewness": 0.71368, "splits": [281.62987, 434.87676, 564.10708, 682.28828, 798.22905, 902.48076, 1006.61765, 1105.0627, 1202.37446, 1299.68325, 1403.93095, 1509.17768, 1619.37075, 1736.02126, 1866.72843, 1997.55037, 2133.06964, 2278.35631, 2429.78897, 2593.50774, 2768.13211, 2943.117, 3122.14712, 3329.04166, 3566.74781, 3857.49465, 4161.05567, 4482.81853, 4880.93708, 5308.38602, 5742.58205], "standard_deviation": 1559.25487, "sum": 1365463383, "sum_squares": 4621637096965, "variance": 2431275.7493}}, "000006": {"column_number": 6, "datatype": "int16", "name": "Shade at 9am", "optype": "numeric", "order": 6, "preferred": true, "summary": {"bins": [[0, 13], [36, 1], [46, 2], [57.08824, 34], [65.86667, 45], [74.03623, 138], [82.5404, 198], [90.98737, 396], [98.8, 455], [105.32569, 654], [112.07087, 1016], [118.58647, 1330], [125.14966, 2058], [132.09458, 2897], [138.14291, 2806], [144.3106, 4633], [151.76373, 7449], [159.36809, 8449], [165.71703, 8803], [172.65561, 16635], [179.37306, 16831], [185.64801, 23975], [190.842, 17551], [197.89465, 54027], [206.06643, 48580], [211.813, 38358], [217.34132, 60655], [225.25027, 103838], [233.01451, 61212], [239.33217, 52630], [245.32083, 27229], [250.85199, 18114]], "kurtosis": 1.87549, "maximum": 254, "mean": 212.14605, "median": 217.73175, "minimum": 0, "missing_count": 0, "population": 581012, "skewness": -1.18114, "splits": [149.38309, 165.31428, 174.84957, 181.47204, 186.78605, 191.12186, 194.90341, 198.39496, 201.44387, 204.22615, 206.69297, 209.46001, 211.59675, 213.48349, 215.74647, 217.73175, 219.57549, 221.34687, 222.89541, 224.44808, 226.31364, 227.97803, 229.66092, 231.37182, 233.12086, 235.02691, 237.07156, 239.05238, 241.54195, 244.43506, 248.23065], "standard_deviation": 26.76989, "sum": 123259400, "sum_squares": 26565362804, "variance": 716.62695}}, "000007": {"column_number": 7, "datatype": "int16", "name": "Shade at noon", "optype": "numeric", "order": 7, "preferred": true, "summary": {"bins": [[0, 5], [30, 1], [42.33333, 3], [53, 2], [63.5, 2], [69.5, 2], [75.75, 4], [81, 5], [88.8, 15], [98.08108, 37], [104.84783, 46], [111.97222, 72], [119.02885, 104], [124.65789, 114], [132.06582, 471], [139.80998, 521], [146.08161, 870], [152.61459, 1645], [160.81256, 3345], [170.54063, 7014], [178.21018, 6461], [184.93446, 11734], [190.77026, 10969], [196.0971, 17797], [203.23866, 40890], [209.6767, 36761], [215.68785, 66578], [221.94604, 69103], [228.48822, 98286], [235.04354, 71113], [241.34527, 62678], [249.30785, 74364]], "kurtosis": 2.06618, "maximum": 254, "mean": 223.31872, "median": 226.08421, "minimum": 0, "missing_count": 0, "population": 581012, "skewness": -1.06305, "splits": [178.83342, 190.14835, 196.82692, 201.43442, 205.0155, 208.11345, 210.54722, 212.90633, 214.98371, 216.7157, 218.3065, 220.01107, 221.59098, 223.125, 224.72811, 226.08421, 227.34831, 228.69121, 230.06598, 231.33942, 232.74478, 234.33324, 235.83687, 237.44629, 239.16412, 240.8585, 242.85233, 245.04806, 247.05207, 249.2844, 251.78412], "standard_deviation": 19.7687, "sum": 129750854, "sum_squares": 29202854060, "variance": 390.80139}}, "000008": {"column_number": 8, "datatype": "int16", "name": "Shade at 3pm", "optype": "numeric", "order": 8, "preferred": true, "summary": {"bins": [[0.03506, 1369], [6.94536, 183], [14.88016, 509], [22.35922, 721], [32.39851, 2276], [41.90102, 2061], [49.75175, 3001], [57.24987, 3914], [65.03605, 5992], [72.09741, 6221], [81.26397, 15805], [90.80625, 15210], [99.42556, 24885], [107.90183, 29337], [117.51055, 52596], [126.82616, 46791], [134.75841, 51033], [142.74759, 56084], [150.46027, 45349], [158.2927, 45674], [166.6664, 38109], [174.00372, 26877], [181.04127, 29031], [188.96343, 25400], [197.5362, 20845], [206.46307, 12918], [214.95208, 8682], [221.87776, 3354], [228.16096, 3827], [236.36497, 2181], [244.16809, 702], [250.77333, 75]], "kurtosis": 0.39843, "maximum": 254, "mean": 142.52826, "median": 142.75893, "minimum": 0, "missing_count": 0, "population": 581012, "skewness": -0.27705, "splits": [66.55933, 82.91286, 93.35245, 100.36887, 106.32269, 111.0352, 115.37503, 119.22801, 122.5471, 125.83879, 128.90074, 131.89437, 134.7661, 137.47839, 140.1944, 142.75893, 145.4669, 148.24925, 151.1427, 154.13602, 157.38618, 160.83264, 164.43772, 168.21079, 172.42442, 176.85791, 181.46744, 186.57144, 192.61677, 200.1169, 211.52004], "standard_deviation": 38.27453, "sum": 82810631, "sum_squares": 12654001389, "variance": 1464.93959}}, "000009": {"column_number": 9, "datatype": "int16", "name": "Dist. to fire", "optype": "numeric", "order": 9, "preferred": true, "summary": {"bins": [[108.35727, 4568], [271.73436, 17155], [483.86021, 36060], [655.92053, 24388], [830.84726, 44846], [1042.34467, 44228], [1257.69912, 47547], [1480.92601, 49425], [1713.75909, 45930], [1936.49739, 38829], [2189.23318, 50060], [2439.88409, 31697], [2688.71703, 40404], [2963.84769, 18035], [3223.25215, 15324], [3485.31589, 10317], [3718.57494, 6432], [3978.87747, 8912], [4245.84296, 5451], [4421.98558, 2635], [4584.62571, 4419], [4787.50417, 4197], [5009.17147, 4858], [5279.28177, 5068], [5492.22143, 2651], [5677.12572, 4160], [5888.99775, 3115], [6049.00295, 2033], [6220.16066, 3523], [6450.12221, 3633], [6719.88211, 738], [6954.43316, 374]], "kurtosis": 1.64578, "maximum": 7173, "mean": 1980.29123, "median": 1709.08178, "minimum": 0, "missing_count": 0, "population": 581012, "skewness": 1.28864, "splits": [326.19163, 467.46813, 572.96869, 668.88893, 762.42102, 852.69345, 937.63058, 1024.54034, 1109.9599, 1195.52814, 1279.68871, 1362.92756, 1446.3406, 1530.8396, 1618.79161, 1709.08178, 1802.48123, 1899.47469, 1998.79174, 2101.3976, 2208.34937, 2317.27874, 2431.36171, 2550.56314, 2676.30192, 2828.59272, 3043.97168, 3364.89943, 3868.62918, 4595.55588, 5529.97565], "standard_deviation": 1324.19521, "sum": 1150572966, "sum_squares": 3297268244304, "variance": 1753492.9536}}, "00000a": {"column_number": 10, "datatype": "string", "name": "Wilderness Area", "optype": "categorical", "order": 10, "preferred": true, "summary": {"categories": [["Rawah", 260796], ["Comanche Peak", 253364], ["Cache la Poudre", 36968], ["Neota", 29884]], "missing_count": 0}, "term_analysis": {"enabled": true}}, "00000b": {"column_number": 11, "datatype": "string", "name": "Climate", "optype": "categorical", "order": 11, "preferred": true, "summary": {"categories": [["Montane + subalpine", 285199], ["Montane", 93593], ["Lower montane", 35947], ["Montane dry + montane", 602], ["Montane dry", 284]], "missing_count": 165387}, "term_analysis": {"enabled": true}}, "00000c": {"column_number": 12, "datatype": "string", "name": "Geology", "optype": "categorical", "order": 12, "preferred": true, "summary": {"categories": [["Igneous", 302082], ["Glacial", 92272], ["Alluvium", 20987], ["Sedimentary", 284]], "missing_count": 165387}, "term_analysis": {"enabled": true}}, "00000d": {"column_number": 13, "datatype": "string", "name": "Forest Type", "optype": "categorical", "order": 13, "preferred": true, "summary": {"categories": [["Lodgepole Pine", 283301], ["Spruce-Fur", 211840], ["Ponderosa Pine", 35754], ["Krummholz", 20510], ["Douglas-fir", 17367], ["Aspen", 9493], ["Cottonwood-Willow", 2747]], "missing_count": 0}, "term_analysis": {"enabled": true}}, "00000e": {"column_number": 14, "datatype": "double", "description": "", "label": "", "name": "Anomaly Score", "optype": "numeric", "order": 14, "preferred": true, "summary": {"bins": [[0.3286, 1], [0.35281, 523], [0.37062, 2884], [0.38907, 8021], [0.40659, 18021], [0.42424, 38678], [0.44348, 61668], [0.45999, 53173], [0.4784, 91465], [0.49798, 62239], [0.51541, 62535], [0.53367, 49286], [0.5513, 36840], [0.57043, 34920], [0.59124, 21563], [0.61064, 13555], [0.62995, 8953], [0.65163, 6833], [0.674, 3044], [0.69379, 1899], [0.71355, 1429], [0.73963, 1425], [0.76353, 399], [0.7813, 598], [0.80098, 218], [0.81846, 285], [0.83784, 231], [0.85692, 133], [0.88476, 109], [0.91067, 39], [0.93441, 27], [0.95995, 18]], "kurtosis": 2.09925, "maximum": 0.97893, "mean": 0.50197, "median": 0.49398, "minimum": 0.3286, "missing_count": 0, "population": 581012, "skewness": 0.94842, "splits": [0.40494, 0.41807, 0.42714, 0.43458, 0.441, 0.44682, 0.45256, 0.45739, 0.4618, 0.46647, 0.47112, 0.47544, 0.47971, 0.48466, 0.48919, 0.49398, 0.49872, 0.50377, 0.50889, 0.51385, 0.51924, 0.52506, 0.53134, 0.538, 0.54532, 0.55358, 0.56315, 0.57376, 0.58707, 0.60529, 0.63698], "standard_deviation": 0.06405, "sum": 291653.49007, "sum_squares": 148786.52533, "variance": 0.0041}}}, "fields_meta": {"count": 15, "effective_fields": 15, "limit": 1000, "offset": 0, "query_total": 15, "total": 15}, "input_fields": ["000000", "000001", "000002", "000003", "000004", "000005", "000006", "000007", "000008", "000009", "00000a", "00000b", "00000c", "00000d", "00000e"], "locale": "en_US", "missing_numeric_rows": 0, "missing_tokens": [""], "name": "Forest Cover - batchanomalyscore", "new_fields": [], "number_of_anomalies": 0, "number_of_anomalyscores": 0, "number_of_associations": 0, "number_of_associationsets": 0, "number_of_batchanomalyscores": 0, "number_of_batchcentroids": 0, "number_of_batchpredictions": 0, "number_of_centroids": 0, "number_of_clusters": 0, "number_of_correlations": 0, "number_of_ensembles": 0, "number_of_evaluations": 0, "number_of_logisticregressions": 0, "number_of_models": 0, "number_of_predictions": 0, "number_of_statisticaltests": 0, "objective_field": {"column_number": 14, "datatype": "double", "description": "", "id": "00000e", "label": "", "name": "Anomaly Score", "optype": "numeric", "order": 14}, "origin_batch_resource": "batchanomalyscore/56de1498200d5a217c0017f4", "origin_batch_status": true, "output_fields": [], "price": 0.0, "private": true, "project": "project/5671c5dd1d5505103e0008d7", "ranges": null, "refresh_field_types": false, "refresh_preferred": false, "replacements": null, "resource": "dataset/56de150e200d5a217d003e78", "rows": 581012, "sample_rates": null, "seeds": null, "shared": false, "size": 51633668, "source": "source/5564ff5faf447f667b0005af", "source_status": false, "statisticaltest": null, "status": {"bytes": 51633668, "code": 5, "elapsed": 39468, "field_errors": [], "message": "The dataset has been created", "progress": 1.0, "row_format_errors": [], "serialized_rows": 581012, "task": "Done"}, "subscription": true, "tags": ["uci", "forest cover"], "tde_download": {"code": 0, "excluded_input_fields": [], "input_fields": [], "message": "", "preview": []}, "term_limit": 1000, "updated": "2016-03-08T00:55:22.392000", "user_metadata": {}} |
var candidateIntervals = [2, 2.5, 5, 10]; | |
function prettyRange (initRange, size) { | |
var minimum = initRange[0]; | |
var maximum = initRange[1]; | |
if (minimum != maximum) { | |
var diff = (maximum - minimum) / size; | |
var tens = Math.floor(Math.log10(diff)); | |
var tscale = Math.pow(10, tens); | |
var rem = diff / tscale; | |
var minIndex; | |
var minDiff = 1E20; | |
for (i in candidateIntervals) { | |
var c = candidateIntervals[i]; | |
var cDiff = c - rem; | |
if (cDiff > 0 && cDiff < minDiff) { | |
minDiff = cDiff; | |
minIndex = i; | |
} | |
} | |
var interval = candidateIntervals[minIndex] * tscale; | |
var newMin = interval * Math.floor(minimum / interval); | |
var newMax = newMin + interval * size; | |
if (newMax < maximum) { | |
return prettyRange([newMin, newMax], size); | |
} else if (newMax == maximum) { | |
if (newMax == 0) { | |
newMax = 1E-8; | |
} else { | |
newMax = newMax * 1.000001; | |
} | |
return prettyRange([newMin, newMax], size); | |
} else { | |
return [newMin, newMax]; | |
} | |
} else { | |
return [minimum, maximum]; | |
} | |
} | |
function truncate (val) { | |
return Math.round(1E5 * val) / 1E5; | |
} | |
function pickEdges(range, size) { | |
var newRange = prettyRange(range, size); | |
var step = truncate((newRange[1] - newRange[0]) / size); | |
var edges = []; | |
var truncatedEnd = truncate(range[1]); | |
for (var i = 0; i <= size; i++) { | |
var prevEdge = truncate(newRange[0] + (step * (i - 1))); | |
var edge = truncate(prevEdge + step); | |
if (prevEdge <= truncatedEnd) { | |
edges.push(edge); | |
} | |
} | |
return {step: step, edges: edges, range: [edges[0], edges[edges.length - 1]]}; | |
} | |
function findField(selection, data) { | |
if (selection.id == null) return null; | |
var fieldIds = data.fields.map(function (field) {return field.id;}); | |
var column = fieldIds.indexOf(selection.id); | |
data.fields[column].column = column; | |
return data.fields[column]; | |
} | |
function makeAxisIndexer (selection, data, numBins, catBins) { | |
var field = findField(selection, data); | |
var range = selection.range; | |
if (range == null) { | |
if (field.optype == "numeric") { | |
range = [field.minimum, field.maximum]; | |
} else { | |
range = field.categories; | |
if (range.length > catBins) { | |
range = range.slice(0, catBins); | |
} | |
} | |
} | |
var axis; | |
if (field.optype == "numeric") { | |
axis = pickEdges(range, numBins); | |
axis.binCount = axis.edges.length - 1; | |
var edges = axis.edges; | |
var minRange = edges[0]; | |
var maxRange = edges[edges.length - 1]; | |
var step = axis.step; | |
axis.indexer = function (val) { | |
var index = -1; | |
if (val != null && val >= minRange && val <= maxRange) { | |
index = Math.floor(truncate((val - minRange) / step)); | |
} | |
return index; | |
} | |
} else { | |
axis = {range: range, binCount: range.length}; | |
var indexMap = field.categories.map(function (cat) { return range.indexOf(cat)}); | |
axis.indexer = function (val) { | |
var index = -1; | |
if (val != null) { | |
index = indexMap[val];; | |
} | |
return index; | |
} | |
} | |
axis.optype = field.optype; | |
axis.column = field.column; | |
return axis; | |
} | |
function genHeatmap(data, xSelection, ySelection, cSelection, numBins, catBins) { | |
var colorField = findField(cSelection, data); | |
var xIndexInfo = makeAxisIndexer(xSelection, data, numBins, catBins); | |
var xNumeric = xIndexInfo.optype == "numeric"; | |
var xIndexer = xIndexInfo.indexer; | |
var yIndexInfo = makeAxisIndexer(ySelection, data, numBins, catBins); | |
var yNumeric = yIndexInfo.optype == "numeric"; | |
var yIndexer = yIndexInfo.indexer; | |
var counts = []; | |
for (var i = 0; i < xIndexInfo.binCount; i++) { | |
counts.push(new Int32Array(yIndexInfo.binCount)); | |
} | |
var fullCatCounts = null; | |
var catCounts = null; | |
var sums = null; | |
var targetCat = null; | |
if (cSelection.targetCat != null) { | |
targetCat = colorField.categories.indexOf(cSelection.targetCat); | |
} | |
if (colorField != null) { | |
if (colorField.optype == "numeric") { | |
sums = []; | |
for (var i = 0; i < xIndexInfo.binCount; i++) { | |
sums.push(new Float64Array(yIndexInfo.binCount)); | |
} | |
} else { | |
if (targetCat != null) { | |
catCounts = []; | |
for (var i = 0; i < xIndexInfo.binCount; i++) { | |
catCounts.push(new Int32Array(yIndexInfo.binCount)); | |
} | |
} else { | |
var cats = colorField.categories.length; | |
fullCatCounts = []; | |
for (var i = 0; i < xIndexInfo.binCount; i++) { | |
var row = []; | |
for (var j = 0; j < yIndexInfo.binCount; j++) { | |
row.push(new Int32Array(cats)); | |
} | |
fullCatCounts.push(row); | |
} | |
} | |
} | |
} | |
var xData = data.data[xIndexInfo.column]; | |
var yData = data.data[yIndexInfo.column]; | |
var cData = null; | |
if (colorField != null) { | |
cData = data.data[colorField.column]; | |
} | |
var maxBinCount = 0; | |
var totalCount = 0; | |
var rowCounts = new Int32Array(xIndexInfo.binCount); | |
var colCounts = new Int32Array(yIndexInfo.binCount); | |
for (i in xData) { | |
var x = xIndexer(xData[i]); | |
var y = yIndexer(yData[i]); | |
if (x >= 0 && x < xIndexInfo.binCount && y >= 0 && y < yIndexInfo.binCount) { | |
if (cData != null && cData[i] == null) { | |
continue; | |
} | |
counts[x][y]++; | |
rowCounts[x]++; | |
colCounts[y]++; | |
totalCount++; | |
maxBinCount = Math.max(maxBinCount, counts[x][y]); | |
if (cData != null) { | |
if (sums != null && cData[i]) { | |
sums[x][y] += cData[i]; | |
} | |
if (catCounts != null && cData[i] == targetCat) { | |
catCounts[x][y]++; | |
} | |
if (fullCatCounts != null) { | |
fullCatCounts[x][y][cData[i]]++; | |
} | |
} | |
} | |
} | |
var result = {x: xIndexInfo, | |
y: yIndexInfo, | |
c: colorField, | |
totalCount: totalCount, | |
counts: counts}; | |
if (sums != null) { | |
result.sums = sums; | |
} | |
if (catCounts != null) { | |
result.catCounts = catCounts; | |
} | |
if (fullCatCounts != null) { | |
catCounts = []; | |
var mostCommon = []; | |
for (var x = 0; x < xIndexInfo.binCount; x++) { | |
mostCommon.push(new Int16Array(yIndexInfo.binCount)); | |
catCounts.push(new Int32Array(yIndexInfo.binCount)); | |
for (var y = 0; y < yIndexInfo.binCount; y++) { | |
var dist = fullCatCounts[x][y]; | |
var maxCat = -1; | |
var maxCount = -1; | |
for (var z = 0; z < dist.length; z++) { | |
if (dist[z] > maxCount) { | |
maxCat = z; | |
maxCount = dist[z]; | |
} | |
} | |
mostCommon[x][y] = maxCat; | |
catCounts[x][y] = maxCount; | |
} | |
} | |
result.catCounts = catCounts; | |
result.mostCommon = mostCommon; | |
} | |
return result; | |
} | |
function differenceSum(counts, xNumeric, yNumeric) { | |
var rows = counts.length; | |
var cols = counts[0].length; | |
var total = 0; | |
var diff = 0; | |
for (var i = 0; i < rows; i++) { | |
for (var j = 0; j < cols; j++) { | |
var pop = counts[i][j]; | |
total += pop; | |
if (xNumeric) { | |
if (i < rows - 1) { | |
diff += Math.abs(pop - counts[i+1][j]); | |
} else { | |
diff += pop; | |
} | |
if (xNumeric && i > 0) { | |
diff += Math.abs(pop - counts[i-1][j]); | |
} else { | |
diff += pop; | |
} | |
} | |
if (yNumeric) { | |
if (j < cols - 1) { | |
diff += Math.abs(pop - counts[i][j+1]); | |
} else { | |
diff += pop; | |
} | |
if (j > 0) { | |
diff += Math.abs(pop - counts[i][j-1]); | |
} else { | |
diff += pop; | |
} | |
} | |
} | |
} | |
return diff / total; | |
} | |
function heatmap(data, xSelection, ySelection, cSelection, opts) { | |
var xNumeric = findField(xSelection, data).optype == "numeric"; | |
var yNumeric = findField(ySelection, data).optype == "numeric"; | |
if (opts.numBins != null || (!xNumeric && !yNumeric)) { | |
return genHeatmap(data, xSelection, ySelection, cSelection, | |
opts.numBins, opts.catBins); | |
} else { | |
var binCandidates; | |
if (xNumeric && yNumeric) { | |
binCandidates = [256, 128, 64, 32, 16, 8, 4]; | |
} else { | |
binCandidates = [128, 64, 32, 16, 8, 4]; | |
} | |
var minScore = null; | |
var bestResult = null; | |
for (i in binCandidates) { | |
var result = genHeatmap(data, xSelection, ySelection, cSelection, | |
binCandidates[i], opts.catBins); | |
var score = differenceSum(result.counts, xNumeric, yNumeric); | |
if (minScore == null || minScore >= score) { | |
minScore = score; | |
bestResult = result; | |
} | |
} | |
} | |
return bestResult; | |
} |
function cartesianProduct() { | |
var args = [].slice.call(arguments); | |
var end = args.length - 1; | |
var result = []; | |
function addTo(curr, start) { | |
var first = args[start]; | |
var last = (start === end); | |
for (var i = 0; i < first.length; ++i) { | |
var copy = curr.slice(); | |
copy.push(first[i]); | |
if (last) { | |
result.push(copy); | |
} else { | |
addTo(copy, start + 1); | |
} | |
} | |
} | |
if (args.length) { | |
addTo([], 0); | |
} else { | |
result.push([]); | |
} | |
return result; | |
} | |
function range (v) { | |
return Array.apply(null, Array(v)).map(function (_, i) {return i;}) | |
} | |
function binList (grid) { | |
return cartesianProduct(range(grid.x.binCount), range(grid.y.binCount)); | |
} |
</script> | |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
.domain { | |
stroke: none; | |
fill: none; | |
} | |
.field { | |
cursor: pointer; | |
-moz-user-select: none; | |
-khtml-user-select: none; | |
-webkit-user-select: none; | |
-ms-user-select: none; | |
user-select: none; | |
} | |
.brush .extent { | |
stroke: #fff; | |
fill-opacity: .125; | |
shape-rendering: crispEdges; | |
} | |
svg { | |
-webkit-user-select: none; /* webkit (safari, chrome) browsers */ | |
-moz-user-select: none; /* mozilla browsers */ | |
-khtml-user-select: none; /* webkit (konqueror) browsers */ | |
-ms-user-select: none; /* IE10+ */ | |
} | |
#shading-slider { | |
width: 90px; | |
} | |
.selector { | |
margin-bottom: 15px; | |
} | |
#axis { | |
position:absolute; | |
} | |
#heatmap { | |
} | |
div#pdp { | |
float: left; | |
margin-right: 5px; | |
} | |
div#sidebar { | |
padding-top: 20px; | |
} | |
div.field-info { | |
margin-bottom: 10px; | |
} | |
div.field-name { | |
color: #999; | |
margin-right: 10px; | |
} | |
div.field-value { | |
} | |
</style> | |
<body oncontextmenu="return false;"> | |
<div id="pdp"></div> | |
<div id="sidebar"> | |
<form id="controls-form"> | |
<div class="selector"> | |
<div>X-Axis</div> | |
<select id="x-select"></select> | |
</div> | |
<div class="selector"> | |
<div>Y-Axis</div> | |
<select id="y-select"></select> | |
</div> | |
<div class="selector"> | |
<div>Color Field</div> | |
<select id="color-select"></select> | |
</div> | |
<div class="selector"> | |
<div>Focus Category</div> | |
<select id="focus-select"></select> | |
</div> | |
<div class="selector"> | |
<div>Density Shading</div> | |
<input id="shading-slider" type="range" min="0" max="1" step="0.1" value="0.5"/> | |
</div> | |
<div class="selector"> | |
<div>Max Bins</div> | |
<select id="bins-select"> | |
<option value="dynamic" selected>Dynamic</option> | |
<option value="256">256</option> | |
<option value="128">128</option> | |
<option value="64">64</option> | |
<option value="32"">32</option> | |
<option value="16">16</option> | |
<option value="8">8</option> | |
</select> | |
</div> | |
</form> | |
<div id="x-field" class="field-info"> | |
<div id="x-name" class="field-name"></div> | |
<div id="x-value" class="field-value"></div> | |
</div> | |
<div id="y-field" class="field-info"> | |
<div id="y-name" class="field-name"></div> | |
<div id="y-value" class="field-value"></div> | |
</div> | |
<div id="c-field" class="field-info"> | |
<div id="c-name" class="field-name"></div> | |
<div id="c-value" class="field-value"></div> | |
</div> | |
</div> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="med-cover.js"></script> | |
<script src="data.js"></script> | |
<script src="grid.js"></script> | |
<script> | |
function toggle_option (selectId, index, disabled) { | |
document.getElementById(selectId) | |
.getElementsByTagName("option")[index].disabled = disabled; | |
} | |
function getParam(key) { | |
if(key=(new RegExp('[?&]'+encodeURIComponent(key)+'=([^&]*)')) | |
.exec(location.search)) | |
return decodeURIComponent(key[1]); | |
} | |
function setParam(key, value) { | |
key = encodeURI(key); value = encodeURI(value); | |
var s = document.location.search; | |
var kvp = key+"="+value; | |
var r = new RegExp("(&|\\?)"+key+"=[^\&]*"); | |
s = s.replace(r,"$1"+kvp); | |
if(!RegExp.$1) {s += (s.length>0 ? '&' : '?') + kvp;}; | |
window.history.replaceState({}, "", s); | |
} | |
function removeParam(key) { | |
var sourceURL = document.location.search; | |
var rtn = sourceURL.split("?")[0], | |
param, | |
params_arr = [], | |
queryString = (sourceURL.indexOf("?") !== -1) ? sourceURL.split("?")[1] : ""; | |
if (queryString !== "") { | |
params_arr = queryString.split("&"); | |
for (var i = params_arr.length - 1; i >= 0; i -= 1) { | |
param = params_arr[i].split("=")[0]; | |
if (param === key) { | |
params_arr.splice(i, 1); | |
} | |
} | |
rtn = rtn + "?" + params_arr.join("&"); | |
} | |
window.history.replaceState({}, "", rtn); | |
} | |
var margin = {bottom: 40, left: 50, right: 20, top: 20}; | |
var width = 640 - margin.left; | |
var height = 480 - margin.bottom; | |
var axisSVG = d3.select("#pdp").append("svg") | |
.attr("id", "axis") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.bottom + margin.top) | |
.append("g") | |
.attr("transform", | |
"translate(" + margin.left + "," + margin.top + ")"); | |
var canvas = d3.select("#pdp").append("canvas") | |
.attr("id", "heatmap") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.bottom + margin.top); | |
var context = canvas.node().getContext("2d"); | |
d3.json("cover-dataset.json", function(error, dataset) { | |
if ('dataset' in dataset) { | |
dataset = dataset.dataset; | |
} | |
var fields = dataset.fields; | |
if (!Array.isArray(fields)){ | |
var fieldsArr = []; | |
for (fid in fields) { | |
var field = fields[fid]; | |
field.id = fid; | |
fieldsArr.push(field); | |
} | |
fields = fieldsArr; | |
} | |
var maxNumBins = 128; | |
var maxCatBins = 16; | |
var x = getParam("x"); | |
if (x == null) x = 0; | |
x = Number(x); | |
setParam("x", x); | |
var y = getParam("y"); | |
if (y == null) y = 5; | |
y = Number(y); | |
setParam("y", y); | |
var c = getParam("c"); | |
if (c == null) c = fields.length - 2; | |
c = Number(c); | |
setParam("c", c); | |
var targetFields = [fields[x], fields[y]]; | |
var xSelection = {id: fields[x].id}; | |
var ySelection = {id: fields[y].id}; | |
var cSelection = {}; | |
if (c >= 0) cSelection.id = fields[c].id; | |
var opts = {maxNumBins: maxNumBins, maxCatBins: maxCatBins}; | |
var binCanvasHeight; | |
var binCanvasWidth; | |
var hm; | |
var colorSelector = d3.select("#color-select"); | |
colorSelector.append("option").attr("value", "#noValue").text("None"); | |
colorSelector.selectAll(".c-option") | |
.data(fields).enter() | |
.append("option") | |
.attr("class", "c-option") | |
.attr("value", function(d) {return d.id;}) | |
.text(function(d) {return d.name;}); | |
document.getElementById("color-select").selectedIndex = c + 1; | |
colorSelector.on("change", | |
function () { | |
c = this.selectedIndex - 1; | |
setParam("c", c); | |
updateColorSelector(); | |
resetFocusSelector(); | |
updateHeatMap(); | |
updateColorFn(); | |
redraw(true); | |
}); | |
updateColorSelector(); | |
var focusSelector = d3.select("#focus-select"); | |
focusSelector.append("option").attr("value", "#noValue").text("Most common"); | |
focusSelector.on("change", | |
function () { | |
if (this.selectedIndex > 0) { | |
cSelection.targetCat = | |
fields[c].summary.categories[this.selectedIndex - 1][0]; | |
} else { | |
delete cSelection.targetCat; | |
} | |
setParam("focus", this.selectedIndex - 1); | |
updateHeatMap(); | |
updateColorFn(); | |
redraw(false); | |
}); | |
updateFocusSelector(); | |
var focusParam = getParam("focus"); | |
if (focusParam == null) { | |
focusParam = -1; | |
} | |
focusParam = Number(focusParam); | |
document.getElementById("focus-select").selectedIndex = focusParam + 1; | |
if (focusParam >= 0) { | |
cSelection.targetCat = fields[c].summary.categories[focusParam][0]; | |
} | |
var binsIndex = getParam("bins"); | |
var binSelect = document.getElementById("bins-select"); | |
if (binsIndex == null) binsIndex = 0; | |
binsIndex = Number(binsIndex); | |
binSelect.selectedIndex = binsIndex; | |
if (binsIndex > 0) { | |
opts.numBins = Number(binSelect.options[binsIndex].value); | |
} | |
d3.select("#bins-select") | |
.on("change", | |
function () { | |
if (this.value == "dynamic") { | |
delete opts.numBins; | |
} else { | |
opts.numBins = this.value; | |
} | |
setParam("bins", this.selectedIndex); | |
updateHeatMap(); | |
updateColorFn(); | |
redraw(true); | |
}); | |
updateHeatMap(); | |
updateColorFn(); | |
d3.select("#x-name").text(fields[x].name); | |
d3.select("#x-value").text("-"); | |
d3.select("#y-name").text(fields[y].name); | |
d3.select("#y-value").text("-"); | |
d3.select("#c-name").text("Total Count"); | |
d3.select("#objective-value").text("-"); | |
var xSelector = d3.select("#x-select"); | |
xSelector.selectAll(".x-option") | |
.data(fields).enter() | |
.append("option") | |
.attr("class", "x-option") | |
.attr("value", function(d) {return d.id;}) | |
.text(function(d) {return d.name;}); | |
document.getElementById("x-select").selectedIndex = x; | |
toggle_option("x-select", y, true); | |
xSelector.on("change", | |
function () { | |
var oldX = x; | |
var newX = this.selectedIndex; | |
toggle_option("y-select", oldX, false); | |
toggle_option("y-select", newX, true); | |
document.getElementById("y-select") | |
.getElementsByTagName("option")[newX].disabled = true; | |
x = newX; | |
setParam("x", x); | |
d3.select("#x-name").text(fields[x].name); | |
targetFields[0] = fields[x]; | |
xSelection = {id: fields[x].id}; | |
delete ySelection.range; | |
updateHeatMap(); | |
redraw(true); | |
}); | |
var ySelector = d3.select("#y-select"); | |
ySelector.selectAll(".y-option") | |
.data(fields).enter() | |
.append("option") | |
.attr("class", "y-option") | |
.attr("value", function(d) {return d.id;}) | |
.text(function(d) {return d.name;}); | |
document.getElementById("y-select").selectedIndex = y; | |
toggle_option("y-select", x, true); | |
ySelector.on("change", | |
function () { | |
var oldY = y; | |
var newY = this.selectedIndex; | |
toggle_option("x-select", oldY, false); | |
toggle_option("x-select", newY, true); | |
document.getElementById("x-select") | |
.getElementsByTagName("option")[newY].disabled = true; | |
y = newY; | |
setParam("y", y); | |
d3.select("#y-name").text(fields[y].name); | |
targetFields[1] = fields[y]; | |
ySelection = {id: fields[y].id}; | |
delete xSelection.range; | |
updateHeatMap(); | |
redraw(true); | |
}); | |
var shading = getParam("shading"); | |
if (shading == null) { | |
shading = 3; | |
} | |
shading = Number(shading) / 10; | |
document.getElementById("shading-slider").value = shading; | |
d3.select("#shading-slider") | |
.on("input", | |
function () { | |
shading = this.value; | |
setParam("shading", shading * 10); | |
updateDensityFn(); | |
updateCells(); | |
}); | |
var brushX = d3.scale.identity().domain([0, width]); | |
var brushY = d3.scale.identity().domain([0, height]); | |
function brushed() { | |
brushExtent = brush.extent(); | |
} | |
function sortNumber(a,b) { | |
return a - b; | |
} | |
function findRange(axis, canvasRange, scale, isX) { | |
var newRange = []; | |
if (axis.optype == "numeric") { | |
newRange.push(scale.invert(canvasRange[0])); | |
newRange.push(scale.invert(canvasRange[1])); | |
newRange.sort(sortNumber); | |
} else { | |
var tempRange = []; | |
if (isX) { | |
tempRange.push(Math.floor(canvasRange[0] / binCanvasWidth)); | |
tempRange.push(Math.floor(canvasRange[1] / binCanvasWidth)); | |
} else { | |
tempRange.push(Math.floor((height - canvasRange[0]) / binCanvasHeight)); | |
tempRange.push(Math.floor((height - canvasRange[1]) / binCanvasHeight)); | |
} | |
tempRange.sort(sortNumber); | |
newRange = axis.range.slice(tempRange[0], tempRange[1] + 1); | |
} | |
return newRange; | |
} | |
function brushended() { | |
if (!d3.event.sourceEvent) return; // only transition after input | |
var canvasX = [brushExtent[0][0], brushExtent[1][0]]; | |
var canvasY = [brushExtent[0][1], brushExtent[1][1]]; | |
if (canvasX[0] == canvasX[1] || canvasY[0] == canvasY[1]) { | |
delete xSelection.range; | |
delete ySelection.range; | |
} else { | |
xSelection.range = findRange(hm.x, canvasX, xScale, true); | |
ySelection.range = findRange(hm.y, canvasY, yScale, false); | |
} | |
d3.select(this).call(brush.extent([[0, 0], [0, 0]])); | |
updateHeatMap(); | |
updateColorFn(); | |
redraw(true); | |
} | |
var gx, gy; | |
var xAxis, yAxis; | |
var xScale; | |
var yScale; | |
var predictor; | |
var densityFn; | |
var pMin, pMax; | |
makeAxis(); | |
updateColorSelector(); | |
redraw(true); | |
var brushExtent; | |
var brush = d3.svg.brush() | |
.x(brushX) | |
.y(brushY) | |
.on("brush", brushed) | |
.on("brushend", brushended); | |
axisSVG.append("g") | |
.attr("class", "brush") | |
.on("mousemove", | |
function(d) { | |
var coords = d3.mouse(this); | |
var inputs = []; | |
var gridIndex = coordsToGridIndex(coords); | |
var gx = gridIndex[0]; | |
var gy = gridIndex[1]; | |
if (hm.x.optype == "numeric") { | |
inputs.push(xScale.invert(coords[0])); | |
} else { | |
inputs.push(hm.x.range[gx]); | |
} | |
if (hm.y.optype == "numeric") { | |
inputs.push(yScale.invert(coords[1])); | |
} else { | |
inputs.push(hm.y.range[gy]); | |
} | |
var output; | |
var xOut; | |
var yOut; | |
if (gx < hm.x.binCount && gy < hm.y.binCount) { | |
if (c < 0) { | |
output = prettyVal(hm.counts[gx][gy]); | |
} else { | |
if (fields[c].optype == "numeric") { | |
var sum = hm.sums[gx][gy]; | |
var pop = hm.counts[gx][gy]; | |
if (pop == 0) { | |
output = "No data"; | |
} else { | |
output = prettyVal(sum / pop) + " (" + pop + " points)"; | |
} | |
} else { | |
var cat; | |
if (cSelection.targetCat == null) { | |
cat = hm.c.categories[hm.mostCommon[gx][gy]]; | |
} else { | |
cat = cSelection.targetCat; | |
} | |
var total = hm.counts[gx][gy]; | |
if (total > 0) { | |
var catCount = hm.catCounts[gx][gy]; | |
if (catCount == 0) { | |
cat = "---"; | |
} | |
output = cat + " (" + catCount + " of " + total + ")"; | |
} else { | |
output = "No data"; | |
} | |
} | |
} | |
xOut = binText(inputs[0], hm.x); | |
yOut = binText(inputs[1], hm.y); | |
} else { | |
output = "-"; | |
xOut = "-"; | |
yOut = "-"; | |
} | |
d3.select("#x-value").text(prettyVal(xOut)); | |
d3.select("#y-value").text(prettyVal(yOut)); | |
d3.select("#c-value").text(output); | |
}) | |
.on("mouseout", function(d) { | |
d3.select("#x-value").text("-"); | |
d3.select("#y-value").text("-"); | |
d3.select("#c-value").text("-"); | |
}) | |
.call(brush) | |
.call(brush.event); | |
function updateColorSelector() { | |
if (c >= 0) { | |
var text = fields[c].name; | |
if (fields[c].optype == "numeric") { | |
text += " (mean)"; | |
} | |
d3.select("#c-name").text(text); | |
cSelection = {id: fields[c].id}; | |
} else { | |
d3.select("#c-name").text("Total Count"); | |
cSelection = {}; | |
} | |
} | |
function resetFocusSelector() { | |
updateFocusSelector(); | |
document.getElementById("focus-select").selectedIndex = 0; | |
setParam("focus", -1); | |
} | |
function updateFocusSelector() { | |
if (c >= 0 && fields[c].optype == "categorical") { | |
var categories = fields[c].summary.categories.map(function (d) {return d[0];}); | |
focusSelector.selectAll(".f-option").remove(); | |
focusSelector.selectAll(".f-option") | |
.data(categories).enter() | |
.append("option") | |
.attr("class", "f-option") | |
.attr("value", function(d) {return categories.indexOf(d);}) | |
.text(function(d) {return d}); | |
document.getElementById("focus-select").disabled = false; | |
} else { | |
focusSelector.selectAll(".f-option").remove(); | |
document.getElementById("focus-select").disabled = true; | |
} | |
} | |
function binText(val, axis) { | |
if (axis.optype == "numeric") { | |
var index = axis.indexer(val); | |
var edges = axis.edges; | |
return edges[index] + " to " + edges[index + 1]; | |
} else { | |
return val; | |
} | |
} | |
function updateDensityMax() { | |
pMax = -1E20; | |
var counts; | |
if (cSelection.targetCat == null) { | |
counts = hm.counts; | |
} else { | |
counts = hm.catCounts; | |
} | |
var binIds = binList(hm); | |
for (var i = 0; i < binIds.length; i++) { | |
var p = counts[binIds[i][0]][binIds[i][1]]; | |
pMax = Math.max(pMax, p); | |
} | |
} | |
function updateDensityFn() { | |
var densityScale; | |
if (shading == 0) { | |
densityScale = function (d) {return 1}; | |
} else { | |
densityScale = d3.scale.pow().exponent(shading).domain([0, pMax]); | |
} | |
if (cSelection.targetCat == null) { | |
counts = hm.counts; | |
} else { | |
counts = hm.catCounts; | |
} | |
densityFn = function (d) { | |
return densityScale(counts[d[0]][d[1]]); | |
}; | |
} | |
var colorFn; | |
function updateColorFn() { | |
if (c < 0) { | |
var white = d3.rgb("#fff"); | |
colorFn = function (d) {return white}; | |
} else if (fields[c].optype == "categorical") { | |
var catColors; | |
if (hm.c.categories.length > 10) { | |
catColors = d3.scale.category20(); | |
} else { | |
catColors = d3.scale.category10(); | |
} | |
catColors.domain(hm.c.categories); | |
colorFn = function (d) { | |
var cat; | |
if (hm.catCounts[d[0]][d[1]] == 0) { | |
return d3.rgb("#000"); | |
} else if (cSelection.targetCat == null) { | |
cat = hm.c.categories[hm.mostCommon[d[0]][d[1]]] | |
} else { | |
cat = cSelection.targetCat; | |
} | |
return catColors(cat); | |
}; | |
} else { | |
var meanMin = 1E20; | |
var meanMax = -1E20; | |
var binIds = binList(hm); | |
for (var i = 0; i < binIds.length; i++) { | |
var sum = hm.sums[binIds[i][0]][binIds[i][1]]; | |
var pop = hm.counts[binIds[i][0]][binIds[i][1]]; | |
if (pop > 0) { | |
var mean = sum / pop; | |
meanMin = Math.min(meanMin, mean); | |
meanMax = Math.max(meanMax, mean); | |
} | |
} | |
var numColors = d3.scale.linear().domain([meanMin, meanMax]); | |
numColors = numColors.range(["#11f", "#f11"]); | |
var black = d3.rgb("#000"); | |
colorFn = function (d) { | |
var sum = hm.sums[d[0]][d[1]]; | |
var pop = hm.counts[d[0]][d[1]]; | |
if (pop > 0) { | |
return numColors(sum / pop); | |
} else { | |
return black; | |
} | |
}; | |
} | |
} | |
function redraw(redrawAxis) { | |
updateDensityMax(); | |
updateDensityFn(); | |
if (redrawAxis) { | |
updateScales(); | |
updateAxis(); | |
} | |
updateCells(); | |
} | |
function makeAxis() { | |
gy = axisSVG.append("g").attr("class", "y-axis"); | |
gx = axisSVG.append("g") | |
.attr("class", "x-axis") | |
.attr("transform", "translate(" + 0 + "," + height + ")"); | |
} | |
function updateAxis() { | |
var currentY = gy.transition().duration(700).call(yAxis); | |
if (targetFields[1].optype == "categorical") { | |
currentY.selectAll("text") | |
.attr("y", (binCanvasHeight / 2) - 10) | |
.attr("x", 4) | |
.style("fill", "#fff") | |
.style("stroke", "#000") | |
.style("stroke-width", 0.3) | |
.style("font-size", "13") | |
.style("font-weight", "bolder") | |
.style("font-family", "Monospace") | |
.style("stroke-linecap", "butt") | |
.style("stroke-linejoin", "miter") | |
.style("text-anchor", "start"); | |
} | |
var currentX = gx.transition().duration(700).call(xAxis); | |
if (targetFields[0].optype == "categorical") { | |
currentX.selectAll("text") | |
.attr("y", (binCanvasWidth / 2) - 15) | |
.attr("x", 4) | |
.attr("transform", "rotate(-90)") | |
.style("fill", "#fff") | |
.style("stroke", "#000") | |
.style("stroke-width", 0.3) | |
.style("font-size", "13") | |
.style("font-weight", "bolder") | |
.style("font-family", "Monospace") | |
.style("stroke-linecap", "butt") | |
.style("stroke-linejoin", "miter") | |
.style("text-anchor", "start"); | |
} | |
} | |
function customAxisFormat(d) { | |
return d3.format("s")(Math.round(d * 1E4) / 1E4); | |
} | |
function updateScales () { | |
if (targetFields[0].optype == "numeric") { | |
xScale = d3.scale.linear() | |
.range([0, width]) | |
.domain([hm.x.range[0], | |
hm.x.range[1]]); | |
} else { | |
xScale = d3.scale.ordinal() | |
.domain(hm.x.range) | |
.rangePoints([0, width], 1); | |
} | |
if (targetFields[1].optype == "numeric") { | |
yScale = d3.scale.linear() | |
.range([height, 0]) | |
.domain([hm.y.range[0], | |
hm.y.range[1]]); | |
} else { | |
yScale = d3.scale.ordinal() | |
.domain(hm.y.range) | |
.rangePoints([height, 0], 1); | |
} | |
xAxis = d3.svg.axis() | |
.scale(xScale) | |
.orient("bottom"); | |
yAxis = d3.svg.axis() | |
.scale(yScale) | |
.orient("left"); | |
if (targetFields[0].optype == "numeric") { | |
xAxis.tickFormat(customAxisFormat); | |
} | |
if (targetFields[1].optype == "numeric") { | |
yAxis.tickFormat(customAxisFormat); | |
} | |
} | |
function prettyVal(d) { | |
if (typeof d === 'string' || d instanceof String) { | |
return d; | |
} else { | |
return d = Math.round(d * 1000) / 1000; | |
} | |
} | |
function densityColorShift(color, loc) { | |
var density = densityFn(loc); | |
color = d3.rgb(color); | |
color.r = Math.round(color.r * density); | |
color.g = Math.round(color.g * density); | |
color.b = Math.round(color.b * density); | |
return color; | |
} | |
function updateCells() { | |
var cxFn = canvasXFn(); | |
var cyFn = canvasYFn(); | |
var maxBins = Math.max(hm.x.binCount, hm.y.binCount); | |
var alpha = Math.pow(Math.max((220 - maxBins), 0) / 256, 2); | |
var lineColor = "rgba(0, 0, 0, " + alpha + ")"; | |
context.strokeStyle=lineColor; | |
binList(hm).forEach(function(d, i) { | |
context.beginPath(); | |
context.rect(cxFn(d) + margin.left, | |
cyFn(d) + margin.top, | |
binCanvasWidth + 1, | |
binCanvasHeight + 1); | |
context.fillStyle=densityColorShift(colorFn(d), d); | |
context.fill(); | |
/* context.stroke(); */ | |
context.closePath(); | |
}); | |
} | |
function updateHeatMap() { | |
hm = heatmap(data, xSelection, ySelection, cSelection, opts); | |
binCanvasWidth = width / hm.x.binCount; | |
binCanvasHeight = height / hm.y.binCount; | |
} | |
function coordsToGridIndex (coords) { | |
var x = Math.floor(coords[0] / binCanvasWidth); | |
var y = Math.floor((height - coords[1]) / binCanvasHeight); | |
return [x, y]; | |
} | |
function canvasXFn () { | |
return function(binId) {return binId[0] * binCanvasWidth}; | |
} | |
function canvasYFn () { | |
return function(binId) { | |
return height - binCanvasHeight - (binId[1] * binCanvasHeight) | |
}; | |
} | |
}); | |
</script> | |
</body> |