├── .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;
--------------------------------------------------------------------------------