Skip to content

Commit a0d02b4

Browse files
committed
week 9
1 parent 77e3cd5 commit a0d02b4

6 files changed

Lines changed: 533 additions & 4 deletions

File tree

observablehq.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export default {
3838
{ name: "Dashboard", path: "/lab_2/index" },
3939
{ name: "Week 8 Notes", path: "/lab_2/week_8_notes" },
4040
{ name: "Week 8 Class", path: "/lab_2/week_8_class" },
41+
{ name: "Week 9 Notes", path: "/lab_2/week_9_notes" },
42+
{ name: "Week 9 Class", path: "/lab_2/week_9_class" },
4143
],
4244
},
4345
],
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
show_name,cost_per_episode_usd,number_of_episodes,total_production_cost_usd
2+
Stranger Things,12000000,42,504000000
3+
The Crown,13000000,60,780000000
4+
Wednesday,8500000,8,68000000
5+
Money Heist,3500000,41,143500000
6+
Squid Game,2400000,9,21600000
7+
The Witcher,10000000,24,240000000
8+
Bridgerton,7500000,24,180000000
9+
Dark,4200000,26,109200000
10+
Ozark,6800000,44,299200000
11+
The Last of Us,15000000,9,135000000
12+
House of the Dragon,20000000,10,200000000
13+
Breaking Bad,3000000,62,186000000
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
show_name,avg_weekly_viewers,launch_date,weeks_since_launch,total_estimated_viewership
2+
Stranger Things,15200000,2016-07-15,486,7387200000
3+
The Crown,9800000,2016-11-04,470,4606000000
4+
Wednesday,18500000,2022-11-23,154,2849000000
5+
Money Heist,11400000,2017-05-02,444,5061600000
6+
Squid Game,28200000,2021-09-17,216,6091200000
7+
The Witcher,14100000,2019-12-20,307,4328700000
8+
Bridgerton,16300000,2020-12-25,254,4140200000
9+
Dark,8200000,2017-12-01,414,3394800000
10+
Ozark,12700000,2017-07-21,433,5499100000
11+
The Last of Us,21500000,2023-01-15,147,3160500000
12+
House of the Dragon,19800000,2022-08-21,168,3326400000
13+
Breaking Bad,8900000,2008-01-20,929,8268100000

src/lab_2/week_8_notes.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ This is helpful, but wouldn't it be nice if these dots correspond to the price a
254254
</details>
255255
<br><br>
256256

257-
## Data joins
257+
## Data Joins
258258

259259
Lab 2 includes multiple datasets which introduces new challenges when we want to marry the data points. There may be instances where we want to filter to state values, combine data, or reference values from one dataset into another.
260260

@@ -358,15 +358,17 @@ const people_with_state_again = people.map(personObject => ({
358358
display(people_with_state_again)
359359
```
360360

361+
These are just a couple ways to do data joins in javascript, but this is an example of something that AI can be very helpful at, with some clear direction and requests for simple JS functions to achieve what you're looking for.
362+
361363

362364
**Example 2: Find a value from one dataset in another dataset**
363365

364366
Now that we know how to do this join, we can do these arrow functions within the channel itself.
365367

366368
Before we get into the join code here, it's important to remember:
367-
1. Data channels can be functions, so we could use that to our advantage to get from one data point to a related data point in another dataset
369+
1. Data channels can be functions, so we could use that to our advantage to get from one data point to a related data point in another dataset.
368370
2. When we define arrow functions, we have to have a very clear understanding of what is being passed to the function. If we need to, we can use `console.log(data)` within that function to debug.
369-
3. Historically we have just used the generic `d` declaration in our functions (`(d) => d.price`), but we cannot use that twice in two nested functions -- we have to use another variable (commonly, `e`, or a helpful word, like `event => event.Date`).
371+
3. Historically we have just used the generic `d` declaration in our functions (`(d) => d.price`), but we _cannot_ use `d` twice within two nested functions (`(d) => { d.events.filter((d) => d.attendance) }`) -- we have to use another variable (commonly, `e`, or a helpful word, like `event => event.Date`).
370372

371373
Let's make another dropdown closer to this example that we can leverage in the below chart.
372374
```js
@@ -381,6 +383,12 @@ const selectedStockEvents = events.filter(d => d["Related Tickers"].includes(yet
381383
display(selectedStockData[0])
382384
```
383385

386+
When we finally return to our original intention stated earlier:
387+
388+
>Ideally the circle could be positioned on the line. This means we would have to position the event at the appropriate x value (date), then look up the y value for the stock, and use that for the y value of the dot.
389+
390+
We can use the channel function to look up the price value for that day in the other dataset.
391+
384392
Just like in the earlier example, we will use two marks for this example. The first mark is the stock line data (`Plot.line()`), and the second mark is the stock event data (`Plot.dot()`). Each has its own dataset. When we render the `y` value of the event mark, we will look for the stock value for that date in the other dataset.
385393

386394
```js echo
@@ -421,12 +429,14 @@ Plot.plot({
421429
x: selectedStockEvents[0].Date, // position at the event date
422430
y: selectedStockData.find(e => { // y position at the ticker line value on this date
423431
return e.Date.toDateString() === selectedStockEvents[0].Date.toDateString()
424-
})?.Close
432+
})?.Close // the ? here just means that only return it if it exists, and don't "fail" if its undefined.
425433
}),
426434
]
427435
})
428436
```
429437
438+
Now we know how to use values from one dataset within a visualization of another dataset!
439+
430440
<hr/>
431441
432442
## Color Scales

src/lab_2/week_9_class.md

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
---
2+
title: "Week 9 Class"
3+
toc: false
4+
---
5+
6+
7+
# Last Class Review
8+
```js
9+
// const stocks = await FileAttachment("./stock_data/stocks.csv").csv({ typed: true })
10+
// const events = await FileAttachment("./stock_data/stock_events.csv").csv({ typed: true })
11+
// display(stocks.slice(0, 10))
12+
// display(events)
13+
```
14+
15+
<!-- Create an array of unique tickers: -->
16+
```js
17+
// const allTickers = stocks.map(d => d.Ticker)
18+
// // display(allTickers)
19+
// const setTickers = new Set(allTickers)
20+
// const uniqueTickers = Array.from(setTickers)
21+
// display(uniqueTickers)
22+
```
23+
24+
<!-- ```js
25+
const selectedStock = view(Inputs.select(
26+
[null, ...uniqueTickers],
27+
{ value: "AAPL" } //"select" }
28+
))
29+
``` -->
30+
31+
<!-- Selected stock is: ${selectedStock} -->
32+
33+
<!-- ```js
34+
const filteredStocks = stocks.filter(d => d.Ticker === selectedStock)
35+
const filteredEvents = events.filter(d => d["Related Tickers"].includes(selectedStock))
36+
display(filteredEvents)
37+
``` -->
38+
39+
<!-- ```js
40+
display(width)
41+
``` -->
42+
43+
<!-- ```js
44+
Plot.plot({
45+
title: selectedStock === null
46+
? "pick a stock to continue"
47+
: `Viewing: ${selectedStock}`,
48+
height: 200,
49+
width,
50+
marks: [
51+
Plot.line(
52+
// stocks,
53+
filteredStocks,
54+
{
55+
x: "Date",
56+
y: "Close",
57+
z: "Ticker",
58+
// Changing transparency
59+
stroke: d => d["Ticker"] === selectedStock ? "black" : "none",
60+
}),
61+
Plot.linearRegressionY(filteredStocks, {x: "Date", y: "Close", stroke: "red"}),
62+
Plot.ruleY([0]),
63+
Plot.ruleX([new Date(2018, 0, 1)]),
64+
Plot.dot(
65+
filteredEvents,
66+
{
67+
x: "Date",
68+
y: 0,
69+
tip: true,
70+
channels: {
71+
"Event": "Event Name",
72+
"Notes": "Notes"
73+
}
74+
}
75+
),
76+
Plot.tip([filteredEvents[11]], {
77+
x: "Date", //filterEvents.date
78+
// x: filteredEvents[0].Date
79+
channels: {
80+
"Event": "Event Name",
81+
"Notes": "Notes"
82+
}
83+
})
84+
]
85+
})
86+
``` -->
87+
<!--
88+
```js
89+
Plot.plot({
90+
title: selectedStock === null
91+
? "pick a stock to continue"
92+
: `Viewing: ${selectedStock}`,
93+
height: 200,
94+
width,
95+
marks: [
96+
Plot.line(
97+
// stocks,
98+
filteredStocks,
99+
{
100+
x: "Date",
101+
y: "Close",
102+
z: "Ticker",
103+
}),
104+
Plot.ruleY([0]),
105+
Plot.dot(
106+
filteredEvents,
107+
{
108+
x: d => d["Date"],
109+
y: event => {
110+
const thisStockObj = filteredStocks.filter(stock =>
111+
stock.Date.toDateString() === event.Date.toDateString()
112+
// && event["Related Tickers"].includes(stock.Ticker)
113+
// && stock.Ticker === selectedStock
114+
)
115+
console.log(thisStockObj)
116+
// return 0
117+
return thisStockObj[0]?.Close || 0
118+
},
119+
tip: true,
120+
channels: {
121+
"Event": "Event Name",
122+
"Notes": "Notes"
123+
}
124+
}
125+
),
126+
]
127+
})
128+
``` -->
129+
130+
131+
132+
```js
133+
const viewership = await FileAttachment('./viewership_data/viewership.csv').csv({ typed: true })
134+
const cost = await FileAttachment('./viewership_data/production_cost.csv').csv({ typed: true })
135+
136+
display(viewership)
137+
display(cost)
138+
```
139+
140+
```js
141+
view(Inputs.table(viewership))
142+
```
143+
144+
145+
<!-- ```js
146+
Plot.plot({
147+
width,
148+
marginLeft: 120,
149+
marks: [
150+
Plot.barX(viewership,
151+
{
152+
x: "total_estimated_viewership",
153+
y: "show_name",
154+
sort: { y: "-x" }
155+
}
156+
)
157+
]
158+
})
159+
```
160+
161+
162+
```js
163+
Plot.plot({
164+
width,
165+
marginLeft: 120,
166+
marks: [
167+
Plot.barX(cost,
168+
{
169+
x: "total_production_cost_usd",
170+
y: "show_name",
171+
sort: { y: "-x" }
172+
}
173+
)
174+
]
175+
})
176+
``` -->
177+
178+
<!-- ```js
179+
const newData = cost.map(d => ({ ...d, newValue: "E"}))
180+
view(Inputs.table(newData))
181+
``` -->
182+
183+
184+
185+
```js
186+
Plot.plot({
187+
width,
188+
marginLeft: 120,
189+
x: {
190+
tickFormat: tick => `${tick} vpd`
191+
},
192+
color: {
193+
scheme: "YlOrRd",
194+
legend: true,
195+
tickFormat: tick => d3.format(".1s")(tick)
196+
},
197+
marks: [
198+
Plot.barX(viewership, // always look here
199+
{
200+
y: d => d["show_name"],
201+
fill: "total_estimated_viewership",
202+
x: (views) => {
203+
// console.log("show viewers:", views)
204+
const thisShowCost = cost.find(c => {
205+
// console.log("c:", c)
206+
// console.log("check:",
207+
// c.show_name,
208+
// views.show_name,
209+
// c.show_name === views.show_name)
210+
return c.show_name === views.show_name
211+
})
212+
// console.log("thisShowCost", thisShowCost)
213+
const newMetric = views.total_estimated_viewership / thisShowCost.total_production_cost_usd
214+
return newMetric
215+
},
216+
sort: { y: "-x" }
217+
}
218+
)
219+
]
220+
})
221+
```
222+
223+
224+
# AI HELP
225+
226+
Here's what I asked AI:
227+
<div style="font-family: monospace; font-size: 12px; background: lightgrey; border-radius: 2px; padding: 15px 10px">
228+
I am working with Observable Plot, and I would like to join two datasets in this file (viewership, costs) on show name. I want to make a new metric, TOTAL views per TOTAL dollar (spent).
229+
230+
Here is the cost data structure:
231+
{
232+
show_name: "Stranger Things"
233+
cost_per_episode_usd: 12000000
234+
number_of_episodes: 42
235+
total_production_cost_usd: 504000000
236+
}
237+
238+
Here is the views data structure:
239+
{
240+
show_name: "Stranger Things"
241+
avg_weekly_viewers: 15200000
242+
launch_date: 2016-07-15
243+
weeks_since_launch: 486
244+
total_estimated_viewership: 7387200000
245+
}
246+
</div>
247+
248+
It returned:
249+
```js
250+
// Join the datasets and create the new metric
251+
const joinedData = viewership.map(show => {
252+
// Find the matching cost data for this show
253+
const matchingCost = cost.find(c => c.show_name === show.show_name);
254+
255+
if (matchingCost) {
256+
return {
257+
show_name: show.show_name,
258+
total_estimated_viewership: show.total_estimated_viewership,
259+
total_production_cost_usd: matchingCost.total_production_cost_usd,
260+
views_per_dollar: show.total_estimated_viewership / matchingCost.total_production_cost_usd
261+
};
262+
}
263+
return null; // If no matching cost data found
264+
}).filter(d => d !== null); // Remove any shows without cost data
265+
266+
display(joinedData);
267+
```
268+
<!-- selectedStock: ${select} -->
269+
270+
<div class="card">
271+
${Plot.plot({
272+
width,
273+
marginLeft: 120,
274+
title: "Views per Dollar Spent",
275+
marks: [
276+
Plot.barX(joinedData, {
277+
x: "views_per_dollar",
278+
y: "show_name",
279+
sort: { y: "-x" },
280+
tip: true
281+
})
282+
]
283+
})}
284+
</div>

0 commit comments

Comments
 (0)