├── .gitignore ├── LICENSE ├── README.md ├── examples ├── api_example │ ├── index.html │ └── mySketch.js ├── bar_example │ ├── index.html │ └── mySketch.js ├── box_plot_example │ ├── index.html │ └── mySketch.js ├── density_plot_example │ ├── index.html │ └── mySketch.js ├── dom_control_example │ ├── index.html │ └── mySketch.js ├── facetingexample │ ├── index.html │ └── mySketch.js ├── firstexample │ ├── index.html │ └── mySketch.js ├── secondexample │ ├── index.html │ └── mySketch.js ├── simplearraytest │ ├── index.html │ └── mySketch.js ├── simplesvg_barexample │ ├── index.html │ └── mySketch.js ├── simplesvg_boxexample │ ├── index.html │ └── mySketch.js ├── simplesvg_example │ ├── index.html │ └── mySketch.js └── testexample │ ├── datasets.js │ ├── diamonds.json │ ├── index.html │ └── mySketch.js ├── ggplot2-cheatsheet.pdf ├── lib ├── p5.plot.js ├── p5.plot.old.js ├── p5.simpleplot.js └── p5.simpleplotsvg.js ├── rtests └── testing │ ├── .RData │ ├── .Rhistory │ ├── testbar.R │ └── testing.Rproj └── support ├── datasets.js ├── diamonds.json ├── economics.json ├── mpg.json └── seals.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .git/ 3 | .Rproj.user 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Integrated Digital Media, NYU 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # p5.js-plot 2 | p5.plot! 3 | 4 | ## Documentation 5 | ### JSONs 6 | ``` 7 | // to use existing datasets 8 | var diamonds, mpg, seals, economics; 9 | 10 | function preload() { 11 | diamonds = loadJSON("https://raw.githubusercontent.com/IDMNYU/p5.js-plot/master/support/diamonds.json"); 12 | seals = loadJSON("https://raw.githubusercontent.com/IDMNYU/p5.js-plot/master/support/seals.json"); 13 | mpg = loadJSON("https://raw.githubusercontent.com/IDMNYU/p5.js-plot/master/support/mpg.json"); 14 | economics = loadJSON("https://raw.githubusercontent.com/IDMNYU/p5.js-plot/master/support/economics.json"); 15 | } 16 | ``` 17 | ### Getting Started 18 | ``` 19 | // initiate a variable 20 | let foo; 21 | function setup(){ 22 | // create a new p5.plot instance and store it in the variable 23 | foo = new p5.Plot(); 24 | } 25 | ``` 26 | The p5.plot object instance takes in the following constructors: 27 | - data 28 | 29 | Takes in an array of objects 30 | - xkey 31 | 32 | Specify the key value for x axis. 33 | - ykey 34 | 35 | Specify the key value for y axis. 36 | - type 37 | 38 | Supports "line", "point", "area", "density", "box", "histogram", "pie" 39 | - left 40 | 41 | The left position of the graph. Takes a number. 42 | - top 43 | 44 | The top position of the graph. Takes a number. 45 | - right 46 | 47 | The right position of the graph. Takes a number. 48 | - bottom 49 | 50 | The bottom position of the graph. Takes a number. 51 | - background 52 | 53 | Whether to draw background. Takes ```true``` or ```false```. 54 | - backgroundcolor 55 | - gridcolor 56 | - gridweight 57 | - cols 58 | 59 | The number of columns of the grid. 60 | - rows 61 | 62 | The number of the rows of the grid. 63 | - fillcolor 64 | 65 | The filling color of the graph. 66 | - strokecolor 67 | - strokeweight 68 | - pointdiameter 69 | 70 | The numeric value of the diameter of the points on the graph. 71 | - bins 72 | 73 | Number of bins to group the datasets. 74 | 75 | 76 | 77 | ### Types of Graphs 78 | - Line graph 79 | 80 | {type: 'line'} 81 | 82 | - Point graph 83 | 84 | {type: 'point'} 85 | 86 | - Area graph 87 | 88 | {type: 'area'} 89 | 90 | - Density graph, one contineous variable 91 | 92 | {type: 'density'} 93 | 94 | - box and whisker plot 95 | 96 | {type: 'box'} 97 | 98 | - Histogram 99 | 100 | {type: 'histogram'}, one contineous variable 101 | 102 | - Pie chart 103 | 104 | {type: 'pie'} 105 | 106 | ### Functions 107 | - redraw() 108 | 109 | Put this in draw to use the hover function. 110 | Example: 111 | ``` 112 | foo.redraw() 113 | ``` 114 | - hover() 115 | 116 | Now supports point graph, line graph and histogram. 117 | Example: 118 | ``` 119 | foo.hover(mouseX, mouseY, 'point'); 120 | foo.hover(mouseX, mouseY, 'bin'); 121 | ``` 122 | ## WORKING ON: 123 | - Fixing graphs by incorporating multiple xkey values and multiple colors 124 | (line graph, point graph, area graph done) 125 | 126 | 127 | ## TO DO: 128 | - Fix hover function (a new way to add data in each graph function) 129 | - multiple xkeys AND multiple ykeys faceting 130 | - graph annotation, such as title 131 | - scales, coordinate system 132 | -------------------------------------------------------------------------------- /examples/api_example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/api_example/mySketch.js: -------------------------------------------------------------------------------- 1 | let earthquakes; 2 | let myData = []; 3 | let foo; 4 | 5 | function preload(){ 6 | earthquakes = loadJSON('https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson'); 7 | } 8 | 9 | function setup(){ 10 | for (let i=0; i< earthquakes.features.length; i++){ 11 | let lat = earthquakes.features[i].geometry.coordinates[0]; 12 | let long = earthquakes.features[i].geometry.coordinates[1]; 13 | myData.push({lat, long}); 14 | } 15 | createCanvas(windowWidth, windowHeight); 16 | background(255); 17 | // CONSTRUCTOR: 18 | foo = new p5.Plot({left: width*0.2, top: height*0.3, right: width*0.8, bottom: height*0.7, fillcolor:[[255, 0, 0]], backgroundcolor:100, rows:0, cols:0 }); 19 | foo.plot({data: myData, type: 'point', xkey: 'lat', ykey: 'long'}); 20 | } 21 | 22 | function draw() { 23 | background(255); 24 | foo.redraw(); 25 | foo.hover(mouseX, mouseY, 'point'); 26 | } 27 | -------------------------------------------------------------------------------- /examples/bar_example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/bar_example/mySketch.js: -------------------------------------------------------------------------------- 1 | var foo; // p5.Plot() object 2 | 3 | var barData = [{"x":"a", "y":10}, {"x":"b", "y":16}, {"x":"c", "y":5}]; 4 | var barData2 = [{"x":"a"}, {"x":"b"}, {"x":"c"}, {"x":"a"}, {"x":"a"}, {"x":"b"}]; 5 | 6 | function setup() { 7 | createCanvas(windowWidth, windowHeight); 8 | background(255); 9 | 10 | // CONSTRUCTOR: 11 | foo = new p5.Plot({ left: width*0.2, top: height*0.3, right: width*0.8, bottom: height*0.7}); 12 | 13 | foo.plot({ type: 'bar', data: barData, xkey: "x", ykey: "y", strokeweight: 2}); 14 | //foo.plot({ type: 'bar', data: barData2, xkey: "x", ykey: "XSUM", strokeweight: 2}); 15 | //foo.plot({ type: 'box', data: mpg, xkey: 'year', ykey: 'displ', strokeweight: 2}); 16 | //foo.plot({ type: 'box', data: boxData, xkey: 'y', ykey: 'x', strokeweight: 2}); 17 | 18 | } 19 | 20 | function draw() { 21 | background(255); 22 | foo.redraw(); 23 | } 24 | -------------------------------------------------------------------------------- /examples/box_plot_example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/box_plot_example/mySketch.js: -------------------------------------------------------------------------------- 1 | var foo; // p5.Plot() object 2 | 3 | var boxData = [{"x":13, "y":"a"}, {"x":16, "y":"a"}, {"x":57, "y":"a"}, {"x":34, "y":"a"}, {"x":26, "y":"a"}, {"x":67, "y":"a"}, {"x":12, "y":"a"}, 4 | {"x":45, "y":"b"}, {"x":32, "y":"b"}, {"x":24, "y":"b"}, {"x":86, "y":"b"}, {"x":65, "y":"b"}, {"x":37, "y":"b"}, {"x":98, "y":"b"}]; 5 | 6 | function setup() { 7 | createCanvas(windowWidth, windowHeight); 8 | background(255); 9 | 10 | // CONSTRUCTOR: 11 | foo = new p5.Plot({ left: width*0.2, top: height*0.3, right: width*0.8, bottom: height*0.7, background: false}); 12 | 13 | foo.plot({ type: 'box', data: economics, xkey: null, ykey: 'pop', strokeweight: 2}); 14 | //foo.plot({ type: 'box', data: mpg, xkey: 'year', ykey: 'displ', strokeweight: 2}); 15 | //foo.plot({ type: 'box', data: boxData, xkey: 'y', ykey: 'x', strokeweight: 2}); 16 | 17 | } 18 | 19 | function draw() { 20 | background(255); 21 | foo.redraw(); 22 | } 23 | -------------------------------------------------------------------------------- /examples/density_plot_example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/density_plot_example/mySketch.js: -------------------------------------------------------------------------------- 1 | var dfile, diamonds; // load from JSON 2 | 3 | var foo; // p5.Plot() object 4 | 5 | function preload() { 6 | dfile = loadStrings('../../support/diamonds.json'); // load the big file 7 | } 8 | 9 | function setup() { 10 | createCanvas(windowWidth, windowHeight); 11 | background(255); 12 | 13 | diamonds = JSON.parse(dfile); 14 | // CONSTRUCTOR: 15 | foo = new p5.Plot({ left: width*0.2, top: height*0.3, right: width*0.8, bottom: height*0.7 }); 16 | 17 | // PLOT COMMAND: 18 | // DENSITY 19 | foo.plot({ type: 'density', data: economics, xkey: 'pop', ykey: null, strokeweight: 3, pointdiameter: 5}); 20 | } 21 | 22 | function draw() { 23 | background(255); 24 | foo.redraw(); 25 | //foo.hover(mouseX, mouseY, 'point'); 26 | } 27 | -------------------------------------------------------------------------------- /examples/dom_control_example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/dom_control_example/mySketch.js: -------------------------------------------------------------------------------- 1 | let foo; // p5.Plot() object 2 | let minBinNum = 2; 3 | let maxBinNum = 30; 4 | let binNum = 2; 5 | let slider; 6 | 7 | function setup(){ 8 | createCanvas(windowWidth, windowHeight); 9 | slider = createSlider(minBinNum, maxBinNum, 1); 10 | slider.position(100, 100); 11 | slider.style('width', '80px'); 12 | slider.changed(changeBin); 13 | background(255); 14 | 15 | // CONSTRUCTOR: 16 | foo = new p5.Plot({ left: width*0.2, top: height*0.3, right: width*0.8, bottom: height*0.7 }); 17 | 18 | // PLOT COMMAND: 19 | // HISTOGRAM 20 | foo.plot({ type: 'histogram', data: economics, xkey: 'pop', strokeweight: 5, bins: binNum}); 21 | } 22 | 23 | function draw() { 24 | background(255); 25 | text('current bin number: '+ binNum, 100, 80) 26 | foo.redraw(); 27 | foo.hover(mouseX, mouseY, 'bin'); 28 | } 29 | 30 | function changeBin(){ 31 | binNum = slider.value(); 32 | foo.plot({bins: binNum}); 33 | } 34 | -------------------------------------------------------------------------------- /examples/facetingexample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/facetingexample/mySketch.js: -------------------------------------------------------------------------------- 1 | var survey = []; 2 | 3 | var foo; // p5.Plot() object 4 | 5 | var bar = [{x: 50}, {x: 75}, {x: 33}]; 6 | 7 | var a = 0.1; 8 | 9 | function preload() { 10 | } 11 | 12 | function setup() { 13 | createCanvas(windowWidth, windowHeight); 14 | background(255); 15 | 16 | // make a fake survey 17 | for(let i = 0;i<50;i++) 18 | { 19 | var yikes = {}; 20 | yikes.q1 = floor(random(6)); 21 | yikes.q2 = floor(random(6)); 22 | yikes.q3 = floor(random(6)); 23 | yikes.q4 = floor(random(6)); 24 | yikes.q5 = floor(random(6)); 25 | 26 | survey.push(yikes); 27 | } 28 | 29 | console.log(survey); 30 | // CONSTRUCTOR: 31 | //foo = new p5.Plot(); // easy 32 | foo = new p5.Plot({ left: width*0.2, top: height*0.3, right: width*0.8, bottom: height*0.7 }); 33 | //foo = new p5.Plot({ left: 100, top: 100, right: 400, bottom: 200, backgroundcolor: 'lightBlue' }); 34 | // BAR 35 | //foo.plot({ barwidth: a, type: 'bar2', data: survey, xkey: 'q1', strokeweight: 5}); 36 | foo.plot({ type: 'area', data: survey, xkey: ['q1', 'q2', 'q3', 'q4'], ykey:"q5", strokeweight: [1, 2, 3, 4, 5, 6, 7], strokecolor:['red', 'green', 'blue'], fillcolor:['red', 'green', 'blue']}); 37 | } 38 | 39 | function draw() { 40 | //background(255); 41 | 42 | 43 | //a = a+.1; 44 | //foo.hover(mouseX, mouseY, 'point'); 45 | //foo.hover(mouseX, mouseY, 'bin'); 46 | } 47 | 48 | function keyPressed() { 49 | 50 | } 51 | -------------------------------------------------------------------------------- /examples/firstexample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/firstexample/mySketch.js: -------------------------------------------------------------------------------- 1 | var dfile, diamonds; // load from JSON 2 | 3 | var foo; // p5.Plot() object 4 | 5 | var mylook = {strokecolor: [255, 0, 255], fillcolor: [0, 255, 0]}; 6 | var myotherlook = {strokecolor: [0, 0, 255], fillcolor: [128, 128, 0]}; 7 | var mythirdlook = {backgroundcolor: 'Black', gridcolor: 'White'}; 8 | var crazygrid = {rows: 50, cols: 50, backgroundcolor: 'Black', gridcolor: 'White'}; 9 | 10 | var lukecrap = [{stuff: 50, things: 20}, {stuff: 55, things: 33}, {stuff: 33, things: 45}]; 11 | var myData = [{"x":5, "y":10}, {"x":5, "y":10}, {"x":5, "y":10}, {"x":5, "y":10}, {"x":5, "y":10}, {"x":5, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":17, "y":10}, {"x":17, "y":10}, {"x":17, "y":10}, {"x":17, "y":10}, {"x":17, "y":10}]; 12 | var boxData = [{"x":13, "y":"a"}, {"x":16, "y":"a"}, {"x":57, "y":"a"}, {"x":34, "y":"a"}, {"x":26, "y":"a"}, {"x":67, "y":"a"}, {"x":12, "y":"a"}, 13 | {"x":45, "y":"b"}, {"x":32, "y":"b"}, {"x":24, "y":"b"}, {"x":86, "y":"b"}, {"x":65, "y":"b"}, {"x":37, "y":"b"}, {"x":98, "y":"b"}]; 14 | var pieData = [{"x":13, "y":"a"}, {"x":16, "y":"b"}, {"x":57, "y":"c"}, {"x":34, "y":"d"}]; 15 | 16 | function preload() { 17 | dfile = loadStrings('../../support/diamonds.json'); // load the big file 18 | //diamonds = loadJSON("https://raw.githubusercontent.com/IDMNYU/p5.js-plot/master/support/diamonds.json"); 19 | console.log(diamonds); 20 | } 21 | 22 | var stylelist = [mylook, myotherlook, mythirdlook]; 23 | var whichstyle = 0; 24 | 25 | function setup() { 26 | createCanvas(windowWidth, windowHeight); 27 | background(255); 28 | 29 | diamonds = JSON.parse(dfile); 30 | // mix and match: 31 | 32 | // CONSTRUCTOR: 33 | //foo = new p5.Plot(); // easy 34 | foo = new p5.Plot({ left: width*0.2, top: height*0.3, right: width*0.8, bottom: height*0.7 }); 35 | //foo = new p5.Plot({ left: 100, top: 100, right: 400, bottom: 200, backgroundcolor: 'lightBlue' }); 36 | 37 | //noLoop(); 38 | background(255); 39 | // PLOT COMMAND: 40 | // LINE 41 | //foo.plot({data: mpg, xkey: 'year', ykey: 'displ', strokeweight: 5}); // default line 42 | //foo.plot({type: 'line', data: lukecrap, xkey: 'stuff', ykey: 'things'}); 43 | //foo.plot({ type: 'line', data: economics, xkey: 'pop', ykey: 'unemploy', strokeweight: 5 }, stylelist[whichstyle]); 44 | 45 | // POINT 46 | //foo.plot({type: 'point', data: mpg, xkey: 'year', ykey: 'displ', strokeweight: 5}); 47 | //foo.plot({type: 'point', data: lukecrap, xkey: 'stuff', ykey: 'things', strokeweight: 5}, stylelist[whichstyle]); 48 | //foo.plot({ type: 'point', data: economics, xkey: 'pop', ykey: 'unemploy', strokeweight: 5 }, stylelist[whichstyle]); 49 | //foo.plot({ type: 'point', data: mpg, xkey: 'cty', ykey: 'hwy'}); 50 | foo.plot({ type: 'point', data: diamonds, xkey: 'carat', ykey: 'price', strokecolor: [255, 0, 0, 32], fillcolor: [128, 128, 255, 32] }); 51 | //foo.plot({ type: 'point', data: diamonds, xkey: 'carat', ykey: 'price', strokecolor: [255, 0, 0, 32], fillcolor: [128, 128, 255, 32] }); 52 | //foo.plot({ type: 'point', data: diamonds, xkey: 'carat', ykey: 'price', strokecolor: [255, 0, 0, 32], fillcolor: [128, 128, 255, 32] }, crazygrid); 53 | 54 | // AREA 55 | //foo.plot({ type: 'area', data: economics, xkey: 'pop', ykey: 'unemploy', strokeweight: 5 }, stylelist[whichstyle]); // custom look 56 | 57 | // HISTOGRAM 58 | //foo.plot({ type: 'histogram', data: economics, xkey: 'pop', strokeweight: 5}); 59 | 60 | // PIE 61 | //foo.plot({type: 'pie', data: pieData, xkey:'x', background: false}); 62 | 63 | // not yet..................................................................... 64 | // BOX 65 | //foo.plot({ type: 'box', data: economics, xkey: 'pop', strokeweight: 5}); 66 | //foo.plot({ type: 'box', data: mpg, xkey: 'displ', ykey: 'year', strokeweight: 5}); 67 | //foo.plot({ type: 'box', data: diamonds, xkey: 'price', ykey: 'clarity', strokeweight: 1}); 68 | //foo.plot({ type: 'box', data: boxData, xkey: 'x', ykey: 'y', strokeweight: 5}); 69 | 70 | // DENSITY 71 | //foo.plot({ type: 'density', data: economics, xkey: 'pop', strokeweight: 5}); 72 | 73 | 74 | 75 | } 76 | 77 | function draw() { 78 | background(255); 79 | foo.redraw(); 80 | foo.hover(mouseX, mouseY, 'point'); 81 | //foo.hover(mouseX, mouseY, 'bin'); 82 | } 83 | 84 | function keyPressed() { 85 | whichstyle = (whichstyle+1)%stylelist.length; 86 | foo.plot(stylelist[whichstyle]); 87 | 88 | } 89 | -------------------------------------------------------------------------------- /examples/secondexample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/secondexample/mySketch.js: -------------------------------------------------------------------------------- 1 | var dfile, diamonds; // load from JSON 2 | 3 | var foo; // p5.Plot() object 4 | 5 | function preload() { 6 | } 7 | 8 | function setup() { 9 | createCanvas(windowWidth, windowHeight); 10 | background(255); 11 | 12 | // CONSTRUCTOR: 13 | //foo = new p5.Plot(); // easy 14 | foo = new p5.Plot({ left: width*0.2, top: height*0.3, right: width*0.8, bottom: height*0.7 }); 15 | //foo = new p5.Plot({ left: 100, top: 100, right: 400, bottom: 200, backgroundcolor: 'lightBlue' }); 16 | 17 | background(255); 18 | //foo.plot({ type: 'point', data: mpg, xkey: 'cty', ykey: 'hwy', strokecolor: [255, 0, 0, 32], fillcolor: [128, 128, 255, 32] }); 19 | 20 | 21 | // AREA 22 | //foo.plot({ type: 'area', data: economics, xkey: 'pop', ykey: 'unemploy', strokeweight: 5 }, stylelist[whichstyle]); // custom look 23 | 24 | // HISTOGRAM 25 | foo.plot({ type: 'histogram', data: mpg, xkey: 'trans', strokeweight: 5}); 26 | 27 | // PIE 28 | //foo.plot({type: 'pie', data: pieData, xkey:'x', background: false}); 29 | 30 | // not yet..................................................................... 31 | // BOX 32 | //foo.plot({ type: 'box', data: economics, xkey: 'pop', strokeweight: 5}); 33 | //foo.plot({ type: 'box', data: mpg, xkey: 'displ', ykey: 'year', strokeweight: 5}); 34 | //foo.plot({ type: 'box', data: diamonds, xkey: 'price', ykey: 'clarity', strokeweight: 1}); 35 | //foo.plot({ type: 'box', data: boxData, xkey: 'x', ykey: 'y', strokeweight: 5}); 36 | 37 | // DENSITY 38 | //foo.plot({ type: 'density', data: economics, xkey: 'pop', strokeweight: 5}); 39 | 40 | 41 | 42 | } 43 | 44 | function draw() { 45 | background(255); 46 | foo.redraw(); 47 | foo.hover(mouseX, mouseY, 'point'); 48 | //foo.hover(mouseX, mouseY, 'bin'); 49 | } 50 | 51 | function keyPressed() { 52 | whichstyle = (whichstyle+1)%stylelist.length; 53 | foo.plot(stylelist[whichstyle]); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /examples/simplearraytest/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/simplearraytest/mySketch.js: -------------------------------------------------------------------------------- 1 | var foo; // p5.Plot() object 2 | 3 | var mylook = {strokecolor: [255, 0, 255], fillcolor: [0, 255, 0]}; 4 | 5 | var d = [{stuff: 50, things: 20}, {stuff: 55, things: 33}, {stuff: 33, things: 45}]; 6 | var e = [-1, 0, 10, 50, -33, 2.5, 0]; 7 | 8 | function setup() { 9 | createCanvas(windowWidth, windowHeight); 10 | background(255); 11 | 12 | // CONSTRUCTOR: 13 | foo = new p5.Plot({left: width*0.2, top: height*0.3, right: width*0.8, bottom: height*0.7}); 14 | 15 | //noLoop(); 16 | background(255); 17 | 18 | // PLOT COMMAND: 19 | // LINE 20 | foo.plot({ type: 'line', data: e}); 21 | } 22 | 23 | function draw() { 24 | background(255); 25 | foo.redraw(); 26 | foo.hover(mouseX, mouseY, 'point'); 27 | } 28 | -------------------------------------------------------------------------------- /examples/simplesvg_barexample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/simplesvg_barexample/mySketch.js: -------------------------------------------------------------------------------- 1 | // test bar1 2 | //let myData = [{letter:'a'},{letter:'a'},{letter:'a'},{letter:'a'},{letter:'b'},{letter:'b'},{letter:'c'},{letter:'c'},{letter:'c'}]; 3 | //let myData = ['a', 'a', 'a', 'b', 'b', 'donut']; 4 | 5 | // test bar2 6 | let myData = [{letter:'a', amt:10},{letter:'a', amt:5},{letter:'a',amt:10},{letter:'b', amt:50},{letter:'b',amt:10},{letter:'c',amt:5},{letter:'c',amt:5},{letter:'c',amt:5}]; 7 | 8 | let foo; 9 | let myPlot; 10 | 11 | 12 | function setup(){ 13 | createCanvas(800, 400); 14 | 15 | background(255, 0, 0); 16 | //console.log(myData); 17 | 18 | foo = new p5.Plot({data: myData, fillcolor: [180, 50, 50, 100], type: ['bar2'], width: 500, height: 250}); 19 | myPlot = foo.plot(); 20 | } 21 | 22 | function draw() { 23 | background(200); 24 | text(frameRate().toFixed(2), width-50, 50); 25 | foo.draw(0, 0, width, height); 26 | } 27 | -------------------------------------------------------------------------------- /examples/simplesvg_boxexample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/simplesvg_boxexample/mySketch.js: -------------------------------------------------------------------------------- 1 | // test box plot 2 | // discrete x, continues y 3 | 4 | //let myData = [{"fruit":"apple", "num":13}, {"fruit":"apple", "num":16}, {"fruit":"apple", "num":57}, {"fruit":"apple", "num":34}, {"fruit":"apple", "num":26}, {"fruit":"apple", "num":67}, {"fruit":"apple", "num":12}, {"fruit":"banana", "num":45}, {"fruit":"banana", "num":32}, {"fruit":"banana", "num":24}, {"fruit":"banana", "num":86}, {"fruit":"banana", "num":65}, {"fruit":"banana", "num":37}, {"fruit":"banana", "num":98}]; 5 | 6 | // just a set of numbers 7 | let myData = [13, 16, 57, 87, 92, 10, 120, 30, 72, 101]; 8 | 9 | let foo; 10 | let myPlot; 11 | 12 | 13 | function setup(){ 14 | createCanvas(800, 400); 15 | 16 | background(255, 0, 0); 17 | //console.log(myData); 18 | 19 | //foo = new p5.Plot({data: myData, xkey: 'fruit', ykey: 'num', strokecolor: [180, 50, 50, 200], type: ['box'], width: 500, height: 250}); 20 | foo = new p5.Plot({data: myData, strokecolor: [180, 50, 50, 200], type: ['box'], width: 500, height: 250}); 21 | myPlot = foo.plot(); 22 | } 23 | 24 | function draw() { 25 | background(200); 26 | text(frameRate().toFixed(2), width-50, 50); 27 | foo.draw(0, 0, width, height); 28 | } 29 | -------------------------------------------------------------------------------- /examples/simplesvg_example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/simplesvg_example/mySketch.js: -------------------------------------------------------------------------------- 1 | let earthquakes; 2 | let myData = []; 3 | let foo; 4 | let x = -100; 5 | let y = 100; 6 | 7 | let myPlot; 8 | 9 | function preload(){ 10 | earthquakes = loadJSON('https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson'); 11 | 12 | } 13 | 14 | function setup(){ 15 | createCanvas(800, 400); 16 | 17 | background(255, 0, 0); 18 | for (let i=0; i< earthquakes.features.length; i++){ 19 | let lat = earthquakes.features[i].geometry.coordinates[0]; 20 | let long = earthquakes.features[i].geometry.coordinates[1]; 21 | myData.push({lat, long}); 22 | } 23 | //console.log(myData); 24 | 25 | // CONSTRUCTOR: 26 | console.log(colorMode()._colorMaxes); 27 | //colorMode(RGB); 28 | colorMode(HSL); 29 | foo = new p5.Plot({data: myData, fillcolor: [180, 50, 50, 1], type: ['point', 'line'], xkey: 'lat', ykey: 'long', width: 500, height: 250}); 30 | myPlot = foo.plot(); 31 | } 32 | 33 | function draw() { 34 | //background(random()*255, random()*255, random()*255); 35 | background(200); 36 | text(frameRate().toFixed(2), width-50, 50); 37 | //x-=10; 38 | //y+=10; 39 | // tint(0, 255, 0); 40 | // rect(0, 0, mouseX, mouseY); 41 | // foo.draw(0, 0, mouseX, mouseY); 42 | //rect(0, 0, width, height); 43 | foo.draw(0, 0, width, height); 44 | 45 | fill(255, 255, 255, 150); 46 | ellipse(width/2, height/2, 200, 200); 47 | 48 | //myData.push({lat:x,long:y}); 49 | 50 | //mydiv.position(mouseX, mouseY); 51 | //console.log(foo.plotData); 52 | } 53 | 54 | function keyTyped() { 55 | myData.push({lat:random(foo._xmin, foo._xmax),long:random(foo._ymin, foo._ymax)}); 56 | foo.data = myData; 57 | } 58 | -------------------------------------------------------------------------------- /examples/testexample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/testexample/mySketch.js: -------------------------------------------------------------------------------- 1 | var dfile, diamonds; // load from JSON 2 | 3 | var foo; // p5.Plot() object 4 | 5 | var mylook = {strokecolor: [255, 0, 255], fillcolor: [0, 255, 0]}; 6 | var myotherlook = {strokecolor: [0, 0, 255], fillcolor: [128, 128, 0]}; 7 | var mythirdlook = {backgroundcolor: 'Black', gridcolor: 'White'}; 8 | var crazygrid = {rows: 50, cols: 50, backgroundcolor: 'Black', gridcolor: 'White'}; 9 | 10 | var lukecrap = [{stuff: 50, things: 20}, {stuff: 55, things: 33}, {stuff: 33, things: 45}]; 11 | var myData = [{"x":5, "y":10}, {"x":5, "y":10}, {"x":5, "y":10}, {"x":5, "y":10}, {"x":5, "y":10}, {"x":5, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":10, "y":10}, {"x":17, "y":10}, {"x":17, "y":10}, {"x":17, "y":10}, {"x":17, "y":10}, {"x":17, "y":10}]; 12 | var boxData = [{"x":13, "y":"a"}, {"x":16, "y":"a"}, {"x":57, "y":"a"}, {"x":34, "y":"a"}, {"x":26, "y":"a"}, {"x":67, "y":"a"}, {"x":12, "y":"a"}, 13 | {"x":45, "y":"b"}, {"x":32, "y":"b"}, {"x":24, "y":"b"}, {"x":86, "y":"b"}, {"x":65, "y":"b"}, {"x":37, "y":"b"}, {"x":98, "y":"b"}]; 14 | var pieData = [{"x":13, "y":"a"}, {"x":16, "y":"b"}, {"x":57, "y":"c"}, {"x":34, "y":"d"}]; 15 | 16 | function preload() { 17 | dfile = loadStrings('diamonds.json'); // load the big file 18 | } 19 | 20 | var stylelist = [mylook, myotherlook, mythirdlook]; 21 | var whichstyle = 0; 22 | 23 | function setup() { 24 | createCanvas(windowWidth, windowHeight); 25 | background(255); 26 | 27 | diamonds = JSON.parse(dfile); 28 | // mix and match: 29 | 30 | // CONSTRUCTOR: 31 | //foo = new p5.Plot(); // easy 32 | foo = new p5.Plot({ left: width*0.2, top: height*0.3, right: width*0.8, bottom: height*0.7 }); 33 | //foo = new p5.Plot({ left: 100, top: 100, right: 400, bottom: 200, backgroundcolor: 'lightBlue' }); 34 | 35 | //noLoop(); 36 | background(255); 37 | // PLOT COMMAND: 38 | // LINE 39 | //foo.plot({data: mpg, xkey: 'year', ykey: 'displ', strokeweight: 5}); // default line 40 | //foo.plot({type: 'line', data: lukecrap, xkey: 'stuff', ykey: 'things'}); 41 | foo.plot({ type: 'line', data: economics, xkey: 'pop', ykey: 'unemploy', strokeweight: 5 }, stylelist[whichstyle]); 42 | 43 | // POINT 44 | //foo.plot({type: 'point', data: mpg, xkey: 'year', ykey: 'displ', strokeweight: 5}); 45 | //foo.plot({type: 'point', data: lukecrap, xkey: 'stuff', ykey: 'things', strokeweight: 5}, stylelist[whichstyle]); 46 | //foo.plot({ type: 'point', data: economics, xkey: 'pop', ykey: 'unemploy', strokeweight: 5 }, stylelist[whichstyle]); 47 | //foo.plot({ type: 'point', data: mpg, xkey: 'cty', ykey: 'hwy'}); 48 | //foo.plot({ type: 'point', data: diamonds, xkey: 'carat', ykey: 'price', strokecolor: [255, 0, 0, 32], fillcolor: [128, 128, 255, 32] }); 49 | //foo.plot({ type: 'point', data: diamonds, xkey: 'carat', ykey: 'price', strokecolor: [255, 0, 0, 32], fillcolor: [128, 128, 255, 32] }); 50 | //foo.plot({ type: 'point', data: diamonds, xkey: 'carat', ykey: 'price', strokecolor: [255, 0, 0, 32], fillcolor: [128, 128, 255, 32] }, crazygrid); 51 | 52 | // AREA 53 | //foo.plot({ type: 'area', data: economics, xkey: 'pop', ykey: 'unemploy', strokeweight: 5 }, stylelist[whichstyle]); // custom look 54 | 55 | // HISTOGRAM 56 | //foo.plot({ type: 'histogram', data: economics, xkey: 'pop', strokeweight: 5}); 57 | 58 | // PIE 59 | //foo.plot({type: 'pie', data: pieData, xkey:'x', background: false}); 60 | 61 | // not yet..................................................................... 62 | // BOX 63 | //foo.plot({ type: 'box', data: economics, xkey: 'pop', strokeweight: 5}); 64 | //foo.plot({ type: 'box', data: mpg, xkey: 'displ', ykey: 'year', strokeweight: 5}); 65 | //foo.plot({ type: 'box', data: diamonds, xkey: 'price', ykey: 'clarity', strokeweight: 1}); 66 | //foo.plot({ type: 'box', data: boxData, xkey: 'x', ykey: 'y', strokeweight: 5}); 67 | 68 | // DENSITY 69 | //foo.plot({ type: 'density', data: economics, xkey: 'pop', strokeweight: 5}); 70 | 71 | 72 | 73 | } 74 | 75 | function draw() { 76 | background(255); 77 | foo.redraw(); 78 | foo.hover(mouseX, mouseY, 'point'); 79 | //foo.hover(mouseX, mouseY, 'bin'); 80 | } 81 | 82 | function keyPressed() { 83 | whichstyle = (whichstyle+1)%stylelist.length; 84 | foo.plot(stylelist[whichstyle]); 85 | 86 | } 87 | -------------------------------------------------------------------------------- /ggplot2-cheatsheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDMNYU/p5.js-plot/6b4c0ab6e1e1a8bf4a302d175067026ef127113a/ggplot2-cheatsheet.pdf -------------------------------------------------------------------------------- /lib/p5.plot.js: -------------------------------------------------------------------------------- 1 | // p5.Plot 2 | // "grammar of graphics" influenced data viz for p5.js 3 | // creative coding summer vibes team, NYU IDM, 2018 4 | // 5 | 6 | 7 | // the plan should be 8 | // the constructor lets you set up whatever parameters you want 9 | // but won't render anything 10 | // plot() renders to a p5.createGraphics 11 | // redraw() plunks down the p5.graphics context already plot()'ed 12 | // hover() draws the fucker on top of the graphics context 13 | 14 | // the usual craziness: 15 | (function (root, factory) { 16 | if (typeof define === 'function' && define.amd) 17 | define('p5.func', ['p5'], function (p5) { (factory(p5));}); 18 | else if (typeof exports === 'object') 19 | factory(require('../p5')); 20 | else 21 | factory(root['p5']); 22 | }(this, function (p5) { 23 | 24 | // 25 | // start real stuff 26 | // 27 | 28 | // new style: 29 | p5.Plot = class { 30 | 31 | // this runs when you instantiate: 32 | // (also contains property defaults) 33 | constructor (_args) { 34 | // 35 | // defaults: 36 | // 37 | this.backgroundcolor = 'Cornsilk'; 38 | this.gridcolor = 'DarkSlateBlue'; 39 | this.gridweight = 4; 40 | this._fillcolor = ['WhiteSmoke']; 41 | this._strokecolor = ['DarkRed']; 42 | this._strokeweight = [1]; 43 | this.pointdiameter = 20; 44 | this.background = true; 45 | this.type = 'line'; // type of plot 46 | this.stat = 'bin'; // statistical transformation for 1-var plots 47 | this.bins = 30; // number of slices in binning plots 48 | //this._bins = 30; // does bin number change when faceting? 49 | this.xlabel = 'x'; // axis label 50 | this.ylabel = 'y'; // axis label 51 | this.xlabelvisible = true; 52 | this.ylabelvisible = true; 53 | this.cols = 5; 54 | this.rows = 5; 55 | this.left = 0; 56 | this.top = 0; 57 | this.right = width; 58 | this.bottom = height; 59 | this.data = {}; 60 | //this.xkey = ""; // key value for x axis 61 | //this.ykey = ""; // key value for y axis 62 | this._xkey = []; 63 | this._ykey = []; 64 | //this.pd = 1; // pixeldensity 65 | this.barpct = 0.5; 66 | 67 | this.typelist = {}; 68 | 69 | // function definitions 70 | this.typelist.line = { // 1 continuous 71 | // continuous function x y 72 | xtype: 'continuous', 73 | ytype: 'continuous', 74 | function: this.drawLineGraph 75 | }; 76 | 77 | this.typelist.point = { // continuous x, continuous y 78 | xtype: 'continuous', 79 | ytype: 'continuous', 80 | function: this.drawPointGraph 81 | }; 82 | 83 | this.typelist.area = { // 1 continuous 84 | // continuous function x y 85 | xtype: 'continuous', 86 | ytype: 'continuous', 87 | function: this.drawAreaGraph 88 | }; 89 | 90 | this.typelist.density = { // 1 continuous 91 | xtype: 'continuous', 92 | ytype: 'none', 93 | function: this.drawDensityGraph 94 | }; 95 | 96 | this.typelist.box = { // discrete x, continuous y 97 | xtype: 'discrete', 98 | ytype: 'continuous', 99 | function: this.drawBoxPlot 100 | }; 101 | 102 | this.typelist.histogram = { // 1 continuous variable 103 | xtype: 'continuous', 104 | ytype: 'none', 105 | function: this.drawHistogram 106 | }; 107 | 108 | this.typelist.bar = { // discrete x, continuous y 109 | xtype: 'discrete', 110 | ytype: 'continuous', 111 | function: this.drawBar 112 | }; 113 | 114 | this.typelist.bar2 = { // discrete x, continuous y 115 | xtype: 'discrete', 116 | ytype: 'none', 117 | function: this.drawBar2 118 | }; 119 | 120 | this.typelist.pie = { 121 | xtype: 'discrete', 122 | ytype: 'continuous', 123 | function: this.drawPieChart 124 | }; 125 | 126 | 127 | //get strokecolor () { return this._strokecolor}; 128 | // 129 | // end defaults 130 | // 131 | 132 | // internals: 133 | this._xmin; // internal 134 | this._xmax; // internal 135 | this._ymin; // internal 136 | this._ymax; // internal 137 | 138 | // integrate arguments: 139 | // this is an awesome ES6 hack where the Object.assign() 140 | // method lets you splice shit from one Object literal into 141 | // another Object, just replacing whatever's there. 142 | for(let i in arguments) 143 | { 144 | Object.assign(this, arguments[i]); 145 | } 146 | 147 | push(); 148 | this.graphics = createGraphics((this.right-this.left), (this.bottom-this.top)); 149 | pop(); 150 | //this.graphics.pixelDensity(this.pd); 151 | 152 | this.plotData = []; // create a new dataset to workwith instead of changing the original!!!!!!!!!!!! 153 | console.log('p5 plot!'); 154 | 155 | }; // end of constructor 156 | 157 | // setters: 158 | set fillcolor (fillcolor) { 159 | this._fillcolor = Array.isArray(fillcolor) ? fillcolor : [fillcolor]; 160 | }; 161 | set strokecolor (strokecolor) { 162 | this._strokecolor = Array.isArray(strokecolor) ? strokecolor : [strokecolor]; 163 | }; 164 | set strokeweight (strokeweight) { 165 | this._strokeweight = Array.isArray(strokeweight) ? strokeweight : [strokeweight]; 166 | }; 167 | set xkey (xkey) { 168 | this._xkey = Array.isArray(xkey) ? xkey : [xkey]; 169 | }; 170 | set ykey (ykey) { 171 | this._ykey = Array.isArray(ykey) ? ykey : [ykey]; 172 | }; 173 | 174 | set barwidth(_v) // bar percentage 175 | { 176 | this.barpct = constrain(_v, 0, 1); 177 | }; 178 | 179 | // MAIN PLOTTER FUNCTION 180 | // 181 | plot (_args) { 182 | 183 | // integrate arguments (see above): 184 | for(let i in arguments) 185 | { 186 | Object.assign(this, arguments[i]); 187 | } 188 | 189 | this.parseData(); // figure out min and max scalings, etc. 190 | 191 | this.graphics.clear(); 192 | 193 | // draw a background? 194 | if(this.background) this.drawBackground(); 195 | 196 | // which graph style? 197 | this.typelist[this.type].function(this); 198 | 199 | this.redraw(); 200 | }; // END OF MAIN PLOTTER FUNCTION 201 | 202 | // 203 | // DRAW A BACKGROUND 204 | // 205 | drawBackground(){ 206 | this.graphics.push(); 207 | // this.graphics.scale(1/this.pd); 208 | // dont need bg rect anymore cuz graphics is a new canvas 209 | this.graphics.background(this.backgroundcolor); 210 | 211 | this.graphics.stroke(this.gridcolor); 212 | this.graphics.strokeWeight(this.gridweight); 213 | 214 | // map one more line than given 215 | // vertical lines 216 | for(let i = 0;i=this.plotData[i]._hoverx && 257 | _x<=this.plotData[i]._hoverx+this.plotData[i]._hoverw && 258 | _y>=this.plotData[i]._hovery && 259 | _y<=this.plotData[i]._hovery+this.plotData[i]._hoverh) 260 | { 261 | hitme = i; 262 | break; 263 | } 264 | } 265 | } 266 | // PART 2 - DO THE HOVER 267 | if(hitme>-1) 268 | { 269 | push(); 270 | var bgc = color(this.backgroundcolor); 271 | bgc.setAlpha(100); 272 | fill(bgc); 273 | var fgc = color(this.strokecolor); 274 | fgc.setAlpha(255); 275 | stroke(fgc); 276 | rect(_x, _y, 200, 100); 277 | noStroke(); 278 | fill(fgc); 279 | textSize(12); 280 | 281 | if(_hittype=='point') { 282 | text("DATA:", this.plotData[hitme]._hoverx+10, this.plotData[hitme]._hovery+20); 283 | text(this.xkey + ": " + this.plotData[hitme][this.xkey], this.plotData[hitme]._hoverx+10, this.plotData[hitme]._hovery+40); 284 | text(this.ykey + ": " + this.plotData[hitme][this.ykey], this.plotData[hitme]._hoverx+10, this.plotData[hitme]._hovery+60); 285 | } 286 | else if(_hittype=='bin') { 287 | // highlight bin 288 | text("Bin "+ (hitme+1), _x+10, _y+20) 289 | text("Frequency: " + this.plotData[hitme].freq, _x+10, _y+40); 290 | text("Range: " + this.plotData[hitme].minBound +" to "+this.plotData[hitme].maxBound, _x+10, _y+60); 291 | push(); 292 | noFill(); 293 | stroke(0); 294 | strokeWeight(this.strokeweight); 295 | rect(this.plotData[hitme]._hoverx, this.plotData[hitme]._hovery, this.plotData[hitme]._hoverw, this.plotData[hitme]._hoverh) 296 | pop(); 297 | } 298 | pop(); 299 | } 300 | } 301 | 302 | // 303 | // parseData() - MAKE SENSE OF THE DATASET 304 | // 305 | parseData() { 306 | // STEP ONE: 307 | // what happens if the data array is not made up of object literals 308 | 309 | // simple array test: 310 | if(Array.isArray(this.data) && typeof(this.data[0])==="number") 311 | { 312 | var _newdata = this.tokenize(this.data); // fix 313 | this.data = _newdata; // swap 314 | } 315 | // STEP TWO: 316 | // fix if we have no xkey / ykey defined 317 | if(this._xkey.length==0){ 318 | this._xkey = [Object.keys(this.data[0])[0]]; 319 | } 320 | if(this._ykey.length==0){ 321 | this._ykey = [Object.keys(this.data[0])[1]]; 322 | } 323 | 324 | console.log('_xkey', this._xkey, '_ykey', this._ykey); 325 | 326 | // STEP THREE: 327 | // make sure the keys are the right type 328 | console.log(this.typelist[this.type].xtype + " " + this.typelist[this.type].ytype); 329 | 330 | // & faceting 331 | /* old method 332 | if (Array.isArray(this.xkey)){ 333 | this._xmin = this.data[0][this.xkey[0]]; 334 | this._xmax = this.data[0][this.xkey[0]]; 335 | } 336 | else{ 337 | this._xmin = this.data[0][this.xkey]; 338 | this._xmax = this.data[0][this.xkey]; 339 | } 340 | if (Array.isArray(this.ykey)){ 341 | this._ymin = this.data[0][this.ykey[0]]; 342 | this._ymax = this.data[0][this.ykey[0]]; 343 | } 344 | else{ 345 | this._ymin = this.data[0][this.ykey]; 346 | this._ymax = this.data[0][this.ykey]; 347 | } 348 | */ 349 | 350 | this._xmin = this.data[0][this._xkey[0]]; 351 | this._xmax = this.data[0][this._xkey[0]]; 352 | this._ymin = this.data[0][this._ykey[0]]; 353 | this._ymax = this.data[0][this._ykey[0]]; 354 | 355 | /* old method 356 | for(let i=0;ithis._xmax) this._xmax = this.data[i][this.xkey[j]]; 363 | currentData[this.xkey[j]] = this.data[i][this.xkey[j]]; 364 | } 365 | // min and max of total 366 | } 367 | else{ 368 | if(this.data[i][this.xkey]this._xmax) this._xmax = this.data[i][this.xkey]; 370 | currentData[this.xkey] = this.data[i][this.xkey]; 371 | } 372 | 373 | // ykey 374 | if (Array.isArray(this.ykey)){ // ykey is array 375 | for (let i=0; ithis._ymax) this._ymax = this.data[i][this.ykey[j]]; 378 | currentData[this.ykey[i]] = this.data[i][this.ykey[i]]; 379 | } 380 | } 381 | else{ 382 | if(this.data[i][this.ykey]this._ymax) this._ymax = this.data[i][this.ykey]; 384 | currentData[this.ykey] = this.data[i][this.ykey]; 385 | } 386 | this.plotData.push(currentData); 387 | } 388 | */ 389 | 390 | for(let i=0;ithis._xmax) this._xmax = this.data[i][this._xkey[j]]; 396 | currentData[this._xkey[j]] = this.data[i][this._xkey[j]]; 397 | } 398 | 399 | // ykey 400 | for (let k=0; kthis._ymax) this._ymax = this.data[i][this._ykey[k]]; 403 | currentData[this._ykey[k]] = this.data[i][this._ykey[k]]; 404 | } 405 | 406 | // data we actually use 407 | this.plotData.push(currentData); 408 | } 409 | } // end of parseData 410 | 411 | // 412 | // 413 | // SORT AN ARRAY BASED ON A KEY 414 | // 415 | sortData(_key) { 416 | // sort by xkey 417 | this.data.sort(function(a, b) { 418 | return a[_key] - b[_key]; 419 | }); 420 | 421 | this.plotData.sort(function(a, b) { 422 | return a[_key] - b[_key]; 423 | }); 424 | } 425 | 426 | // 427 | // TOKENIZE - utility to JSONify a simple array 428 | // 429 | tokenize(_arr) { 430 | var a = []; 431 | for(var i in _arr) 432 | { 433 | var j = {}; 434 | j.index = i; 435 | j.value = _arr[i]; 436 | a.push(j); 437 | } 438 | return(a); 439 | } 440 | 441 | // 442 | // LINE GRAPH 443 | // 444 | drawLineGraph(that) { 445 | console.log('Line Graph!'); 446 | 447 | /* 448 | let plotxArr = new Array(that.plotData.length); 449 | let plotyArr = new Array(that.plotData.length); 450 | let hoverxArr = new Array(that.plotData.length); 451 | let hoveryArr = new Array(that.plotData.length); 452 | 453 | for (let k = 0; k < that.plotData.length; k++) { 454 | plotxArr[k] = new Array(that.xkey.length); 455 | plotyArr[k] = new Array(that.xkey.length); 456 | hoverxArr[k] = new Array(that.xkey.length); 457 | hoveryArr[k] = = new Array(that.xkey.length); 458 | } 459 | */ 460 | 461 | that.graphics.push(); 462 | // need to figure out a way to do this for all graphs 463 | // faceting: multiple xkeys 464 | // iterate through all x keys 465 | console.log(that._xkey.length); 466 | 467 | // what happens when multiple xkeys and ykeys? 468 | for (let i=0; i= currentMinBound) && (currentValue maxFreq){ 703 | maxFreq = currentFreq; 704 | } 705 | } 706 | 707 | that.graphics.push(); 708 | 709 | that.graphics.fill(that.fillcolor); 710 | that.graphics.stroke(that.strokecolor); 711 | that.graphics.strokeWeight(that.strokeweight); 712 | 713 | // okay, so here if we want to have a hover function, and a plotData, 714 | // the plotData should just have the length of the bins 715 | // we need to at least store 4 hover values: 716 | // _hoverx _hovery, _hoverw, hoverh 717 | // for plot values, also 4 718 | // I'm just gonna reset plotData to empty here 719 | that.plotData = binArr; 720 | 721 | // start to draw rectangles!!! 722 | that.graphics.rectMode(CORNER); // x, y, w, h 723 | let drawWidth = (that.right-that.left)/numBins; // width of each rect 724 | let currentX = 0; // in graphics, start with 0 725 | for (let p=0; pvalueMax){ 904 | valueMax = that.data[k][ykey]; 905 | } 906 | } 907 | 908 | let yQuartileBoundsArr = that.quartileBounds(valueArr); 909 | // map minimum, first quartile, median, third quartile, and maximum into the graph 910 | // two graphs should have a common scale instead of their own scale 911 | let boxMin = map(yQuartileBoundsArr[0], valueMin, valueMax, 0, that.graphics.width); 912 | let boxQ1 = map(yQuartileBoundsArr[1], valueMin, valueMax, 0, that.graphics.width); 913 | let boxMedian = map(yQuartileBoundsArr[2], valueMin, valueMax, 0, that.graphics.width); 914 | let boxQ3 = map(yQuartileBoundsArr[3], valueMin, valueMax, 0, that.graphics.width); 915 | let boxMax = map(yQuartileBoundsArr[4], valueMin, valueMax, 0, that.graphics.width); 916 | 917 | console.log(boxMin+' '+boxQ1+' '+boxMedian+' '+boxQ3+' '+ boxMax); 918 | 919 | // graph multiple horizontal box plots after dealing with data 920 | 921 | // the height of box, keep it constant 922 | //let boxHeight = this.bottom-this.top; 923 | 924 | that.drawOneBox(boxMin, boxQ1, boxMedian, boxQ3, boxMax, boxY, boxHeight); 925 | 926 | //draw next box, the Y pos will increase! 927 | boxY += boxMargin + boxHeight; 928 | } 929 | that.graphics.pop(); 930 | } 931 | 932 | 933 | 934 | // find the median 935 | // if array is odd number, median is middle number 936 | // if array is even number, median is middle two numbers added then divide by two 937 | getMedian(sampleArr){ 938 | sampleArr.sort(function(a, b){return a - b}); 939 | // even 940 | if (sampleArr.length%2 === 0){ 941 | let numA = sampleArr[sampleArr.length/2 - 1]; 942 | let numB = sampleArr[sampleArr.length/2]; 943 | return (numA + numB)/2; 944 | } 945 | // odd 946 | else{ 947 | return sampleArr[(sampleArr.length - 1)/2]; 948 | } 949 | } 950 | 951 | // find medians and quartiles 952 | quartileBounds(sampleArr){ 953 | // must sort array first 954 | sampleArr.sort(function(a, b){return a - b}); 955 | let _firstHalf; 956 | let _secondHalf; 957 | // even 958 | if (sampleArr.length%2 === 0){ 959 | _firstHalf = sampleArr.slice(0, sampleArr.length/2); 960 | _secondHalf = sampleArr.slice(sampleArr.length/2, sampleArr.length); 961 | } 962 | // odd 963 | else { 964 | _firstHalf = sampleArr.slice(0, (sampleArr.length-1)/2); 965 | _secondHalf = sampleArr.slice(((sampleArr.length-1)/2)+1, sampleArr.length); 966 | } 967 | let _0percent = min(sampleArr); 968 | 969 | // find the medians for each split 970 | let _25percent = this.getMedian(_firstHalf); 971 | let _75percent = this.getMedian(_secondHalf); 972 | 973 | let _50percent = this.getMedian(sampleArr); 974 | let _100percent = max(sampleArr); 975 | 976 | return [ _0percent, _25percent, _50percent, _75percent, _100percent]; 977 | } 978 | 979 | drawOneBox(boxMin, boxQ1, boxMed, boxQ3, boxMax, boxY, boxHeight){ 980 | this.graphics.line(boxMin, boxY+boxHeight/4, boxMin, boxY+boxHeight/4+boxHeight/2); // minimum 981 | 982 | this.graphics.line(boxQ1, boxY, boxQ1, boxY+boxHeight); // Q1 983 | 984 | this.graphics.line(boxMed, boxY, boxMed, boxY+boxHeight); // median 985 | 986 | this.graphics.line(boxQ3, boxY, boxQ3, boxY+boxHeight); // Q3 987 | 988 | this.graphics.line(boxMax, boxY+boxHeight/4, boxMax, boxY+boxHeight/4+boxHeight/2); //maximum 989 | 990 | // connect 991 | this.graphics.line(boxQ1, boxY, boxQ3, boxY); // top of box 992 | this.graphics.line(boxQ1, boxY+boxHeight, boxQ3, boxY+boxHeight); // bot of box 993 | this.graphics.line(boxMin, boxY+boxHeight/2, boxQ1, boxY+boxHeight/2); 994 | this.graphics.line(boxQ3, boxY+boxHeight/2, boxMax, boxY+boxHeight/2); 995 | } 996 | 997 | // 998 | // DENSITY GRAPH 999 | // 1000 | drawDensityGraph(that){ 1001 | // density graph is taking one contineous variable 1002 | // here we assume a bin is given, !!!!!!!!!!!!but possibly no bin and discrete data is given!!!!!!!!! 1003 | // mapping frequencies within each bin 1004 | // find the percentage of the frequency 1005 | 1006 | // here let's assume we only take xkey 1007 | let xkey = that.xkey; 1008 | //let ykey = that.ykey; 1009 | 1010 | let xmin = that._xmin; 1011 | let xmax = that._xmax; 1012 | //let ymin = that._ymin; 1013 | //let ymax = that._ymax; 1014 | 1015 | let numBins = that.bins; 1016 | let binRange = (xmax-xmin)/numBins; 1017 | // create an empty array with numBins of items, later will store the number of values in that bin 1018 | let binFreqArr = new Array(numBins); 1019 | 1020 | that.sortData(xkey); // may not be necessary as we only looking for frequency 1021 | 1022 | let currentMinBound = xmin; 1023 | let currentMaxBound = xmin+binRange; 1024 | for (let j=0; j= currentMinBound) && (currentValue0) prevFreq = binFreqArr[q-1]; 1057 | 1058 | let currentFreq = binFreqArr[q]; 1059 | 1060 | if(qthis.data[i]._plotx-flakiness&&_xthis.data[i]._ploty-flakiness&&_ythis._xmax) this._xmax = this.data[i][xkey]; 190 | if(this.data[i][ykey]this._ymax) this._ymax = this.data[i][ykey]; 192 | } 193 | 194 | } 195 | 196 | // 197 | // sortData() - SORT AN ARRAY BASED ON A KEY 198 | // 199 | sortData(_key) { 200 | // sort by xkey 201 | this.data.sort(function(a, b) { 202 | return a[_key] - b[_key]; 203 | }); 204 | 205 | 206 | } 207 | 208 | // 209 | // LINE GRAPH 210 | // 211 | drawLineGraph() { 212 | let xkey = this.xkey; 213 | let ykey = this.ykey; 214 | 215 | let xmin = this._xmin; 216 | let xmax = this._xmax; 217 | let ymin = this._ymin; 218 | let ymax = this._ymax; 219 | let px = 0; 220 | let py = 0; 221 | 222 | push(); 223 | 224 | fill(this.fillcolor); 225 | stroke(this.strokecolor); 226 | strokeWeight(this.strokeweight); 227 | 228 | this.sortData(xkey); 229 | for(let i in this.data) 230 | { 231 | this.data[i]._plotx = map(this.data[i][xkey], xmin, xmax, this.left, this.right); 232 | this.data[i]._ploty = map(this.data[i][ykey], ymin, ymax, this.bottom, this.top); 233 | let x = this.data[i]._plotx; 234 | let y = this.data[i]._ploty; 235 | if(i>0) line(px, py, x, y); 236 | px = x; 237 | py = y; 238 | } 239 | pop(); 240 | 241 | } 242 | 243 | // 244 | // POINT GRAPH 245 | // 246 | drawPointGraph() { 247 | let xkey = this.xkey; 248 | let ykey = this.ykey; 249 | 250 | let xmin = this._xmin; 251 | let xmax = this._xmax; 252 | let ymin = this._ymin; 253 | let ymax = this._ymax; 254 | 255 | push(); 256 | 257 | fill(this.fillcolor); 258 | stroke(this.strokecolor); 259 | strokeWeight(this.strokeweight); 260 | 261 | for(let i in this.data) 262 | { 263 | this.data[i]._plotx = map(this.data[i][xkey], xmin, xmax, this.left, this.right); 264 | this.data[i]._ploty = map(this.data[i][ykey], ymin, ymax, this.bottom, this.top); 265 | let x = this.data[i]._plotx; 266 | let y = this.data[i]._ploty; 267 | 268 | ellipse(x,y,5,5); 269 | } 270 | 271 | pop(); 272 | 273 | } 274 | 275 | }; // end of p5.Plot() 276 | 277 | 278 | })); // end of craziness 279 | 280 | p5.Plot.prototype.drawAlex = function() 281 | { 282 | 283 | } 284 | 285 | /* 286 | p5.Plot.prototype.drawAlexHistogram = function(){ 287 | // histogram is taking one contineous variable 288 | // mapping frequencies within each bin 289 | // here let's assume we only take xkey to plot our histogram 290 | let xkey = this.xkey; 291 | //let ykey = this.ykey; 292 | 293 | let xmin = this._xmin; 294 | let xmax = this._xmax; 295 | //let ymin = this._ymin; 296 | //let ymax = this._ymax; 297 | 298 | let numBins = this.bins; 299 | let binRange = (xmax-xmin)/numBins; 300 | let binArr = new Array(numBins); 301 | 302 | this.sortData(xkey); // may not be necessary as we only looking for frequency 303 | 304 | let currentMinBound = xmin; 305 | let currentMaxBound = xmin+binRange; 306 | for (let j=0; j= currentMinBound) && (currentValue maxFreq){ 330 | maxFreq = currentFreq; 331 | } 332 | } 333 | 334 | console.log(minFreq); 335 | console.log(maxFreq); 336 | 337 | push(); 338 | 339 | fill(this.fillcolor); 340 | stroke(this.strokecolor); 341 | strokeWeight(this.strokeweight); 342 | 343 | // start to draw rectangles!!! 344 | rectMode(CORNER); // x, y, w, h 345 | drawWidth = (this.right-this.left)/numBins; // width of each rect 346 | let currentX = this.left; 347 | for (let q=0; q0) vertex(x, y); 386 | } 387 | vertex(this.right, this.bottom); 388 | 389 | endShape(CLOSE); 390 | 391 | pop(); 392 | 393 | 394 | } 395 | */ 396 | /* 397 | p5.Plot.prototype.drawBoxPlot = function(){ 398 | // draw box plot 399 | // graph minimum, first quartile, median, third quartile, and maximum 400 | 401 | // only makes sense when there's discrete y and continuous x or; 402 | // discrete x and continuous y 403 | // for example: 404 | // boxData = [{"x":13, "y":"a"}, {"x":16, "y":"a"}, {"x":57, "y":"a"}, {"x":34, "y":"a"}, {"x":26, "y":"a"}, {"x":67, "y":"a"}, {"x":12, "y":"a"}, 405 | {"x":45, "y":"b"}, {"x":32, "y":"b"}, {"x":24, "y":"b"}, {"x":86, "y":"b"}, {"x":65, "y":"b"}, {"x":37, "y":"b"}, {"x":98, "y":"b"}]; 406 | 407 | 408 | // here lets assume xkey is contineous and 409 | // ykey is discrete 410 | // draw horizontal graphs 411 | // the number of ykey represent number of boxes 412 | let xkey = this.xkey; 413 | let ykey = this.ykey; 414 | 415 | // if x is contineous, find min & max 416 | let xmin = this._xmin; 417 | let xmax = this._xmax; 418 | 419 | push(); 420 | 421 | fill(this.fillcolor); 422 | stroke(this.strokecolor); 423 | strokeWeight(this.strokeweight); 424 | 425 | // if there's more than one set of continuous data 426 | // put every unique y value into the array 427 | let boxArr = []; 428 | let valueMin = xmin; //if given y value, this is useful 429 | let valueMax = xmax; 430 | 431 | // check in our data, how many unique y & push them into new array 432 | // if no ykey is given, y would just be default 1, apparently 433 | for(let i in this.data){ 434 | if (boxArr.includes(this.data[i][ykey])){ 435 | } 436 | else{ 437 | boxArr.push(this.data[i][ykey]); 438 | } 439 | } 440 | 441 | let numBox = boxArr.length; 442 | let boxMargin = ((this.bottom-this.top)/numBox)/10; 443 | let boxY = this.top+boxMargin; 444 | let boxHeight = (this.bottom-this.top)/numBox - boxMargin*2; 445 | 446 | // for every box array value, draw a box 447 | for (let j=0; jvalueMax){ 457 | valueMax = this.data[k][xkey] 458 | } 459 | } 460 | 461 | let xQuartileBoundsArr = quartileBounds(valueArr); 462 | // map minimum, first quartile, median, third quartile, and maximum into the graph 463 | // two graphs should have a common scale instead of their own scale 464 | let boxMin = map(xQuartileBoundsArr[0], valueMin, valueMax, this.left, this.right); 465 | let boxQ1 = map(xQuartileBoundsArr[1], valueMin, valueMax, this.left, this.right); 466 | let boxMedian = map(xQuartileBoundsArr[2], valueMin, valueMax, this.left, this.right); 467 | let boxQ3 = map(xQuartileBoundsArr[3], valueMin, valueMax, this.left, this.right); 468 | let boxMax = map(xQuartileBoundsArr[4], valueMin, valueMax, this.left, this.right); 469 | 470 | console.log(boxMin+' '+boxQ1+' '+boxMedian+' '+boxQ3+' '+ boxMax); 471 | 472 | // graph multiple horizontal box plots after dealing with data 473 | 474 | // the height of box, keep it constant 475 | //let boxHeight = this.bottom-this.top; 476 | 477 | drawOneBox(boxMin, boxQ1, boxMedian, boxQ3, boxMax, boxY, boxHeight); 478 | 479 | //draw next box, the Y pos will increase! 480 | boxY += boxMargin + boxHeight; 481 | } 482 | pop(); 483 | } 484 | 485 | // find the median 486 | // if array is odd number, median is middle number 487 | // if array is even number, median is middle two numbers added then divide by two 488 | function getMedian(sampleArr){ 489 | sampleArr.sort(function(a, b){return a - b}); 490 | // even 491 | if (sampleArr.length%2 === 0){ 492 | let numA = sampleArr[sampleArr.length/2 - 1]; 493 | let numB = sampleArr[sampleArr.length/2]; 494 | return (numA + numB)/2; 495 | } 496 | // odd 497 | else{ 498 | return sampleArr[(sampleArr.length - 1)/2]; 499 | } 500 | } 501 | 502 | // find medians and quartiles 503 | function quartileBounds(sampleArr){ 504 | // must sort array first 505 | sampleArr.sort(function(a, b){return a - b}); 506 | let _firstHalf; 507 | let _secondHalf; 508 | // even 509 | if (sampleArr.length%2 === 0){ 510 | _firstHalf = sampleArr.slice(0, sampleArr.length/2); 511 | _secondHalf = sampleArr.slice(sampleArr.length/2, sampleArr.length); 512 | } 513 | // odd 514 | else { 515 | _firstHalf = sampleArr.slice(0, (sampleArr.length-1)/2); 516 | _secondHalf = sampleArr.slice(((sampleArr.length-1)/2)+1, sampleArr.length); 517 | } 518 | let _0percent = min(sampleArr); 519 | 520 | // find the medians for each split 521 | let _25percent = getMedian(_firstHalf); 522 | let _75percent = getMedian(_secondHalf); 523 | 524 | let _50percent = getMedian(sampleArr); 525 | let _100percent = max(sampleArr); 526 | 527 | return [ _0percent, _25percent, _50percent, _75percent, _100percent]; 528 | } 529 | 530 | function drawOneBox(boxMin, boxQ1, boxMed, boxQ3, boxMax, boxY, boxHeight){ 531 | line(boxMin, boxY+boxHeight/4, boxMin, boxY+boxHeight/4+boxHeight/2); // minimum 532 | 533 | line(boxQ1, boxY, boxQ1, boxY+boxHeight); // Q1 534 | 535 | line(boxMed, boxY, boxMed, boxY+boxHeight); // median 536 | 537 | line(boxQ3, boxY, boxQ3, boxY+boxHeight); // Q3 538 | 539 | line(boxMax, boxY+boxHeight/4, boxMax, boxY+boxHeight/4+boxHeight/2); //maximum 540 | 541 | // connect 542 | line(boxQ1, boxY, boxQ3, boxY); // top of box 543 | line(boxQ1, boxY+boxHeight, boxQ3, boxY+boxHeight); // bot of box 544 | line(boxMin, boxY+boxHeight/2, boxQ1, boxY+boxHeight/2); 545 | line(boxQ3, boxY+boxHeight/2, boxMax, boxY+boxHeight/2); 546 | } 547 | */ 548 | /* 549 | p5.Plot.prototype.drawDensityGraph = function(){ 550 | // density graph is taking one contineous variable 551 | // here we assume a bin is given, !!!!!!!!!!!!but possibly no bin and discrete data is given!!!!!!!!! 552 | // mapping frequencies within each bin 553 | // find the percentage of the frequency 554 | 555 | // here let's assume we only take xkey 556 | let xkey = this.xkey; 557 | //let ykey = this.ykey; 558 | 559 | let xmin = this._xmin; 560 | let xmax = this._xmax; 561 | //let ymin = this._ymin; 562 | //let ymax = this._ymax; 563 | 564 | let numBins = this.bins; 565 | let binRange = (xmax-xmin)/numBins; 566 | // create an empty array with numBins of items, later will store the number of values in that bin 567 | let binFreqArr = new Array(numBins); 568 | 569 | this.sortData(xkey); // may not be necessary as we only looking for frequency 570 | 571 | let currentMinBound = xmin; 572 | let currentMaxBound = xmin+binRange; 573 | for (let j=0; j= currentMinBound) && (currentValue0) prevFreq = binFreqArr[q-1]; 607 | 608 | let currentFreq = binFreqArr[q]; 609 | 610 | if(qthis._xmax) this._xmax = this.data[i][xkey]; 794 | if(this.data[i][ykey]this._ymax) this._ymax = this.data[i][ykey]; 796 | } 797 | } 798 | } 799 | 800 | 801 | ///////////// STUFF SALLY WORKED ON ///////////////////////// 802 | 803 | p5.Plot.prototype.drawBarGraph = function() 804 | { 805 | //let xkey = this.xkey; 806 | //let ykey = this.ykey; 807 | let key; 808 | let max; 809 | let keyArr; 810 | let keyObj; 811 | let spacing 812 | 813 | this._ymin = 0; 814 | this._xmin = 0; 815 | 816 | if (this.xkey != 0){ 817 | keyArr = this.barSort(this.xkey); 818 | key = this.xkey; 819 | keyObj = this.barParse(key); 820 | spacing = (this.right - this.left)/keyArr.length; 821 | } 822 | else if (this.ykey != 1){ 823 | keyArr = this.barSort(this.ykey); 824 | key = this.ykey; 825 | keyObj = this.barParse(key); 826 | spacing = (this.bottom - this.top)/keyArr.length 827 | } 828 | 829 | fill(this.fillcolor); 830 | stroke(this.strokecolor); 831 | strokeWeight(this.strokeweight); 832 | max = keyObj[0].quantity; 833 | 834 | for(let i in keyObj){ 835 | if(keyObj[i].quantity > max){max = keyObj[i].quantity;} 836 | } 837 | 838 | if (key == this.xkey){ 839 | this._xmax = keyArr.length; 840 | this._ymax = max; 841 | } 842 | else if (key == this.ykey){ 843 | this._xmax = max; 844 | this._ymax = keyArr.length; 845 | } 846 | 847 | 848 | push(); 849 | let x; 850 | let y; 851 | let w; 852 | let h; 853 | 854 | if (key == this.xkey){ 855 | x = this.left; 856 | y= 0; 857 | w= this.left; 858 | h= 0; 859 | } 860 | else if (key == this.ykey){ 861 | x = this.left; 862 | y = this.top; 863 | w = 0; 864 | h = this.top; 865 | } 866 | 867 | rectMode(CORNERS); 868 | 869 | for(let k=0; k < keyObj.length; k++) 870 | { 871 | if (key == this.xkey){ 872 | y = map(keyObj[k].quantity, 0, this._ymax, this.bottom, this.top); 873 | w += spacing; 874 | h = this.bottom; 875 | rect(x, y, w, h) 876 | x += spacing; 877 | } 878 | else if (key == this.ykey){ 879 | h += spacing; 880 | w = map(keyObj[k].quantity, 0, max, this.left, this.right) 881 | rect(x, y, w, h) 882 | y+= spacing; 883 | } 884 | } 885 | 886 | pop(); 887 | } 888 | 889 | p5.Plot.prototype.barSort = function(_key){ 890 | keyArr = [this.data[0][_key]]; 891 | this.data[0][_key] = 0; 892 | 893 | for(let i=1;i qmax){qmax = keyObj[i].quantity;} 945 | } 946 | 947 | console.log(keyObj); 948 | 949 | push(); 950 | 951 | let xone = (this.right - this.left) / xDots; 952 | let xhalf = xone / 2; 953 | let yone = (this.top - this.bottom)/yDots 954 | let yhalf = yone / 2 955 | 956 | 957 | let x = this.left + xhalf; 958 | let y = this.bottom + yhalf; 959 | let w; 960 | 961 | if (yone <= xone){w = yone;} 962 | else{w = xone;} 963 | 964 | ellipseMode(CENTER); 965 | 966 | 967 | for(let k=0; k < keyObj.length; k++) { 968 | let dotNum = keyObj[k].quantity / yDots; 969 | for(let j = 0; j < dotNum; j++){ 970 | ellipse(x, y, w); 971 | y += yone; 972 | } 973 | x += xone; 974 | y = this.bottom + yhalf; 975 | 976 | } 977 | pop(); 978 | 979 | } 980 | 981 | 982 | p5.Plot.prototype.drawHistogram = function(){ 983 | 984 | let range; 985 | let min; 986 | let max; 987 | let key; 988 | let bars; 989 | 990 | if (this.xkey != 0){ 991 | range = this._xmax - this._xmin; 992 | max = this._xmax; 993 | min = this._xmin; 994 | key = this.xkey; 995 | bars = this.cols; 996 | } 997 | else if (this.ykey != 1){ 998 | range = this._ymax - this._ymin; 999 | max = this._ymax; 1000 | min = this._ymin; 1001 | key = this.ykey; 1002 | bars = this.rows; 1003 | } 1004 | while (range % bars != 0){ 1005 | range += 1; 1006 | } 1007 | let barRange = range / bars; 1008 | let keyArr = this.findKeys(barRange, min,max); 1009 | let keyObj = this.histParse(keyArr, key, barRange); 1010 | 1011 | fill(this.fillcolor); 1012 | stroke(this.strokecolor); 1013 | strokeWeight(this.strokeweight); 1014 | 1015 | let qmax = keyObj[0].quantity; 1016 | 1017 | for(let i in keyObj){ 1018 | if(keyObj[i].quantity > qmax){qmax = keyObj[i].quantity;} 1019 | } 1020 | 1021 | console.log(keyObj); 1022 | 1023 | push(); 1024 | 1025 | let x; 1026 | let y; 1027 | let w; 1028 | let h; 1029 | let spacing 1030 | 1031 | if (key == this.xkey){ 1032 | x = this.left; 1033 | y= 0; 1034 | w= this.left; 1035 | h= 0; 1036 | spacing = (this.right - this.left)/(this.cols); 1037 | 1038 | } 1039 | else if (key == this.ykey){ 1040 | x = this.left; 1041 | y = this.top; 1042 | w = 0; 1043 | h = this.top; 1044 | spacing = (this.top - this.bottom)/this.rows; 1045 | } 1046 | 1047 | rectMode(CORNERS); 1048 | 1049 | for(let k=0; k < keyObj.length; k++) 1050 | { 1051 | if (key == this.xkey){ 1052 | y = map(keyObj[k].quantity, 0, qmax, this.bottom, this.top); 1053 | w += spacing; 1054 | h = this.bottom; 1055 | rect(x, y, w, h) 1056 | x += spacing; 1057 | 1058 | } 1059 | else if (key == this.ykey){ 1060 | h -= spacing; 1061 | w = map(keyObj[k].quantity, 0, qmax, this.left, this.right) 1062 | rect(x, y, w, h) 1063 | y-= spacing; 1064 | } 1065 | } 1066 | 1067 | 1068 | pop(); 1069 | 1070 | } 1071 | 1072 | p5.Plot.prototype.findKeys = function(barRange, min, max){ 1073 | let keyArr = []; 1074 | let mult = 0; 1075 | while ((mult * barRange) < min){ 1076 | mult += 1; 1077 | } 1078 | mult -=1; 1079 | for (i = 0; i < this.cols; i++){ 1080 | keyArr.push(mult); 1081 | mult += 1; 1082 | } 1083 | return keyArr; 1084 | } 1085 | 1086 | p5.Plot.prototype.histParse = function(keyArr, key, barRange){ 1087 | keyObj = [{"key": (keyArr[0]* barRange) + "-" + ((keyArr[0] + 1) * barRange), "quantity": 0}]; 1088 | 1089 | for(let j=1; j= keyArr[keyArr.length - 1] * barRange){ 1097 | keyObj[keyArr.length - 1].quantity += 1; 1098 | } 1099 | else if (num >= keyArr[i] * barRange && num < keyArr[i + 1] * barRange){ 1100 | keyObj[i].quantity += 1 1101 | } 1102 | } 1103 | } 1104 | return keyObj; 1105 | } 1106 | -------------------------------------------------------------------------------- /lib/p5.simpleplot.js: -------------------------------------------------------------------------------- 1 | // p5.Plot 2 | // "grammar of graphics" influenced data viz for p5.js 3 | // creative coding summer vibes team, NYU IDM, 2018 4 | // 5 | 6 | 7 | // the plan should be 8 | // the constructor lets you set up whatever parameters you want 9 | // but won't render anything 10 | // plot() renders to a p5.createGraphics 11 | // redraw() plunks down the p5.graphics context already plot()'ed 12 | // hover() draws the fucker on top of the graphics context 13 | 14 | // the usual craziness: 15 | (function (root, factory) { 16 | if (typeof define === 'function' && define.amd) 17 | define('p5.func', ['p5'], function (p5) { (factory(p5));}); 18 | else if (typeof exports === 'object') 19 | factory(require('../p5')); 20 | else 21 | factory(root['p5']); 22 | }(this, function (p5) { 23 | 24 | // 25 | // start real stuff 26 | // 27 | 28 | // new style: 29 | p5.Plot = class { 30 | 31 | // this runs when you instantiate: 32 | // (also contains property defaults) 33 | constructor (_args) { 34 | 35 | // 36 | // defaults: 37 | // 38 | this.type = 'line'; // type of plot 39 | this.stat = 'bin'; // statistical transformation for 1-var plots 40 | this.bins = 30; // number of slices in binning plots 41 | this.left = 0; 42 | this.top = 0; 43 | this.pointdiameter = 5; 44 | this.right = width; 45 | this.bottom = height; 46 | this._data = {}; 47 | //this.xkey = ""; // key value for x axis 48 | //this.ykey = ""; // key value for y axis 49 | this._xkey = []; 50 | this._ykey = []; 51 | this._needsparse = true; 52 | this._needssort = true; 53 | 54 | this.typelist = {}; 55 | 56 | // function definitions 57 | this.typelist.line = { // continuous function x y 58 | xtype: 'continuous', 59 | ytype: 'continuous', 60 | function: this.drawLineGraph 61 | }; 62 | 63 | this.typelist.point = { // continuous x, continuous y 64 | xtype: 'continuous', 65 | ytype: 'continuous', 66 | function: this.drawPointGraph 67 | }; 68 | 69 | // 70 | // end defaults 71 | // 72 | 73 | // internals: 74 | this._xmin; // internal 75 | this._xmax; // internal 76 | this._ymin; // internal 77 | this._ymax; // internal 78 | 79 | 80 | // integrate arguments: 81 | // this is an awesome ES6 hack where the Object.assign() 82 | // method lets you splice shit from one Object literal into 83 | // another Object, just replacing whatever's there. 84 | for(let i in arguments) 85 | { 86 | Object.assign(this, arguments[i]); 87 | } 88 | 89 | this.plotData = []; // create a new dataset to workwith instead of changing the original 90 | console.log('p5 plot!'); 91 | 92 | }; // end of constructor 93 | 94 | // setters: 95 | set xkey (xkey) { 96 | this._xkey = Array.isArray(xkey) ? xkey : [xkey]; 97 | } 98 | get xkey() { 99 | return this._xkey; 100 | } 101 | set ykey (ykey) { 102 | this._ykey = Array.isArray(ykey) ? ykey : [ykey]; 103 | } 104 | get ykey() { 105 | return this._ykey; 106 | } 107 | set data (data) { 108 | this._data = data; 109 | this._needsparse = true; 110 | this._needssort = true; 111 | } 112 | get data() { 113 | return this._data; 114 | } 115 | 116 | 117 | 118 | // MAIN PLOTTER FUNCTION 119 | // 120 | plot (_args) { 121 | 122 | // integrate arguments (see above): 123 | for(let i in arguments) 124 | { 125 | Object.assign(this, arguments[i]); 126 | } 127 | // console.log(this.dataUnchanged(this.prevdata, this._data)); 128 | // how do we only run this once unless the 'data' parameter changes: 129 | // if (!this.dataUnchanged(this.prevdata, this._data)){ 130 | // this.parseData(); // figure out min and max scalings, etc. 131 | // } 132 | 133 | if(this._needsparse) this.parseData(); 134 | 135 | // which graph style? 136 | // draw the graphs 137 | if(Array.isArray(this.type)) { 138 | for(let i in this.type) 139 | { 140 | this.typelist[this.type[i]].function(this); 141 | } 142 | } 143 | else { 144 | this.typelist[this.type].function(this); 145 | } 146 | 147 | }; // END OF MAIN PLOTTER FUNCTION 148 | 149 | // 150 | // parseData() - MAKE SENSE OF THE DATASET 151 | // 152 | parseData() { 153 | console.log("PARSING!!! " + millis()); 154 | //console.log(this.dataUnchanged()); 155 | // STEP ONE: 156 | // what happens if the data array is not made up of object literals 157 | 158 | // simple array test: 159 | if(Array.isArray(this._data) && typeof(this._data[0])==="number") 160 | { 161 | var _newdata = this.tokenize(this._data); // fix 162 | this._data = _newdata; // swap 163 | } 164 | 165 | // STEP TWO: 166 | // fix if we have no xkey / ykey defined 167 | if(this._xkey.length==0){ 168 | this._xkey = [Object.keys(this._data[0])[0]]; 169 | } 170 | if(this._ykey.length==0){ 171 | this._ykey = [Object.keys(this._data[0])[1]]; 172 | } 173 | 174 | // STEP THREE: 175 | // make sure the keys are the right type 176 | // console.log(this.typelist[this.type].xtype + " " + this.typelist[this.type].ytype); 177 | 178 | this._xmin = this._data[0][this._xkey[0]]; 179 | this._xmax = this._data[0][this._xkey[0]]; 180 | this._ymin = this._data[0][this._ykey[0]]; 181 | this._ymax = this._data[0][this._ykey[0]]; 182 | 183 | for(let i=0;ithis._xmax) this._xmax = this._data[i][this._xkey[j]]; 189 | currentData[this._xkey[j]] = this._data[i][this._xkey[j]]; 190 | } 191 | 192 | // ykey 193 | for (let k=0; kthis._ymax) this._ymax = this._data[i][this._ykey[k]]; 196 | currentData[this._ykey[k]] = this._data[i][this._ykey[k]]; 197 | } 198 | 199 | // data we actually use 200 | this.plotData.push(currentData); 201 | } 202 | 203 | this._needsparse = false; 204 | 205 | } // end of parseData 206 | 207 | // 208 | // SORT AN ARRAY BASED ON A KEY 209 | // 210 | sortData(_key) { 211 | console.log("SORTING!!! " + millis()); 212 | // sort by xkey 213 | this._data.sort(function(a, b) { 214 | return a[_key] - b[_key]; 215 | }); 216 | 217 | this.plotData.sort(function(a, b) { 218 | return a[_key] - b[_key]; 219 | }); 220 | 221 | this._needssort = false; 222 | } 223 | 224 | // 225 | // TOKENIZE - utility to JSONify a simple array 226 | // 227 | tokenize(_arr) { 228 | var a = []; 229 | for(var i in _arr) 230 | { 231 | var j = {}; 232 | j.index = i; 233 | j.value = _arr[i]; 234 | a.push(j); 235 | } 236 | return(a); 237 | } 238 | 239 | // 240 | // LINE GRAPH 241 | // 242 | drawLineGraph(that) { 243 | 244 | push(); 245 | // need to figure out a way to do this for all graphs 246 | // faceting: multiple xkeys 247 | // iterate through all x keys 248 | 249 | // what happens when multiple xkeys and ykeys? 250 | for (let i=0; i'; 204 | this.svgfoot = ''; 205 | 206 | // which graph style? 207 | // DRAW THE GRAPHS!!! 208 | if(Array.isArray(this.type)) { 209 | for(let i in this.type) 210 | { 211 | this.typelist[this.type[i]].function(this); 212 | } 213 | } 214 | else { 215 | this.typelist[this.type].function(this); 216 | } 217 | 218 | this.drawBG(this); 219 | 220 | // concatenate HTML and make it base64 221 | svg64 = btoa(this.svghead+this.bgsvghtml+this.svghtml+this.svgfoot); 222 | 223 | // prepend a base64 "header" 224 | plotSVGURL = b64Start + svg64; 225 | 226 | // load to p5.Image 227 | this.plotImg = loadImage(plotSVGURL); 228 | 229 | 230 | }; // END OF MAIN PLOTTER FUNCTION 231 | 232 | // draw function display 233 | draw(_x=this.left, _y=this.top, _w=this.width, _h=this.height){ 234 | image(this.plotImg, _x, _y, _w, _h); 235 | } 236 | 237 | // 238 | // parseData() - MAKE SENSE OF THE DATASET 239 | // 240 | parseData() { 241 | // console.log("PARSING!!! " + millis()); 242 | // console.log(this.dataUnchanged()); 243 | // STEP ONE: 244 | // what happens if the data array is not made up of object literals 245 | 246 | // simple array test: 247 | if(Array.isArray(this._data) && typeof(this._data[0])==="number") 248 | { 249 | var _newdata = this.tokenize(this._data); // fix 250 | this._data = _newdata; // swap 251 | } 252 | else if(Array.isArray(this._data) && typeof(this._data[0])==="string") 253 | { 254 | var _newdata = this.strtokenize(this._data); // fix 255 | this._data = _newdata; // swap 256 | } 257 | 258 | // STEP TWO: 259 | // fix if we have no xkey / ykey defined 260 | if(this._xkey.length==0){ 261 | this._xkey = [Object.keys(this._data[0])[0]]; 262 | } 263 | if(this._ykey.length==0){ 264 | this._ykey = [Object.keys(this._data[0])[1]]; 265 | } 266 | 267 | // STEP THREE: 268 | // make sure the keys are the right type 269 | // console.log(this.typelist[this.type].xtype + " " + this.typelist[this.type].ytype); 270 | 271 | this._xmin = this._data[0][this._xkey[0]]; 272 | this._xmax = this._data[0][this._xkey[0]]; 273 | this._ymin = this._data[0][this._ykey[0]]; 274 | this._ymax = this._data[0][this._ykey[0]]; 275 | 276 | for(let i=0;ithis._xmax) this._xmax = this._data[i][this._xkey[j]]; 282 | currentData[this._xkey[j]] = this._data[i][this._xkey[j]]; 283 | } 284 | 285 | // ykey 286 | for (let k=0; kthis._ymax) this._ymax = this._data[i][this._ykey[k]]; 289 | currentData[this._ykey[k]] = this._data[i][this._ykey[k]]; 290 | } 291 | 292 | currentData.constant = "1"; 293 | 294 | // data we actually use 295 | this.plotData.push(currentData); 296 | } 297 | 298 | this._needsparse = false; 299 | 300 | } // end of parseData 301 | 302 | // 303 | // SORT AN ARRAY BASED ON A KEY 304 | // 305 | sortData(_key) { 306 | // console.log("SORTING!!! " + millis()); 307 | // sort by xkey 308 | this._data.sort(function(a, b) { 309 | return a[_key] - b[_key]; 310 | }); 311 | 312 | this.plotData.sort(function(a, b) { 313 | return a[_key] - b[_key]; 314 | }); 315 | 316 | this._needssort = false; 317 | } 318 | 319 | // 320 | // TOKENIZE - utility to JSONify a simple array 321 | // 322 | tokenize(_arr) { 323 | console.log("tokenizing!"); 324 | var a = []; 325 | for(var i in _arr) 326 | { 327 | var j = {}; 328 | j.index = i; 329 | j.value = _arr[i]; 330 | a.push(j); 331 | } 332 | this._istokenized = true; 333 | return(a); 334 | } 335 | 336 | // 337 | // STRTOKENIZE - utility to JSONify a simple string array 338 | // 339 | strtokenize(_arr) { 340 | var a = []; 341 | for(var i in _arr) 342 | { 343 | var j = {}; 344 | j.key = _arr[i]; 345 | a.push(j); 346 | } 347 | this._istokenized = true; 348 | return(a); 349 | } 350 | 351 | // 352 | // LINE GRAPH 353 | // 354 | drawLineGraph(that) { 355 | 356 | push(); 357 | // need to figure out a way to do this for all graphs 358 | // faceting: multiple xkeys 359 | // iterate through all x keys 360 | 361 | // what happens when multiple xkeys and ykeys? 362 | for (let i=0; i'; 382 | that.gridcols = 10; 383 | 384 | } 385 | 386 | // 387 | // POINT GRAPH 388 | // 389 | drawPointGraph(that) { 390 | push(); 391 | 392 | // iterate through all xkeys 393 | for (let i=0; i'; 403 | 404 | } 405 | } 406 | pop(); 407 | that.gridcols = 10; 408 | } 409 | 410 | drawBarGraph1(that){ 411 | // discrete x, count occurances of each unique x 412 | let uniqueXArr = []; 413 | let countArr = []; 414 | 415 | for(let i=0;i'; 438 | 439 | /* how to draw rect in svg 440 | 442 | */ 443 | barX += barW; 444 | } 445 | 446 | that.gridcols = uniqueXArr.length; 447 | that.gridcollabs = uniqueXArr; 448 | console.log(that.svghtml); 449 | } 450 | 451 | drawBarGraph2(that){ 452 | // discrete x, continuous y, add all y for each unique x 453 | let uniqueXArr = []; 454 | let totalYArr = []; 455 | 456 | for(let i=0;i'; 483 | 484 | /* how to draw rect in svg 485 | 487 | */ 488 | barX += barW; 489 | } 490 | 491 | that.gridcols = uniqueXArr.length; 492 | that.gridcollabs = uniqueXArr; 493 | console.log(that.svghtml); 494 | } 495 | 496 | drawBoxPlot(that){ 497 | // data: discrete x, continuous y, where every unique x is one box plot, and we use the set of corresponding y numbers 498 | // OR a set of numbers, where we CANNOT tokenize 499 | // find minimum, first quartile, median, third quartile, and maximum for each box plot 500 | let oxkey = that._xkey; 501 | that._xkey = "constant"; 502 | 503 | console.log(that.plotData); 504 | let uniqueXArr = []; 505 | // do your thing 506 | 507 | 508 | // restore xkey 509 | that._xkey = oxkey; 510 | } 511 | 512 | // 513 | // Utility Functions 514 | // 515 | 516 | // find the median 517 | // if array is odd number, median is middle number 518 | // if array is even number, median is middle two numbers added then divide by two 519 | // takes in a number array, return the median number 520 | getMedian(sampleArr){ 521 | sampleArr.sort(function(a, b){return a - b}); // sort from low to high 522 | // even 523 | if (sampleArr.length%2 === 0){ 524 | let numA = sampleArr[sampleArr.length/2 - 1]; 525 | let numB = sampleArr[sampleArr.length/2]; 526 | return (numA + numB)/2; 527 | } 528 | // odd 529 | else{ 530 | return sampleArr[(sampleArr.length - 1)/2]; 531 | } 532 | } 533 | 534 | // find medians and quartiles 535 | // takes in a number array, gives an array of values: minimum, first quartile, median, third quartile, and maximum 536 | quartileBounds(sampleArr){ 537 | sampleArr.sort(function(a, b){return a - b}); // sort from low to high 538 | let _firstHalf; 539 | let _secondHalf; 540 | // even 541 | if (sampleArr.length%2 === 0){ 542 | _firstHalf = sampleArr.slice(0, sampleArr.length/2); 543 | _secondHalf = sampleArr.slice(sampleArr.length/2, sampleArr.length); 544 | } 545 | // odd 546 | else { 547 | _firstHalf = sampleArr.slice(0, (sampleArr.length-1)/2); 548 | _secondHalf = sampleArr.slice(((sampleArr.length-1)/2)+1, sampleArr.length); 549 | } 550 | let _0percent = min(sampleArr); 551 | 552 | // find the medians for each split 553 | let _25percent = this.getMedian(_firstHalf); 554 | let _75percent = this.getMedian(_secondHalf); 555 | 556 | let _50percent = this.getMedian(sampleArr); 557 | let _100percent = max(sampleArr); 558 | 559 | return [ _0percent, _25percent, _50percent, _75percent, _100percent]; 560 | } 561 | 562 | // draw grid background 563 | drawBG(that) 564 | { 565 | // lines 566 | let x0 = that.padding*that.aa; 567 | let x1 = (that.width-that.padding)*that.aa; 568 | let y0 = that.padding*that.aa; 569 | let y1 = (that.height-that.padding)*that.aa; 570 | let i, xi, yi; 571 | 572 | // bounding box 573 | this.bgsvghtml += ''; 574 | this.bgsvghtml += ''; 575 | this.bgsvghtml += ''; 576 | this.bgsvghtml += ''; 577 | 578 | for(i = 1;i'; 584 | if(that.gridcollabs.length>0) 585 | { 586 | this.bgsvghtml += ''+that.gridcollabs[i-1]+''; 587 | } 588 | } 589 | 590 | for(i = 1;i'; 596 | } 597 | 598 | console.log(this.bgsvghtml); 599 | } 600 | 601 | colorfucker(_c) 602 | { 603 | var rc; 604 | var cm0 = colorMode()._colorMaxes[colorMode()._colorMode][0]; // r/h 605 | var cm1 = colorMode()._colorMaxes[colorMode()._colorMode][1]; // g/s 606 | var cm2 = colorMode()._colorMaxes[colorMode()._colorMode][2]; // b/b/l 607 | var cm3 = colorMode()._colorMaxes[colorMode()._colorMode][3]; // a 608 | 609 | // in CSS, the maxes are: 610 | // for rgba: 255, 255, 255, 1 611 | // for hsla: 360, 100%, 100%, 1 612 | 613 | if(Array.isArray(_c)){ 614 | if(_c.length==1) rc = "rgb("+_c[0]+", " + _c[0] + ", " + _c[0] + ")"; 615 | if(_c.length==2) rc = "rgba("+_c[0]+", " + _c[0] + ", " + _c[0] + ", " + _c[1]/255 + ")"; 616 | if(_c.length==3&&colorMode()._colorMode=="rgb") rc = "rgb("+_c[0]/cm0*255+", " + _c[1]/cm1*255 + ", " + _c[2]/cm2*255 + ")"; 617 | if(_c.length==4&&colorMode()._colorMode=="rgb") rc = "rgba("+_c[0]/cm0*255+", " + _c[1]/cm1*255 + ", " + _c[2]/cm2*255 + ", " + _c[3]/cm3 + ")"; 618 | if(_c.length==3&&(colorMode()._colorMode=="hsb"||colorMode()._colorMode=="hsl")) rc = "hsl("+_c[0]/cm0*360+", " + _c[1]/cm1*100 + "%, " + _c[2]/cm2*100 + "%)"; 619 | if(_c.length==4&&(colorMode()._colorMode=="hsb"||colorMode()._colorMode=="hsl")) rc = "hsla("+_c[0]/cm0*360+", " + _c[1]/cm1*100 + "%, " + _c[2]/cm2*100 + "%, " + _c[3]/cm3 + ")"; 620 | } 621 | else if(Number.isInteger(_c)) { 622 | rc = "rgb("+_c+", " + _c + ", " + _c + ")"; 623 | } 624 | else { 625 | rc = _c; 626 | } 627 | return(rc); 628 | } 629 | 630 | }; // end of p5.Plot() 631 | })); // end of craziness 632 | -------------------------------------------------------------------------------- /rtests/testing/.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDMNYU/p5.js-plot/6b4c0ab6e1e1a8bf4a302d175067026ef127113a/rtests/testing/.RData -------------------------------------------------------------------------------- /rtests/testing/.Rhistory: -------------------------------------------------------------------------------- 1 | library(ggplot2) 2 | library(usmap) 3 | library(gtable) 4 | library(grid) 5 | library(gridExtra) 6 | library(reshape2) 7 | install.packages(gridExtra) 8 | install.packages('gridExtra') 9 | library(ggplot2) 10 | library(usmap) 11 | library(gtable) 12 | library(grid) 13 | library(gridExtra) 14 | library(reshape2) 15 | library(reshape2) 16 | library(tidyverse) 17 | b = ggplot(mpg, aes(fl)) 18 | b + geom_bar() 19 | mpg 20 | b <= ggplot(mpg, aes(fl)) 21 | b + geom_bar() 22 | library(ggplot2) 23 | library(usmap) 24 | library(gtable) 25 | library(grid) 26 | library(gridExtra) 27 | library(reshape2) 28 | library(tidyverse) 29 | b <= ggplot(mpg, aes(fl)) 30 | b <- ggplot(mpg, aes(fl)) 31 | b + geom_bar() 32 | g <- ggplot(mpg, aes(class, hwy)) 33 | g+geom_bar(state="identity") 34 | g <- ggplot(mpg, aes(class, hwy)) 35 | g+geom_bar(stat="identity") 36 | g <- ggplot(mpg, aes(fl, hwy)) 37 | g+geom_bar(stat="identity") 38 | b <- ggplot(mpg, aes(fl)) 39 | b + geom_bar() 40 | g <- ggplot(mpg, aes(fl, hwy)) 41 | g+geom_bar(stat="identity") 42 | g <- ggplot(mpg, aes(x=fl, y=hwy)) 43 | g+geom_bar(stat="identity") 44 | b <- ggplot(mpg, aes(x=fl)) 45 | b + geom_bar() 46 | g <- ggplot(mpg, aes(x=fl, y=hwy)) 47 | g+geom_bar(stat="identity") 48 | mpg 49 | g <- ggplot(mpg, aes(x=fl, y=hwy)) 50 | g+geom_bar() 51 | g <- ggplot(mpg, aes(x=fl)) 52 | g+geom_bar() 53 | b <- ggplot(mpg, aes(x=fl)) 54 | b + geom_bar() 55 | # count up how many of each kind of 'fl': 56 | b <- ggplot(mpg, aes(x=fl)) 57 | b + geom_bar() 58 | # count up how much 'hwy' is in each 'fl': 59 | g <- ggplot(mpg, aes(x=hwy, y=fl)) 60 | g+geom_bar(stat="identity") 61 | # count up how much 'hwy' is in each 'fl': 62 | g <- ggplot(mpg, aes(x=hwy, y=fl)) 63 | g+geom_bar() 64 | # count up how much 'hwy' is in each 'fl': 65 | g <- ggplot(mpg, aes(x=fl, y=hwy)) 66 | g+geom_bar(stat="identity") 67 | library(ggplot2) 68 | library(usmap) 69 | library(gtable) 70 | library(grid) 71 | library(gridExtra) 72 | library(reshape2) 73 | library(tidyverse) 74 | mpg 75 | # count up how many of each kind of 'fl': 76 | b <- ggplot(mpg, aes(x=fl)) 77 | b + geom_bar() 78 | # count up how much 'hwy' is in each 'fl': 79 | g <- ggplot(mpg, aes(x=fl, y=hwy)) 80 | g+geom_bar(stat="identity") 81 | library(ggplot2) 82 | library(usmap) 83 | library(gtable) 84 | library(grid) 85 | library(gridExtra) 86 | library(reshape2) 87 | library(tidyverse) 88 | mpg 89 | # count up how many of each kind of 'fl': 90 | b <- ggplot(mpg, aes(x=fl)) 91 | b + geom_bar() 92 | # count up how much 'hwy' is in each 'fl': 93 | g <- ggplot(mpg, aes(x=fl, y=hwy)) 94 | g+geom_bar(stat="identity") 95 | # count up how many of each kind of 'fl': 96 | b <- ggplot(mpg, aes(x=fl)) 97 | b + geom_bar() 98 | # count up how much 'hwy' is in each 'fl': 99 | g <- ggplot(mpg, aes(x=fl, y=hwy)) 100 | g+geom_bar(stat="identity") 101 | # count up how many of each kind of 'fl': 102 | b <- ggplot(mpg, aes(x=fl)) 103 | b + geom_bar() 104 | f <- ggplot(mpg, aes(cty, hwy)) 105 | f+geom_point() 106 | f+geom_smooth(model=lm) 107 | f+geom_point() 108 | f+geom_smooth(model=lm) 109 | f+geom_point()+geom_smooth(model=lm) 110 | f 111 | f 112 | mpg 113 | f 114 | f<-manufacturer 115 | fdeaths 116 | library(ggplot2) 117 | library(usmap) 118 | library(gtable) 119 | library(grid) 120 | library(gridExtra) 121 | library(reshape2) 122 | library(tidyverse) 123 | f <- ggplot(mpg, aes(cty, hwy)) 124 | a <- ggplot(mpg, aes(hwy)) 125 | ,bwei