-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
448 lines (407 loc) · 23.3 KB
/
Copy pathindex.html
File metadata and controls
448 lines (407 loc) · 23.3 KB
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
<!DOCTYPE html>
<html>
<head>
<title>Objects in Processing.R</title>
<link rel="icon" href="favicon.ico" type="image/x-icon" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="Author" content="Ce Gao" />
<meta name="Publisher" content="Processing" />
<meta name="Keywords" content="Processing, Processing, Interactive Media, Electronic Arts, Programming, gaocegege, R Language" />
<meta name="Description" content="R Language Mode for Processing extends the Processing Development Environment with the R Language." />
<script src="/javascript/modernizr-2.6.2.touch.js" type="text/javascript"></script>
<link href="/css/style.css" rel="stylesheet" type="text/css" />
</head>
<body id="Langauge-en" onload="" >
<div id="container">
<div id="header">
<a href="/" title="Back to R Language Mode" class="processing-logo no-cover"></a>
</div>
<a id="TOP" name="TOP"></a>
<div id="navigation">
<div class="navBar" id="mainnav">
<a href="/">Cover</a><br/>
<a href="/reference/">Reference</a><br/>
<a href="/tutorials/">Tutorials</a><br/>
<!-- <a href="/examples/">Examples</a><br/> -->
<a href="https://github.com/gaocegege/Processing.R/issues">Bugs</a>
</div>
</div>
<div class="content">
<body>
<h1 style="line-height: 0.7em;">Objects in Processing.R</h1>
<h3 style="line-height: 0.7em;"><em>Shawn T. O'Neil</em></h3>
<table width="656">
<tr>
<td>
<h3>What's an object?</h3>
<p>The usual business of programming involves <em>data</em> (lists, vectors, matrices, etc.) and <em>functions</em>, which take data as input and <em>do something</em> (like draw a circle) or <em>return</em> something (maybe the result of a complex calculation). </p>
<p>Frequently, the same pieces of data and function are used repeatedly as a group--to simulate a moving ball for example, we will have data on the ball's location (x and y), its speed (how many pixels it will move in the x and y direction in the next timestep), a radius, and maybe something like an ID string. A function like <code>move()</code> would take the position and speed data, and update the position. A function like <code>display()</code> needs position information and the radius to draw the ball.</p>
<p>An <strong>object</strong> is a more formal way to group all of these pieces together. Objects are not strictly necessary for writing programs, but by organizing related data and functions they can simplify the process considerably. </p>
<p>We'll often talk about <strong>classes</strong> as well--a class is the "blueprint" for potentially many objects of the same type. The objects themselves are the actual collections of data built from the class template. Let's consider our ball example, a <code>Ball</code> class is code that specifies that all <code>Ball</code> objects must have an <code>xloc</code>, <code>yloc</code>, <code>xspeed</code>, <code>yspeed</code>, <code>radius</code>, and <code>id</code>, as well as a function <code>display()</code> and a function <code>move()</code>. </p>
<p><img src="imgs/ball_class_and_objects.png" alt="A Ball class is like a general diagram, individual Ball objects are concrete instances of that class" style="width: 645px;"/></p>
<p>In a way, the word <code>Ball</code> itself is a bit of data associated with an object, since we need some way to know that an object <code>x</code> is a <code>Ball</code>, and not, say, a <code>Car</code>. In Processing.R we recommend capital initials for class names (e.g. <code>Ball</code> rather than <code>ball</code>).</p>
<blockquote>
<p>Note: Capitaliing classes (<code>Ball</code>, not <code>ball</code>) is a coding convention. It is very consistently observed in some languages (like Processing / Java) and less in others (p5.js / Javascript, Processing.R / R). Don't be too surprised to see exceptions to this rule in R code!</p>
</blockquote>
<p>When talking about classes, some special terminology is also used. Functions that that are part of classes (and hence part of the objects of that class) are called <strong>methods</strong>. The variables belonging to each object are called <strong>instance variables</strong>, which hold different values for each <em>instance</em> of the class. In the figure above, <code>radius</code> has a different value for each Ball object.</p>
<h3>Objects in R</h3>
<p>This idea of classes serving to collect data and methods (not functions!) into single objects hasn't been around forever, and over the years different programming languages have captured the idea in different ways. Today, the most popular languages like Java, C++, Python, and even JavaScript have settled on a pattern where a class template is defined within a single chunk of code. If you've used any of these languages, this chunk of JavaScript might look familiar (if not, feel free to just skim):</p>
<pre><code>// This code is JavaScript, not R...
class Ball(x, y, xs, yx, r, i) {
this.xloc = x;
this.yloc = y;
this.xspeed = xs;
this.yspeed = ys;
this.radius = r;
this.id = i;
this.move = function() {
this.xloc = this.xloc + this.xspeed;
this.yloc = this.yloc + this.yspeed;
}
this.display = function() {
ellipse(this.xloc, this.yloc, this.radius, this.radius);
}
}
var b1 = new Ball(55, 75, 2, -1, 20, "Ball1");
var b2 = new Ball(107, 165, -3, 3.2, 10, "Ball2");
b1.move();
b1.display();
b2.move();
b2.display();
</code></pre>
<p>This code defines a <code>Ball</code> class (blueprint), creates two <code>Ball</code> objects <code>b1</code> and <code>b2</code>, and then asks each in turn to move itself then display itself... but that's enough JavaScript--this tutorial is supposed to be about R! Although modern versions of R can follow this same sort of coding pattern, it hasn't always, since R originally drew inspiration from the statistical language and functional languages Scheme and Lisp.</p>
<p>Over the years, R has been graced with <em>three</em> different ways to define classes in code.</p>
<ol>
<li>S3 Classes - these are the oldest, and the most commonly found in R</li>
<li>S4 Classes - these utilize a hybrid of S3 class concepts, and more modern syntax similar to the JavaScript example above</li>
<li>Reference Classes (RC) - the most recently added, these are very similar to classes defined by Java, JavaScript, Python, C++, etc.</li>
</ol>
<p><strong>Processing.R supports S3 classes only</strong> -- S3 classes are the most commonly found in R code, and they are what will be covered in this tutorial.</p>
<blockquote>
<p>Note: When looking at R code "in the wild" be careful not to mix S3, S4, and RC classes -- and keep in mind that only S3 is supported in Processing.R.</p>
</blockquote>
<h3>Attributes and Lists</h3>
<p>Before we can write some classes in R, we need to discuss a feature of R that is not found in many other languages: <strong>attributes</strong>. R attributes are a kind of "metadata" that we can attach to any other data. </p>
<p>For these examples we will be experimenting with code in a Processing.R sketch inside the <code>setup</code> function, and periodically running the sketch to see the results.</p>
<pre><code>setup <- function() {
exit()
}
</code></pre>
<p>Let's create a random sample of 100 numbers using the <code>rnorm()</code> function:</p>
<pre><code>samp <- rnorm(100, mean = 20, sd = 2)
print(samp)
</code></pre>
<blockquote>
<p>c(17.476707120743, 21.36868260950083, 17.8269424011346, 20.07978640322603, 21.12157543421291,... 100 elements total</p>
</blockquote>
<p>We may want to remember, for later use, what kind of data this is. We can do this by making up a "sampletype" attribute and adding it to our sample with the <code>attr()</code> function:</p>
<p>attr(samp, "sampletype") <- "Normal Sample"</p>
<p>Then, later, we can extract attributes:</p>
<pre><code>setup <- function() {
samp <- rnorm(100, mean = 20, sd = 2)
attr(samp, "sampletype") <- "Normal Sample"
print(samp)
print("\n")
print(attr(samp, "sampletype")) # Prints "Normal Sample"
exit()
}
</code></pre>
<p>Attributes are also how R stores class information. Let's define a numeric <strong>vector</strong> containing some information for a ball:</p>
<pre><code>setup <- function() {
b1 <- c(55, 75, 2, -1, 20) # xloc, yloc, xspeed, yspeed, radius
attr(b1, "class") <- "Ball"
print(b1)
print("\n")
print(attr(b1, "class"))
exit()
}
</code></pre>
<p>Now, as far as R is concerned, <code>b1</code> is a <code>Ball</code> object! This is because <code>"class"</code> is an attribute that R treats specially to hold this information. This is so common that there's a special function <code>class()</code> just to set the class attribute of an object:</p>
<pre><code>class(b1) <- "Ball"
</code></pre>
<p>We can assign attributes to any kind of data in R. Here we've used a numeric vector of 5 numbers to store data about the ball. This isn't too flexible--vectors (created with the <code>c()</code> function) can only store one type of data (numbers in this case) as a basic array. <strong>Lists</strong>, on the other hand, are more flexible: they can hold vectors of different kinds, and even other lists. Maybe we want to store ball data as a location vector, a speed vector, a radius number (actually a vector of length 1 in R), and an id:</p>
<pre><code>b1 <- list(c(55, 75), c(2, -1), 20, "Ball1")
class(b1) <- "Ball"
</code></pre>
<p>Another cool thing about lists (and vectors too, actually) is that list elements can have names:</p>
<pre><code>b1 <- list(loc = c(55, 75), speed = c(2, -1),
radius = 20, id = "Ball1")
class(b1) <- "Ball"
</code></pre>
<p>This way, we can work with elements by their name, using a <code>$</code>-sign.</p>
<pre><code>setup <- function() {
b1 <- list(loc = c(55, 75), speed = c(2, -1), radius = 20, id = "Ball1")
class(b1) <- "Ball"
print(b1)
print("\n")
print(class(b1)) # prints "Ball"
print("\n")
print(b1$loc) # prints "c(55, 75)"
print("\n")
print(b1$loc[2]) # prints "215.0"
exit()
}
</code></pre>
<p>We can assign to new entries of a list by using a new name as well:</p>
<pre><code>b1$volume <- pi * b1$radius ^ 2 # pi is built into R
</code></pre>
<p>And, since <code>loc</code> and <code>speed</code> are both vectors, and R is <em>vectorized</em> (most operations work on vectors in an element-by-element manner), we can do something like this to print where the ball will be next:</p>
<pre><code>print(b1$loc + b1$speed) # prints 202, 214
</code></pre>
<p>By the way, <strong>constructor</strong> is the special name for a function that creates an object of the proper form. Usually the function name is the same as the class name:</p>
<pre><code>setup <- function() {
b1 <- Ball(55, 75, 2, -2, 20, "Ball1")
print(b1)
exit()
}
Ball <- function(x, y, xs, ys, r, i) {
newb <- list(loc = c(x, y), speed = c(xs, ys),
radius = r, id = i)
class(newb) <- "Ball"
return(newb)
}
</code></pre>
<h3>Methods</h3>
<p>The above covers how we can collect different kinds of data together, and assign a "class" to that collection. But what about the class functions--the methods--that we want to build to go along with the data? In the simplest case, we can just create a function. here's one that takes a Ball object, add the speed to the location, and returns it:</p>
<pre><code>move <- function(someball) {
someball$loc <- someball$loc + someball$speed
return(someball)
}
</code></pre>
<p>To use it, we can create a Ball object, and call the function.</p>
<pre><code>b1 <- Ball(55, 75, 2, -1, 20, "Ball1")
b2 <- move(b1)
print(b1$loc) # prints 55, 75
print(b2$loc) # prints 202, 214
</code></pre>
<p>Notice that we've now got two ball objects, <code>b1</code> and <code>b2</code>, and they have different locations. This is because most R functions are <em>pass-by-value</em>, or, if it helps, "pass-by-copy." This means that inside the <code>move()</code> function the variable <code>someball</code> is effectively a <em>copy</em> of what was passed to the function; the function then modifies this copy and returns it. (Sidenote: many languages are not pass-by-value, and don't make copies in this way. R's Reference Classes operate more similarly to those languages.)</p>
<p>If we want to modify the <code>b1</code> ball we can reassign the variable from the old ball object to the new one.</p>
<pre><code>b1 <- move(b1)
</code></pre>
<p>R does a lot of work behind the scenes to make this copying as efficient as possible, so try not to stress about it. While we're at it, let's define a <code>display()</code> function:</p>
<pre><code>display <- function(someball) {
ellipse(someball$loc[1], someball$loc[2],
someball$radius, someball$radius)
}
</code></pre>
<p>In order to make this actually display we will need to call if from the Processing.R <code>draw</code> loop function. Let's modify our sketch, adding <code>draw</code>, removing <code>exit()</code> from <code>setup</code> so that the draw window will stay open, and adding <code>noLoop()</code> to draw so that the sketch will draw once, then pause.</p>
<pre><code>setup <- function() {
b1 <- Ball(55, 75, 2, -1, 20, "Ball1")
b1 <- move(b1)
print(b1$loc) # prints 55, 75
}
draw <- function() {
display(b1)
noLoop()
}
Ball <- function(x, y, xs, ys, r, i) {
newb <- list(loc = c(x, y), speed = c(xs, ys),
radius = r, id = i)
class(newb) <- "Ball"
return(newb)
}
move <- function(someball) {
someball$loc <- someball$loc + someball$speed
return(someball)
}
display <- function(someball) {
ellipse(someball$loc[1], someball$loc[2],
someball$radius, someball$radius)
}
</code></pre>
<h3>Dispatch</h3>
<p>We're getting closer. The trouble here is that there's nothing really "attaching" the <code>move()</code> and <code>display()</code> functions to <code>Ball</code> objects. This is a shame, because they'll only really work with <code>Ball</code> objects, not objects of other types.</p>
<p>To motivate what we mean, we need to come up with some other type of object that could move and be displayed. How about a <code>Particle</code> (like a particle of pollen)? Particles will also have an x and y location, but each particle moves by randomly adjusting its location (so it wiggles), and we'll always draw them with a small radius of 2 pixels.</p>
<pre><code># Constructor
Particle <- function(x, y) {
newp <- list(loc = c(x, y))
class(newp) <- "Particle"
return(newp)
}
# function for moving a particle
move <- function(someparticle) {
someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 2)
someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 2)
return(someparticle)
}
# function for displaying a particle
display <- function(someparticle) {
ellipse(someparticle$loc[1], someparticle$loc[2], 2, 2)
}
</code></pre>
<p>Now we can create a couple of particles, have them move, and display them:</p>
<pre><code>p1 <- Particle(400, 400)
p2 <- Particle(500, 500)
p1 <- move(p1)
p2 <- move(p2)
display(p1)
display(p2)
</code></pre>
<p>But wait! We've defined functions <code>move()</code> and <code>display()</code>; do these overwrite the ones we wrote earlier for balls? Yes! And that's a problem.</p>
<p>One solution is to make these functions class-specific (and remember, we call class-specific functions <em>methods</em>), by putting the name of the class as part of the function name:</p>
<pre><code># move method for Ball object
move.Ball <- function(someball) {
someball$loc <- someball$loc + someball$speed
return(someball)
}
# move method for Particle objects
move.Particle <- function(someparticle) {
someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 0, sd = 2)
someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 0, sd = 2)
return(somparticle)
}
</code></pre>
<blockquote>
<p>Note: In R, unlike in Java or JavaScript, the <code>.</code> character isn't very special: it can be used in variable and function names just like any other character. As we'll see though, it is necessary to use this naming scheme for class-specific methods.)</p>
</blockquote>
<p>Now we can say something like this without worry:</p>
<pre><code>p1 <- move.Particle(p1)
b1 <- move.Ball(b1)
</code></pre>
<p>To make our code cleaner, it would be nice if we could define a generic <code>move()</code> function, and if the parameter given had class <code>"Ball"</code> then it called <code>move.Ball()</code>, and if it had class <code>"Particle"</code> then it called <code>move.Particle()</code>. We could try something like this</p>
<pre><code>move <- function(x) {
if(attr(x, "class") == "Ball") {
answer <- move.Ball(x)
return(answer)
} else if(attr(x, "class") == "Particle") {
answer <- move.Particle(x)
return(answer)
}
}
</code></pre>
<p>That's ok, but it turns out this functionality is built into R. Here's the "official" way to do it.</p>
<pre><code># R definition for the generic function.
move <- function(x) {
UseMethod("move", x)
}
</code></pre>
<p>The function <code>UseMethod()</code> does exactly what we want: it looks at the class of <code>x</code>, calls <code>move.<class of x>()</code> instead, and returns the answer. </p>
<p>This is known as <strong>dispatch</strong>, and a function that "dispatches" to a method based on class information is called a <strong>generic</strong> function.</p>
<hr />
<p>Compared to languages like Java, C++, etc., R S3 objects have the same basic stuff--data, class information, and methods. But, whereas Java et al. collect all of this into a single chunk of code, R S3 objects have all of these pieces defined separately. It is the <code>"class"</code> attribute that ties them all together conceptually. In Processing.R, many of these pieces should live in the same file (or tab) to help with reading. If functions for multiple classes appear in the smae long piece of code, organize them by grouping them together and labeling them with comments.</p>
<h3>Putting it together</h3>
<p>Finally, let's write a program that simulates two ball objects and two particle objects.</p>
<blockquote>
<p>Note: Processing.R currently does not support multiple tabs in the PDE editing window -- all code must appear in the one main tab. Ideally, we would separate our code into three tabs -- the main code first, then the Ball code into its own tab and the Particle code into its own tab. For now we'll place all of the code into different sections of the main script tab and label those sections with code comments.</p>
</blockquote>
<p>We will also store all objects (both Balls and Particles) as elements of a single global <code>objects</code> list.</p>
<pre><code>#####################
## Main program code
#####################
# global "objects" list to store Balls and Particles
objects <- list()
# settings: create window
settings <- function() {
size(400, 400)
}
# setup: add objects to objects list
setup <- function() {
# ball in upper-right, moving leftward & down
objects$b1 <- Ball(350, 50, -1.5, 1.2, 15, "ball1")
# ball in uppr-left, moving rightward & down
objects$b2 <- Ball(50, 50, 1.2, 1.5, 20, "ball2")
# particle in lower-left
objects$p1 <- Particle(50, 350)
# particle in lower-right
objects$p2 <- Particle(350, 350)
}
# draw: each frame, update each object
draw <- function() {
background(255, 255, 255)
display(objects$b1)
display(objects$b2)
display(objects$p1)
display(objects$p2)
objects$b1 <- move(objects$b1)
objects$b2 <- move(objects$b2)
objects$p1 <- move(objects$p1)
objects$p2 <- move(objects$p2)
# reset sketch every 300 frames
if(frameCount %% 300 == 0) {
processing$setup()
}
}
##########################################
## Ball class
##########################################
# constructor
Ball <- function(x, y, xs, ys, r, i) {
newb <- list(loc = c(x, y), speed = c(xs, ys),
radius = r, id = i)
class(newb) <- "Ball"
return(newb)
}
# display method
display.Ball <- function(someball) {
ellipse(someball$loc[1], someball$loc[2],
someball$radius, someball$radius)
}
# move method -- returns updated ball
move.Ball <- function(someball) {
someball$loc <- someball$loc + someball$speed
return(someball)
}
#############################################
## Particle class
#############################################
# constructor
Particle <- function(x, y) {
newp <- list(loc = c(x, y))
class(newp) <- "Particle"
return(newp)
}
# display method
display.Particle <- function(someparticle) {
ellipse(someparticle$loc[1], someparticle$loc[2], 2, 2)
}
# move method
move.Particle <- function(someparticle) {
someparticle$loc[1] <- someparticle$loc[1] + rnorm(1, mean = 0, sd = 2)
someparticle$loc[2] <- someparticle$loc[2] + rnorm(1, mean = 0, sd = 2)
return(someparticle)
}
#####################
## Generic functions
#####################
move <- function(x) {
UseMethod("move", x)
}
display <- function(x) {
UseMethod("display", x)
}
</code></pre>
<h3>Improvements</h3>
<p>One obvious modification would be to use a for-loop to display and move each object; because we use the same generic <code>move()</code> and <code>display()</code> functions for both types of objects, we needn't be concerned about whether each object is a <code>Ball</code> or <code>Particle</code>. Here we use <code>[[]]</code>-syntax to access list elements by index number. (With vectors we can use <code>[]</code>-syntax to identify elements, but with lists <code>[]</code> always references a <em>sub-list</em>, rather than the element stored at a particular location.)</p>
<pre><code>draw <- function() {
background(255, 255, 255)
for(i in seq(1:length(objects))) {
display(objects[[i]])
objects[[i]] <- move(objects[[i]])
}
}
</code></pre>
<p>Alternatively, we can use R's <code>lapply()</code> function, which <em>applies</em> a function to each element of a given list. If the function returns something, <code>lapply()</code> returns a list of the returned answers.</p>
<pre><code>draw <- function() {
background(255, 255, 255)
lapply(objects, display)
objects <- lapply(objects, move)
}
</code></pre>
</td>
</tr>
</table>
</body>
<!-- Creative Commons License -->
<div class="license">
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border: none" src="http://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a>
</div>
</div>
<div id="footer">
<div id="copyright">Processing is an open project intiated by <a href="http://benfry.com/">Ben Fry</a> and <a href="http://reas.com">Casey Reas</a>. It is developed by a <a href="http://processing.org/about/people/">small team of volunteers</a>.</div>
</div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="/javascript/jquery-1.9.1.min.js"><\/script>');</script>
<script src="/javascript/site.js" type="text/javascript"></script>
</body>
</html>