Skip to content

Commit e142eff

Browse files
authored
Merge pull request #279 from YousefED/demos-backup
Backup demos
2 parents 10a6c78 + 09e0fad commit e142eff

File tree

4 files changed

+554
-0
lines changed

4 files changed

+554
-0
lines changed

tmp-notebooks/demo-backups/api.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# File upload using API
2+
3+
For this demo we are going to connect our notebook to an external API. Let's see if we can quickly
4+
create a filesharing application that allows you to share a file from your device and create a link that allows someone else to download the file.
5+
6+
We start by exporting an async function that is responsible for making the API call. I found this public API called <a href="https://file.io" target="_blank">file.io</a> that allows you to upload files for free! In this function we use the native `fetch`
7+
function to make the post request to the API endpoint.
8+
9+
```typescript
10+
export async function uploadFile(file: File) {
11+
// Create formdata for a multipart/form-data request
12+
const formData = new FormData();
13+
formData.append("file", file);
14+
15+
const response = await fetch("https://file.io", {
16+
method: "POST",
17+
body: formData,
18+
}).then((response) => response.json());
19+
20+
if (response.status !== 200 || !response.success) {
21+
throw new Error("Upload failed");
22+
}
23+
24+
return response;
25+
}
26+
```
27+
28+
## Creating a React upload component
29+
30+
To allow file uploading we need a file input field that can supply the `File` to the `$.uploadFile()` function.
31+
With the `react-dropzone` library we can quickly create a ninput that also allows file drag and drop. In the `onDrop()` function we call `$.uploadFile()` and depending on it's success alter the components state.
32+
Notice that I manually created a promise so we can use it in other code blocks.
33+
34+
```typescript
35+
import { useDropzone } from "react-dropzone";
36+
import { useState } from "react";
37+
import styled from "styled-components";
38+
39+
const getColor = (props: any) => {
40+
if (props.isDragAccept) {
41+
return "#00e676";
42+
}
43+
if (props.isDragReject) {
44+
return "#ff1744";
45+
}
46+
if (props.isFocused) {
47+
return "#2196f3";
48+
}
49+
return "#eeeeee";
50+
};
51+
52+
const Container = styled.div`
53+
flex: 1;
54+
display: flex;
55+
flex-direction: column;
56+
align-items: center;
57+
padding: 50px;
58+
border-width: 2px;
59+
border-radius: 2px;
60+
border-color: ${(props) => getColor(props)};
61+
border-style: dashed;
62+
background-color: #fafafa;
63+
color: #bdbdbd;
64+
outline: none;
65+
transition: border 0.24s ease-in-out;
66+
`;
67+
68+
export let uploadResponse: { link: string };
69+
70+
function StyledDropzone() {
71+
const [completed, setCompleted] = useState(false);
72+
const [response, setResponse] = useState({ name: "", link: "" });
73+
74+
async function onDrop(acceptedFiles: File[]) {
75+
try {
76+
const response = await $.uploadFile(acceptedFiles[0]);
77+
$.uploadResponse = response;
78+
setResponse(response);
79+
setCompleted(true);
80+
} catch (e) {
81+
alert(e.message);
82+
}
83+
}
84+
85+
const { getRootProps, getInputProps, isFocused, isDragAccept, isDragReject } =
86+
useDropzone({ accept: "image/*", onDrop });
87+
88+
return completed ? (
89+
<div>
90+
Uploaded @
91+
<a href={response.link} target="_blank">
92+
{response.link}
93+
</a>
94+
</div>
95+
) : (
96+
<div className="container">
97+
<Container {...getRootProps({ isFocused, isDragAccept, isDragReject })}>
98+
<input {...getInputProps()} />
99+
<p>Drag 'n' drop a file here, or click to select file</p>
100+
</Container>
101+
</div>
102+
);
103+
}
104+
105+
export default <StyledDropzone />;
106+
```
107+
108+
## Generate a QR code
109+
110+
Maybe you want to quickly download the file on your mobile phone? We can use another API to generate a QR code that contains the download link of our uploaded file.
111+
112+
```typescript
113+
export default $.uploadResponse ? (
114+
<img
115+
src={`https://api.qrserver.com/v1/create-qr-code/?size=100x100&data=${$.uploadResponse.link}`}
116+
/>
117+
) : (
118+
<></>
119+
);
120+
```

tmp-notebooks/demo-backups/charts.md

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
# Using Charts
2+
3+
Because of TypeCells support for React we can use all of the powerful React charting libraries. I'd like to explore two libraries in this demo: <a href="https://vega.github.io/vega-lite/" target="_blank">VegaLite</a> and <a href="https://www.chartjs.org/" target="_blank">Chart.js</a>.
4+
5+
Let's see if we can do something interesting with some live weather data. I've found a public api called <a href="https://open-meteo.com/" target="_blank">Open-Meteo</a> that can provide us with some weather data. For this demo I entered the GPS coordinates of Amsterdam. We can use `fetch` to make the api call and then directly export it's response as a JavaScript object.
6+
7+
```typescript
8+
// Location coordinates of Amsterdam
9+
export let lat = typecell.Input(<input type="text" disabled />, 52.3738);
10+
export let long = typecell.Input(<input type="text" disabled />, 4.891);
11+
12+
export default (
13+
<div>
14+
<p>GPS coords</p>
15+
{lat} <br></br>
16+
{long}
17+
</div>
18+
);
19+
```
20+
21+
```typescript
22+
// Make api call and directly convert the response to a JS object
23+
export const weatherData = await fetch(
24+
`https://api.open-meteo.com/v1/forecast?latitude=${$.lat}&longitude=${$.long}&hourly=temperature_2m,precipitation`
25+
).then((response) => response.json());
26+
```
27+
28+
As you can see in the response we received an hourly rain and temperature forecast for multiple days. For our first chart I'd like to display the amount of rain in mm per hour for the current day.
29+
First we need to transform `hourly.time` and `hourly.precipitation` into a single array of objects. We can map and filter the exported `weatherData` and create a new exported variable called `precipitationData`.
30+
31+
```typescript
32+
export const forecastData = $.weatherData.hourly.precipitation
33+
// Map to object
34+
.map((precipitation: number, i: number) => {
35+
const date = new Date($.weatherData.hourly.time[i]);
36+
const temperature_2m = $.weatherData.hourly.temperature_2m[i];
37+
38+
return {
39+
precipitation,
40+
date,
41+
temperature: temperature_2m,
42+
hour: date.getHours(),
43+
};
44+
})
45+
// Filter objects to only get the hours of today
46+
.filter(
47+
(data: { precipitation: number; date: Date; hour: number }) =>
48+
data.date.getDate() === new Date().getDate()
49+
);
50+
```
51+
52+
## First chart with VegaLite
53+
54+
Now that we've got some data we can create our first chart! After importing `react-vega` we can use the newly created `$.forecastData` dataset to show the precipitation forecast per hour in a line chart. I also added an additional line to display the current time in the chart.
55+
56+
```typescript
57+
import { VegaLite } from "react-vega";
58+
59+
const spec = {
60+
$schema: "https://vega.github.io/schema/vega-lite/v5.json",
61+
autosize: "fit",
62+
width: "700",
63+
layer: [
64+
// Config for precipitation forecast
65+
{
66+
mark: "line",
67+
data: { values: $.forecastData },
68+
encoding: {
69+
y: {
70+
field: "precipitation",
71+
type: "quantitative",
72+
},
73+
x: {
74+
field: "hour",
75+
},
76+
},
77+
},
78+
// Config for displaying current time
79+
{
80+
data: { values: [{ hour: new Date().getHours() }] },
81+
mark: { type: "rule", strokeDash: [2, 2], size: 2, color: "red" },
82+
encoding: {
83+
x: { field: "hour" },
84+
},
85+
},
86+
],
87+
};
88+
89+
export default <VegaLite spec={spec} />;
90+
```
91+
92+
Very nice, we managed to create a first chart using real api data!
93+
But what if we would like to know the forecast of another city? If we update the exported latitude and longitude variables we automatically trigger the previous api call and therefor also rerender the chart.
94+
95+
Try it out!
96+
<small>(Click the arrow on the side of the chart below to show the code of the dropdown)</small>
97+
98+
```typescript
99+
// @default-collapsed
100+
export let select = typecell.Input(
101+
<select>
102+
<option value="Amsterdam">Amsterdam</option>
103+
<option value="London">London</option>
104+
<option value="Istanbul">Istanbul</option>
105+
</select>,
106+
"Amsterdam"
107+
);
108+
109+
export default (
110+
<div>
111+
<b>Select other city</b> <br></br>
112+
{select}
113+
</div>
114+
);
115+
```
116+
117+
```typescript
118+
switch ($.select[0]) {
119+
case "Amsterdam":
120+
$.lat = 52.3738;
121+
$.long = 4.891;
122+
return;
123+
case "London":
124+
$.lat = 51.509865;
125+
$.long = -0.118092;
126+
return;
127+
case "Istanbul":
128+
$.lat = 41.047867;
129+
$.long = 28.898272;
130+
return;
131+
default:
132+
return;
133+
}
134+
```
135+
136+
## Next up - Chart.js
137+
138+
Notice that we also have temperature data in the `$.forecastData` array. Instead of showing the rain forecast, let's try and make a bar chart with the temperature data per hour. Chart.js works a little different compared to VegaLite. Instead of providing a single data array we need to separate labels and the data values.
139+
140+
```typescript
141+
import {
142+
Chart as ChartJS,
143+
CategoryScale,
144+
LinearScale,
145+
BarElement,
146+
Title,
147+
Tooltip,
148+
Legend,
149+
} from "chart.js";
150+
import { Bar } from "react-chartjs-2";
151+
152+
ChartJS.register(
153+
CategoryScale,
154+
LinearScale,
155+
BarElement,
156+
Title,
157+
Tooltip,
158+
Legend
159+
);
160+
161+
export const options = {
162+
responsive: true,
163+
height: 100,
164+
};
165+
166+
// Get the labels by mapping the forecastData object into the hour as a string
167+
const labels = $.forecastData.map(
168+
(d: { precipitation: number; hour: number }) => d.hour.toString()
169+
);
170+
171+
export const data = {
172+
labels,
173+
datasets: [
174+
{
175+
label: "Temperature",
176+
// We do the same here for temperature
177+
data: $.forecastData.map(
178+
(d: { temperature: number; hour: number }) => d.temperature
179+
),
180+
backgroundColor: "rgba(43, 99, 132, 0.8)",
181+
},
182+
],
183+
};
184+
185+
export default (
186+
<div>
187+
<Bar options={options} data={data} />
188+
</div>
189+
);
190+
```

tmp-notebooks/demo-backups/maps.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Leaflet Maps
2+
3+
Let's see what we can do with an interactive geographical map within TypeCell.
4+
For this demo we will use the <a href="https://leafletjs.com/" target="_blank">Leaflet</a> library to display our map.
5+
6+
According to the Leaflet documentation we first need to load the css stylesheet before we can use the map. We can import the stylesheet using a css codeblock. You can change the codeblock type in the bottom right corner.
7+
8+
```css
9+
@import url("https://unpkg.com/[email protected]/dist/leaflet.css");
10+
```
11+
12+
Next we will setup a basic map using the Leaflet library with openstreetmap.
13+
Simply import the leaflet library and add the required configuration according to the Leaflet documentaiton.
14+
In this case I've added the code for generating the map in an exported function in order to reuse it later.
15+
16+
It's necessary to provide Leaflet with a tile provider. For this demo I've used the `OpenStreetMap.Mapnik` provider.
17+
There are plenty of tile options to choose from (Find more tile providers <a href="https://leaflet-extras.github.io/leaflet-providers/preview/" target="_blank">here</a>).
18+
19+
```typescript
20+
import * as L from "leaflet";
21+
22+
export function generateMap() {
23+
const container = document.createElement("div");
24+
container.style.cssText = "width: 100%; height: 400px";
25+
const map = L.map(container).setView([48.505, 17.09], 4);
26+
27+
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
28+
maxZoom: 19,
29+
attribution:
30+
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
31+
}).addTo(map);
32+
33+
return { element: container, map };
34+
}
35+
36+
export default generateMap().element;
37+
```
38+
39+
Voila! We now have a working map that we can interact with in TypeCell.
40+
41+
## Add airport locations ✈️
42+
43+
What fun is a map without markers? Let's add the biggest airports in Europe to a map.
44+
I've found a csv file that lists the locations of all airports worldwide which we can use to find all airport locations.
45+
46+
Using the native `fetch` function we can download the entire csv file as a string. Next, we parse the csv file using `papaparse`. Simply import the module and use the `parse` function to parse the csv into JavaScript objects. Finally, filter the airports by continent and airport type and export it.
47+
48+
```typescript
49+
import * as Papa from "papaparse";
50+
51+
const airportCsv = await fetch(
52+
"https://davidmegginson.github.io/ourairports-data/airports.csv"
53+
).then((response) => response.text());
54+
55+
// Pass the row type to the parser
56+
const { data } = Papa.parse<{
57+
latitude_deg: string;
58+
longitude_deg: string;
59+
continent: string;
60+
type: string;
61+
}>(airportCsv, {
62+
header: true,
63+
transformHeader: (header) => header.toLowerCase().split(" ").join(""),
64+
});
65+
66+
// Filter and export airports
67+
export const airports = data.filter(
68+
(airport) => airport.continent === "EU" && airport.type === "large_airport"
69+
);
70+
```
71+
72+
As you can see, all the airports are exported above. You are able to inspect all exported airports by clicking on the little arrow in front of `airports` above. From now on we can use `$.airports` in other code blocks.
73+
74+
Let's prepare the code for a new map with the airport markers. We can use the `generateMap` function that we created before to create a new map and loop over all the airports to add a marker for each one.
75+
76+
```typescript
77+
import * as L from "leaflet";
78+
79+
const { element, map } = $.generateMap();
80+
81+
for (let airport of $.airports) {
82+
L.marker([+airport.latitude_deg, +airport.longitude_deg]).addTo(map);
83+
}
84+
85+
export default element;
86+
```

0 commit comments

Comments
 (0)