-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
visualization blog edits #66
Merged
Merged
Changes from 8 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
f75a717
renamed the directory to reflect the title
jspaaks 27135e1
bunch of stylistic changes/rephrasing
jspaaks 373ff9e
couple more cleanups
jspaaks d2ba4eb
cli.cpp had wrong type
jspaaks 5f00223
wrong indent
jspaaks b6d8862
more cleanup, style, rephrase
jspaaks 4e0c376
Update README.md
jspaaks 771d717
Update README.md
jspaaks e211118
links updated
jspaaks fd8fec3
Merge branch 'jspaaks-visualization-edits' of https://github.com/NLES…
jspaaks File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
|
||
Running C++ code in a web browser is all nice, but we really want to grab someones attention by visualizing something. In this blog we are going to make a plot from the results coming from our C++ code. | ||
|
||
To make a plot we need some data. In a [previous](TODO fix url ../js-webapp) post we found the root of an equation using the Newton-Raphson algorithm implemented in C++ and compiled to a WebAsssembly module. | ||
To make a plot we need some data. In the [previous post](../run-your-c%2B%2B-code-on-the-web) we found the root of an equation using the Newton-Raphson algorithm implemented in C++ and compiled to a WebAsssembly module. | ||
A single root value makes for a depressing plot. The Newton-Raphson algorithm uses iterations to find the root so we will capture the data of each iteration and plot those. | ||
|
||
 | ||
|
@@ -14,12 +14,12 @@ Let's make changes to the C++ code to store the data from the iterations. | |
|
||
To store data of an iteration we will use a structure with the following variables: | ||
|
||
* x, x value, starts with initial guess and ends with root result | ||
* y, result of passing x through equation | ||
* slope, slope or derivative at value x | ||
* delta_x, y divided by slope | ||
* `x`: x value, starting with the value of `initial_guess` and ending with the estimate of the `equation`'s root | ||
* `y`: result of passing `x` through `equation` | ||
* `slope`: result of passing `x` through `derivative` | ||
* `delta_x`: `y` divided by `slope` | ||
|
||
We will add `iterations` public property to the NewtonRaphson which is a vector of iteration structs. So the `newtonraphson.hpp` becomes | ||
We will add a vector of `Iteration` `structs` named `iterations` as a public property to the `NewtonRaphson` class. So `newtonraphson.hpp` becomes: | ||
|
||
```cpp | ||
#ifndef H_NEWTONRAPHSON_HPP | ||
|
@@ -47,7 +47,7 @@ class NewtonRaphson { | |
``` | ||
File: _newtonraphson.hpp_ | ||
|
||
The `newtonraphson.cpp` is rewritten from a while loop to a do while loop like with a push to the iterations vector each cycle. | ||
The `do` loop in `newtonraphson.cpp` is updated to include a `push_back` to the `iterations` vector. This way, we can record the value of relevant variables in each cycle, as follows: | ||
|
||
```cpp | ||
#include "newtonraphson.hpp" | ||
|
@@ -72,7 +72,7 @@ float NewtonRaphson::solve(float initial_guess) { | |
``` | ||
File: _newtonraphson.cpp_. | ||
|
||
Before we go into Emscripten world, lets first test our c++ code. We will check if the iteration property is actually populated correctly by wrapping the code in a main function, adding some print statements, compiling it and running it. | ||
Before we go into the Emscripten world, let's first test our C++ code. We can check if the iteration property is populated correctly, by extending the command line interface we made in the [previous blog](../run-your-c%2B%2B-code-on-the-web) as follows: | ||
|
||
```cpp | ||
#include <iostream> | ||
|
@@ -101,13 +101,13 @@ int main() { | |
``` | ||
File: _cli.cpp_. | ||
|
||
Compile it with | ||
Compile it with: | ||
|
||
```shell | ||
g++ -o cli.exe newtonraphson.cpp cli.cpp | ||
``` | ||
|
||
Run with | ||
Run with: | ||
|
||
```shell | ||
./cli.exe | ||
|
@@ -119,14 +119,14 @@ index = 4 x = -1.02 y = -0.28 slope = 14.40 delta_x = -0.02 | |
index = 5 x = -1.00 y = -0.00 slope = 14.01 delta_x = -0.00 | ||
``` | ||
|
||
The last iteration has `-1.00` as x, which is what we expected. | ||
The last iteration has `x = -1.00`, which is what we expected. | ||
|
||
## Bindings | ||
|
||
Emscripten can handle simple types like float and int, but needs help exposing more complex types to JavaScript like the iterations property. | ||
We need to use [value_object](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#value-types) to expose the Iteration struct and [register_vector](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#built-in-type-conversions) as the iterations property type. | ||
Emscripten can handle simple types like `float` and `int`, but needs help exposing more complex types to JavaScript like the `iterations` property. | ||
We need to use [`value_object`](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#value-types) to expose the `Iteration` `struct` and [`register_vector`](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#built-in-type-conversions) as the `iterations` property type. | ||
|
||
So the bindings look like | ||
So the bindings look like this: | ||
|
||
```cpp | ||
#include <emscripten/bind.h> | ||
|
@@ -154,41 +154,23 @@ EMSCRIPTEN_BINDINGS(newtonraphson) { | |
``` | ||
File: _bindings.cpp_. | ||
|
||
Same as in [previous blog](TODO) we can compile to a WebAssembly module with Emscripten using `emcc` command | ||
We can now compile our C++ code to a WebAssembly module with Emscripten using `emcc` command, exactly [like we did before](../run-your-c%2B%2B-code-on-the-web): | ||
|
||
```shell | ||
emcc -I. -o newtonraphson.js -Oz -s MODULARIZE=1 \ | ||
-s EXPORT_NAME=createModule --bind newtonraphson.cpp bindings.cpp | ||
``` | ||
|
||
<!-- | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I forgot about that one, nice to see #65 |
||
TODO do we want to explain how we can run snippet below? | ||
|
||
To run test the WebAssembly module in a web browser we can use it's build-in console | ||
|
||
1. startup a web server to host newtonraphson.js and newtonraphson.wasm with `python3 -m http.server 8000` | ||
2. goto webserver adress [http://localhost:8000](http://localhost:8080) in browser | ||
3. open the console in the web browsers DevTools (press F12 to open) | ||
|
||
Import the WebAssembly JavaScript binding file with | ||
|
||
```javascript | ||
const response = await fetch('http://localhost:8000/newtonraphson.js'); | ||
const text = await response.text(); | ||
eval(text); | ||
const {NewtonRaphson} = await createModule(); | ||
``` | ||
--> | ||
|
||
To get the iteration data in JavaScript we use the following code | ||
|
||
```javascript | ||
const initial_guess = -4; | ||
const tolerance = 0.001; | ||
const newtonraphson = new NewtonRaphson(tolerance); | ||
newtonraphson.solve(initial_guess); | ||
// newtonraphson.iterations is a vector object which not consumeable by Vega | ||
// So convert Emscripten vector of objects to JavaScript array of objects | ||
// newtonraphson.iterations is a vector object, which is not | ||
// consumeable by Vega, so we need to convert Emscripten's | ||
// vector of objects to a JavaScript array of objects first | ||
const iterations = new Array( | ||
newtonraphson.iterations.size() | ||
).fill().map( | ||
|
@@ -198,7 +180,7 @@ const iterations = new Array( | |
); | ||
``` | ||
|
||
Let's have a look at the data we want to plot, by logging it to the with `console.log(JSON.stringify(iterations, null, 2))` to get | ||
Let's have a look at the data we want to plot, by logging it to the console with `console.log(JSON.stringify(iterations, null, 2))`, which should return the following data: | ||
|
||
```json | ||
[ | ||
|
@@ -259,9 +241,9 @@ So let's plot the iteration index against the y found in each iteration to see h | |
|
||
The Vega-Lite specification is constructed out of the following blocks | ||
|
||
* data, the iterations we want to plot as an array of iteration objects | ||
* mark, for line plot use [line](https://vega.github.io/vega-lite/docs/line.html) marker | ||
* encoding, which field should go on which axis | ||
* `"data"`, the iterations we want to plot as an array of iteration objects | ||
* `"encoding"`, which field should go on which axis | ||
* `"mark"`, for line plot use [line](https://vega.github.io/vega-lite/docs/line.html) marker | ||
|
||
```js | ||
const spec = { | ||
|
@@ -286,7 +268,7 @@ const spec = { | |
}; | ||
``` | ||
|
||
To render a specification we need to use the `vegaEmbed(element, spec)` method which accepts a HTML element and a Vega-Lite specification. | ||
To render a specification we need to use the `vegaEmbed(element, spec)` method which accepts an HTML element and a Vega-Lite specification. | ||
|
||
```html | ||
<html> | ||
|
@@ -306,7 +288,7 @@ To render a specification we need to use the `vegaEmbed(element, spec)` method w | |
</html> | ||
``` | ||
|
||
The complete HTML pages looks like | ||
The complete HTML page looks like this: | ||
|
||
```html | ||
<html> | ||
|
@@ -360,15 +342,15 @@ The complete HTML pages looks like | |
</body> | ||
</html> | ||
``` | ||
File: _scatter.html. | ||
File: _scatter.html_. | ||
|
||
We'll need a web server to display the HTML page in a web browser. For this, we'll use the http.server module from Python 3 to host all files on port 8000, like so: | ||
We'll need a web server to display the HTML page in a web browser. For this, we'll use the `http.server` module from Python 3 to host all files on port 8000, like so: | ||
|
||
```shell | ||
python3 -m http.server 8000 | ||
``` | ||
|
||
When we visit the web page at [http://localhost:8000/scatter.html](http://localhost:8000/scatter.html), we will be greeted by the following plot. We can zoom with mouse wheel and pan by dragging. Also when we hover over a point we get a tooltip with all iteration data. | ||
When we visit the web page at [http://localhost:8000/scatter.html](http://localhost:8000/scatter.html), we will be greeted by the following plot. We can zoom with the mouse wheel and pan by dragging. Hovering over a point shows a tooltip with relevant data at that point. | ||
|
||
[](https://nlesc-jcer.github.io/run-cpp-on-web/js-plot/scatter.html) | ||
(Click on image to get interactive version) | ||
|
@@ -377,7 +359,7 @@ When we visit the web page at [http://localhost:8000/scatter.html](http://localh | |
|
||
In the first blog of this series we plotted the equation and root as | ||
|
||
 | ||
 | ||
|
||
It would be nice to write a specification of this plot together with the iterations the root finding algorithm went through. | ||
Vega-Lite can superimpose one chart on top of another with [layers](https://vega.github.io/vega-lite/docs/layer.html) keyword. | ||
|
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,8 +4,8 @@ | |
#include "newtonraphson.hpp" | ||
|
||
int main() { | ||
double initial_guess = -4; | ||
double tolerance = 0.001; | ||
float initial_guess = -4; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice inconsistency find |
||
float tolerance = 0.001; | ||
NewtonRaphson newtonraphson(tolerance); | ||
newtonraphson.solve(initial_guess); | ||
|
||
|
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Links are already rendered differently, they do not need more highlighting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strictly speaking I don't care to highlight them, but I want to emphasize that I'm referring to something in the code. It's your call though.