-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathProgfunStats.scala
455 lines (379 loc) · 15.8 KB
/
ProgfunStats.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
package progfun
/** object representing a *grouped* bar graph of students'
* experience with other programming languages and paradigms
*/
object ExperienceBarGraph extends GroupedBarGraphFactory with App {
import CourseraData._
/* file name to output to */
val name = "experience.html"
/* label for the y-axis */
def label: String = "Percentage"
/* the captions represent the legend (the colors for each bar).
for the moment, it must begin with a string called "Key". this will be removed shortly */
val captions = List("Key",
"No experience / not seen it at all",
"I've seen and understand some code",
"I have some experience writing code",
"I'm fluent",
"I'm an expert")
private val langs = List(javaExp, cExp, pythonExp, dotNetExp, jsExp, funcExp, lispExp)
/* this is effectively a List[(String, List[Int])]
* it represents the data that goes into your bar graph
* where the String is the label on the x-axis, and the
* List[Int] is the list of values for each bar */
val data =
List("Java", "C/C++/Objective-C", "Python/Ruby/Perl", "C#/.NET",
"JavaScript", "Haskell/OCaml/ML/F#", "Lisp/Scheme/Clojure").zipWithIndex map { case (lang, langNum) =>
val percentages = 1 to 5 map { i =>
val num = langs(langNum).filter(_ == captions(i)).size
(num.toDouble / total * 100).round.toInt
}
(lang, percentages.toList)
}
writeHtml()
}
/** object representing a *grouped* bar graph of students'
* reported difficulty relative to Java/C/C++/FP expertise
*/
object ExperienceDifficultyBarGraph extends GroupedBarGraphFactory with App {
import CourseraData.users
/* file name to output to */
val name = "experience-vs-difficulty.html"
/* width and height of final plot. Overrides default of 960 x 480 */
override val width = 450
override val height = 240
/* the captions represent the legend (the colors for each bar).
for the moment, it must begin with a string called "Key". this will be removed shortly */
val captions = List("Key","1","2","3","4","5")
/* label for the y-axis */
def label = "Percentage"
def getExperts(selector: User => String) =
users.filter(user => selector(user) == "I'm an expert" || selector(user) == "I'm fluent")
val cers = getExperts(_.cExp)
val javaers = getExperts(_.javaExp)
val fpers = getExperts(_.funcExp)
def makeDifficultyMap(usrs: List[User]): Map[Int, Long] =
usrs.groupBy(user => user.difficultyHW)
.map(kv => (kv._1, (kv._2.length.toDouble/usrs.length*100).round))
val difficultyC = makeDifficultyMap(cers)
val difficultyJava = makeDifficultyMap(javaers)
val difficultyFP = makeDifficultyMap(fpers)
/* this effectively returns a List[(String, Int)]
* it represents the data that goes into your bar graph
* where the String is the label on the x-axis, and the
* Int is the value for each bar */
def data =
List(
("C/C++/Objective-C", difficultyC.toList.sorted.map(_._2)),
("Java", difficultyJava.toList.sorted.map(_._2)),
("Haskell/OCaml/ML/F#", difficultyFP.toList.sorted.map(_._2))
)
writeHtml()
}
/** object representing a *grouped* bar graph of students'
* reported difficulty relative to educational background
*/
object BackgroundDifficultyBarGraph extends GroupedBarGraphFactory with App {
import CourseraData.users
/* file name to output to */
val name = "background-vs-difficulty.html"
/* width and height of final plot. Overrides default of 960 x 480 */
override val width = 450
override val height = 240
/* the captions represent the legend (the colors for each bar).
for the moment, it must begin with a string called "Key". this will be removed shortly */
val captions = List("Key","1","2","3","4","5")
/* label for the y-axis */
def label = "Percentage"
val nonCSFields = List(
"Electrical Engineering",
"Mechanical Engineering",
"Business/Marketing",
"Physics",
"Life Sciences",
"Liberal Arts",
"Fine Arts"
)
val nonCSUsers = users.filter(user => nonCSFields.contains(user.field))
val csUsers = users.filter(user => user.field == "Computer Science" || user.field == "Computer/Software Engineering")
def makeDifficultyMap(usrs: List[User]): Map[Int, Long] =
usrs.groupBy(user => user.difficultyHW)
.map(kv => (kv._1, (kv._2.length.toDouble/usrs.length*100).round))
val difficultyNonCS = makeDifficultyMap(nonCSUsers)
val difficultyCS = makeDifficultyMap(csUsers)
val difficultyAll = makeDifficultyMap(users)
/* this effectively returns a List[(String, Int)]
* it represents the data that goes into your bar graph
* where the String is the label on the x-axis, and the
* Int is the value for each bar */
def data =
List(
("Non-CS Field", difficultyNonCS.toList.sorted.map(_._2)),
("All Respondents", difficultyAll.toList.sorted.map(_._2)),
("CS or CE", difficultyCS.toList.sorted.map(_._2))
)
writeHtml()
}
/** object representing a *grouped* bar graph of students'
* reported difficulty relative to highest level of education
*/
object EducationDifficultyBarGraph extends GroupedBarGraphFactory with App {
import CourseraData.users
/* file name to output to */
val name = "education-vs-difficulty.html"
/* width and height of final plot. Overrides default of 960 x 480 */
override val width = 800
override val height = 320
/* the captions represent the legend (the colors for each bar).
for the moment, it must begin with a string called "Key". this will be removed shortly */
val captions = List("Key","1","2","3","4","5")
/* label for the y-axis */
def label = "Percentage"
def makeDifficultyByDegree(deg: String): Map[Int, Long] = {
val usrsByDeg = users.filter(user => user.degree == deg)
val perc = usrsByDeg.groupBy(user => user.difficultyHW)
.map(kv => (kv._1, (kv._2.length.toDouble/usrsByDeg.length*100).round))
val withAllKeys = (List(1, 2, 3, 4, 5) map { key =>
if (perc.isDefinedAt(key)) (key, perc(key))
else (key, 0L)
}).toMap
withAllKeys
}
val difficultyNoHs = makeDifficultyByDegree("No High School (or equivalent)")
val difficultySomeHs = makeDifficultyByDegree("Some High School (or equivalent)")
val difficultyHs = makeDifficultyByDegree("High School (or equivalent)")
val difficultySomeColl = makeDifficultyByDegree("Some College (or equivalent)")
val difficultyBachelor = makeDifficultyByDegree("Bachelor's Degree (or equivalent)")
val difficultyMaster = makeDifficultyByDegree("Master's Degree (or equivalent)")
val difficultyDoctorate = makeDifficultyByDegree("Doctorate Degree (or equivalent)")
/* this effectively returns a List[(String, Int)]
* it represents the data that goes into your bar graph
* where the String is the label on the x-axis, and the
* Int is the value for each bar */
def data =
List(
("No HS", difficultyNoHs.toList.sorted.map(_._2)),
("Some HS", difficultySomeHs.toList.sorted.map(_._2)),
("HS", difficultyHs.toList.sorted.map(_._2)),
("Some Univ", difficultySomeColl.toList.sorted.map(_._2)),
("Bachelor", difficultyBachelor.toList.sorted.map(_._2)),
("Master", difficultyMaster.toList.sorted.map(_._2)),
("PhD", difficultyDoctorate.toList.sorted.map(_._2))
)
writeHtml()
}
/** object representing the plot of population density vs the world map
*/
// please note that WorldMapFactory needs a bit of reorganization
// so be aware that it might soon be revised a bit.
// after reorganization, you will be provided with a list of ISOs,
// and you will have to provide values (AnyVal) associated with each
// and implement a field called `data` as with other Factories
object WorldMapDensityGraph extends WorldMapFactory with App {
/* file name to output to */
val name = "worldmap-density.html"
writeHtml()
}
/** object representing a *simple* bar graph of students'
* highest level of education
*/
object EducationBarGraph extends SimpleBarGraphFactory with App {
import CourseraData.degrees
/* file name to output to */
val name = "education.html"
/* width and height of final plot. Overrides default of 960 x 480 */
override val width = 450
override val height = 500
override val color = "#CF5300"
override val margin = "{top: 20, right: 20, bottom: 60, left: 40}"
/* the label on the y axis */
val label = "Percentage"
val degreeLabels = List(
"No HS",
"Some HS",
"HS",
"Some Univ",
"Bachelor",
"Master",
"PhD",
"Other"
)
/* this is effectively a List[(String, Int)]
* it represents the data that goes into your bar graph
* where the String is the label on the x-axis, and the
* Int is the value for each bar */
val data = {
val degreeOpts = List(
"No High School (or equivalent)",
"Some High School (or equivalent)",
"High School (or equivalent)",
"Some College (or equivalent)",
"Bachelor's Degree (or equivalent)",
"Master's Degree (or equivalent)",
"Doctorate Degree (or equivalent)"
)
val toShort = (degreeOpts zip degreeLabels).toMap
val (listed, other) = degrees.partition(degree => degreeOpts.contains(degree))
listed.groupBy(deg => deg)
.map { case (k, v) => (toShort(k), v.length) }
.toList
.sortWith((p1, p2) => degreeLabels.indexOf(p1._1) < degreeLabels.indexOf(p2._1))
.map { case (deg, count) => (deg, (count.toDouble / degrees.length * 100).round.toInt) }
}
writeHtml()
}
/** object representing a pie chart which represents students'
* what interested students in the course
*/
object WhatInterestedYouPieChart extends PieChartFactory with App {
/* file name to output to */
val name = "what-interested-you.html"
/* this represents the data that goes into your pie chart
* where the String is the label, and the Int is the
* value for each slice of the chart */
def data: List[(String, Int)] = getFreqs(CourseraData.whatInterestedYou)
writeHtml()
}
/** object representing a pie chart which represents students'
* plan to apply what they have learned in the course
*/
object WhereApplyPieChart extends PieChartFactory with App {
/* file name to output to */
val name = "where-apply.html"
/* this represents the data that goes into your pie chart
where the String is the label, and the Int is the
value for each slice of the chart */
def data: List[(String, Int)] = getFreqs(CourseraData.whereApply)
writeHtml()
}
/** object representing a *grouped* bar graph of preferred
* editor use outside of the course versus editor use for
* the course
*/
object EditorGroupedBarGraph extends GroupedBarGraphFactory with App {
import CourseraData.{ prefEditor, courseEditor, total }
/* file name to output to */
val name = "editors.html"
/* width and height of final plot. Overrides default of 960 x 480 */
override val width = 500
override val height = 240
/* the captions represent the legend (the colors for each bar).
for the moment, it must begin with a string called "Key". this will be removed shortly */
val captions = List("Key","Preferred for use outside of the course","Used for majority of course")
/* the label on the y axis */
val label = "Percentage"
def edtitorFreqs(choices: List[String], xs: List[String]) = {
val (editors, other) = getFreqWithOther(choices, xs)
val (netbeans, trueOther) = other.map(_.toLowerCase)
.partition(_ == "netbeans")
val editorCount = editors ++ List(("Netbeans", netbeans.length),("Other", trueOther.length))
editorCount
}
val prefEditorChoices = List("Eclipse","IntelliJ","Sublime Text","Visual Studio","XCode","TextMate","emacs","vim")
val prefEditorCount = edtitorFreqs(prefEditorChoices, prefEditor)
val prefEditorToGraph = {
val (vsOrXcode, wrongOther) = prefEditorCount.partition { case (ed, cnt) => ed == "Visual Studio" || ed == "XCode" }
val toAddToOther = vsOrXcode(0)._2 + vsOrXcode(1)._2
wrongOther.map { case (ed, cnt) => if (ed == "Other") (ed, cnt + toAddToOther) else (ed, cnt) }
}
val courseEditorChoices = List("Eclipse","IntelliJ","Sublime Text","TextMate","emacs","vim")
val courseEditorCount = edtitorFreqs(courseEditorChoices, courseEditor)
/* this effectively returns a List[(String, Int)]
* it represents the data that goes into your bar graph
* where the String is the label on the x-axis, and the
* Int is the value for each bar */
def data = {
val (courseEds, courseCnts) = courseEditorCount.unzip
val (prefEds, prefCnts) = prefEditorToGraph.unzip
val unsorted = prefEds.zip(courseCnts.zip(prefCnts).map { case (courseCount, prefCount) =>
val coursePerc = percentOf(courseCount, total)
val prefPerc = percentOf(prefCount, total)
List(prefPerc, coursePerc)
})
val refList = courseEditorChoices ++ List("Netbeans", "Other")
unsorted.sortWith((p, q) => refList.indexOf(p._1) < refList.indexOf(q._1))
.map(p => if (p._1.startsWith("Sublime")) ("Sublime", p._2) else p)
}
writeHtml()
}
/** object representing a *simple* bar graph of
* students' interest in a follow-up course
*/
object FollowupCourseBarGraph extends SimpleBarGraphFactory with App {
import CourseraData.followupCourse
/* file name to output to */
val name = "followup-course.html"
/* width and height of final plot. Overrides default of 960 x 480 */
override val width = 250
override val height = 250
override val maxy = 70
override val color = "#5E4175"
/* the label on the y axis */
val label = "Percentage"
/* this represents the data that goes into your bar graph
* where the String is the label on the x-axis, and the
* Int is the value for each bar */
def data: List[(String, Int)] = {
val counts =
getFreqs(followupCourse)
.sortBy(_._1)
.map { case (name, value) =>
(name.toString, (value.toDouble / followupCourse.length * 100).round.toInt)
}
val correctedLabels: List[(String, Int)] =
List(("1 Not Interested", counts(0)._2)) ++ counts.drop(1).take(3) ++ List(("5 Absolutely!",counts(4)._2))
correctedLabels
}
writeHtml()
}
/** object representing a *simple* bar graph which
* represents how "worth it" the course was for students
*/
object WorthItBarGraph extends SimpleBarGraphFactory with App {
import CourseraData.worthIt
/* file name to output to */
val name = "worth-it.html"
/* width and height of final plot. Overrides default of 960 x 480 */
override val width = 250
override val height = 250
override val maxy = 70
/* the label on the y axis */
val label = "Percentage"
/* this represents the data that goes into your bar graph
* where the String is the label on the x-axis, and the
* Int is the value for each bar */
def data: List[(String, Int)] = {
val counts =
getFreqs(worthIt)
.sortBy(_._1)
.map { case (name, value) =>
(name.toString, (value.toDouble / worthIt.length * 100).round.toInt)
}
val correctedLabels: List[(String, Int)] =
List(("1 Disagree", counts(0)._2)) ++ counts.drop(1).take(3) ++ List(("5 Agree",counts(4)._2))
correctedLabels
}
writeHtml()
}
/** Shortcut for generating all graphs.
* Add any new graph to this list, and in sbt,
* run progfun.ProgfunStats to generate all graphs
*/
object ProgfunStats extends App {
List[GraphFactory with App](
ExperienceBarGraph,
ExperienceDifficultyBarGraph,
BackgroundDifficultyBarGraph,
EducationDifficultyBarGraph,
WorldMapDensityGraph,
EducationBarGraph,
WhereApplyPieChart,
WhatInterestedYouPieChart,
EditorGroupedBarGraph,
FollowupCourseBarGraph,
WorthItBarGraph
).foreach { graph =>
graph.main(Array())
println("generated " + graph.name)
}
}