├── .gitignore ├── README.md ├── section-1 ├── data │ ├── nyc-data.csv │ ├── simpleData.csv │ ├── simpleData_noRegions.csv │ └── simpleData_noRegions.json ├── in-class │ ├── index.html │ └── sketch.js ├── load-csv-data │ ├── index.html │ └── sketch.js └── load-json-data │ ├── index.html │ └── sketch.js ├── section-2 ├── data │ ├── time-machine-clean.json │ ├── time-machine.txt │ └── yelp-pizzerias.json ├── node-autocomplete-api │ ├── autocomplete_results.json │ ├── callAPI.js │ └── package.json ├── node-clean-text │ └── clean.js ├── node-puppeteer │ ├── getTimes.js │ ├── package.json │ ├── pizzaMenus.js │ ├── simpleScraping.js │ └── yarn.lock ├── rita-pos-matching │ ├── _DS_Store │ ├── index.html │ ├── libraries │ │ └── rita-full.min.js │ └── sketch.js └── sentence-histogram │ ├── index.html │ └── sketch.js ├── section-3 ├── city-council-districts │ └── index.html ├── data │ ├── CityCouncilDistricts.geojson │ └── Mobile_activity_3months_scrambled.csv ├── generate-geometry │ └── index.html ├── mapbox-mobile-phones │ └── index.html └── node-convert-to-geojson │ ├── convert.js │ ├── package-lock.json │ └── package.json └── section-4 ├── d3-bubbleplot ├── index.html └── sketch.js ├── d3-update-pattern └── index.html ├── data ├── worldwide-health-lifeexpectancy-cut.csv └── worldwide-health-lifeexpectancy.csv ├── p5-bubbleplot ├── index.html └── sketch.js ├── p5-d3-bubbleplot ├── index.html └── sketch.js └── threejs-bubbleplot ├── index.html └── lib └── TrackballControls.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Data Art – ITP Fall 2018 2 | 3 | * Instructor: Genevieve Hoffman 4 | * Instructor e-mail: ghoffman@nyu.edu 5 | * Office Hours: Fridays, 4:30 – 6pm. Sign up on [google calendar](https://calendar.google.com/calendar/selfsched?sstoken=UU1URHpmUlVpc1JyfGRlZmF1bHR8ZmQ4YjEyYjA2M2NjZTc0MjM0OGU0YmMzZDQ3OWU5Yzk) 6 | * Class Logistics: Tuesdays, 6:30 – 9pm 7 | 8 | ## Aims of Course 9 | 10 | Fascinating and terrifying things are happening at the intersection of data and culture. Our lives are being constantly measured, and information about us is being surveilled, stolen, and commodified. Dialogue around this data revolution has been dominated by corporations, governments, and industry - but what about the arts? In this class, we’ll investigate the means by which artists can engage (and are engaging) in the collection, processing, and representation of data. Using a research-focused, prototype-based approach, we’ll build a series of collective and individual projects to interrogate the ‘new data reality’. Students will use Processing, along with a variety of analog media or open-source data and visualization tools (such as D3.js, OpenRefine, MapBox, Mappa and THREE.js). 11 | 12 | ## Course Themes & Section Projects 13 | 14 | This course will be divided into four 'sections', each focusing on a different aspect of data art: 15 | 16 | 1. **Data & Aesthetic** 17 | 2. **Text, Archives & Memory Stores** 18 | 3. **Data & Publics** 19 | 4. **Ethics, Humans & Responsibility** 20 | 21 | Each of these sections will begin with an introductory survey of work being done in this area, and a 'workshop' going over a few important technical points. The next class(es) will involve a discussion around assigned readings and a review of available tools, code libraries, and techniques. The last class in a section will feature a guest speaker, and brief (5 minute max) presentations of project work (see below). 22 | 23 | For each of these sections, you will complete a small project, which will be assigned on the first day of the section and will be due on the last. The first assignment will be individual and realized. For the last three assignments, you have the choice of doing a conceptual project, or a realized one: 24 | 25 | * **Conceptual projects** should be focused on possibility without constraint. What would or could you build if you were not restricted by materials, budget, technological possibility, or coding skills? The deliverable is a project proposal, much as you might submit for an art funding grant, or to a client pitching a potential project. Both written and visual descriptions of the project are required, and you may include audiovisual samples as well if that's helpful for getting the idea across. 26 | 27 | * **Realized projects** will be built in the 2-3 weeks between assignment at the end of the section's first class and the due date. They should be posted to this repo with source code if applicable, and written up with a blog post. 28 | 29 | *For the last three assignments, each student will be required to complete one conceptual project, and two realized projects. It is your choice as to which of the last three sections you choose for which.* 30 | 31 | The first project is required to be an individual project. For the last three assignments, the project can be done as an individual project, or in groups of up to three students. *Each student will be required to do at least one group project.* 32 | 33 | ## Expectations and Workload 34 | 35 | You can expect to have 3-4 assigned readings for each thematic section. You must complete all readings prior to class, and come ready to participate in discussion. Projects must be posted to this GitHub repo in the appropriate folder, along with source code (where applicable) before the start of class when the assignment is due. A brief blog post about the project is also required to be completed before the start of class. 36 | 37 | ## Grading 38 | 39 | If we were using a percentage-based grading system, the numbers would look something like this: 40 | 41 | Class participation: 30% 42 | Semester Projects: 70% 43 | Since we’re not using a percentage-based grading system, let me put it another way: if you’re an active contributor to our discussions in class, and you complete your assignments, and you make something ambitious/excellent as a final project, you’ll pass this class. If you don’t, you won’t. 44 | 45 | ## Class Rules 46 | 47 | (i) Everyone shows up to class on time. If you’re going to be late, let me know in advance. If you need to miss a class for a real reason, you must also let me know in advance. 48 | 49 | (ii) Everyone does the readings. For the most part, they’re short, fun, and useful. Students will be responsible for leading class discussion on readings on a rotating basis. 50 | 51 | (iii) All assignment work is due at the beginning of class. Everyone gets a free pass for one late assignment. After that, any assignments not ready for the start of class will be counted as incomplete. A completed blog post about each assignment is required. 52 | 53 | (iv) Everyone in the class must attend office hours at least once in the first three weeks of class. 54 | 55 | (v) We’ll have a series of guest speakers coming into class over the course of the term. I will provide resources to learn about their work prior to their visits – everyone in class must do their homework and be prepared to learn from our guests. 56 | 57 | (vi) I am 100% dedicated to an inclusive, harassment-free experience for everyone regardless of gender, race, sexual orientation, disability, background, appearance, or religion. I will not tolerate harassment of class participants in any form. 58 | 59 | ## Touchstones 60 | 61 | (i) Gary Shteyngart - Super Sad True Love Story 62 | 63 | (ii) Brian K. Vaughan, Marcos Martin and Muntsa Vicente - The Private Eye - http://panelsyndicate.com/comics/tpeye 64 | 65 | ## Syllabus 66 | 67 | ### Data & Aesthetic 68 | 69 | **Readings:** 70 | * [A Concise Taxonomy for Describing Data as an Art Material,](http://www.mitpressjournals.org/doi/pdf/10.1162/LEON_a_01414) Julie Freeman, Geraint Wiggins, Gavin Starks and Mark Sandler 71 | * [What Would Feminist Data Visualization Look Like?](https://civic.mit.edu/feminist-data-visualization) Catherine D'Ignazio 72 | * [DataViz - The UnEmpathetic Art,](https://responsibledata.io/dataviz-the-unempathetic-art/) Mushon Zer-Aviv 73 | * [Picturing the Self in the Age of Data,](http://proxy.library.nyu.edu/login?url=http://search.ebscohost.com/login.aspx?direct=true&db=asu&AN=96975438&site=ehost-live) Dan Weiskopf 74 | 75 | **Watch:** 76 | * [Subtle Data,](https://vimeo.com/72246588) Stefanie Posavec speaking at the 2013 Eyeo Festival 77 | * [How I Learned to Love Data Visualization (Again),](https://vimeo.com/159297152) Jon Schwabish speaking at the 2015 Visualized Conference 78 | 79 | **Assignment:** 80 | * Data (Self)Portrait: Create a self-portrait or portrait of someone else. The portrait must be derived from a data set, or use data as a material. 81 | * Due Week 4, September 25th. Documentation should be posted and a link emailed before class begins 82 | 83 | September 4th – Week 1. The lay of the land & introductions - [slides](https://drive.google.com/open?id=1kgTB-9lz4qS0vNXsMAGZpL9nSZWpjmgD) shown in class 84 | 85 | September 11th – Week 2. Topic Survey & technical overview (data translation) - [slides](https://drive.google.com/open?id=1lZocBzoTYxg54XfVdBbSKh30wq6pnhFb) shown in class 86 | 87 | September 18th – Week 3. Discussion of readings & technical workshop (ES6 Intro) - [slides](https://drive.google.com/file/d/1wK1-iiQkN0Upe5ulnRf9KZaftPBptr1i/view?usp=sharing) shown in class 88 | 89 | September 25th - Week 4. Guest Speaker ([Brian House](https://brianhouse.net/)) & [Project](https://github.com/veev/DataArtFall2018/wiki/Data-(Self)-Portrait) presentations 90 | 91 | ### Text, Archives & Memory Stores 92 | 93 | **Readings:** 94 | * [Consider the Boolean,](https://source.opennews.org/articles/consider-boolean) Jacob Harris 95 | * [On a Collections as Data Imperative,](http://digitalpreservation.gov/meetings/dcs16/tpadilla_OnaCollectionsasDataImperative_final.pdf) Thomas Padilla 96 | * [A Sea of Data: Apophenia and Pattern (Mis-)Recognition,](http://www.e-flux.com/journal/72/60480/a-sea-of-data-apophenia-and-pattern-mis-recognition/) Hito Steyerl 97 | * [Abundant Images and the Collective Sublime,](http://circulationexchange.org/articles/abundantimages.html) Kate Palmer Albers 98 | 99 | October 2nd – Week 5. Topic survey & technical workshop (RiTA) - [slides](https://drive.google.com/open?id=1gYWfdaiX24P3TDGsV9Kwi6W_7_83t5_n) show in class 100 | 101 | October 9th - NO CLASS, Legislative Day 102 | 103 | October 16th – Week 6. Discussion of readings & overview of other resources (puppeteer.js) - [slides](https://docs.google.com/presentation/d/1UvfWT64ZXkD3xCrxYQGq_MVAwvSx8gs1o-FrbbWQ-_A/edit?usp=sharing) shown in class 104 | 105 | October 23rd – Week 7. Guest Speaker ([Roopa Vasudevan](https://rouxpz.com/)) & Project presentations 106 | 107 | ### Data & Publics 108 | 109 | **Readings:** 110 | 111 | * [Rethinking Maps: Thinking about Maps,](https://makingmaps.files.wordpress.com/2009/08/rethinking_maps_introduction_pageproof.pdf) Rob Kitchin, Chris Perkins & Martin Dodge 112 | * [Here Be Dragons: Finding the Blank Spaces in a Well-Mapped World,](http://www.vqronline.org/essays-articles/2017/01/here-be-dragons) Lois Parshley 113 | * [Mapping’s Intelligent Agents](https://placesjournal.org/article/mappings-intelligent-agents/) Shannon Mattern 114 | * [IMG MGMT: The Nine Eyes of Google Street View,](http://artfcity.com/2009/08/12/img-mgmt-the-nine-eyes-of-google-street-view/) Jon Rafman 115 | 116 | October 30th – Week 8. Topic survey & technical workshop (Web Maps / Public Data) - [slides](https://drive.google.com/open?id=1LFdUv0XEP97gH7Gz5WamaiNf_vYaqFfR) shown in class 117 | 118 | November 6th – Week 9. Discussion of readings & overview of other resources (Leaflet.js / Mapbox GL / Mappa + p5.js / Turf.js) - [slides](https://drive.google.com/open?id=1wqvJZGTy5Ifwo2R1bUnQ0N_scw-5PuOT) shown in class 119 | 120 | November 13th – Week 10. Guest Speaker (Mahir Yavuz) & Project presentations 121 | 122 | ### Ethics, Humans & Responsibility 123 | 124 | **Readings:** 125 | * [Critical Questions for Big Data,](https://people.cs.kuleuven.be/~bettina.berendt/teaching/ViennaDH15/boyd_crawford_2012.pdf) danah boyd & Kate Crawford 126 | * [Big data problems we face today can be traced to the social ordering practices of the 19th century,](http://blogs.lse.ac.uk/impactofsocialsciences/2015/10/13/ideological-inheritances-in-the-data-revolution/) Joanne Travaglia & Hamish Robertson 127 | * [A chronology of tactics: Art tackles Big Data and the environment,](http://journals.sagepub.com/doi/abs/10.1177/2053951716665869) Brooke Singer 128 | * [You Say Data, I Say System,](https://hackernoon.com/you-say-data-i-say-system-54e84aa7a421) Jer Thorp 129 | 130 | November 20th – Week 11. Topic survey & overview of the landscape - [slides](https://drive.google.com/file/d/1kvxzyURjg3QWGPk98nUleT7T63i4sEok/view?usp=sharing) shown in class 131 | 132 | November 27th – Week 12. Discussion of readings & Color + Data Visualization & D3 - [slides](https://drive.google.com/file/d/17xZTm5SY54s0Py-wHHJDNeaOJcYkHbn4/view?usp=sharing) shown in class 133 | 134 | December 4th – Week 13. Technical workshop (THREE.js / Unity) - [slides](https://drive.google.com/open?id=1VWbgs9ofjYieevDYZvt1B6RCvHEzr9qD) shown in class 135 | 136 | December 11th - Week 14. Guest Speaker ([Brooke Singer](http://www.bsing.net/site/)) & Project presentations 137 | -------------------------------------------------------------------------------- /section-1/data/nyc-data.csv: -------------------------------------------------------------------------------- 1 | country/region,estimate,marginOfError 2 | Europe,"474,312","+/-11,900" 3 | Northern Europe,"52,372","+/-4,120" 4 | United Kingdom (inc. Crown Dependencies),"33,824","+/-3,643" 5 | "United Kingdom, excluding England and Scotland","18,084","+/-2,554" 6 | England,"14,550","+/-2,511" 7 | Scotland,"1,190",+/-653 8 | Ireland,"12,669","+/-1,947" 9 | Denmark,"1,197",+/-572 10 | Norway,"1,057",+/-488 11 | Sweden,"2,914",+/-977 12 | Other Northern Europe,711,+/-581 13 | Western Europe:,"53,443","+/-4,409" 14 | Austria,"5,108","+/-1,316" 15 | Belgium,"3,364","+/-1,054" 16 | France,"19,354","+/-2,850" 17 | Germany,"18,502","+/-2,102" 18 | Netherlands,"3,348","+/-1,296" 19 | Switzerland,"3,626","+/-1,657" 20 | Other Western Europe,141,+/-146 21 | Southern Europe:,"81,889","+/-4,739" 22 | Greece,"20,409","+/-2,704" 23 | Italy,"47,124","+/-3,475" 24 | Portugal,"1,948",+/-811 25 | Azores Islands,0,+/-190 26 | Spain,"10,323","+/-2,292" 27 | Other Southern Europe,"2,085","+/-2,093" 28 | Eastern Europe:,"285,759","+/-10,381" 29 | Albania,"19,072","+/-3,768" 30 | Belarus,"11,252","+/-1,790" 31 | Bulgaria,"5,527","+/-1,467" 32 | Croatia,"4,101",+/-893 33 | Czechoslovakia (includes Czech Republic and Slovakia),"5,007","+/-1,293" 34 | Hungary,"7,554","+/-1,828" 35 | Latvia,"1,965",+/-756 36 | Lithuania,"2,594",+/-802 37 | Macedonia,"3,666","+/-2,398" 38 | Moldova,"4,668","+/-1,125" 39 | Poland,"50,272","+/-5,065" 40 | Romania,"12,495","+/-2,143" 41 | Russia,"59,668","+/-5,051" 42 | Ukraine,"66,798","+/-4,971" 43 | Bosnia and Herzegovina,"1,684",+/-838 44 | Serbia,"3,949","+/-1,885" 45 | Other Eastern Europe,"25,487","+/-4,496" 46 | "Europe, n.e.c.",849,+/-442 47 | Asia,"944,962","+/-13,932" 48 | Eastern Asia:,"473,725","+/-13,182" 49 | China:,"388,783","+/-12,570" 50 | "China, excluding Hong Kong and Taiwan","331,465","+/-12,853" 51 | Hong Kong,"36,534","+/-3,333" 52 | Taiwan,"20,784","+/-2,573" 53 | Japan,"19,378","+/-3,130" 54 | Korea,"65,528","+/-5,903" 55 | Other Eastern Asia,36,+/-59 56 | South Central Asia:,"280,556","+/-15,047" 57 | Afghanistan,"3,504","+/-1,806" 58 | Bangladesh,"82,351","+/-7,520" 59 | India,"87,796","+/-8,123" 60 | Iran,"5,832","+/-1,618" 61 | Kazakhstan,"3,473","+/-1,120" 62 | Nepal,"9,147","+/-2,644" 63 | Pakistan,"47,111","+/-6,587" 64 | Sri Lanka,"5,051","+/-1,701" 65 | Uzbekistan,"32,947","+/-5,247" 66 | Other South Central Asia,"3,344","+/-1,009" 67 | South Eastern Asia:,"107,397","+/-7,259" 68 | Cambodia,"1,591",+/-704 69 | Indonesia,"3,760","+/-1,159" 70 | Laos,170,+/-189 71 | Malaysia,"9,144","+/-2,272" 72 | Burma,"8,636","+/-2,524" 73 | Philippines,"60,266","+/-6,336" 74 | Singapore,"2,839",+/-863 75 | Thailand,"5,939","+/-1,712" 76 | Vietnam,"15,052","+/-3,253" 77 | Other South Eastern Asia,0,+/-190 78 | Western Asia:,"80,817","+/-6,671" 79 | Iraq,765,+/-465 80 | Israel,"25,325","+/-3,190" 81 | Jordan,"1,691",+/-745 82 | Kuwait,"1,516",+/-951 83 | Lebanon,"4,328","+/-1,425" 84 | Saudi Arabia,"1,541",+/-833 85 | Syria,"4,962","+/-1,410" 86 | Yemen,"12,821","+/-3,452" 87 | Turkey,"10,806","+/-2,608" 88 | Armenia,"2,801","+/-1,973" 89 | Other Western Asia,"14,261","+/-2,687" 90 | "Asia,n.e.c.","2,467","+/-1,003" 91 | Africa,"146,652","+/-10,447" 92 | Eastern Africa,"8,045","+/-1,588" 93 | Eritrea,285,+/-309 94 | Ethiopia,"2,106",+/-984 95 | Kenya,"2,311","+/-1,105" 96 | Somalia,354,+/-580 97 | Other Eastern Africa,"2,989","+/-1,060" 98 | Middle Africa:,"1,877",+/-614 99 | Cameroon,421,+/-319 100 | Other Middle Africa,"1,456",+/-545 101 | Northern Africa,"30,799","+/-4,041" 102 | Egypt,"18,813","+/-3,313" 103 | Morocco,"6,439","+/-1,659" 104 | Sudan,"1,916","+/-1,299" 105 | Other Northern Africa,"3,631","+/-1,266" 106 | Southern Africa,"4,127","+/-1,725" 107 | South Africa,"3,407","+/-1,438" 108 | Other Southern Africa,720,+/-781 109 | Western Africa,"89,397","+/-8,804" 110 | Cabo Verde,0,+/-190 111 | Ghana,"28,133","+/-4,803" 112 | Liberia,"2,214","+/-1,087" 113 | Nigeria,"26,206","+/-4,203" 114 | Sierra Leone,"2,084","+/-1,119" 115 | Other Western Africa,"30,760","+/-5,978" 116 | "Africa, n.e.c.","12,407","+/-3,173" 117 | Oceania,"10,259","+/-1,696" 118 | Australia and New Zealand Subregion,"9,687","+/-1,738" 119 | Australia,"8,259","+/-1,716" 120 | Other Australian and New Zealand Subregion,"1,428",+/-561 121 | Fiji,0,+/-190 122 | "Oceania, n.e.c.",572,+/-365 123 | Americas,"1,636,281","+/-21,181" 124 | Latin America,"1,611,888","+/-21,298" 125 | Caribbean,"888,594","+/-21,464" 126 | Bahamas,657,+/-403 127 | Barbados,"20,194","+/-2,695" 128 | Cuba,"15,667","+/-2,476" 129 | Dominica,"8,065","+/-1,962" 130 | Dominican Republic,"433,473","+/-17,926" 131 | Grenada,"19,186","+/-2,353" 132 | Haiti,"89,368","+/-7,376" 133 | Jamaica,"170,211","+/-9,315" 134 | St. Vincent and the Grenadines,"14,547","+/-2,472" 135 | Trinidad and Tobago,"86,439","+/-5,385" 136 | West Indies,"10,951","+/-2,058" 137 | Other Caribbean,"19,836","+/-2,636" 138 | Central America,"301,343","+/-13,916" 139 | Mexico,"180,329","+/-11,806" 140 | Belize,"5,660","+/-1,359" 141 | Costa Rica,"4,597","+/-1,731" 142 | El Salvador,"28,269","+/-4,435" 143 | Guatemala,"28,805","+/-5,330" 144 | Honduras,"28,691","+/-4,343" 145 | Nicaragua,"8,503","+/-2,283" 146 | Panama,"16,213","+/-2,716" 147 | Other Central America,276,+/-268 148 | South America:,"421,951","+/-14,045" 149 | Argentina,"11,117","+/-2,588" 150 | Bolivia,"2,981","+/-1,059" 151 | Brazil,"13,124","+/-2,113" 152 | Chile,"3,944","+/-1,194" 153 | Colombia,"71,135","+/-6,556" 154 | Ecuador,"129,108","+/-10,599" 155 | Guyana,"144,909","+/-6,866" 156 | Peru,"30,077","+/-4,298" 157 | Uruguay,"2,439",+/-920 158 | Venezuela,"8,237","+/-2,202" 159 | Other South America,"4,880","+/-1,276" 160 | Northern America,"24,393","+/-3,333" 161 | Canada,"23,848","+/-3,304" 162 | Other Northern America,545,+/-353 -------------------------------------------------------------------------------- /section-1/data/simpleData.csv: -------------------------------------------------------------------------------- 1 | country,estimate,marginOfError 2 | Northern Europe,928644,16770 3 | United Kingdom (inc. Crown Dependencies),683473,13753 4 | United Kingdom excluding England and Scotland,310243,9571 5 | England,319734,9589 6 | Scotland,53496,3645 7 | Ireland,120144,6262 8 | Denmark,29039,2609 9 | Norway,24982,2645 10 | Sweden,46335,3628 11 | Other Northern Europe,24671,2648 12 | Western Europe,964714,16839 13 | Austria,43401,3026 14 | Belgium,34232,2938 15 | France,173561,8607 16 | Germany,585298,12124 17 | Netherlands,88580,6180 18 | Switzerland,37115,3317 19 | Other Western Europe,2527,776 20 | Southern Europe,787767,16505 21 | Greece,141325,6452 22 | Italy,352492,11766 23 | Portugal,176803,8390 24 | Azores Islands,27072,3439 25 | Spain,108953,6903 26 | Other Southern Europe,8194,2545 27 | Eastern Europe,2097040,29599 28 | Albania,89744,9135 29 | Belarus,56958,5339 30 | Bulgaria,67377,5183 31 | Croatia,36978,3546 32 | Czechoslovakia (includes Czech Republic and Slovakia),66631,5112 33 | Hungary,70255,5330 34 | Latvia,21364,2476 35 | Lithuania,31458,3872 36 | Macedonia,26277,4621 37 | Moldova,43564,5058 38 | Poland,419332,12547 39 | Romania,159546,7917 40 | Russia,386529,13859 41 | Ukraine,345620,11934 42 | Bosnia and Herzegovina,107969,9021 43 | Serbia,36969,4673 44 | Other Eastern Europe,130469,8453 45 | Europe n.e.c.,11497,2703 46 | Eastern Asia,4085872,43120 47 | China,2676697,35859 48 | China excluding Hong Kong and Taiwan,2065431,33869 49 | Hong Kong,233373,7808 50 | Taiwan,377893,12637 51 | Japan,335767,11198 52 | Korea,1060019,20054 53 | Other Eastern Asia,13389,3024 54 | South Central Asia,3797442,44695 55 | Afghanistan,70653,6928 56 | Bangladesh,228682,14479 57 | India,2389639,31113 58 | Iran,394223,14189 59 | Kazakhstan,29859,3389 60 | Nepal,120886,8823 61 | Pakistan,379435,17427 62 | Sri Lanka,52971,5613 63 | Uzbekistan,65375,5987 64 | Other South Central Asia,65719,7114 65 | South Eastern Asia,4228958,40229 66 | Cambodia,166268,9301 67 | Indonesia,90833,7010 68 | Laos,197016,9812 69 | Malaysia,69308,5119 70 | Burma,137567,10011 71 | Philippines,1982369,30007 72 | Singapore,36252,3382 73 | Thailand,247205,10349 74 | Vietnam,1300515,27733 75 | Other South Eastern Asia,1625,673 76 | Western Asia,1088369,22530 77 | Iraq,215193,13794 78 | Israel,129680,6876 79 | Jordan,81767,8063 80 | Kuwait,31781,3643 81 | Lebanon,119613,8361 82 | Saudi Arabia,96783,8403 83 | Syria,82681,6286 84 | Yemen,44337,6088 85 | Turkey,116336,8283 86 | Armenia,86217,6658 87 | Other Western Asia,83981,7429 88 | Asia n.e.c.,48538,4922 89 | Eastern Africa,612560,21605 90 | Eritrea,39063,5274 91 | Ethiopia,228745,13680 92 | Kenya,129905,10130 93 | Somalia,89153,7277 94 | Other Eastern Africa,125694,9018 95 | Middle Africa,128584,11508 96 | Cameroon,51172,7568 97 | Other Middle Africa,77412,9776 98 | Northern Africa,345832,15019 99 | Egypt,185872,11556 100 | Morocco,71654,5503 101 | Sudan,46037,6708 102 | Other Northern Africa,42269,4655 103 | Southern Africa,98865,6281 104 | South Africa,94141,5867 105 | Other Southern Africa,4724,1384 106 | Western Africa,766341,24249 107 | Cabo Verde,43352,5264 108 | Ghana,155532,10846 109 | Liberia,79497,7804 110 | Nigeria,323635,18271 111 | Sierra Leone,42065,5812 112 | Other Western Africa,122260,9856 113 | Africa n.e.c.,110075,9089 114 | Australia and New Zealand Subregion,113277,6339 115 | Australia,83573,5527 116 | Other Australian and New Zealand Subregion,29704,2990 117 | Fiji,41936,4822 118 | Oceania n.e.c.,83450,6289 119 | Latin America,22111409,88225 120 | Caribbean,4165453,49473 121 | Bahamas,34796,3735 122 | Barbados,51739,4829 123 | Cuba,1210674,23840 124 | Dominica,32370,4110 125 | Dominican Republic,1063239,28770 126 | Grenada,29982,3185 127 | Haiti,675546,22289 128 | Jamaica,711134,19231 129 | St. Vincent and the Grenadines,22950,2820 130 | Trinidad and Tobago,227295,8816 131 | West Indies,33011,4485 132 | Other Caribbean,72717,6064 133 | Central America,15027927,80951 134 | Mexico,11643298,77644 135 | Belize,48811,5371 136 | Costa Rica,90109,5646 137 | El Salvador,1352357,31379 138 | Guatemala,927593,23812 139 | Honduras,599030,25695 140 | Nicaragua,256171,12391 141 | Panama,103625,5810 142 | Other Central America,6933,1586 143 | South America,2918029,40362 144 | Argentina,181233,9339 145 | Bolivia,78093,6898 146 | Brazil,361374,15675 147 | Chile,95104,6986 148 | Colombia,699399,20772 149 | Ecuador,441257,19017 150 | Guyana,281408,12349 151 | Peru,445921,17981 152 | Uruguay,43971,5051 153 | Venezuela,255520,13320 154 | Other South America,34749,3674 155 | Northern America,838476,17172 156 | Canada,830628,17129 157 | Other Northern America,7848,1589 158 | -------------------------------------------------------------------------------- /section-1/data/simpleData_noRegions.csv: -------------------------------------------------------------------------------- 1 | country,estimate,marginOfError 2 | United Kingdom excluding England and Scotland,310243,9571 3 | England,319734,9589 4 | Scotland,53496,3645 5 | Ireland,120144,6262 6 | Denmark,29039,2609 7 | Norway,24982,2645 8 | Sweden,46335,3628 9 | Other Northern Europe,24671,2648 10 | Austria,43401,3026 11 | Belgium,34232,2938 12 | France,173561,8607 13 | Germany,585298,12124 14 | Netherlands,88580,6180 15 | Switzerland,37115,3317 16 | Other Western Europe,2527,776 17 | Greece,141325,6452 18 | Italy,352492,11766 19 | Portugal,176803,8390 20 | Azores Islands,27072,3439 21 | Spain,108953,6903 22 | Other Southern Europe,8194,2545 23 | Albania,89744,9135 24 | Belarus,56958,5339 25 | Bulgaria,67377,5183 26 | Croatia,36978,3546 27 | Czechoslovakia (includes Czech Republic and Slovakia),66631,5112 28 | Hungary,70255,5330 29 | Latvia,21364,2476 30 | Lithuania,31458,3872 31 | Macedonia,26277,4621 32 | Moldova,43564,5058 33 | Poland,419332,12547 34 | Romania,159546,7917 35 | Russia,386529,13859 36 | Ukraine,345620,11934 37 | Bosnia and Herzegovina,107969,9021 38 | Serbia,36969,4673 39 | Other Eastern Europe,130469,8453 40 | China excluding Hong Kong and Taiwan,2065431,33869 41 | Hong Kong,233373,7808 42 | Taiwan,377893,12637 43 | Japan,335767,11198 44 | Korea,1060019,20054 45 | Other Eastern Asia,13389,3024 46 | Afghanistan,70653,6928 47 | Bangladesh,228682,14479 48 | India,2389639,31113 49 | Iran,394223,14189 50 | Kazakhstan,29859,3389 51 | Nepal,120886,8823 52 | Pakistan,379435,17427 53 | Sri Lanka,52971,5613 54 | Uzbekistan,65375,5987 55 | Other South Central Asia,65719,7114 56 | Cambodia,166268,9301 57 | Indonesia,90833,7010 58 | Laos,197016,9812 59 | Malaysia,69308,5119 60 | Burma,137567,10011 61 | Philippines,1982369,30007 62 | Singapore,36252,3382 63 | Thailand,247205,10349 64 | Vietnam,1300515,27733 65 | Other South Eastern Asia,1625,673 66 | Iraq,215193,13794 67 | Israel,129680,6876 68 | Jordan,81767,8063 69 | Kuwait,31781,3643 70 | Lebanon,119613,8361 71 | Saudi Arabia,96783,8403 72 | Syria,82681,6286 73 | Yemen,44337,6088 74 | Turkey,116336,8283 75 | Armenia,86217,6658 76 | Other Western Asia,83981,7429 77 | Eritrea,39063,5274 78 | Ethiopia,228745,13680 79 | Kenya,129905,10130 80 | Somalia,89153,7277 81 | Other Eastern Africa,125694,9018 82 | Middle Africa,128584,11508 83 | Cameroon,51172,7568 84 | Other Middle Africa,77412,9776 85 | Egypt,185872,11556 86 | Morocco,71654,5503 87 | Sudan,46037,6708 88 | Other Northern Africa,42269,4655 89 | South Africa,94141,5867 90 | Other Southern Africa,4724,1384 91 | Cabo Verde,43352,5264 92 | Ghana,155532,10846 93 | Liberia,79497,7804 94 | Nigeria,323635,18271 95 | Sierra Leone,42065,5812 96 | Other Western Africa,122260,9856 97 | Australia,83573,5527 98 | Other Australian and New Zealand Subregion,29704,2990 99 | Fiji,41936,4822 100 | Caribbean,4165453,49473 101 | Bahamas,34796,3735 102 | Barbados,51739,4829 103 | Cuba,1210674,23840 104 | Dominica,32370,4110 105 | Dominican Republic,1063239,28770 106 | Grenada,29982,3185 107 | Haiti,675546,22289 108 | Jamaica,711134,19231 109 | St. Vincent and the Grenadines,22950,2820 110 | Trinidad and Tobago,227295,8816 111 | West Indies,33011,4485 112 | Other Caribbean,72717,6064 113 | Mexico,11643298,77644 114 | Belize,48811,5371 115 | Costa Rica,90109,5646 116 | El Salvador,1352357,31379 117 | Guatemala,927593,23812 118 | Honduras,599030,25695 119 | Nicaragua,256171,12391 120 | Panama,103625,5810 121 | Other Central America,6933,1586 122 | Argentina,181233,9339 123 | Bolivia,78093,6898 124 | Brazil,361374,15675 125 | Chile,95104,6986 126 | Colombia,699399,20772 127 | Ecuador,441257,19017 128 | Guyana,281408,12349 129 | Peru,445921,17981 130 | Uruguay,43971,5051 131 | Venezuela,255520,13320 132 | Other South America,34749,3674 133 | Canada,830628,17129 134 | Other Northern America,7848,1589 -------------------------------------------------------------------------------- /section-1/data/simpleData_noRegions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "country": "United Kingdom excluding England and Scotland", 4 | "estimate": "310243", 5 | "marginOfError": "9571" 6 | }, 7 | { 8 | "country": "England", 9 | "estimate": "319734", 10 | "marginOfError": "9589" 11 | }, 12 | { 13 | "country": "Scotland", 14 | "estimate": "53496", 15 | "marginOfError": "3645" 16 | }, 17 | { 18 | "country": "Ireland", 19 | "estimate": "120144", 20 | "marginOfError": "6262" 21 | }, 22 | { 23 | "country": "Denmark", 24 | "estimate": "29039", 25 | "marginOfError": "2609" 26 | }, 27 | { 28 | "country": "Norway", 29 | "estimate": "24982", 30 | "marginOfError": "2645" 31 | }, 32 | { 33 | "country": "Sweden", 34 | "estimate": "46335", 35 | "marginOfError": "3628" 36 | }, 37 | { 38 | "country": "Other Northern Europe", 39 | "estimate": "24671", 40 | "marginOfError": "2648" 41 | }, 42 | { 43 | "country": "Austria", 44 | "estimate": "43401", 45 | "marginOfError": "3026" 46 | }, 47 | { 48 | "country": "Belgium", 49 | "estimate": "34232", 50 | "marginOfError": "2938" 51 | }, 52 | { 53 | "country": "France", 54 | "estimate": "173561", 55 | "marginOfError": "8607" 56 | }, 57 | { 58 | "country": "Germany", 59 | "estimate": "585298", 60 | "marginOfError": "12124" 61 | }, 62 | { 63 | "country": "Netherlands", 64 | "estimate": "88580", 65 | "marginOfError": "6180" 66 | }, 67 | { 68 | "country": "Switzerland", 69 | "estimate": "37115", 70 | "marginOfError": "3317" 71 | }, 72 | { 73 | "country": "Other Western Europe", 74 | "estimate": "2527", 75 | "marginOfError": "776" 76 | }, 77 | { 78 | "country": "Greece", 79 | "estimate": "141325", 80 | "marginOfError": "6452" 81 | }, 82 | { 83 | "country": "Italy", 84 | "estimate": "352492", 85 | "marginOfError": "11766" 86 | }, 87 | { 88 | "country": "Portugal", 89 | "estimate": "176803", 90 | "marginOfError": "8390" 91 | }, 92 | { 93 | "country": "Azores Islands", 94 | "estimate": "27072", 95 | "marginOfError": "3439" 96 | }, 97 | { 98 | "country": "Spain", 99 | "estimate": "108953", 100 | "marginOfError": "6903" 101 | }, 102 | { 103 | "country": "Other Southern Europe", 104 | "estimate": "8194", 105 | "marginOfError": "2545" 106 | }, 107 | { 108 | "country": "Albania", 109 | "estimate": "89744", 110 | "marginOfError": "9135" 111 | }, 112 | { 113 | "country": "Belarus", 114 | "estimate": "56958", 115 | "marginOfError": "5339" 116 | }, 117 | { 118 | "country": "Bulgaria", 119 | "estimate": "67377", 120 | "marginOfError": "5183" 121 | }, 122 | { 123 | "country": "Croatia", 124 | "estimate": "36978", 125 | "marginOfError": "3546" 126 | }, 127 | { 128 | "country": "Czechoslovakia (includes Czech Republic and Slovakia)", 129 | "estimate": "66631", 130 | "marginOfError": "5112" 131 | }, 132 | { 133 | "country": "Hungary", 134 | "estimate": "70255", 135 | "marginOfError": "5330" 136 | }, 137 | { 138 | "country": "Latvia", 139 | "estimate": "21364", 140 | "marginOfError": "2476" 141 | }, 142 | { 143 | "country": "Lithuania", 144 | "estimate": "31458", 145 | "marginOfError": "3872" 146 | }, 147 | { 148 | "country": "Macedonia", 149 | "estimate": "26277", 150 | "marginOfError": "4621" 151 | }, 152 | { 153 | "country": "Moldova", 154 | "estimate": "43564", 155 | "marginOfError": "5058" 156 | }, 157 | { 158 | "country": "Poland", 159 | "estimate": "419332", 160 | "marginOfError": "12547" 161 | }, 162 | { 163 | "country": "Romania", 164 | "estimate": "159546", 165 | "marginOfError": "7917" 166 | }, 167 | { 168 | "country": "Russia", 169 | "estimate": "386529", 170 | "marginOfError": "13859" 171 | }, 172 | { 173 | "country": "Ukraine", 174 | "estimate": "345620", 175 | "marginOfError": "11934" 176 | }, 177 | { 178 | "country": "Bosnia and Herzegovina", 179 | "estimate": "107969", 180 | "marginOfError": "9021" 181 | }, 182 | { 183 | "country": "Serbia", 184 | "estimate": "36969", 185 | "marginOfError": "4673" 186 | }, 187 | { 188 | "country": "Other Eastern Europe", 189 | "estimate": "130469", 190 | "marginOfError": "8453" 191 | }, 192 | { 193 | "country": "China excluding Hong Kong and Taiwan", 194 | "estimate": "2065431", 195 | "marginOfError": "33869" 196 | }, 197 | { 198 | "country": "Hong Kong", 199 | "estimate": "233373", 200 | "marginOfError": "7808" 201 | }, 202 | { 203 | "country": "Taiwan", 204 | "estimate": "377893", 205 | "marginOfError": "12637" 206 | }, 207 | { 208 | "country": "Japan", 209 | "estimate": "335767", 210 | "marginOfError": "11198" 211 | }, 212 | { 213 | "country": "Korea", 214 | "estimate": "1060019", 215 | "marginOfError": "20054" 216 | }, 217 | { 218 | "country": "Other Eastern Asia", 219 | "estimate": "13389", 220 | "marginOfError": "3024" 221 | }, 222 | { 223 | "country": "Afghanistan", 224 | "estimate": "70653", 225 | "marginOfError": "6928" 226 | }, 227 | { 228 | "country": "Bangladesh", 229 | "estimate": "228682", 230 | "marginOfError": "14479" 231 | }, 232 | { 233 | "country": "India", 234 | "estimate": "2389639", 235 | "marginOfError": "31113" 236 | }, 237 | { 238 | "country": "Iran", 239 | "estimate": "394223", 240 | "marginOfError": "14189" 241 | }, 242 | { 243 | "country": "Kazakhstan", 244 | "estimate": "29859", 245 | "marginOfError": "3389" 246 | }, 247 | { 248 | "country": "Nepal", 249 | "estimate": "120886", 250 | "marginOfError": "8823" 251 | }, 252 | { 253 | "country": "Pakistan", 254 | "estimate": "379435", 255 | "marginOfError": "17427" 256 | }, 257 | { 258 | "country": "Sri Lanka", 259 | "estimate": "52971", 260 | "marginOfError": "5613" 261 | }, 262 | { 263 | "country": "Uzbekistan", 264 | "estimate": "65375", 265 | "marginOfError": "5987" 266 | }, 267 | { 268 | "country": "Other South Central Asia", 269 | "estimate": "65719", 270 | "marginOfError": "7114" 271 | }, 272 | { 273 | "country": "Cambodia", 274 | "estimate": "166268", 275 | "marginOfError": "9301" 276 | }, 277 | { 278 | "country": "Indonesia", 279 | "estimate": "90833", 280 | "marginOfError": "7010" 281 | }, 282 | { 283 | "country": "Laos", 284 | "estimate": "197016", 285 | "marginOfError": "9812" 286 | }, 287 | { 288 | "country": "Malaysia", 289 | "estimate": "69308", 290 | "marginOfError": "5119" 291 | }, 292 | { 293 | "country": "Burma", 294 | "estimate": "137567", 295 | "marginOfError": "10011" 296 | }, 297 | { 298 | "country": "Philippines", 299 | "estimate": "1982369", 300 | "marginOfError": "30007" 301 | }, 302 | { 303 | "country": "Singapore", 304 | "estimate": "36252", 305 | "marginOfError": "3382" 306 | }, 307 | { 308 | "country": "Thailand", 309 | "estimate": "247205", 310 | "marginOfError": "10349" 311 | }, 312 | { 313 | "country": "Vietnam", 314 | "estimate": "1300515", 315 | "marginOfError": "27733" 316 | }, 317 | { 318 | "country": "Other South Eastern Asia", 319 | "estimate": "1625", 320 | "marginOfError": "673" 321 | }, 322 | { 323 | "country": "Iraq", 324 | "estimate": "215193", 325 | "marginOfError": "13794" 326 | }, 327 | { 328 | "country": "Israel", 329 | "estimate": "129680", 330 | "marginOfError": "6876" 331 | }, 332 | { 333 | "country": "Jordan", 334 | "estimate": "81767", 335 | "marginOfError": "8063" 336 | }, 337 | { 338 | "country": "Kuwait", 339 | "estimate": "31781", 340 | "marginOfError": "3643" 341 | }, 342 | { 343 | "country": "Lebanon", 344 | "estimate": "119613", 345 | "marginOfError": "8361" 346 | }, 347 | { 348 | "country": "Saudi Arabia", 349 | "estimate": "96783", 350 | "marginOfError": "8403" 351 | }, 352 | { 353 | "country": "Syria", 354 | "estimate": "82681", 355 | "marginOfError": "6286" 356 | }, 357 | { 358 | "country": "Yemen", 359 | "estimate": "44337", 360 | "marginOfError": "6088" 361 | }, 362 | { 363 | "country": "Turkey", 364 | "estimate": "116336", 365 | "marginOfError": "8283" 366 | }, 367 | { 368 | "country": "Armenia", 369 | "estimate": "86217", 370 | "marginOfError": "6658" 371 | }, 372 | { 373 | "country": "Other Western Asia", 374 | "estimate": "83981", 375 | "marginOfError": "7429" 376 | }, 377 | { 378 | "country": "Eritrea", 379 | "estimate": "39063", 380 | "marginOfError": "5274" 381 | }, 382 | { 383 | "country": "Ethiopia", 384 | "estimate": "228745", 385 | "marginOfError": "13680" 386 | }, 387 | { 388 | "country": "Kenya", 389 | "estimate": "129905", 390 | "marginOfError": "10130" 391 | }, 392 | { 393 | "country": "Somalia", 394 | "estimate": "89153", 395 | "marginOfError": "7277" 396 | }, 397 | { 398 | "country": "Other Eastern Africa", 399 | "estimate": "125694", 400 | "marginOfError": "9018" 401 | }, 402 | { 403 | "country": "Middle Africa", 404 | "estimate": "128584", 405 | "marginOfError": "11508" 406 | }, 407 | { 408 | "country": "Cameroon", 409 | "estimate": "51172", 410 | "marginOfError": "7568" 411 | }, 412 | { 413 | "country": "Other Middle Africa", 414 | "estimate": "77412", 415 | "marginOfError": "9776" 416 | }, 417 | { 418 | "country": "Egypt", 419 | "estimate": "185872", 420 | "marginOfError": "11556" 421 | }, 422 | { 423 | "country": "Morocco", 424 | "estimate": "71654", 425 | "marginOfError": "5503" 426 | }, 427 | { 428 | "country": "Sudan", 429 | "estimate": "46037", 430 | "marginOfError": "6708" 431 | }, 432 | { 433 | "country": "Other Northern Africa", 434 | "estimate": "42269", 435 | "marginOfError": "4655" 436 | }, 437 | { 438 | "country": "South Africa", 439 | "estimate": "94141", 440 | "marginOfError": "5867" 441 | }, 442 | { 443 | "country": "Other Southern Africa", 444 | "estimate": "4724", 445 | "marginOfError": "1384" 446 | }, 447 | { 448 | "country": "Cabo Verde", 449 | "estimate": "43352", 450 | "marginOfError": "5264" 451 | }, 452 | { 453 | "country": "Ghana", 454 | "estimate": "155532", 455 | "marginOfError": "10846" 456 | }, 457 | { 458 | "country": "Liberia", 459 | "estimate": "79497", 460 | "marginOfError": "7804" 461 | }, 462 | { 463 | "country": "Nigeria", 464 | "estimate": "323635", 465 | "marginOfError": "18271" 466 | }, 467 | { 468 | "country": "Sierra Leone", 469 | "estimate": "42065", 470 | "marginOfError": "5812" 471 | }, 472 | { 473 | "country": "Other Western Africa", 474 | "estimate": "122260", 475 | "marginOfError": "9856" 476 | }, 477 | { 478 | "country": "Australia", 479 | "estimate": "83573", 480 | "marginOfError": "5527" 481 | }, 482 | { 483 | "country": "Other Australian and New Zealand Subregion", 484 | "estimate": "29704", 485 | "marginOfError": "2990" 486 | }, 487 | { 488 | "country": "Fiji", 489 | "estimate": "41936", 490 | "marginOfError": "4822" 491 | }, 492 | { 493 | "country": "Caribbean", 494 | "estimate": "4165453", 495 | "marginOfError": "49473" 496 | }, 497 | { 498 | "country": "Bahamas", 499 | "estimate": "34796", 500 | "marginOfError": "3735" 501 | }, 502 | { 503 | "country": "Barbados", 504 | "estimate": "51739", 505 | "marginOfError": "4829" 506 | }, 507 | { 508 | "country": "Cuba", 509 | "estimate": "1210674", 510 | "marginOfError": "23840" 511 | }, 512 | { 513 | "country": "Dominica", 514 | "estimate": "32370", 515 | "marginOfError": "4110" 516 | }, 517 | { 518 | "country": "Dominican Republic", 519 | "estimate": "1063239", 520 | "marginOfError": "28770" 521 | }, 522 | { 523 | "country": "Grenada", 524 | "estimate": "29982", 525 | "marginOfError": "3185" 526 | }, 527 | { 528 | "country": "Haiti", 529 | "estimate": "675546", 530 | "marginOfError": "22289" 531 | }, 532 | { 533 | "country": "Jamaica", 534 | "estimate": "711134", 535 | "marginOfError": "19231" 536 | }, 537 | { 538 | "country": "St. Vincent and the Grenadines", 539 | "estimate": "22950", 540 | "marginOfError": "2820" 541 | }, 542 | { 543 | "country": "Trinidad and Tobago", 544 | "estimate": "227295", 545 | "marginOfError": "8816" 546 | }, 547 | { 548 | "country": "West Indies", 549 | "estimate": "33011", 550 | "marginOfError": "4485" 551 | }, 552 | { 553 | "country": "Other Caribbean", 554 | "estimate": "72717", 555 | "marginOfError": "6064" 556 | }, 557 | { 558 | "country": "Mexico", 559 | "estimate": "11643298", 560 | "marginOfError": "77644" 561 | }, 562 | { 563 | "country": "Belize", 564 | "estimate": "48811", 565 | "marginOfError": "5371" 566 | }, 567 | { 568 | "country": "Costa Rica", 569 | "estimate": "90109", 570 | "marginOfError": "5646" 571 | }, 572 | { 573 | "country": "El Salvador", 574 | "estimate": "1352357", 575 | "marginOfError": "31379" 576 | }, 577 | { 578 | "country": "Guatemala", 579 | "estimate": "927593", 580 | "marginOfError": "23812" 581 | }, 582 | { 583 | "country": "Honduras", 584 | "estimate": "599030", 585 | "marginOfError": "25695" 586 | }, 587 | { 588 | "country": "Nicaragua", 589 | "estimate": "256171", 590 | "marginOfError": "12391" 591 | }, 592 | { 593 | "country": "Panama", 594 | "estimate": "103625", 595 | "marginOfError": "5810" 596 | }, 597 | { 598 | "country": "Other Central America", 599 | "estimate": "6933", 600 | "marginOfError": "1586" 601 | }, 602 | { 603 | "country": "Argentina", 604 | "estimate": "181233", 605 | "marginOfError": "9339" 606 | }, 607 | { 608 | "country": "Bolivia", 609 | "estimate": "78093", 610 | "marginOfError": "6898" 611 | }, 612 | { 613 | "country": "Brazil", 614 | "estimate": "361374", 615 | "marginOfError": "15675" 616 | }, 617 | { 618 | "country": "Chile", 619 | "estimate": "95104", 620 | "marginOfError": "6986" 621 | }, 622 | { 623 | "country": "Colombia", 624 | "estimate": "699399", 625 | "marginOfError": "20772" 626 | }, 627 | { 628 | "country": "Ecuador", 629 | "estimate": "441257", 630 | "marginOfError": "19017" 631 | }, 632 | { 633 | "country": "Guyana", 634 | "estimate": "281408", 635 | "marginOfError": "12349" 636 | }, 637 | { 638 | "country": "Peru", 639 | "estimate": "445921", 640 | "marginOfError": "17981" 641 | }, 642 | { 643 | "country": "Uruguay", 644 | "estimate": "43971", 645 | "marginOfError": "5051" 646 | }, 647 | { 648 | "country": "Venezuela", 649 | "estimate": "255520", 650 | "marginOfError": "13320" 651 | }, 652 | { 653 | "country": "Other South America", 654 | "estimate": "34749", 655 | "marginOfError": "3674" 656 | }, 657 | { 658 | "country": "Canada", 659 | "estimate": "830628", 660 | "marginOfError": "17129" 661 | }, 662 | { 663 | "country": "Other Northern America", 664 | "estimate": "7848", 665 | "marginOfError": "1589" 666 | } 667 | ] -------------------------------------------------------------------------------- /section-1/in-class/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | P5 - D3 - Vanilla JS 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /section-1/in-class/sketch.js: -------------------------------------------------------------------------------- 1 | 2 | //read in data from csv 3 | // v4 + v3 callback way 4 | // d3.csv('../data/nyc-data.csv', (error, data) => { 5 | // if (error) throw error 6 | // console.log(data) 7 | // }) 8 | 9 | // v5 Promises way 10 | d3.csv('../data/nyc-data.csv').then(data => { 11 | // console.log(data) 12 | }).catch(e => { 13 | console.log(e) 14 | }) 15 | 16 | // read in multiple data files with Promise.all 17 | Promise.all([ 18 | d3.csv('../data/nyc-data.csv'), 19 | d3.csv('../data/simpleData.csv') 20 | ]).then(([nycData, usaData]) => { 21 | console.log(nycData) 22 | // console.log(usaData) 23 | const processedNYC = processData(nycData, true) 24 | const processedUSA = processData(usaData, false) 25 | }) 26 | 27 | function processData(data, isNYCData) { 28 | // change the property names (keys) of the objects in the data 29 | // convert the string values to numbers with the + operator (parseInt()) 30 | // remove strings and excess characters before converting to numbers with replace() and slice() 31 | const mapped = data.map( d => { 32 | // console.log(d) 33 | return { 34 | 'country': isNYCData ? d['country/region'] : d['country'], // turnary operator - acts like an "if/else" statement 35 | 'population': +d['estimate'].replace(/,/g, ''), 36 | 'marginOfError': +d.marginOfError.replace(/,/g, '').slice(3) 37 | } 38 | }).map( d => { return {...d, errorFraction: d.marginOfError / d.population} }) // spread operator (...) gets the values from the object passed into the function 39 | console.log(mapped) 40 | 41 | // filter out regions from data -- use an array of stop words 42 | const regionsToFilter = ['Europe', 'Asia', 'Africa', 'America', 'Caribbean', 'Subregion', 'excluding'] 43 | const noRegions = mapped.filter( d => { 44 | //The every() method tests whether all elements in the array pass the test implemented by the provided function. 45 | return regionsToFilter.every( region => { 46 | // returns true if country names do not contain words in the RegionsToFilter array (stop words) 47 | return d.country.indexOf(region) === -1 48 | }) 49 | }) 50 | console.log(noRegions) 51 | 52 | // use reduce to get total foreign born population from countries, don't double count people from regions (why we filtered) 53 | const total = noRegions.reduce((acc, d) => acc + d.population, 0) 54 | console.log(total) 55 | 56 | // sort the array of countries in ascending order based on population, or descending order 57 | // for more information on sort: https://teamtreehouse.com/community/javascript-sort-method-how-does-the-comparison-actually-work 58 | // we slice the array we want to sort first in order to copy it and not mutate the original data or other arrays 59 | const ascendingPop = noRegions.slice(0).sort((a,b) => a.population - b.population) 60 | console.log(ascendingPop) 61 | const descendingPop = noRegions.slice(0).sort((a,b) => b.population - a.population) 62 | console.log(descendingPop) 63 | 64 | // return the data once it's processed how we want it 65 | return ascendingPop 66 | } -------------------------------------------------------------------------------- /section-1/load-csv-data/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | load csv data example 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /section-1/load-csv-data/sketch.js: -------------------------------------------------------------------------------- 1 | let populations; 2 | let objArray = []; 3 | 4 | function preload() { 5 | populations = loadTable("../data/simpleData_noRegions.csv", "csv", "header"); 6 | } 7 | 8 | function setup() { 9 | // put setup code here 10 | console.log(populations.getRowCount() + " total rows in table"); 11 | console.log(populations.getColumnCount() + " total columns in table"); 12 | 13 | // how do we want to work with our Table Data? 14 | console.log(populations.getObject()); 15 | 16 | console.log(populations.getArray()); 17 | 18 | console.log(populations.getRows()); 19 | 20 | // What if we want to work with an Array of Objects - let's create that 21 | // Create an array of objects - declare it globally to access it in draw function too 22 | 23 | for (let i = 0; i < populations.getRowCount(); i++) { 24 | 25 | // get the object from each CSV row - country, estimate, margin of error 26 | //console.log(populations.getRow(i)); 27 | let oldObj = populations.getRow(i).obj; 28 | 29 | let newObj = {}; 30 | newObj.country = oldObj.country; 31 | // interpret as a number instead of a string with parseInt 32 | newObj.estimate = parseInt(oldObj.estimate); 33 | newObj.error = parseInt(oldObj.marginOfError); 34 | // put the object into the array 35 | objArray.push(newObj); 36 | } 37 | 38 | console.log(objArray); 39 | } 40 | 41 | function draw() { 42 | // put drawing code here 43 | 44 | // How might you sort the countries by population estimate? 45 | 46 | // How might you visually represent the population estimates? 47 | // Try a few different ways 48 | // Think about shape, color, text 49 | // Once you feel comfortable with drawing a static representation, think about adding interactivity 50 | } -------------------------------------------------------------------------------- /section-1/load-json-data/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | load json data example 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /section-1/load-json-data/sketch.js: -------------------------------------------------------------------------------- 1 | let populations; 2 | let objArray = []; 3 | 4 | function preload() { 5 | // Don't use preload() function for JSON files, 6 | // currently a bug in p5 where it doesn't return JSON Arrays only JSON Objects 7 | // populations = loadJSON('../data/simpleData_noRegions.json'); 8 | } 9 | 10 | function setup() { 11 | // put setup code here 12 | // load static data set here 13 | loadJSON('../data/simpleData_noRegions.json', callback); 14 | } 15 | 16 | function callback(data) { 17 | console.log('done loading data'); 18 | console.log(data); 19 | populations = data; 20 | 21 | //if the data is loaded, start working with it 22 | if (populations) { 23 | for (let i = 0; i < populations.length; i++) { 24 | //console.log(populations[i]); 25 | 26 | let name = populations[i].country; 27 | let population = populations[i].estimate; 28 | //sampling error of the estimate, estimate could be + or - the margin of error 29 | let error = populations[i].marginOfError; 30 | 31 | //get magnitude of error compared to population estimate; 32 | let errorFraction = populations[i].marginOfError / population; 33 | //console.log(errorFraction); 34 | 35 | console.log(name, population, error) 36 | } 37 | } 38 | } 39 | 40 | function draw() { 41 | // put drawing code here 42 | 43 | if (populations) { 44 | // How might you sort the countries by population estimate? 45 | 46 | // How might you visually represent the population estimates? 47 | // Try a few different ways 48 | // Think about shape, color, text 49 | // Once you feel comfortable with drawing a static representation, think about adding interactivity 50 | 51 | } 52 | } -------------------------------------------------------------------------------- /section-2/data/yelp-pizzerias.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "_id": "58ae56467b947e2e79a2f7b3", 3 | "distance": 92.26509407076, 4 | "review_count": 1162, 5 | "name": "NY Pizza Suprema", 6 | "rating": 4, 7 | "url": "https://www.yelp.com/biz/ny-pizza-suprema-new-york?adjust_creative=ArEVrZ-_cCxPph97oAQkgg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=ArEVrZ-_cCxPph97oAQkgg", 8 | "price": "$", 9 | "coordinates": { 10 | "latitude": 40.7502059936523, 11 | "longitude": -73.9953231811523 12 | }, 13 | "phone": "+12125948939", 14 | "image_url": "https://s3-media4.fl.yelpcdn.com/bphoto/EqbDXneMuQP6pw6GemVdQA/o.jpg", 15 | "is_closed": false, 16 | "display_phone": "(212) 594-8939", 17 | "id": "ny-pizza-suprema-new-york", 18 | "categories": [ 19 | { 20 | "alias": "pizza", 21 | "title": "Pizza" 22 | } 23 | ], 24 | "location": { 25 | "city": "New York", 26 | "display_address": [ 27 | "413 8th Ave", 28 | "New York, NY 10001" 29 | ], 30 | "address1": "413 8th Ave", 31 | "address2": "", 32 | "address3": "", 33 | "state": "NY", 34 | "country": "US", 35 | "zip_code": "10001" 36 | } 37 | }, 38 | { 39 | "_id": "58ae56467b947e2e79a2f7ec", 40 | "distance": 555.4650850324, 41 | "review_count": 619, 42 | "name": "Waldy's Wood Fired Pizza & Penne", 43 | "rating": 4, 44 | "url": "https://www.yelp.com/biz/waldys-wood-fired-pizza-and-penne-new-york-5?adjust_creative=ArEVrZ-_cCxPph97oAQkgg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=ArEVrZ-_cCxPph97oAQkgg", 45 | "price": "$$", 46 | "coordinates": { 47 | "latitude": 40.7457666039821, 48 | "longitude": -73.9906402533629 49 | }, 50 | "phone": "+12122135042", 51 | "image_url": "https://s3-media4.fl.yelpcdn.com/bphoto/eWJp5A0mUFj7mkq4DKdkbw/o.jpg", 52 | "is_closed": false, 53 | "display_phone": "(212) 213-5042", 54 | "id": "waldys-wood-fired-pizza-and-penne-new-york-5", 55 | "categories": [ 56 | { 57 | "alias": "pizza", 58 | "title": "Pizza" 59 | } 60 | ], 61 | "location": { 62 | "city": "New York", 63 | "display_address": [ 64 | "800 6th Ave", 65 | "New York, NY 10001" 66 | ], 67 | "address1": "800 6th Ave", 68 | "address2": null, 69 | "address3": "", 70 | "state": "NY", 71 | "country": "US", 72 | "zip_code": "10001" 73 | } 74 | }, 75 | { 76 | "_id": "58ae56467b947e2e79a2f7fc", 77 | "distance": 797.8492952119999, 78 | "review_count": 90, 79 | "name": "PN Wood Fired Pizza", 80 | "rating": 4.5, 81 | "url": "https://www.yelp.com/biz/pn-wood-fired-pizza-new-york?adjust_creative=ArEVrZ-_cCxPph97oAQkgg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=ArEVrZ-_cCxPph97oAQkgg", 82 | "price": "$$", 83 | "coordinates": { 84 | "latitude": 40.74475, 85 | "longitude": -73.98772 86 | }, 87 | "phone": "+16469644834", 88 | "image_url": "https://s3-media3.fl.yelpcdn.com/bphoto/aihAr203sHKecqsTHjwgUg/o.jpg", 89 | "is_closed": false, 90 | "display_phone": "(646) 964-4834", 91 | "id": "pn-wood-fired-pizza-new-york", 92 | "categories": [ 93 | { 94 | "alias": "pizza", 95 | "title": "Pizza" 96 | } 97 | ], 98 | "location": { 99 | "city": "New York", 100 | "display_address": [ 101 | "2 W 28th St", 102 | "New York, NY 10001" 103 | ], 104 | "address1": "2 W 28th St", 105 | "address2": "", 106 | "address3": "", 107 | "state": "NY", 108 | "country": "US", 109 | "zip_code": "10001" 110 | } 111 | }, 112 | { 113 | "_id": "58ae56467b947e2e79a2f803", 114 | "distance": 206.86956864739997, 115 | "review_count": 171, 116 | "name": "Rose's Pizza and Pasta", 117 | "rating": 3.5, 118 | "url": "https://www.yelp.com/biz/roses-pizza-and-pasta-new-york?adjust_creative=ArEVrZ-_cCxPph97oAQkgg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=ArEVrZ-_cCxPph97oAQkgg", 119 | "price": "$", 120 | "coordinates": { 121 | "latitude": 40.7516241, 122 | "longitude": -73.9924959 123 | }, 124 | "phone": "+12126297455", 125 | "image_url": "https://s3-media3.fl.yelpcdn.com/bphoto/SdCLlrUyD3QzTvFOl_afTQ/o.jpg", 126 | "is_closed": false, 127 | "display_phone": "(212) 629-7455", 128 | "id": "roses-pizza-and-pasta-new-york", 129 | "categories": [ 130 | { 131 | "alias": "pizza", 132 | "title": "Pizza" 133 | }, 134 | { 135 | "alias": "italian", 136 | "title": "Italian" 137 | } 138 | ], 139 | "location": { 140 | "city": "New York", 141 | "display_address": [ 142 | "1 Penn Plz", 143 | "New York, NY 10119" 144 | ], 145 | "address1": "1 Penn Plz", 146 | "address2": null, 147 | "address3": "", 148 | "state": "NY", 149 | "country": "US", 150 | "zip_code": "10119" 151 | } 152 | }, 153 | { 154 | "_id": "58ae56467b947e2e79a2f911", 155 | "distance": 176.869523746, 156 | "is_closed": false, 157 | "review_count": 58, 158 | "name": "Don Pepi Pizza", 159 | "rating": 3.5, 160 | "url": "https://www.yelp.com/biz/don-pepi-pizza-new-york?adjust_creative=ArEVrZ-_cCxPph97oAQkgg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=ArEVrZ-_cCxPph97oAQkgg", 161 | "price": "$", 162 | "coordinates": { 163 | "latitude": 40.7506946, 164 | "longitude": -73.9923316 165 | }, 166 | "phone": "+12129674385", 167 | "image_url": "https://s3-media3.fl.yelpcdn.com/bphoto/E5R4k6ZQGn3PqfaHJmd9RQ/o.jpg", 168 | "location": { 169 | "city": "New York", 170 | "display_address": [ 171 | "2 Pennsylvania Plz", 172 | "New York, NY 10121" 173 | ], 174 | "address1": "2 Pennsylvania Plz", 175 | "address2": "", 176 | "address3": "", 177 | "state": "NY", 178 | "country": "US", 179 | "zip_code": "10121" 180 | }, 181 | "display_phone": "(212) 967-4385", 182 | "id": "don-pepi-pizza-new-york", 183 | "categories": [ 184 | { 185 | "alias": "pizza", 186 | "title": "Pizza" 187 | } 188 | ] 189 | }, 190 | { 191 | "_id": "58ae56467b947e2e79a2f94e", 192 | "distance": 680.9490585011999, 193 | "review_count": 54, 194 | "name": "Highline Pizza", 195 | "rating": 4, 196 | "url": "https://www.yelp.com/biz/highline-pizza-new-york?adjust_creative=ArEVrZ-_cCxPph97oAQkgg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=ArEVrZ-_cCxPph97oAQkgg", 197 | "price": "$", 198 | "coordinates": { 199 | "latitude": 40.751049, 200 | "longitude": -74.0020523 201 | }, 202 | "phone": "+12125643330", 203 | "image_url": "https://s3-media2.fl.yelpcdn.com/bphoto/TC4FAQrrw4ptQDaOfibe0g/o.jpg", 204 | "is_closed": false, 205 | "display_phone": "(212) 564-3330", 206 | "id": "highline-pizza-new-york", 207 | "categories": [ 208 | { 209 | "alias": "pizza", 210 | "title": "Pizza" 211 | } 212 | ], 213 | "location": { 214 | "city": "New York", 215 | "display_address": [ 216 | "503 W 28th St", 217 | "New York, NY 10001" 218 | ], 219 | "address1": "503 W 28th St", 220 | "address2": null, 221 | "address3": "", 222 | "state": "NY", 223 | "country": "US", 224 | "zip_code": "10001" 225 | } 226 | }, 227 | { 228 | "_id": "58ae56467b947e2e79a2f951", 229 | "distance": 612.2298220728, 230 | "review_count": 172, 231 | "name": "Lazzara's Pizza", 232 | "rating": 3.5, 233 | "url": "https://www.yelp.com/biz/lazzaras-pizza-new-york?adjust_creative=ArEVrZ-_cCxPph97oAQkgg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=ArEVrZ-_cCxPph97oAQkgg", 234 | "price": "$$", 235 | "coordinates": { 236 | "latitude": 40.754057, 237 | "longitude": -73.989497 238 | }, 239 | "phone": "+12129447792", 240 | "image_url": "https://s3-media1.fl.yelpcdn.com/bphoto/0TJfObqXkm4u_O888DT7lA/o.jpg", 241 | "is_closed": false, 242 | "display_phone": "(212) 944-7792", 243 | "id": "lazzaras-pizza-new-york", 244 | "categories": [ 245 | { 246 | "alias": "pizza", 247 | "title": "Pizza" 248 | }, 249 | { 250 | "alias": "sandwiches", 251 | "title": "Sandwiches" 252 | } 253 | ], 254 | "location": { 255 | "city": "New York", 256 | "display_address": [ 257 | "221 W 38th St", 258 | "New York, NY 10018" 259 | ], 260 | "address1": "221 W 38th St", 261 | "address2": "", 262 | "address3": "", 263 | "state": "NY", 264 | "country": "US", 265 | "zip_code": "10018" 266 | } 267 | }, 268 | { 269 | "_id": "58ae56467b947e2e79a2f96e", 270 | "distance": 45.178036216, 271 | "review_count": 184, 272 | "name": "Famous Amadeus Pizza", 273 | "rating": 3, 274 | "url": "https://www.yelp.com/biz/famous-amadeus-pizza-new-york?adjust_creative=ArEVrZ-_cCxPph97oAQkgg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=ArEVrZ-_cCxPph97oAQkgg", 275 | "price": "$", 276 | "coordinates": { 277 | "latitude": 40.749794, 278 | "longitude": -73.994804 279 | }, 280 | "phone": "+12129041112", 281 | "image_url": "https://s3-media3.fl.yelpcdn.com/bphoto/h9gJE_XBnr8FCdOCwvCUfw/o.jpg", 282 | "is_closed": false, 283 | "display_phone": "(212) 904-1112", 284 | "id": "famous-amadeus-pizza-new-york", 285 | "categories": [ 286 | { 287 | "alias": "pizza", 288 | "title": "Pizza" 289 | }, 290 | { 291 | "alias": "italian", 292 | "title": "Italian" 293 | }, 294 | { 295 | "alias": "burgers", 296 | "title": "Burgers" 297 | } 298 | ], 299 | "location": { 300 | "city": "New York", 301 | "display_address": [ 302 | "408 8th Ave", 303 | "New York, NY 10001" 304 | ], 305 | "address1": "408 8th Ave", 306 | "address2": "", 307 | "address3": "", 308 | "state": "NY", 309 | "country": "US", 310 | "zip_code": "10001" 311 | } 312 | }, 313 | { 314 | "_id": "58ae56467b947e2e79a2f9b6", 315 | "distance": 782.1388537583999, 316 | "review_count": 168, 317 | "name": "2 Bros Pizza", 318 | "rating": 3.5, 319 | "url": "https://www.yelp.com/biz/2-bros-pizza-new-york-3?adjust_creative=ArEVrZ-_cCxPph97oAQkgg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=ArEVrZ-_cCxPph97oAQkgg", 320 | "price": "$", 321 | "coordinates": { 322 | "latitude": 40.75695, 323 | "longitude": -73.9935 324 | }, 325 | "phone": "+12127770600", 326 | "image_url": "https://s3-media1.fl.yelpcdn.com/bphoto/3CZHMTCMfXiJnCOhlt-xPw/o.jpg", 327 | "is_closed": false, 328 | "display_phone": "(212) 777-0600", 329 | "id": "2-bros-pizza-new-york-3", 330 | "categories": [ 331 | { 332 | "alias": "pizza", 333 | "title": "Pizza" 334 | } 335 | ], 336 | "location": { 337 | "city": "New York", 338 | "display_address": [ 339 | "542 9th Ave", 340 | "New York, NY 10018" 341 | ], 342 | "address1": "542 9th Ave", 343 | "address2": "", 344 | "address3": "", 345 | "state": "NY", 346 | "country": "US", 347 | "zip_code": "10018" 348 | } 349 | }, 350 | { 351 | "_id": "58ae56467b947e2e79a2f9fe", 352 | "distance": 845.693525006, 353 | "review_count": 274, 354 | "name": "Little Italy Pizza", 355 | "rating": 3.5, 356 | "url": "https://www.yelp.com/biz/little-italy-pizza-new-york-7?adjust_creative=ArEVrZ-_cCxPph97oAQkgg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_search&utm_source=ArEVrZ-_cCxPph97oAQkgg", 357 | "price": "$", 358 | "coordinates": { 359 | "latitude": 40.74758, 360 | "longitude": -73.98481 361 | }, 362 | "phone": "+12124815200", 363 | "image_url": "https://s3-media2.fl.yelpcdn.com/bphoto/aqeToVW35jt2b_Wv544TdA/o.jpg", 364 | "is_closed": false, 365 | "display_phone": "(212) 481-5200", 366 | "id": "little-italy-pizza-new-york-7", 367 | "categories": [ 368 | { 369 | "alias": "pizza", 370 | "title": "Pizza" 371 | } 372 | ], 373 | "location": { 374 | "city": "New York", 375 | "display_address": [ 376 | "2 E 33rd St", 377 | "New York, NY 10016" 378 | ], 379 | "address1": "2 E 33rd St", 380 | "address2": "", 381 | "address3": "", 382 | "state": "NY", 383 | "country": "US", 384 | "zip_code": "10016" 385 | } 386 | } 387 | ] -------------------------------------------------------------------------------- /section-2/node-autocomplete-api/autocomplete_results.json: -------------------------------------------------------------------------------- 1 | { 2 | "how do i": [ 3 | "how do i live", 4 | "how do i", 5 | "how do i breathe", 6 | "how do i look", 7 | "how do i know", 8 | "how do i feel", 9 | "how do i love thee", 10 | "how do i tie a tie", 11 | "how do i live karaoke", 12 | "how do i craft this again" 13 | ], 14 | "what is": [ 15 | "what is love", 16 | "what is ligma", 17 | "what is a pin in fortnite", 18 | "what is asmr", 19 | "what is this", 20 | "what is the alpha tournament", 21 | "what is life", 22 | "what is your name", 23 | "what is bitcoin", 24 | "what is love remix" 25 | ], 26 | "anyone": [ 27 | "anyone", 28 | "anyone of us", 29 | "anyone else", 30 | "anyone but me", 31 | "anyone but you", 32 | "anyone else meme", 33 | "anyone out there", 34 | "anyone anyone", 35 | "anyone can cook", 36 | "anyone can draw" 37 | ], 38 | "i am": [ 39 | "i am", 40 | "i am lil baby", 41 | "i am the one", 42 | "i am frankie", 43 | "i am a mess", 44 | "i am who you say i am video", 45 | "i am legend", 46 | "i am jazz", 47 | "i am the man", 48 | "i am a gummy bear" 49 | ], 50 | "who are": [ 51 | "who are you", 52 | "who are you school 2015", 53 | "who are you really", 54 | "who are we", 55 | "who are u", 56 | "who are you meme", 57 | "who are you people", 58 | "who are you song", 59 | "who are you lyrics", 60 | "who are you vine" 61 | ], 62 | "i think": [ 63 | "i think i'm in love again", 64 | "i think about you", 65 | "i think i want to marry you", 66 | "i think i love you", 67 | "i think i like it", 68 | "i think i need help", 69 | "i think i can fly", 70 | "i think i'm losing my mind", 71 | "i think they like me", 72 | "i think my dog's a democrat" 73 | ] 74 | } -------------------------------------------------------------------------------- /section-2/node-autocomplete-api/callAPI.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | const fs = require('fs') 3 | 4 | // var results = { 5 | // 'how do i': [ 6 | // 'how do i live', 7 | // ... 8 | // ], 9 | // 'what is': [ 10 | // ... 11 | // ] 12 | // } 13 | 14 | const results = {} 15 | 16 | // what search terms do you want to query? 17 | const query = ['how do i', 'what is', 'anyone', 'i am', 'who are', 'i think'] 18 | const service = 'yt'; 19 | const language = 'en'; 20 | 21 | function concatenateUrl(query, service, language) { 22 | // this might be deprecated at any moment, but will work via node for now! It probably won't work if you query via the browser 23 | // More info here: https://webmasters.googleblog.com/2015/07/update-on-autocomplete-api.html 24 | const requestUrl = 'https://www.google.com/complete/search?&client=firefox' + 25 | '&q=' + query + 26 | '&ds=' + service + 27 | '&hl=' + language 28 | 29 | return requestUrl 30 | } 31 | 32 | function callAPI(i) { 33 | console.log('Called callAPI') 34 | console.log(query[i] + ', ' + service + ', ' + language) 35 | const url = concatenateUrl(query[i], service, language) 36 | 37 | // This is the actual API call 38 | request(url, function(error, response, body){ 39 | // console.log(response); 40 | console.log(body) 41 | // This is all NATIVE javascript 42 | console.log(typeof body) // My original data is just a string 43 | const result = JSON.parse(body) // I need to convert it to a JSON object 44 | 45 | console.log(typeof result) 46 | const autocomplete = result[1] // Getting just the autocomplete suggestions 47 | console.log(autocomplete) 48 | 49 | results[query[i]] = autocomplete // add suggestions to results object, use query term as key 50 | console.log(results) 51 | 52 | i++ 53 | if (i < query.length) { 54 | callAPI(i) 55 | } else { 56 | // write out query results to file when all terms in query array have been queried 57 | fs.writeFileSync('autocomplete_results.json', JSON.stringify(results, null, 4), 'utf-8'); 58 | } 59 | }); 60 | } 61 | 62 | // call the function the first time 63 | callAPI(0) -------------------------------------------------------------------------------- /section-2/node-autocomplete-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-autocomplete-api", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "request": "^2.88.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /section-2/node-clean-text/clean.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | // use file system (fs) to read the text file 4 | const text = fs.readFileSync('../data/time-machine.txt', 'utf-8') 5 | // console.log(text) 6 | 7 | // split the text on the *** which marks the beginning and end of the book 8 | const txtArray = text.split('***') 9 | // console.log(txtArray.length) 10 | 11 | // print out the lengths of each portion that was split at *** 12 | txtArray.forEach( t => console.log(t.length)) 13 | 14 | // the book portion is at index 2 according to the length of the characters 15 | const book = txtArray[2] 16 | 17 | // make a JSON object with key / value pairs 18 | const fileInfo = {} 19 | fileInfo['author'] = 'H. G. Wells' 20 | fileInfo.title = 'The Time Machine' 21 | fileInfo.text = book 22 | 23 | // use file system (fs) to write out a new JSON file - stringify since we made a JSON object 24 | fs.writeFileSync('data/time-machine-clean.json', JSON.stringify(fileInfo), 'utf-8') 25 | -------------------------------------------------------------------------------- /section-2/node-puppeteer/getTimes.js: -------------------------------------------------------------------------------- 1 | const puppeteer = require('puppeteer') 2 | 3 | async function getTimes() { 4 | // essentially launching our own version of Chrome, setting it equal to the variable browser 5 | const browser = await puppeteer.launch() 6 | // set headless browser to false to see the program in action 7 | // const browser = await puppeteer.launch({ headless: false }) 8 | // open a new page in the browser and assign it to the variable page 9 | const page = await browser.newPage() 10 | // navigate to the url www.nytimes.com 11 | await page.goto('https://www.nytimes.com/') 12 | // take a screenshot of the webpage, save it as nytimes.png 13 | await page.screenshot({path: 'nytimes.png'}) 14 | // close the browser 15 | await browser.close() 16 | } 17 | 18 | getTimes() -------------------------------------------------------------------------------- /section-2/node-puppeteer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "puppeteer": "^1.9.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /section-2/node-puppeteer/pizzaMenus.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const puppeteer = require('puppeteer') 3 | 4 | const yelpData = JSON.parse(fs.readFileSync('../data/yelp-pizzerias.json', 'utf8')) 5 | 6 | const baseUrl = `https://www.yelp.com` 7 | 8 | async function run() { 9 | const browser = await puppeteer.launch({ headless: false }) // set headless to false if you want to see puppeteer in action 10 | const page = await browser.newPage() 11 | 12 | let idx = 0 13 | 14 | for (let i = idx; i < yelpData.length; i++) { 15 | const id = `${yelpData[i].id}` 16 | //let queryString = `https://www.yelp.com/menu/roccos-pizza-joint-new-york` 17 | const filename = `${id}.json` 18 | console.log(idx, id) 19 | await getRestaurantInfo(page, id, filename) 20 | idx++ 21 | } 22 | 23 | await browser.close() 24 | } 25 | 26 | async function getRestaurantInfo(page, id, filename) { 27 | const queryStringMenu = `https://www.yelp.com/menu/${id}` 28 | const queryStringBiz = `https://www.yelp.com/biz/${id}` 29 | 30 | // get Restaurant Info 31 | await page.waitFor(randomIntFromInterval(900,1200)) 32 | await page.goto(queryStringBiz) 33 | 34 | const NAME_SELECTOR = `#wrap > div.biz-country-us > div > div.top-shelf > div > div.biz-page-header.clearfix > div.biz-page-header-left > div > h1` 35 | const PHONE_SELECTOR = `#wrap > div.biz-country-us > div > div.top-shelf > div > div.biz-page-subheader > div.mapbox-container > div > div.mapbox-text > ul > li:nth-child(4) > span.biz-phone` 36 | 37 | const name = await page.evaluate((sel) => { 38 | let element = document.querySelector(sel) 39 | return element ? element.innerText : null 40 | }, NAME_SELECTOR) 41 | 42 | const phone_number = await page.evaluate((sel) => { 43 | let element = document.querySelector(sel) 44 | return element ? element.innerText : null 45 | }, PHONE_SELECTOR) 46 | 47 | let fileInfo = {} 48 | fileInfo.name = name 49 | fileInfo.phone = phone_number 50 | // console.log(fileInfo) 51 | 52 | // get Menu Stuff - wait for a random amount of time to confuse the servers 53 | await page.waitFor(randomIntFromInterval(900,1200)) 54 | // change page to menu page 55 | await page.goto(queryStringMenu) 56 | // get menu data and write it to a JSON file 57 | await getMenu(page, id, filename, fileInfo) 58 | } 59 | 60 | async function getMenu(page, id, filename, fileInfo) { 61 | const MENU_ROW_ITEM = `#super-container > div.container.biz-menu > div.clearfix.layout-block.layout-a > div.column.column-alpha > div > div > div` 62 | //#super-container > div.container.biz-menu > div.clearfix.layout-block.layout-a > div.column.column-alpha > div > div:nth-child(2) > div:nth-child(1) > div 63 | const menuItems = await page.evaluate((sel) => { 64 | let items = [] 65 | const rows = document.querySelectorAll(sel) 66 | 67 | rows.forEach( row => { 68 | let menuItem = {} 69 | if (row.querySelector('h4')) { 70 | menuItem.name = row.querySelector('h4').innerText 71 | } 72 | if (row.querySelector('p')) { 73 | menuItem.description = row.querySelector('p').innerText 74 | } 75 | if (row.querySelector('div.menu-item-prices.arrange_unit > ul > li.menu-item-price-amount')) { 76 | menuItem.price = row.querySelector('div.menu-item-prices.arrange_unit > ul > li.menu-item-price-amount').innerText 77 | } 78 | // lazaras has prices in this format 79 | if (row.querySelector('div.menu-item-prices.arrange_unit > table > tbody')) { 80 | const prices = row.querySelectorAll('div.menu-item-prices.arrange_unit > table > tbody > tr') 81 | const priceArray = [] 82 | prices.forEach( price => { 83 | let priceInfo = {} 84 | if (price.querySelector('th')) { 85 | priceInfo.description = price.querySelector('th').innerText 86 | } 87 | if (price.querySelector('td')) { 88 | priceInfo.amount = price.querySelector('td').innerText 89 | } 90 | priceArray.push(priceInfo) 91 | }) 92 | menuItem.price = priceArray 93 | } 94 | items.push(menuItem) 95 | }) 96 | return items 97 | }, MENU_ROW_ITEM) 98 | 99 | //console.log(menuItems) 100 | 101 | // if we were able to save a restaurant menu, write it to a file 102 | if (menuItems.length > 0) { 103 | fileInfo.restaurant_id = id 104 | fileInfo.menu = menuItems 105 | // make sure the file pizza-menus exists in the data folder, otherwise you'll get an error 106 | fs.writeFileSync(`../data/pizza-menus/${filename}`, JSON.stringify(fileInfo, null, 4), 'utf8') 107 | console.log(`saved menu for ${fileInfo.name}`) 108 | } else { 109 | console.log(`no menu for ${id}`) 110 | } 111 | } 112 | 113 | // this helps confuse the yelp server so you aren't requesting at the same interval, prevents you from getting shut out more easily 114 | function randomIntFromInterval(min,max) 115 | { 116 | return Math.floor(Math.random()*(max-min+1)+min); 117 | } 118 | 119 | run() -------------------------------------------------------------------------------- /section-2/node-puppeteer/simpleScraping.js: -------------------------------------------------------------------------------- 1 | const puppeteer = require('puppeteer') 2 | 3 | async function scrape() { 4 | const browser = await puppeteer.launch({headless: false}) 5 | const page = await browser.newPage() 6 | 7 | await page.goto('http://books.toscrape.com/') 8 | const lightInTheAtticSelector = '#default > div > div > div > div > section > div:nth-child(2) > ol > li:nth-child(1) > article > div.image_container > a > img' 9 | await page.click(lightInTheAtticSelector) 10 | await page.waitFor(1000) 11 | 12 | const result = await page.evaluate(() => { 13 | let title = document.querySelector('h1').innerText 14 | let price = document.querySelector('.price_color').innerText 15 | 16 | return { 17 | title, 18 | price 19 | } 20 | 21 | }) 22 | 23 | browser.close() 24 | return result 25 | } 26 | 27 | scrape().then((value) => { 28 | console.log(value) // Success! 29 | }) -------------------------------------------------------------------------------- /section-2/node-puppeteer/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | agent-base@^4.1.0: 6 | version "4.2.1" 7 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" 8 | dependencies: 9 | es6-promisify "^5.0.0" 10 | 11 | async-limiter@~1.0.0: 12 | version "1.0.0" 13 | resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" 14 | 15 | balanced-match@^1.0.0: 16 | version "1.0.0" 17 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 18 | 19 | brace-expansion@^1.1.7: 20 | version "1.1.11" 21 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 22 | dependencies: 23 | balanced-match "^1.0.0" 24 | concat-map "0.0.1" 25 | 26 | buffer-from@^1.0.0: 27 | version "1.1.1" 28 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" 29 | 30 | concat-map@0.0.1: 31 | version "0.0.1" 32 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 33 | 34 | concat-stream@1.6.2: 35 | version "1.6.2" 36 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" 37 | dependencies: 38 | buffer-from "^1.0.0" 39 | inherits "^2.0.3" 40 | readable-stream "^2.2.2" 41 | typedarray "^0.0.6" 42 | 43 | core-util-is@~1.0.0: 44 | version "1.0.2" 45 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 46 | 47 | debug@2.6.9: 48 | version "2.6.9" 49 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 50 | dependencies: 51 | ms "2.0.0" 52 | 53 | debug@^3.1.0: 54 | version "3.2.6" 55 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 56 | dependencies: 57 | ms "^2.1.1" 58 | 59 | es6-promise@^4.0.3: 60 | version "4.2.5" 61 | resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054" 62 | 63 | es6-promisify@^5.0.0: 64 | version "5.0.0" 65 | resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" 66 | dependencies: 67 | es6-promise "^4.0.3" 68 | 69 | extract-zip@^1.6.6: 70 | version "1.6.7" 71 | resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" 72 | dependencies: 73 | concat-stream "1.6.2" 74 | debug "2.6.9" 75 | mkdirp "0.5.1" 76 | yauzl "2.4.1" 77 | 78 | fd-slicer@~1.0.1: 79 | version "1.0.1" 80 | resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" 81 | dependencies: 82 | pend "~1.2.0" 83 | 84 | fs.realpath@^1.0.0: 85 | version "1.0.0" 86 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 87 | 88 | glob@^7.0.5: 89 | version "7.1.3" 90 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" 91 | dependencies: 92 | fs.realpath "^1.0.0" 93 | inflight "^1.0.4" 94 | inherits "2" 95 | minimatch "^3.0.4" 96 | once "^1.3.0" 97 | path-is-absolute "^1.0.0" 98 | 99 | https-proxy-agent@^2.2.1: 100 | version "2.2.1" 101 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" 102 | dependencies: 103 | agent-base "^4.1.0" 104 | debug "^3.1.0" 105 | 106 | inflight@^1.0.4: 107 | version "1.0.6" 108 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 109 | dependencies: 110 | once "^1.3.0" 111 | wrappy "1" 112 | 113 | inherits@2, inherits@^2.0.3, inherits@~2.0.3: 114 | version "2.0.3" 115 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 116 | 117 | isarray@~1.0.0: 118 | version "1.0.0" 119 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 120 | 121 | mime@^2.0.3: 122 | version "2.3.1" 123 | resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" 124 | 125 | minimatch@^3.0.4: 126 | version "3.0.4" 127 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 128 | dependencies: 129 | brace-expansion "^1.1.7" 130 | 131 | minimist@0.0.8: 132 | version "0.0.8" 133 | resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 134 | 135 | mkdirp@0.5.1: 136 | version "0.5.1" 137 | resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 138 | dependencies: 139 | minimist "0.0.8" 140 | 141 | ms@2.0.0: 142 | version "2.0.0" 143 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 144 | 145 | ms@^2.1.1: 146 | version "2.1.1" 147 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 148 | 149 | once@^1.3.0: 150 | version "1.4.0" 151 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 152 | dependencies: 153 | wrappy "1" 154 | 155 | path-is-absolute@^1.0.0: 156 | version "1.0.1" 157 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 158 | 159 | pend@~1.2.0: 160 | version "1.2.0" 161 | resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" 162 | 163 | process-nextick-args@~2.0.0: 164 | version "2.0.0" 165 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" 166 | 167 | progress@^2.0.0: 168 | version "2.0.0" 169 | resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" 170 | 171 | proxy-from-env@^1.0.0: 172 | version "1.0.0" 173 | resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" 174 | 175 | puppeteer@^1.9.0: 176 | version "1.9.0" 177 | resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.9.0.tgz#56dba79e7ea4faac807877bee3b23d63291fc59e" 178 | dependencies: 179 | debug "^3.1.0" 180 | extract-zip "^1.6.6" 181 | https-proxy-agent "^2.2.1" 182 | mime "^2.0.3" 183 | progress "^2.0.0" 184 | proxy-from-env "^1.0.0" 185 | rimraf "^2.6.1" 186 | ws "^5.1.1" 187 | 188 | readable-stream@^2.2.2: 189 | version "2.3.6" 190 | resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" 191 | dependencies: 192 | core-util-is "~1.0.0" 193 | inherits "~2.0.3" 194 | isarray "~1.0.0" 195 | process-nextick-args "~2.0.0" 196 | safe-buffer "~5.1.1" 197 | string_decoder "~1.1.1" 198 | util-deprecate "~1.0.1" 199 | 200 | rimraf@^2.6.1: 201 | version "2.6.2" 202 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" 203 | dependencies: 204 | glob "^7.0.5" 205 | 206 | safe-buffer@~5.1.0, safe-buffer@~5.1.1: 207 | version "5.1.2" 208 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 209 | 210 | string_decoder@~1.1.1: 211 | version "1.1.1" 212 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 213 | dependencies: 214 | safe-buffer "~5.1.0" 215 | 216 | typedarray@^0.0.6: 217 | version "0.0.6" 218 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 219 | 220 | util-deprecate@~1.0.1: 221 | version "1.0.2" 222 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 223 | 224 | wrappy@1: 225 | version "1.0.2" 226 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 227 | 228 | ws@^5.1.1: 229 | version "5.2.2" 230 | resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" 231 | dependencies: 232 | async-limiter "~1.0.0" 233 | 234 | yauzl@2.4.1: 235 | version "2.4.1" 236 | resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" 237 | dependencies: 238 | fd-slicer "~1.0.1" 239 | -------------------------------------------------------------------------------- /section-2/rita-pos-matching/_DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veev/DataArtFall2018/9fd4af8624ee40dc894a91d8d5378aa45fb8b2df/section-2/rita-pos-matching/_DS_Store -------------------------------------------------------------------------------- /section-2/rita-pos-matching/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | sentence histogram example 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /section-2/rita-pos-matching/sketch.js: -------------------------------------------------------------------------------- 1 | let timeTravelerMatches 2 | let index = 0 3 | let count = 0 4 | let period = 100 5 | 6 | function setup() { 7 | createCanvas(1200, 800) 8 | loadJSON('../data/time-machine-clean.json', loadText) 9 | } 10 | 11 | function loadText(file) { 12 | console.log('loaded', file) 13 | 14 | // use the RiTa library to split text into sentences 15 | const sentences = RiTa.splitSentences(file.text) 16 | // console.log(sentences) 17 | 18 | // find sentences that follow the same part of speech pattern as the string: 'The Time Traveler was' 19 | timeTravelerMatches = searchByPOS(sentences, 'The Time Traveler was') 20 | console.log(timeTravelerMatches) 21 | } 22 | 23 | function draw() { 24 | // make sure we have an array of matching strings before trying to draw them 25 | if (timeTravelerMatches) { 26 | // settings to draw 27 | background(0) 28 | textSize(24) 29 | textAlign(CENTER, CENTER) 30 | fill(255) 31 | 32 | text(timeTravelerMatches[index], 0, 0, width, height) 33 | 34 | // code to cycle through sentences 35 | count++ 36 | if (count === period) { 37 | if (index < timeTravelerMatches.length - 1) { 38 | index++ 39 | } else { 40 | index = 0 41 | } 42 | count = 0 43 | if (period > 1) period-- 44 | } 45 | } 46 | } 47 | 48 | function searchByPOS(array, posPattern) { 49 | // use RiTa to get part of speech pattern of string 50 | const pos = RiTa.getPosTags(posPattern) 51 | console.log(pos) 52 | 53 | // joing the array of parts of speech so we have a string to match against 54 | const posString = join(pos, ' ') 55 | // console.log(posString) 56 | 57 | // go through the sentences and see which have the same part of speech pattern 58 | const posMatches = array.filter((line, index) => { 59 | const poses = RiTa.getPosTags(line) 60 | 61 | const posesString = join(poses, ' ') 62 | // console.log(posesString) 63 | 64 | // return the ones that match 65 | return posesString.indexOf(posString) != -1 66 | }) 67 | 68 | // return the array of matching sentences 69 | return posMatches 70 | } -------------------------------------------------------------------------------- /section-2/sentence-histogram/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | sentence histogram example 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /section-2/sentence-histogram/sketch.js: -------------------------------------------------------------------------------- 1 | function setup() { 2 | createCanvas(1200, 2000) 3 | loadJSON('../data/time-machine-clean.json', loadText) 4 | } 5 | 6 | function loadText(file) { 7 | console.log('loaded', file) 8 | 9 | // use regex to find the sentences withtin the text, search for punctuation marks like . ! ? 10 | const sentences = file.text.match(/[^\.!\?]+[\.!?]+/g) 11 | 12 | console.log('the book is ' + sentences.length + 'sentences long') 13 | 14 | // make an array for all the character lengths of the sentences 15 | const sentencesLengths = sentences.map( sentence => { 16 | const numChars = sentence.length 17 | return numChars 18 | }) 19 | 20 | console.log("Longest is " + max(sentencesLengths) + " chars long") 21 | console.log("Shortest is " + min(sentencesLengths) + " chars long") 22 | 23 | // make the histogram 24 | sentencesLengths.forEach( (sL, i) => { 25 | console.log(sL, i) 26 | let x = 0 27 | let y = 0 28 | let w = map(sL, min(sentencesLengths), max(sentencesLengths), 2, width - 10) 29 | // color the line according to whether the word time appears in the sentence (red), if not blue 30 | sentences[i].toLowerCase().indexOf('time') > 0 ? fill(255, 0, 0) : fill(0, 0, 255) 31 | noStroke() 32 | rect(x, y + i, w, 1) 33 | }) 34 | } -------------------------------------------------------------------------------- /section-3/city-council-districts/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mobile phones 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 |
21 | 22 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /section-3/generate-geometry/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mobile phones 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 17 | 18 |
19 | 20 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /section-3/mapbox-mobile-phones/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mobile phones 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | 17 |
18 | 19 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /section-3/node-convert-to-geojson/convert.js: -------------------------------------------------------------------------------- 1 | // download csv here: https://developer.here.com/documentation/geovisualization/topics/sample-datasets.html 2 | 3 | const fs = require('fs') 4 | // install node-csv-parse with npm 5 | const parse = require('csv-parse/lib/sync') 6 | 7 | const data = fs.readFileSync('../data/Mobile_activity_3months_scrambled.csv', 'utf8') 8 | // console.log(data.length) 9 | // console.log(data[10]) 10 | const parsedData = parse(data) 11 | // console.log(parsedData.length) 12 | // console.log(parsedData[9]) 13 | 14 | // what format do we want our data in order to put it on a map? 15 | // GeoJson! What kind of geojson is it? 16 | // Point - each coordinate is a point feature (instead of Line, Polygon or MultiPolygon)\ 17 | 18 | // Basic Format of Point feature in GeoJson 19 | /* 20 | { 21 | "type": "Feature", 22 | "geometry": { 23 | "type": "Point", 24 | "coordinates": [ lon, lat] // for NYC [-73.984931, 40.755603] 25 | }, 26 | "properties": { 27 | "timestep": val, 28 | "count": val 29 | } 30 | } 31 | */ 32 | 33 | // Iterate through data array and create feature Point objects for each row 34 | const geoJson = parsedData.map( row => { 35 | 36 | const featureObj = {} 37 | featureObj.type = "Feature" 38 | featureObj.geometry = {} 39 | featureObj.properties = {} 40 | 41 | featureObj.geometry.type = "Point" 42 | featureObj.geometry.coordinates = [row[1], row[0]] 43 | 44 | featureObj.properties.timestep = row[2] 45 | featureObj.properties.count = +row[3] 46 | 47 | return featureObj 48 | }).filter( (feature, index) => index > 0 && feature.properties.timestep === '2') // remove first feature with the header info and only get data for first month 49 | 50 | const geoJsonFeatureCollection = {} 51 | geoJsonFeatureCollection.type = "FeatureCollection" 52 | geoJsonFeatureCollection.features = geoJson 53 | 54 | fs.writeFileSync('../data/Mobile_activity_1month_scrambled.geojson', JSON.stringify(geoJsonFeatureCollection, null, 4), 'utf8') 55 | -------------------------------------------------------------------------------- /section-3/node-convert-to-geojson/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "convert-to-geojson", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "csv-parse": { 8 | "version": "3.1.3", 9 | "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-3.1.3.tgz", 10 | "integrity": "sha512-fs+nzn0lU+e7uZHkY/SvEYiRT3PCvb746csfl238iUXh1D+gzzN4crzgZ7gkVDutoPWYwfrFSQaSAulSeynTlg==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /section-3/node-convert-to-geojson/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "convert-to-geojson", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "convert.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "csv-parse": "^3.1.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /section-4/d3-bubbleplot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Drawing a Bubbleplot with d3 6 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /section-4/d3-bubbleplot/sketch.js: -------------------------------------------------------------------------------- 1 | // Declare some global variables that define our svg 2 | const width = 800, // canvas width and height 3 | height = 500, 4 | margin = 20, 5 | w = width - 2 * margin, // chart area width and height 6 | h = height - 2 * margin; 7 | 8 | // Create scale ranges (what the data will map to: width, height, radius) 9 | // We can create the scale and the range since we know the size we want 10 | // for the display. The domain can be added later once the data is loaded 11 | const xScale = d3.scaleLinear() 12 | .range([margin, width - margin]) // set the domain after loading data 13 | 14 | // d3's origin is at the upper left top 15 | // set yScale so that smaller values start at height of svg 16 | // and larger values are closer to the top 17 | const yScale = d3.scaleLinear() 18 | .range([height - margin, margin]) 19 | 20 | const sizeScale = d3.scalePow() 21 | .exponent(0.5) 22 | .range([10, 100]); 23 | 24 | // Create the svg container to draw into 25 | const svg = d3.select("body") 26 | .append("svg") 27 | .attr("width", width) 28 | .attr("height", height) 29 | .append("g") 30 | 31 | // Create an empty div for the tooltip 32 | const tooltip = d3.select("body") 33 | .append("div") 34 | .style("position", "absolute") 35 | .style("z-index", "10") 36 | .style("visibility", "hidden") 37 | .style("pointer-events", "none!important") 38 | .text("a simple tooltip") 39 | 40 | // Load in our data 41 | // v5 Promises way 42 | d3.csv("../data/worldwide-health-lifeexpectancy-cut.csv").then(data => { 43 | console.log(data) 44 | 45 | // Map the data so it has better key names (accessors) 46 | // We need to use brackets instead of dot notation to access the existing keys 47 | // since they have spaces in the them - access as strings 48 | const mappedData = data.map( d => { 49 | return { 50 | name: d["Country Name"], 51 | code: d["Country Code"], 52 | health: d["2014 Health expenditure, total (% of GDP)"], 53 | life: d["2014 Life expectancy at birth, total (years)"], 54 | population: d["2014 Population, total"] 55 | }; 56 | }); 57 | console.log(mappedData) 58 | 59 | // filter out rows with fields that don't contain all data fields 60 | const filteredData = mappedData.filter( d => { 61 | if (d.health != "" && d.life != "" && d.population != "") { 62 | return d 63 | } 64 | }) 65 | console.log(filteredData) 66 | 67 | // Set the domains of the scales using d3.extent 68 | // (returns the min and max of the data array) 69 | xScale.domain(d3.extent(filteredData, d => { 70 | return +d.life 71 | })) 72 | 73 | yScale.domain(d3.extent(filteredData, d => { 74 | return +d.health 75 | })) 76 | 77 | sizeScale.domain(d3.extent(filteredData, d => { 78 | return +d.population 79 | })) 80 | 81 | // Create our circles, one for each country 82 | // D3 selects svg elements before they exist 83 | // in order to bind data 84 | const circles = svg.selectAll("circle") 85 | .data(filteredData) // bind the data 86 | .enter() // update the subselection with data 87 | .append("circle") //append circle svg elements to svg context 88 | .attr("fill", d3.rgb(255, 0, 255)) // color the circle svg elements 89 | .attr("fill-opacity", 0.2) // make it so they are not fully opaque (since there is overlap) 90 | .attr("cx", d => { 91 | return xScale(+d.life) // the x coordinate comes from the xScale function, mapping the life key value of each data element to the width 92 | }) 93 | .attr("cy", d => { 94 | return yScale(+d.health) // the y coordinate comes from the yScale function, mapping the health key value of each data element to the height 95 | }) 96 | .attr("r", d => { 97 | return sizeScale(+d.population) / 2 // the radius comes from the sizeScale function (a power scale), mapping the population key value between 10 and 100 98 | }) 99 | .on("mouseenter", () => { 100 | tooltip.style("visibility", "visible") // make sure it's visible on entering the element 101 | return tooltip 102 | }) 103 | .on("mousemove", d => { 104 | tooltip.text(d.name) // update tooltip with data we want 105 | tooltip.style('left', d3.event.pageX + 'px') // position the tooltip based on mouseX and mouseY 106 | .style('top', d3.event.pageY - 28 + 'px'); 107 | 108 | return tooltip 109 | }) 110 | .on("mouseout", () => { 111 | return tooltip.style("visibility", "hidden") // turn it off when you leave the element 112 | }) 113 | }).catch( e => { 114 | console.log(e) 115 | }) -------------------------------------------------------------------------------- /section-4/d3-update-pattern/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | d3 Update Pattern 6 | 15 | 16 | 17 |
18 | 19 | 24 | 25 | 26 | 134 | 135 | -------------------------------------------------------------------------------- /section-4/data/worldwide-health-lifeexpectancy-cut.csv: -------------------------------------------------------------------------------- 1 | Country Name,Country Code,"2014 Health expenditure, total (% of GDP)","2014 Life expectancy at birth, total (years)","2014 Population, total" Aruba,ABW,,75.45678049,103795 Afghanistan,AFG,8.18227382,62.90268293,32758020 Angola,AGO,3.30698293,60.80673171,26920466 Albania,ALB,5.88310543,77.99839024,2889104 Andorra,AND,8.12713561,,79223 United Arab Emirates,ARE,3.64398564,77.32936585,9070867 Argentina,ARG,4.78591616,76.134,42981515 Armenia,ARM,4.48014942,74.01958537,2906220 American Samoa,ASM,,,55437 Antigua and Barbuda,ATG,5.54168311,75.92409756,98875 Australia,AUS,9.42230024,82.3,23460694 Austria,AUT,11.20547328,81.4902439,8541575 Azerbaijan,AZE,6.0368632,71.7247561,9535079 Burundi,BDI,7.53556539,56.66331707,9891790 Belgium,BEL,10.5947509,81.28780488,11209057 Benin,BEN,4.59429651,60.31812195,10286712 Burkina Faso,BFA,4.96026323,59.37529268,17585977 Bangladesh,BGD,2.81899856,71.87165854,159405279 Bulgaria,BGR,8.44291326,74.46585366,7223938 Bahrain,BHR,4.98079638,76.72546341,1336397 The Bahamas,BHS,7.74236489,75.21763415,382169 Bosnia and Herzegovina,BIH,9.57201597,76.46356098,3566002 Belarus,BLR,5.68772158,72.97073171,9474511 Belize,BLZ,5.78895004,70.1475122,351694 Bermuda,BMU,,80.79731707,65139 Bolivia,BOL,6.33482729,68.35031707,10562159 Brazil,BRA,8.32283359,74.9582439,204213133 Barbados,BRB,7.469303,75.48390244,283385 Brunei Darussalam,BRN,2.64816289,76.94173171,411704 Bhutan,BTN,3.57301481,69.41797561,776448 Botswana,BWA,5.41200262,64.69439024,2168573 Central African Republic,CAF,4.20022213,50.59104878,4515392 Canada,CAN,10.449582,81.95304878,35544564 Switzerland,CHE,11.65926872,83.19756098,8188649 Channel Islands,CHI,,80.735,162969 Chile,CHL,7.78585767,78.9644878,17613798 China,CHN,5.54822768,75.95719512,1364270000 Cote d'Ivoire,CIV,5.71627357,52.54707317,22531350 Cameroon,CMR,4.10367158,57.08780488,22239904 "Congo, Dem. Rep.",COD,4.32823361,58.74860976,73722860 "Congo, Rep.",COG,5.15141136,63.51531707,4871101 Colombia,COL,7.20129855,73.97895122,47791911 Comoros,COM,6.74764314,63.20214634,759385 Cabo Verde,CPV,4.75969597,72.25431707,526437 Costa Rica,CRI,9.31311229,79.41685366,4757575 Caribbean small states,CSS,6.114070674,72.91101405,7162679 Cuba,CUB,11.05880043,79.38970732,11439767 Curacao,CUW,,77.82439024,155909 Cayman Islands,CYM,,,59172 Cyprus,CYP,7.36761162,80.12204878,1152309 Czech Republic,CZE,7.41091154,78.82439024,10525347 Germany,DEU,11.29700067,81.0902439,80982500 Djibouti,DJI,10.56825612,61.99431707,912164 Dominica,DMA,5.48583257,,72778 Denmark,DNK,10.80495696,80.7,5643475 Dominican Republic,DOM,4.37577756,73.51619512,10405844 Algeria,DZA,7.20717804,75.63502439,39113313 Ecuador,ECU,9.16108824,75.85973171,15903112 Egypt,EGY,5.64211505,71.10956098,91812566 Eritrea,ERI,3.33829318,64.16339024, Spain,ESP,9.02988651,83.22926829,46480882 Estonia,EST,6.37929421,77.03414634,1314545 Ethiopia,ETH,4.88431325,64.50690244,97366774 Finland,FIN,9.67990894,81.1804878,5461512 Fiji,FJI,4.48749874,70.07112195,885806 France,FRA,11.53951975,82.67073171,66331957 Faroe Islands,FRO,,81.48536585,48842 Micronesia,FSM,13.70691454,68.93490244,104015 Gabon,GAB,3.43747162,65.20302439,1875713 United Kingdom,GBR,9.11547172,81.30487805,64613160 Georgia,GEO,7.4166592,72.82063415,3727000 Ghana,GHA,3.55729189,62.11378049,26962563 Gibraltar,GIB,,,34038 Guinea,GIN,5.64479793,58.82490244,11805509 The Gambia,GMB,7.34040076,60.71385366,1917852 Guinea-Bissau,GNB,5.59313736,56.54821951,1725744 Equatorial Guinea,GNQ,3.80407904,57.25553659,1129424 Greece,GRC,8.08426702,81.43658537,10892413 Grenada,GRD,6.09761403,73.35334146,106360 Greenland,GRL,,,56295 Guatemala,GTM,6.20230127,72.76202439,15923559 Guam,GUM,,79.17373171,160967 Guyana,GUY,5.2478035,66.42614634,763393 "Hong Kong SAR, China",HKG,,83.9804878,7241700 Honduras,HND,8.72268046,73.12990244,8809216 Croatia,HRV,7.80324176,77.47804878,4238389 Haiti,HTI,7.55565419,62.71314634,10572466 Hungary,HUN,7.40078093,75.76341463,9866468 Indonesia,IDN,2.84686016,68.8684878,255131116 India,IND,4.68508833,68.05002439,1293859294 Ireland,IRL,7.78319657,81.34878049,4617225 "Iran, Islamic Rep.",IRN,6.8949223,75.47819512,78411092 Iraq,IRQ,5.53887318,69.42560976,35006080 Iceland,ISL,8.85916593,82.86097561,327386 Israel,ISR,7.80830808,82.15365854,8215700 Italy,ITA,9.24791783,83.0902439,60789140 Jamaica,JAM,5.36152479,75.65853659,2862087 Jordan,JOR,7.45299586,74.04495122,8809306 Japan,JPN,10.22874408,83.58780488,127276000 Kazakhstan,KAZ,4.35593983,71.62,17289224 Kenya,KEN,5.72029126,66.19414634,46024250 Kyrgyz Republic,KGZ,6.48376219,70.40243902,5835500 Cambodia,KHM,5.67563855,68.1062439,15270790 Kiribati,KIR,10.21295042,65.87060976,110458 St. Kitts and Nevis,KNA,5.08036532,,53739 "Korea, Rep.",KOR,7.37311255,82.15585366,50746659 Kuwait,KWT,3.04236844,74.6234878,3782450 Lao PDR,LAO,1.86554551,65.92263415,6576397 Lebanon,LBN,6.39370883,79.32626829,5603279 Liberia,LBR,10.03633328,61.5012439,4390737 Libya,LBY,4.96893503,71.71939024,6204108 St. Lucia,LCA,6.71904145,75.10436585,176421 Liechtenstein,LIE,,82.07317073,37127 Sri Lanka,LKA,3.50335011,74.81465854,20771000 Lesotho,LSO,10.61767672,53.09321951,2145785 Lithuania,LTU,6.55211709,74.51707317,2932367 Luxembourg,LUX,6.93787356,82.22926829,556319 Latvia,LVA,5.88069354,74.12439024,1993782 "Macao SAR, China",MAC,,83.42692683,588781 St. Martin (French part),MAF,,79.32195122,31530 Morocco,MAR,5.90777806,75.25514634,34318082 Monaco,MCO,4.337683,,38132 Moldova,MDA,10.32365569,71.16168293,3556397 Madagascar,MDG,3.04135502,65.10131707,23589801 Maldives,MDV,13.73352009,76.85587805,401000 Mexico,MEX,6.29642103,76.69917073,124221600 Marshall Islands,MHL,17.13572274,,52898 "Macedonia, FYR",MKD,6.47637457,75.358,2077495 Mali,MLI,6.86216649,56.98670732,16962846 Malta,MLT,9.74992027,81.94634146,427364 Myanmar,MMR,2.27575459,66.20721951,51924182 Montenegro,MNE,6.41654268,76.63885366,621810 Mongolia,MNG,4.73034173,68.88260976,2923896 Northern Mariana Islands,MNP,,,54468 Mozambique,MOZ,6.97558186,56.99434146,27212382 Mauritania,MRT,3.77269904,62.8702439,4063920 Mauritius,MUS,4.80954464,74.19439024,1260934 Malawi,MWI,11.37795606,61.81660976,17068838 Malaysia,MYS,4.16907804,75.05370732,30228017 Namibia,NAM,8.92868766,62.83892683,2370992 New Caledonia,NCL,,77.57317073,268000 Niger,NER,5.82129922,59.2405122,19148219 Nigeria,NGA,3.66879844,52.54134146,176460502 Nicaragua,NIC,9.04013941,74.77278049,6013997 Netherlands,NLD,10.89729305,81.70731707,16865008 Norway,NOR,9.71971755,82.1,5137232 Nepal,NPL,5.797226,69.49897561,28323241 Nauru,NRU,3.32664948,,11853 New Zealand,NZL,11.0296101,81.40487805,4509700 Pakistan,PAK,2.61391631,66.14919512,185546257 Panama,PAN,8.0257236,77.62543902,3903986 Peru,PER,5.47303468,74.48536585,30973354 Philippines,PHL,4.7099852,68.87017073,100102249 Palau,PLW,9.02153343,,21094 Papua New Guinea,PNG,4.26357082,65.23407317,7755785 Poland,POL,6.35024637,77.60243902,38011735 Puerto Rico,PRI,,79.39012195,3534874 "Korea, Dem. People’s Rep.",PRK,,70.95207317,25116363 Portugal,PRT,9.50107564,81.12195122,10401062 Paraguay,PRY,9.81442131,72.93241463,6552584 West Bank and Gaza,PSE,,73.12812195,4294682 French Polynesia,PYF,,76.50695122,275484 Qatar,QAT,2.18706236,78.3035122,2374419 Romania,ROU,5.56500913,74.96097561,19908979 Russian Federation,RUS,7.07040825,70.74365854,143819666 Rwanda,RWA,7.53155111,66.11334146,11345357 Saudi Arabia,SAU,4.68408481,74.39739024,30776722 Sudan,SDN,8.42877471,63.97473171,37737913 Senegal,SEN,4.66497201,66.25782927,14546111 Singapore,SGP,4.92279194,82.49512195,5469724 Solomon Islands,SLB,5.05106254,70.16231707,575504 Sierra Leone,SLE,11.08990224,50.94260976,7079162 El Salvador,SLV,6.77240285,72.75529268,6281189 San Marino,SMR,6.12906486,,32657 Somalia,SOM,,55.46568293,13513125 Serbia,SRB,10.36881192,75.33658537,7130576 South Sudan,SSD,2.73842073,55.7964878,11530971 Sao Tome and Principe,STP,8.35346606,66.29070732,191266 Suriname,SUR,5.68746988,71.14697561,547928 Slovak Republic,SVK,8.05404755,76.81219512,5418649 Slovenia,SVN,9.23388628,81.07804878,2061980 Sweden,SWE,11.92983965,82.25365854,9696110 Swaziland,SWZ,9.25193954,56.10146341,1295097 Sint Maarten (Dutch part),SXM,,,37685 Seychelles,SYC,3.36981689,73.22926829,91359 Syrian Arab Republic,SYR,3.25453108,70.16321951,19203090 Turks and Caicos Islands,TCA,,,33739 Chad,TCD,3.6211644,52.18107317,13569438 Togo,TGO,5.24687674,59.57634146,7228915 Thailand,THA,4.122164481,74.86404878,68416772 Tajikistan,TJK,6.880884,70.82697561,8362745 Turkmenistan,TKM,2.06738625,67.49068293,5466241 Timor-Leste,TLS,1.47530345,68.29295122,1212814 Tonga,TON,5.17677064,72.70136585,105782 Trinidad and Tobago,TTO,5.93319696,70.45965854,1354493 Tunisia,TUN,7.00385794,75.31434146,11143908 Turkey,TUR,5.41495949,75.15214634,77030628 Tuvalu,TUV,16.53663877,,10908 Tanzania,TZA,5.58011591,64.1184878,52234869 Uganda,UGA,7.22213686,59.15580488,38833338 Ukraine,UKR,7.09573611,71.18658537,45271947 Uruguay,URY,8.5814914,76.98209756,3419546 United States,USA,17.14075435,78.74146341,318563456 Uzbekistan,UZB,5.83852176,70.99339024,30757700 St. Vincent and the Grenadines,VCT,8.63023974,72.9395122,109357 "Venezuela, RB",VEN,5.2567025,74.22614634,30738378 British Virgin Islands,VGB,,,29588 Virgin Islands (U.S.),VIR,,79.77317073,104170 Vietnam,VNM,7.06677833,75.69529268,90728900 Vanuatu,VUT,5.02357493,71.772,258850 Samoa,WSM,7.21510906,74.58007317,192290 Kosovo,XKX,,71.09756098,1821800 "Yemen, Rep.",YEM,5.63699019,64.50717073,26246327 South Africa,ZAF,8.79698456,60.95478049,54146734.74 Zambia,ZMB,4.98676469,60.71534146,15620974 Zimbabwe,ZWE,6.43947119,59.24431707,15411675 -------------------------------------------------------------------------------- /section-4/data/worldwide-health-lifeexpectancy.csv: -------------------------------------------------------------------------------- 1 | Country Name,Country Code,"2014 Health expenditure, total (% of GDP)","2014 Life expectancy at birth, total (years)","2014 Population, total" Aruba,ABW,,75.45678049,103795 Afghanistan,AFG,8.18227382,62.90268293,32758020 Angola,AGO,3.30698293,60.80673171,26920466 Albania,ALB,5.88310543,77.99839024,2889104 Andorra,AND,8.12713561,,79223 Arab World,ARB,4.874426767,70.82758949,390043028 United Arab Emirates,ARE,3.64398564,77.32936585,9070867 Argentina,ARG,4.78591616,76.134,42981515 Armenia,ARM,4.48014942,74.01958537,2906220 American Samoa,ASM,,,55437 Antigua and Barbuda,ATG,5.54168311,75.92409756,98875 Australia,AUS,9.42230024,82.3,23460694 Austria,AUT,11.20547328,81.4902439,8541575 Azerbaijan,AZE,6.0368632,71.7247561,9535079 Burundi,BDI,7.53556539,56.66331707,9891790 Belgium,BEL,10.5947509,81.28780488,11209057 Benin,BEN,4.59429651,60.31812195,10286712 Burkina Faso,BFA,4.96026323,59.37529268,17585977 Bangladesh,BGD,2.81899856,71.87165854,159405279 Bulgaria,BGR,8.44291326,74.46585366,7223938 Bahrain,BHR,4.98079638,76.72546341,1336397 The Bahamas,BHS,7.74236489,75.21763415,382169 Bosnia and Herzegovina,BIH,9.57201597,76.46356098,3566002 Belarus,BLR,5.68772158,72.97073171,9474511 Belize,BLZ,5.78895004,70.1475122,351694 Bermuda,BMU,,80.79731707,65139 Bolivia,BOL,6.33482729,68.35031707,10562159 Brazil,BRA,8.32283359,74.9582439,204213133 Barbados,BRB,7.469303,75.48390244,283385 Brunei Darussalam,BRN,2.64816289,76.94173171,411704 Bhutan,BTN,3.57301481,69.41797561,776448 Botswana,BWA,5.41200262,64.69439024,2168573 Central African Republic,CAF,4.20022213,50.59104878,4515392 Canada,CAN,10.449582,81.95304878,35544564 Central Europe and the Baltics,CEB,6.844175779,76.68547642,103496179 Switzerland,CHE,11.65926872,83.19756098,8188649 Channel Islands,CHI,,80.735,162969 Chile,CHL,7.78585767,78.9644878,17613798 China,CHN,5.54822768,75.95719512,1364270000 Cote d'Ivoire,CIV,5.71627357,52.54707317,22531350 Cameroon,CMR,4.10367158,57.08780488,22239904 "Congo, Dem. Rep.",COD,4.32823361,58.74860976,73722860 "Congo, Rep.",COG,5.15141136,63.51531707,4871101 Colombia,COL,7.20129855,73.97895122,47791911 Comoros,COM,6.74764314,63.20214634,759385 Cabo Verde,CPV,4.75969597,72.25431707,526437 Costa Rica,CRI,9.31311229,79.41685366,4757575 Caribbean small states,CSS,6.114070674,72.91101405,7162679 Cuba,CUB,11.05880043,79.38970732,11439767 Curacao,CUW,,77.82439024,155909 Cayman Islands,CYM,,,59172 Cyprus,CYP,7.36761162,80.12204878,1152309 Czech Republic,CZE,7.41091154,78.82439024,10525347 Germany,DEU,11.29700067,81.0902439,80982500 Djibouti,DJI,10.56825612,61.99431707,912164 Dominica,DMA,5.48583257,,72778 Denmark,DNK,10.80495696,80.7,5643475 Dominican Republic,DOM,4.37577756,73.51619512,10405844 Algeria,DZA,7.20717804,75.63502439,39113313 East Asia & Pacific (excluding high income),EAP,5.256967833,74.18315026,2022021082 Early-demographic dividend,EAR,5.283748459,69.25956118,3083836360 East Asia & Pacific,EAS,6.887218179,75.10255302,2265898057 Europe & Central Asia (excluding high income),ECA,6.420824961,72.29512938,412510951 Europe & Central Asia,ECS,9.501980993,77.20707533,903094668 Ecuador,ECU,9.16108824,75.85973171,15903112 Egypt,EGY,5.64211505,71.10956098,91812566 Euro area,EMU,10.44466255,81.9348744,338429646 Eritrea,ERI,3.33829318,64.16339024, Spain,ESP,9.02988651,83.22926829,46480882 Estonia,EST,6.37929421,77.03414634,1314545 Ethiopia,ETH,4.88431325,64.50690244,97366774 European Union,EUU,10.03950262,80.92222407,508157247 Fragile and conflict affected situations,FCS,5.716773569,61.71015899,482474449 Finland,FIN,9.67990894,81.1804878,5461512 Fiji,FJI,4.48749874,70.07112195,885806 France,FRA,11.53951975,82.67073171,66331957 Faroe Islands,FRO,,81.48536585,48842 Micronesia,FSM,13.70691454,68.93490244,104015 Gabon,GAB,3.43747162,65.20302439,1875713 United Kingdom,GBR,9.11547172,81.30487805,64613160 Georgia,GEO,7.4166592,72.82063415,3727000 Ghana,GHA,3.55729189,62.11378049,26962563 Gibraltar,GIB,,,34038 Guinea,GIN,5.64479793,58.82490244,11805509 The Gambia,GMB,7.34040076,60.71385366,1917852 Guinea-Bissau,GNB,5.59313736,56.54821951,1725744 Equatorial Guinea,GNQ,3.80407904,57.25553659,1129424 Greece,GRC,8.08426702,81.43658537,10892413 Grenada,GRD,6.09761403,73.35334146,106360 Greenland,GRL,,,56295 Guatemala,GTM,6.20230127,72.76202439,15923559 Guam,GUM,,79.17373171,160967 Guyana,GUY,5.2478035,66.42614634,763393 High income,HIC,12.26274085,80.61483831,1175966521 "Hong Kong SAR, China",HKG,,83.9804878,7241700 Honduras,HND,8.72268046,73.12990244,8809216 Heavily indebted poor countries (HIPC),HPC,6.040348315,61.16724084,704745420 Croatia,HRV,7.80324176,77.47804878,4238389 Haiti,HTI,7.55565419,62.71314634,10572466 Hungary,HUN,7.40078093,75.76341463,9866468 IBRD only,IBD,5.926848854,72.34335635,4607807731 IDA & IBRD total,IBT,5.82652382,70.02402922,6112778045 IDA total,IDA,4.46359958,62.92237258,1504970314 IDA blend,IDB,3.831822192,61.03881152,497751634 Indonesia,IDN,2.84686016,68.8684878,255131116 IDA only,IDX,5.169367621,63.8531217,1007218680 Isle of Man,IMN,,,82590 India,IND,4.68508833,68.05002439,1293859294 Not classified,INX,,, Ireland,IRL,7.78319657,81.34878049,4617225 "Iran, Islamic Rep.",IRN,6.8949223,75.47819512,78411092 Iraq,IRQ,5.53887318,69.42560976,35006080 Iceland,ISL,8.85916593,82.86097561,327386 Israel,ISR,7.80830808,82.15365854,8215700 Italy,ITA,9.24791783,83.0902439,60789140 Jamaica,JAM,5.36152479,75.65853659,2862087 Jordan,JOR,7.45299586,74.04495122,8809306 Japan,JPN,10.22874408,83.58780488,127276000 Kazakhstan,KAZ,4.35593983,71.62,17289224 Kenya,KEN,5.72029126,66.19414634,46024250 Kyrgyz Republic,KGZ,6.48376219,70.40243902,5835500 Cambodia,KHM,5.67563855,68.1062439,15270790 Kiribati,KIR,10.21295042,65.87060976,110458 St. Kitts and Nevis,KNA,5.08036532,,53739 "Korea, Rep.",KOR,7.37311255,82.15585366,50746659 Kuwait,KWT,3.04236844,74.6234878,3782450 Latin America & Caribbean (excluding high income),LAC,7.280566123,74.92018456,597035363 Lao PDR,LAO,1.86554551,65.92263415,6576397 Lebanon,LBN,6.39370883,79.32626829,5603279 Liberia,LBR,10.03633328,61.5012439,4390737 Libya,LBY,4.96893503,71.71939024,6204108 St. Lucia,LCA,6.71904145,75.10436585,176421 Latin America & Caribbean,LCN,7.31027174,75.06371707,624331830 Least developed countries: UN classification,LDC,4.76861171,63.67757136,934192321 Low income,LIC,5.747864555,61.59026379,624759914 Liechtenstein,LIE,,82.07317073,37127 Sri Lanka,LKA,3.50335011,74.81465854,20771000 Lower middle income,LMC,4.496193521,67.45876614,2927194316 Low & middle income,LMY,5.807555113,69.97035579,6093019655 Lesotho,LSO,10.61767672,53.09321951,2145785 Late-demographic dividend,LTE,6.067365278,75.33914932,2235382535 Lithuania,LTU,6.55211709,74.51707317,2932367 Luxembourg,LUX,6.93787356,82.22926829,556319 Latvia,LVA,5.88069354,74.12439024,1993782 "Macao SAR, China",MAC,,83.42692683,588781 St. Martin (French part),MAF,,79.32195122,31530 Morocco,MAR,5.90777806,75.25514634,34318082 Monaco,MCO,4.337683,,38132 Moldova,MDA,10.32365569,71.16168293,3556397 Madagascar,MDG,3.04135502,65.10131707,23589801 Maldives,MDV,13.73352009,76.85587805,401000 Middle East & North Africa,MEA,5.321737236,73.12388055,421022841 Mexico,MEX,6.29642103,76.69917073,124221600 Marshall Islands,MHL,17.13572274,,52898 Middle income,MIC,5.808385469,70.92783423,5468259741 "Macedonia, FYR",MKD,6.47637457,75.358,2077495 Mali,MLI,6.86216649,56.98670732,16962846 Malta,MLT,9.74992027,81.94634146,427364 Myanmar,MMR,2.27575459,66.20721951,51924182 Middle East & North Africa (excluding high income),MNA,6.355813808,72.58932144,361077997 Montenegro,MNE,6.41654268,76.63885366,621810 Mongolia,MNG,4.73034173,68.88260976,2923896 Northern Mariana Islands,MNP,,,54468 Mozambique,MOZ,6.97558186,56.99434146,27212382 Mauritania,MRT,3.77269904,62.8702439,4063920 Mauritius,MUS,4.80954464,74.19439024,1260934 Malawi,MWI,11.37795606,61.81660976,17068838 Malaysia,MYS,4.16907804,75.05370732,30228017 North America,NAC,16.51548075,79.06415393,354173159 Namibia,NAM,8.92868766,62.83892683,2370992 New Caledonia,NCL,,77.57317073,268000 Niger,NER,5.82129922,59.2405122,19148219 Nigeria,NGA,3.66879844,52.54134146,176460502 Nicaragua,NIC,9.04013941,74.77278049,6013997 Netherlands,NLD,10.89729305,81.70731707,16865008 Norway,NOR,9.71971755,82.1,5137232 Nepal,NPL,5.797226,69.49897561,28323241 Nauru,NRU,3.32664948,,11853 New Zealand,NZL,11.0296101,81.40487805,4509700 OECD members,OED,12.32153999,80.14410427,1273109967 Oman,OMN,3.55393969,76.89456098,3960925 Other small states,OSS,4.232032482,66.95622134,28759578 Pakistan,PAK,2.61391631,66.14919512,185546257 Panama,PAN,8.0257236,77.62543902,3903986 Peru,PER,5.47303468,74.48536585,30973354 Philippines,PHL,4.7099852,68.87017073,100102249 Palau,PLW,9.02153343,,21094 Papua New Guinea,PNG,4.26357082,65.23407317,7755785 Poland,POL,6.35024637,77.60243902,38011735 Pre-demographic dividend,PRE,4.76775993,59.04751617,830442736 Puerto Rico,PRI,,79.39012195,3534874 "Korea, Dem. People’s Rep.",PRK,,70.95207317,25116363 Portugal,PRT,9.50107564,81.12195122,10401062 Paraguay,PRY,9.81442131,72.93241463,6552584 West Bank and Gaza,PSE,,73.12812195,4294682 Pacific island small states,PSS,5.780170476,70.54402369,2329458 Post-demographic dividend,PST,12.70239129,80.5272136,1092601669 French Polynesia,PYF,,76.50695122,275484 Qatar,QAT,2.18706236,78.3035122,2374419 Romania,ROU,5.56500913,74.96097561,19908979 Russian Federation,RUS,7.07040825,70.74365854,143819666 Rwanda,RWA,7.53155111,66.11334146,11345357 South Asia,SAS,4.372983081,68.20916845,1721840539 Saudi Arabia,SAU,4.68408481,74.39739024,30776722 Sudan,SDN,8.42877471,63.97473171,37737913 Senegal,SEN,4.66497201,66.25782927,14546111 Singapore,SGP,4.92279194,82.49512195,5469724 Solomon Islands,SLB,5.05106254,70.16231707,575504 Sierra Leone,SLE,11.08990224,50.94260976,7079162 El Salvador,SLV,6.77240285,72.75529268,6281189 San Marino,SMR,6.12906486,,32657 Somalia,SOM,,55.46568293,13513125 Serbia,SRB,10.36881192,75.33658537,7130576 Sub-Saharan Africa (excluding high income),SSA,5.476439572,59.39858813,978533722.7 South Sudan,SSD,2.73842073,55.7964878,11530971 Sub-Saharan Africa,SSF,5.474746875,59.39987928,978625081.7 Small states,SST,4.507203565,68.26977195,38251715 Sao Tome and Principe,STP,8.35346606,66.29070732,191266 Suriname,SUR,5.68746988,71.14697561,547928 Slovak Republic,SVK,8.05404755,76.81219512,5418649 Slovenia,SVN,9.23388628,81.07804878,2061980 Sweden,SWE,11.92983965,82.25365854,9696110 Swaziland,SWZ,9.25193954,56.10146341,1295097 Sint Maarten (Dutch part),SXM,,,37685 Seychelles,SYC,3.36981689,73.22926829,91359 Syrian Arab Republic,SYR,3.25453108,70.16321951,19203090 Turks and Caicos Islands,TCA,,,33739 Chad,TCD,3.6211644,52.18107317,13569438 East Asia & Pacific (IDA & IBRD countries),TEA,5.257042068,74.22379227,1996870376 Europe & Central Asia (IDA & IBRD countries),TEC,6.412490615,72.74292048,450522686 Togo,TGO,5.24687674,59.57634146,7228915 Thailand,THA,4.122164481,74.86404878,68416772 Tajikistan,TJK,6.880884,70.82697561,8362745 Turkmenistan,TKM,2.06738625,67.49068293,5466241 Latin America & the Caribbean (IDA & IBRD countries),TLA,7.25635404,74.95507474,608136047 Timor-Leste,TLS,1.47530345,68.29295122,1212814 Middle East & North Africa (IDA & IBRD countries),TMN,6.355813808,72.58283577,356783315 Tonga,TON,5.17677064,72.70136585,105782 South Asia (IDA & IBRD),TSA,4.372983081,68.20916845,1721840539 Sub-Saharan Africa (IDA & IBRD countries),TSS,5.474746875,59.39987928,978625081.7 Trinidad and Tobago,TTO,5.93319696,70.45965854,1354493 Tunisia,TUN,7.00385794,75.31434146,11143908 Turkey,TUR,5.41495949,75.15214634,77030628 Tuvalu,TUV,16.53663877,,10908 Tanzania,TZA,5.58011591,64.1184878,52234869 Uganda,UGA,7.22213686,59.15580488,38833338 Ukraine,UKR,7.09573611,71.18658537,45271947 Upper middle income,UMC,6.169567978,74.92436697,2541065425 Uruguay,URY,8.5814914,76.98209756,3419546 United States,USA,17.14075435,78.74146341,318563456 Uzbekistan,UZB,5.83852176,70.99339024,30757700 St. Vincent and the Grenadines,VCT,8.63023974,72.9395122,109357 "Venezuela, RB",VEN,5.2567025,74.22614634,30738378 British Virgin Islands,VGB,,,29588 Virgin Islands (U.S.),VIR,,79.77317073,104170 Vietnam,VNM,7.06677833,75.69529268,90728900 Vanuatu,VUT,5.02357493,71.772,258850 World,WLD,9.921149564,71.69170194,7268986176 Samoa,WSM,7.21510906,74.58007317,192290 Kosovo,XKX,,71.09756098,1821800 "Yemen, Rep.",YEM,5.63699019,64.50717073,26246327 South Africa,ZAF,8.79698456,60.95478049,54146734.74 Zambia,ZMB,4.98676469,60.71534146,15620974 Zimbabwe,ZWE,6.43947119,59.24431707,15411675 -------------------------------------------------------------------------------- /section-4/p5-bubbleplot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Drawing a Bubbleplot with p5 and d3 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /section-4/p5-bubbleplot/sketch.js: -------------------------------------------------------------------------------- 1 | // Bubblechart for life expectancy and health care spending 2 | // Size circles according to spending? population? 3 | const countries = [] 4 | 5 | function preload() { 6 | table = loadTable('../data/worldwide-health-lifeexpectancy-cut.csv', 'csv', 'header') 7 | } 8 | 9 | function setup() { 10 | console.log(table) 11 | 12 | const width = 800, // canvas width and height 13 | height = 500, 14 | margin = 20, 15 | w = width - 2 * margin, // chart area width and height 16 | h = height - 2 * margin 17 | 18 | createCanvas(width, height) 19 | background(255) 20 | 21 | const cleanData = [] 22 | const healthspending = [] 23 | const lifexpectancies = [] 24 | const populations = [] 25 | 26 | // for each row in table 27 | for (let r = 0; r < table.getRowCount(); r++) { 28 | // fill arrays for each type of data per country 29 | // table.getNum() is buggy, so use table.getString, then cast to a float 30 | const tempHealth = table.getString(r, "2014 Health expenditure, total (% of GDP)") 31 | const tempLifeX = table.getString(r, "2014 Life expectancy at birth, total (years)") 32 | const tempPop = table.getString(r, "2014 Population, total") 33 | 34 | console.log(tempHealth, tempLifeX, tempPop) 35 | 36 | // if any field is empty (NaN) skip data for that row (country) 37 | if (tempHealth != "" && tempLifeX != "" && tempPop != "") { 38 | healthspending.push(float(tempHealth)) 39 | lifexpectancies.push(float(tempLifeX)) 40 | populations.push(float(tempPop)) 41 | } 42 | } 43 | // Make sure the arrays are all the same length 44 | // console.log(healthspending.length, lifexpectancies.length, populations.length); 45 | 46 | // console.log("population: ", min(populations), max(populations)); 47 | // console.log("health spending: ", min(healthspending), max(healthspending)); 48 | // console.log("life expectancy: ", min(lifexpectancies), max(lifexpectancies)); 49 | 50 | for (let i = 0; i < table.getRowCount(); i++) { 51 | // make sure to deal with data as numbers, not strings 52 | const name = table.getString(i, "Country Name") 53 | const population = float(table.getString(i, "2014 Population, total")) 54 | const health = float(table.getString(i, "2014 Health expenditure, total (% of GDP)")) 55 | const lifeX = float(table.getString(i, "2014 Life expectancy at birth, total (years)")) 56 | console.log(population, health, lifeX) 57 | 58 | if (!isNaN(health) && !isNaN(lifeX) && !isNaN(population)) { 59 | // map the data to various dimensions - x position, y position and size of ellipse 60 | // map the sqrt of the population since the domain is so large 61 | const populationSize = map(sqrt(population), sqrt(min(populations)), sqrt(max(populations)), 10, 80) 62 | const lifeXPos = map(lifeX, min(lifexpectancies), max(lifexpectancies), margin, width - margin) 63 | const healthYPos = map(health, min(healthspending), max(healthspending), height - margin, margin) 64 | 65 | // Create a new circle object and store it in the countries array 66 | const c = new Country(name, lifeXPos, healthYPos, populationSize) 67 | countries.push(c) 68 | } 69 | } 70 | } 71 | 72 | function draw() { 73 | background(255) 74 | countries.forEach( function(c) { 75 | c.display() 76 | }); 77 | } 78 | 79 | // Create a class for each Country and visualize it as a circle 80 | function Country(name, x, y, size) { 81 | this.name = name 82 | this.pos = createVector(x, y) 83 | this.size = size 84 | 85 | this.display = function() { 86 | 87 | noStroke() 88 | 89 | if (this.isOverCircle()) { 90 | fill(255, 0, 255, 255) 91 | ellipse(this.pos.x, this.pos.y, this.size, this.size) 92 | this.showName() 93 | } else { 94 | fill(255, 0, 255, 50) 95 | ellipse(this.pos.x, this.pos.y, this.size, this.size) 96 | } 97 | } 98 | 99 | this.showName = function() { 100 | fill(50) 101 | textAlign(CENTER) 102 | text(this.name, this.pos.x, this.pos.y) 103 | } 104 | 105 | // mouseover logic to display name of country 106 | this.isOverCircle = function() { 107 | const distX = this.pos.x - mouseX 108 | const distY = this.pos.y - mouseY 109 | if (sqrt(sq(distX) + sq(distY)) < this.size / 2) { 110 | return true 111 | } else { 112 | return false 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /section-4/p5-d3-bubbleplot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Drawing a Bubbleplot with p5 and d3 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /section-4/p5-d3-bubbleplot/sketch.js: -------------------------------------------------------------------------------- 1 | const countries = [] 2 | 3 | function setup() { 4 | const width = 800, // canvas width and height 5 | height = 500, 6 | margin = 20, 7 | w = width - 2 * margin, // chart area width and height 8 | h = height - 2 * margin; 9 | 10 | //load data with d3, use data within the Promise (after then and before catch) 11 | d3.csv('../data/worldwide-health-lifeexpectancy-cut.csv').then( data => { 12 | console.log(data) 13 | // d3 map functions are useful for creating more convenient data structures 14 | // or applying transformations to values 15 | const mappedData = data.map( function(d) { 16 | return { 17 | name: d["Country Name"], 18 | code: d["Country Code"], 19 | health: d["2014 Health expenditure, total (% of GDP)"], 20 | life: d["2014 Life expectancy at birth, total (years)"], 21 | population: d["2014 Population, total"] 22 | } 23 | }) 24 | console.log(mappedData) 25 | 26 | // filter out rows with fields that don't contain all data fields 27 | const filteredData = mappedData.filter( function(d) { 28 | if (d.health != "" && d.life != "" && d.population != "") { 29 | return d 30 | } 31 | }) 32 | console.log(filteredData) 33 | 34 | // accessor functions which define how to get access to x, y, size and Data values, 35 | // It makes it easier change visualization data: 36 | // suppose you want d.health to be x-axis data instead of d.life. 37 | // so you can just change it in one place instead of multiple 38 | // use the + sign to make sure the data is interpreted as a number, not a string 39 | const popData = function(d) { 40 | return +d.population 41 | } 42 | const healthData = function(d) { 43 | return +d.health 44 | } 45 | const lifeData = function(d) { 46 | return +d.life 47 | } 48 | 49 | console.log(d3.extent(filteredData, popData)) 50 | console.log(d3.extent(filteredData, healthData)) 51 | console.log(d3.extent(filteredData, lifeData)) 52 | 53 | // Use D3 to create scales to position the circles 54 | // P5 has map, which is a linear scale, and lerp, which interpolates between two values 55 | // x-scale 56 | const xScale = d3.scaleLinear() 57 | .domain([d3.min(filteredData, lifeData), d3.max(filteredData, lifeData)]) //set domain to [min,max] of data 58 | .range([margin, width - margin]) // set rage to chart area 59 | //.nice(); //make it nice (the end values will be nice round numbers) 60 | 61 | // same for y-scale 62 | const yScale = d3.scaleLinear() 63 | .domain([d3.min(filteredData, healthData), d3.max(filteredData, healthData)]) 64 | .range([height - margin, margin]) 65 | //.nice(); 66 | 67 | const sizeScale = d3.scalePow() 68 | .exponent(0.5) 69 | .domain([d3.min(filteredData, popData), d3.max(filteredData, popData)]) 70 | .range([10, 100]) 71 | 72 | // create canvas 73 | createCanvas(width, height) 74 | background(255) 75 | 76 | // iterate through the array of data 77 | // create circles from the Country class 78 | for (let i = 0; i < filteredData.length; i++) { 79 | const d = filteredData[i] 80 | fill(255, 0, 255, 50) 81 | noStroke() 82 | const c = new Country( 83 | d.name, 84 | xScale(lifeData(d)), 85 | yScale(healthData(d)), 86 | sizeScale(popData(d)) 87 | ); 88 | // add countries to array 89 | countries.push(c) 90 | //console.log(xScale(lifeData(d)), yScale(healthData(d)), sizeScale(popData(d))); 91 | } 92 | }); 93 | } 94 | 95 | function draw() { 96 | background(255) 97 | // draw circles 98 | countries.forEach( function(c) { 99 | c.display() 100 | }) 101 | } 102 | 103 | // Create a class for each Country and visualize it as a circle 104 | function Country(name, x, y, size) { 105 | this.name = name 106 | this.pos = createVector(x, y) 107 | this.size = size 108 | 109 | this.display = function() { 110 | if (this.isMouseOverCircle()) { 111 | fill(255, 0, 255, 255) 112 | ellipse(this.pos.x, this.pos.y, this.size, this.size) 113 | this.showName() 114 | } else { 115 | fill(255, 0, 255, 50) 116 | ellipse(this.pos.x, this.pos.y, this.size, this.size) 117 | } 118 | } 119 | 120 | this.showName = function() { 121 | fill(50); 122 | text(this.name, this.pos.x, this.pos.y); 123 | } 124 | 125 | // mouseover logic to display name of country 126 | this.isMouseOverCircle = function() { 127 | let distX = this.pos.x - mouseX 128 | let distY = this.pos.y - mouseY 129 | if (sqrt(sq(distX) + sq(distY)) < this.size / 2) { 130 | return true 131 | } else { 132 | return false 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /section-4/threejs-bubbleplot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | My first three.js app 4 | 8 | 9 | 10 | 11 | 12 | 13 | 142 | 143 | -------------------------------------------------------------------------------- /section-4/threejs-bubbleplot/lib/TrackballControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Eberhard Graether / http://egraether.com/ 3 | * @author Mark Lundin / http://mark-lundin.com 4 | * @author Simone Manini / http://daron1337.github.io 5 | * @author Luca Antiga / http://lantiga.github.io 6 | */ 7 | 8 | THREE.TrackballControls = function ( object, domElement ) { 9 | 10 | var _this = this; 11 | var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }; 12 | 13 | this.object = object; 14 | this.domElement = ( domElement !== undefined ) ? domElement : document; 15 | 16 | // API 17 | 18 | this.enabled = true; 19 | 20 | this.screen = { left: 0, top: 0, width: 0, height: 0 }; 21 | 22 | this.rotateSpeed = 1.0; 23 | this.zoomSpeed = 1.2; 24 | this.panSpeed = 0.3; 25 | 26 | this.noRotate = false; 27 | this.noZoom = false; 28 | this.noPan = false; 29 | 30 | this.staticMoving = false; 31 | this.dynamicDampingFactor = 0.2; 32 | 33 | this.minDistance = 0; 34 | this.maxDistance = Infinity; 35 | 36 | this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; 37 | 38 | // internals 39 | 40 | this.target = new THREE.Vector3(); 41 | 42 | var EPS = 0.000001; 43 | 44 | var lastPosition = new THREE.Vector3(); 45 | 46 | var _state = STATE.NONE, 47 | _prevState = STATE.NONE, 48 | 49 | _eye = new THREE.Vector3(), 50 | 51 | _movePrev = new THREE.Vector2(), 52 | _moveCurr = new THREE.Vector2(), 53 | 54 | _lastAxis = new THREE.Vector3(), 55 | _lastAngle = 0, 56 | 57 | _zoomStart = new THREE.Vector2(), 58 | _zoomEnd = new THREE.Vector2(), 59 | 60 | _touchZoomDistanceStart = 0, 61 | _touchZoomDistanceEnd = 0, 62 | 63 | _panStart = new THREE.Vector2(), 64 | _panEnd = new THREE.Vector2(); 65 | 66 | // for reset 67 | 68 | this.target0 = this.target.clone(); 69 | this.position0 = this.object.position.clone(); 70 | this.up0 = this.object.up.clone(); 71 | 72 | // events 73 | 74 | var changeEvent = { type: 'change' }; 75 | var startEvent = { type: 'start' }; 76 | var endEvent = { type: 'end' }; 77 | 78 | 79 | // methods 80 | 81 | this.handleResize = function () { 82 | 83 | if ( this.domElement === document ) { 84 | 85 | this.screen.left = 0; 86 | this.screen.top = 0; 87 | this.screen.width = window.innerWidth; 88 | this.screen.height = window.innerHeight; 89 | 90 | } else { 91 | 92 | var box = this.domElement.getBoundingClientRect(); 93 | // adjustments come from similar code in the jquery offset() function 94 | var d = this.domElement.ownerDocument.documentElement; 95 | this.screen.left = box.left + window.pageXOffset - d.clientLeft; 96 | this.screen.top = box.top + window.pageYOffset - d.clientTop; 97 | this.screen.width = box.width; 98 | this.screen.height = box.height; 99 | 100 | } 101 | 102 | }; 103 | 104 | var getMouseOnScreen = ( function () { 105 | 106 | var vector = new THREE.Vector2(); 107 | 108 | return function getMouseOnScreen( pageX, pageY ) { 109 | 110 | vector.set( 111 | ( pageX - _this.screen.left ) / _this.screen.width, 112 | ( pageY - _this.screen.top ) / _this.screen.height 113 | ); 114 | 115 | return vector; 116 | 117 | }; 118 | 119 | }() ); 120 | 121 | var getMouseOnCircle = ( function () { 122 | 123 | var vector = new THREE.Vector2(); 124 | 125 | return function getMouseOnCircle( pageX, pageY ) { 126 | 127 | vector.set( 128 | ( ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / ( _this.screen.width * 0.5 ) ), 129 | ( ( _this.screen.height + 2 * ( _this.screen.top - pageY ) ) / _this.screen.width ) // screen.width intentional 130 | ); 131 | 132 | return vector; 133 | 134 | }; 135 | 136 | }() ); 137 | 138 | this.rotateCamera = ( function () { 139 | 140 | var axis = new THREE.Vector3(), 141 | quaternion = new THREE.Quaternion(), 142 | eyeDirection = new THREE.Vector3(), 143 | objectUpDirection = new THREE.Vector3(), 144 | objectSidewaysDirection = new THREE.Vector3(), 145 | moveDirection = new THREE.Vector3(), 146 | angle; 147 | 148 | return function rotateCamera() { 149 | 150 | moveDirection.set( _moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0 ); 151 | angle = moveDirection.length(); 152 | 153 | if ( angle ) { 154 | 155 | _eye.copy( _this.object.position ).sub( _this.target ); 156 | 157 | eyeDirection.copy( _eye ).normalize(); 158 | objectUpDirection.copy( _this.object.up ).normalize(); 159 | objectSidewaysDirection.crossVectors( objectUpDirection, eyeDirection ).normalize(); 160 | 161 | objectUpDirection.setLength( _moveCurr.y - _movePrev.y ); 162 | objectSidewaysDirection.setLength( _moveCurr.x - _movePrev.x ); 163 | 164 | moveDirection.copy( objectUpDirection.add( objectSidewaysDirection ) ); 165 | 166 | axis.crossVectors( moveDirection, _eye ).normalize(); 167 | 168 | angle *= _this.rotateSpeed; 169 | quaternion.setFromAxisAngle( axis, angle ); 170 | 171 | _eye.applyQuaternion( quaternion ); 172 | _this.object.up.applyQuaternion( quaternion ); 173 | 174 | _lastAxis.copy( axis ); 175 | _lastAngle = angle; 176 | 177 | } else if ( ! _this.staticMoving && _lastAngle ) { 178 | 179 | _lastAngle *= Math.sqrt( 1.0 - _this.dynamicDampingFactor ); 180 | _eye.copy( _this.object.position ).sub( _this.target ); 181 | quaternion.setFromAxisAngle( _lastAxis, _lastAngle ); 182 | _eye.applyQuaternion( quaternion ); 183 | _this.object.up.applyQuaternion( quaternion ); 184 | 185 | } 186 | 187 | _movePrev.copy( _moveCurr ); 188 | 189 | }; 190 | 191 | }() ); 192 | 193 | 194 | this.zoomCamera = function () { 195 | 196 | var factor; 197 | 198 | if ( _state === STATE.TOUCH_ZOOM_PAN ) { 199 | 200 | factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; 201 | _touchZoomDistanceStart = _touchZoomDistanceEnd; 202 | _eye.multiplyScalar( factor ); 203 | 204 | } else { 205 | 206 | factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed; 207 | 208 | if ( factor !== 1.0 && factor > 0.0 ) { 209 | 210 | _eye.multiplyScalar( factor ); 211 | 212 | } 213 | 214 | if ( _this.staticMoving ) { 215 | 216 | _zoomStart.copy( _zoomEnd ); 217 | 218 | } else { 219 | 220 | _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; 221 | 222 | } 223 | 224 | } 225 | 226 | }; 227 | 228 | this.panCamera = ( function () { 229 | 230 | var mouseChange = new THREE.Vector2(), 231 | objectUp = new THREE.Vector3(), 232 | pan = new THREE.Vector3(); 233 | 234 | return function panCamera() { 235 | 236 | mouseChange.copy( _panEnd ).sub( _panStart ); 237 | 238 | if ( mouseChange.lengthSq() ) { 239 | 240 | mouseChange.multiplyScalar( _eye.length() * _this.panSpeed ); 241 | 242 | pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x ); 243 | pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) ); 244 | 245 | _this.object.position.add( pan ); 246 | _this.target.add( pan ); 247 | 248 | if ( _this.staticMoving ) { 249 | 250 | _panStart.copy( _panEnd ); 251 | 252 | } else { 253 | 254 | _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) ); 255 | 256 | } 257 | 258 | } 259 | 260 | }; 261 | 262 | }() ); 263 | 264 | this.checkDistances = function () { 265 | 266 | if ( ! _this.noZoom || ! _this.noPan ) { 267 | 268 | if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) { 269 | 270 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) ); 271 | _zoomStart.copy( _zoomEnd ); 272 | 273 | } 274 | 275 | if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) { 276 | 277 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) ); 278 | _zoomStart.copy( _zoomEnd ); 279 | 280 | } 281 | 282 | } 283 | 284 | }; 285 | 286 | this.update = function () { 287 | 288 | _eye.subVectors( _this.object.position, _this.target ); 289 | 290 | if ( ! _this.noRotate ) { 291 | 292 | _this.rotateCamera(); 293 | 294 | } 295 | 296 | if ( ! _this.noZoom ) { 297 | 298 | _this.zoomCamera(); 299 | 300 | } 301 | 302 | if ( ! _this.noPan ) { 303 | 304 | _this.panCamera(); 305 | 306 | } 307 | 308 | _this.object.position.addVectors( _this.target, _eye ); 309 | 310 | _this.checkDistances(); 311 | 312 | _this.object.lookAt( _this.target ); 313 | 314 | if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) { 315 | 316 | _this.dispatchEvent( changeEvent ); 317 | 318 | lastPosition.copy( _this.object.position ); 319 | 320 | } 321 | 322 | }; 323 | 324 | this.reset = function () { 325 | 326 | _state = STATE.NONE; 327 | _prevState = STATE.NONE; 328 | 329 | _this.target.copy( _this.target0 ); 330 | _this.object.position.copy( _this.position0 ); 331 | _this.object.up.copy( _this.up0 ); 332 | 333 | _eye.subVectors( _this.object.position, _this.target ); 334 | 335 | _this.object.lookAt( _this.target ); 336 | 337 | _this.dispatchEvent( changeEvent ); 338 | 339 | lastPosition.copy( _this.object.position ); 340 | 341 | }; 342 | 343 | // listeners 344 | 345 | function keydown( event ) { 346 | 347 | if ( _this.enabled === false ) return; 348 | 349 | window.removeEventListener( 'keydown', keydown ); 350 | 351 | _prevState = _state; 352 | 353 | if ( _state !== STATE.NONE ) { 354 | 355 | return; 356 | 357 | } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && ! _this.noRotate ) { 358 | 359 | _state = STATE.ROTATE; 360 | 361 | } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && ! _this.noZoom ) { 362 | 363 | _state = STATE.ZOOM; 364 | 365 | } else if ( event.keyCode === _this.keys[ STATE.PAN ] && ! _this.noPan ) { 366 | 367 | _state = STATE.PAN; 368 | 369 | } 370 | 371 | } 372 | 373 | function keyup( event ) { 374 | 375 | if ( _this.enabled === false ) return; 376 | 377 | _state = _prevState; 378 | 379 | window.addEventListener( 'keydown', keydown, false ); 380 | 381 | } 382 | 383 | function mousedown( event ) { 384 | 385 | if ( _this.enabled === false ) return; 386 | 387 | event.preventDefault(); 388 | event.stopPropagation(); 389 | 390 | if ( _state === STATE.NONE ) { 391 | 392 | _state = event.button; 393 | 394 | } 395 | 396 | if ( _state === STATE.ROTATE && ! _this.noRotate ) { 397 | 398 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); 399 | _movePrev.copy( _moveCurr ); 400 | 401 | } else if ( _state === STATE.ZOOM && ! _this.noZoom ) { 402 | 403 | _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 404 | _zoomEnd.copy( _zoomStart ); 405 | 406 | } else if ( _state === STATE.PAN && ! _this.noPan ) { 407 | 408 | _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 409 | _panEnd.copy( _panStart ); 410 | 411 | } 412 | 413 | document.addEventListener( 'mousemove', mousemove, false ); 414 | document.addEventListener( 'mouseup', mouseup, false ); 415 | 416 | _this.dispatchEvent( startEvent ); 417 | 418 | } 419 | 420 | function mousemove( event ) { 421 | 422 | if ( _this.enabled === false ) return; 423 | 424 | event.preventDefault(); 425 | event.stopPropagation(); 426 | 427 | if ( _state === STATE.ROTATE && ! _this.noRotate ) { 428 | 429 | _movePrev.copy( _moveCurr ); 430 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); 431 | 432 | } else if ( _state === STATE.ZOOM && ! _this.noZoom ) { 433 | 434 | _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 435 | 436 | } else if ( _state === STATE.PAN && ! _this.noPan ) { 437 | 438 | _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 439 | 440 | } 441 | 442 | } 443 | 444 | function mouseup( event ) { 445 | 446 | if ( _this.enabled === false ) return; 447 | 448 | event.preventDefault(); 449 | event.stopPropagation(); 450 | 451 | _state = STATE.NONE; 452 | 453 | document.removeEventListener( 'mousemove', mousemove ); 454 | document.removeEventListener( 'mouseup', mouseup ); 455 | _this.dispatchEvent( endEvent ); 456 | 457 | } 458 | 459 | function mousewheel( event ) { 460 | 461 | if ( _this.enabled === false ) return; 462 | 463 | if ( _this.noZoom === true ) return; 464 | 465 | event.preventDefault(); 466 | event.stopPropagation(); 467 | 468 | switch ( event.deltaMode ) { 469 | 470 | case 2: 471 | // Zoom in pages 472 | _zoomStart.y -= event.deltaY * 0.025; 473 | break; 474 | 475 | case 1: 476 | // Zoom in lines 477 | _zoomStart.y -= event.deltaY * 0.01; 478 | break; 479 | 480 | default: 481 | // undefined, 0, assume pixels 482 | _zoomStart.y -= event.deltaY * 0.00025; 483 | break; 484 | 485 | } 486 | 487 | _this.dispatchEvent( startEvent ); 488 | _this.dispatchEvent( endEvent ); 489 | 490 | } 491 | 492 | function touchstart( event ) { 493 | 494 | if ( _this.enabled === false ) return; 495 | 496 | event.preventDefault(); 497 | 498 | switch ( event.touches.length ) { 499 | 500 | case 1: 501 | _state = STATE.TOUCH_ROTATE; 502 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 503 | _movePrev.copy( _moveCurr ); 504 | break; 505 | 506 | default: // 2 or more 507 | _state = STATE.TOUCH_ZOOM_PAN; 508 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 509 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 510 | _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); 511 | 512 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; 513 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; 514 | _panStart.copy( getMouseOnScreen( x, y ) ); 515 | _panEnd.copy( _panStart ); 516 | break; 517 | 518 | } 519 | 520 | _this.dispatchEvent( startEvent ); 521 | 522 | } 523 | 524 | function touchmove( event ) { 525 | 526 | if ( _this.enabled === false ) return; 527 | 528 | event.preventDefault(); 529 | event.stopPropagation(); 530 | 531 | switch ( event.touches.length ) { 532 | 533 | case 1: 534 | _movePrev.copy( _moveCurr ); 535 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 536 | break; 537 | 538 | default: // 2 or more 539 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 540 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 541 | _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ); 542 | 543 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; 544 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; 545 | _panEnd.copy( getMouseOnScreen( x, y ) ); 546 | break; 547 | 548 | } 549 | 550 | } 551 | 552 | function touchend( event ) { 553 | 554 | if ( _this.enabled === false ) return; 555 | 556 | switch ( event.touches.length ) { 557 | 558 | case 0: 559 | _state = STATE.NONE; 560 | break; 561 | 562 | case 1: 563 | _state = STATE.TOUCH_ROTATE; 564 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 565 | _movePrev.copy( _moveCurr ); 566 | break; 567 | 568 | } 569 | 570 | _this.dispatchEvent( endEvent ); 571 | 572 | } 573 | 574 | function contextmenu( event ) { 575 | 576 | if ( _this.enabled === false ) return; 577 | 578 | event.preventDefault(); 579 | 580 | } 581 | 582 | this.dispose = function () { 583 | 584 | this.domElement.removeEventListener( 'contextmenu', contextmenu, false ); 585 | this.domElement.removeEventListener( 'mousedown', mousedown, false ); 586 | this.domElement.removeEventListener( 'wheel', mousewheel, false ); 587 | 588 | this.domElement.removeEventListener( 'touchstart', touchstart, false ); 589 | this.domElement.removeEventListener( 'touchend', touchend, false ); 590 | this.domElement.removeEventListener( 'touchmove', touchmove, false ); 591 | 592 | document.removeEventListener( 'mousemove', mousemove, false ); 593 | document.removeEventListener( 'mouseup', mouseup, false ); 594 | 595 | window.removeEventListener( 'keydown', keydown, false ); 596 | window.removeEventListener( 'keyup', keyup, false ); 597 | 598 | }; 599 | 600 | this.domElement.addEventListener( 'contextmenu', contextmenu, false ); 601 | this.domElement.addEventListener( 'mousedown', mousedown, false ); 602 | this.domElement.addEventListener( 'wheel', mousewheel, false ); 603 | 604 | this.domElement.addEventListener( 'touchstart', touchstart, false ); 605 | this.domElement.addEventListener( 'touchend', touchend, false ); 606 | this.domElement.addEventListener( 'touchmove', touchmove, false ); 607 | 608 | window.addEventListener( 'keydown', keydown, false ); 609 | window.addEventListener( 'keyup', keyup, false ); 610 | 611 | this.handleResize(); 612 | 613 | // force an update at start 614 | this.update(); 615 | 616 | }; 617 | 618 | THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 619 | THREE.TrackballControls.prototype.constructor = THREE.TrackballControls; --------------------------------------------------------------------------------