├── src ├── assets │ ├── .gitkeep │ ├── home │ │ ├── logo-dsta.png │ │ ├── logo-ntu.jpg │ │ ├── about-robot.jpg │ │ ├── about-taobao.jpg │ │ ├── logo-alibaba.jpg │ │ └── about-freediving.jpg │ ├── foundation-icons │ │ ├── foundation-icons.eot │ │ ├── foundation-icons.ttf │ │ ├── foundation-icons.woff │ │ └── .fontcustom-data │ └── scripts │ │ └── d3.layout.cloud.js ├── app │ ├── components │ │ ├── devt-playground │ │ │ ├── devt-playground.component.css │ │ │ ├── devt-playground.component.html │ │ │ ├── devt-playground.spec.ts │ │ │ └── devt-playground.component.ts │ │ ├── nlp-sentence-encoder │ │ │ ├── nlp-sentence-encoder.component.css │ │ │ ├── nlp-sentence-encoder.component.spec.ts │ │ │ ├── nlp-sentence-encoder.component.html │ │ │ └── nlp-sentence-encoder.component.ts │ │ ├── tfjs-timeseries-stocks │ │ │ ├── tfjs-timeseries-stocks.component.css │ │ │ ├── tfjs-timeseries-stocks.component.spec.ts │ │ │ ├── standalone_demo │ │ │ │ ├── model.js │ │ │ │ └── index.html │ │ │ ├── tfjs-timeseries-stocks-main.ts │ │ │ └── README.md │ │ ├── clustering-d3-force-chart │ │ │ ├── clustering-d3-force-chart.component.css │ │ │ ├── README.md │ │ │ ├── clustering-d3-force-chart.component.html │ │ │ ├── clustering-d3-force-chart.component.ts │ │ │ ├── clustering-d3-force-chart.component.spec.ts │ │ │ └── standalone_demo │ │ │ │ ├── index.html │ │ │ │ └── script.js │ │ ├── rl-value-function-tic-tac-toe │ │ │ ├── rl-value-function-tic-tac-toe.component.css │ │ │ ├── rl-value-function-tic-tac-toe.component.spec.ts │ │ │ ├── tic-tac-toe-agent.ts │ │ │ ├── tic-tac-toe-environment.ts │ │ │ ├── README.md │ │ │ ├── rl-value-function-tic-tac-toe.component.html │ │ │ └── rl-value-function-tic-tac-toe.component.ts │ │ ├── phrases-extraction-d3-wordcloud │ │ │ ├── phrases-extraction-d3-wordcloud.component.css │ │ │ ├── standalone_demo │ │ │ │ ├── assets │ │ │ │ │ ├── imgs │ │ │ │ │ │ ├── clouds3.png │ │ │ │ │ │ ├── stars.png │ │ │ │ │ │ └── twinkling.png │ │ │ │ │ ├── space.css │ │ │ │ │ └── cloud.js │ │ │ │ ├── index.html │ │ │ │ ├── make_wordcloud.js │ │ │ │ └── get_top_phrases.js │ │ │ ├── README.md │ │ │ ├── phrases-extraction-d3-wordcloud.component.spec.ts │ │ │ ├── phrases-extraction-d3-wordcloud.component.html │ │ │ ├── phrases-extraction-d3-wordcloud-wordcloud.js │ │ │ └── phrases-extraction-d3-wordcloud-phrases.js │ │ ├── home │ │ │ ├── home.component.css │ │ │ ├── home.component.spec.ts │ │ │ ├── home.component.ts │ │ │ └── home.component.html │ │ └── _drafts │ │ │ ├── github-api-access-repos.zip │ │ │ └── nlp-sentiment-analysis.zip │ ├── services │ │ ├── global.service.ts │ │ └── global.service.spec.ts │ ├── app.component.ts │ ├── app.component.css │ ├── app.component.html │ ├── app.component.spec.ts │ ├── app-routing.module.ts │ └── app.module.ts ├── favicon.ico ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon_angular.ico ├── index.html ├── main.ts ├── test.ts ├── polyfills.ts └── styles.scss ├── others ├── undo_changes_git.sh ├── pull_git.sh ├── push_git.sh └── cleanup.sh ├── e2e ├── tsconfig.json ├── src │ ├── app.po.ts │ └── app.e2e-spec.ts └── protractor.conf.js ├── tsconfig.app.json ├── tsconfig.spec.json ├── browserslist ├── tsconfig.json ├── .gitignore ├── karma.conf.js ├── package.json ├── tslint.json ├── angular.json └── README.md /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /others/undo_changes_git.sh: -------------------------------------------------------------------------------- 1 | git reset --hard 2 | git clean -fd 3 | -------------------------------------------------------------------------------- /src/app/components/devt-playground/devt-playground.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/nlp-sentence-encoder/nlp-sentence-encoder.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/tfjs-timeseries-stocks/tfjs-timeseries-stocks.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /others/pull_git.sh: -------------------------------------------------------------------------------- 1 | git pull https://github.com/jinglescode/demos.git master 2 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/app/components/clustering-d3-force-chart/clustering-d3-force-chart.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/rl-value-function-tic-tac-toe/rl-value-function-tic-tac-toe.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/phrases-extraction-d3-wordcloud.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/favicon_angular.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/favicon_angular.ico -------------------------------------------------------------------------------- /src/assets/home/logo-dsta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/assets/home/logo-dsta.png -------------------------------------------------------------------------------- /src/assets/home/logo-ntu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/assets/home/logo-ntu.jpg -------------------------------------------------------------------------------- /others/push_git.sh: -------------------------------------------------------------------------------- 1 | git add -A 2 | git commit -m "$1" 3 | git push https://github.com/jinglescode/demos.git master 4 | -------------------------------------------------------------------------------- /src/app/components/home/home.component.css: -------------------------------------------------------------------------------- 1 | .mat-card-avatar { 2 | width: 100px; 3 | border-radius: 0%; 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/home/about-robot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/assets/home/about-robot.jpg -------------------------------------------------------------------------------- /src/assets/home/about-taobao.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/assets/home/about-taobao.jpg -------------------------------------------------------------------------------- /src/assets/home/logo-alibaba.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/assets/home/logo-alibaba.jpg -------------------------------------------------------------------------------- /src/assets/home/about-freediving.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/assets/home/about-freediving.jpg -------------------------------------------------------------------------------- /src/assets/foundation-icons/foundation-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/assets/foundation-icons/foundation-icons.eot -------------------------------------------------------------------------------- /src/assets/foundation-icons/foundation-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/assets/foundation-icons/foundation-icons.ttf -------------------------------------------------------------------------------- /src/assets/foundation-icons/foundation-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/assets/foundation-icons/foundation-icons.woff -------------------------------------------------------------------------------- /others/cleanup.sh: -------------------------------------------------------------------------------- 1 | find . -name '.DS_Store' -type f -delete 2 | find . -name 'Icon?' -type f -delete 3 | find . -name 'package-lock.json' -type f -delete 4 | -------------------------------------------------------------------------------- /src/app/components/_drafts/github-api-access-repos.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/app/components/_drafts/github-api-access-repos.zip -------------------------------------------------------------------------------- /src/app/components/_drafts/nlp-sentiment-analysis.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/app/components/_drafts/nlp-sentiment-analysis.zip -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/standalone_demo/assets/imgs/clouds3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/app/components/phrases-extraction-d3-wordcloud/standalone_demo/assets/imgs/clouds3.png -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/standalone_demo/assets/imgs/stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/app/components/phrases-extraction-d3-wordcloud/standalone_demo/assets/imgs/stars.png -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/standalone_demo/assets/imgs/twinkling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinglescode/demos/HEAD/src/app/components/phrases-extraction-d3-wordcloud/standalone_demo/assets/imgs/twinkling.png -------------------------------------------------------------------------------- /src/app/components/devt-playground/devt-playground.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "include": [ 8 | "src/**/*.ts" 9 | ], 10 | "exclude": [ 11 | "src/test.ts", 12 | "src/**/*.spec.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/app/components/clustering-d3-force-chart/README.md: -------------------------------------------------------------------------------- 1 | # D3 Force Clustering 2 | Clustering nodes by attributes using Force chart with [D3.js](http://www.d3js.org). 3 | 4 | ## Data 5 | Data belongs to [IBM: HR Employee Attrition and Performance](https://www.ibm.com/communities/analytics/watson-analytics-blog/hr-employee-attrition/). 6 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JavaScript Exhibits 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/app/services/global.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, EventEmitter } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | export class GlobalService { 7 | 8 | updatePageTitle = new EventEmitter(); 9 | 10 | constructor() { 11 | 12 | } 13 | 14 | changePageTitle(title:string){ 15 | this.updatePageTitle.emit(title); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/app/services/global.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { GlobalService } from './global.service'; 4 | 5 | describe('GlobalService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: GlobalService = TestBed.get(GlobalService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/app/components/clustering-d3-force-chart/clustering-d3-force-chart.component.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 |
19 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | import 'hammerjs'; 8 | 9 | if (environment.production) { 10 | enableProdMode(); 11 | } 12 | 13 | platformBrowserDynamic().bootstrapModule(AppModule) 14 | .catch(err => console.error(err)); 15 | -------------------------------------------------------------------------------- /browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "esnext", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "target": "es5", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ], 21 | "types": [ 22 | "node" 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/README.md: -------------------------------------------------------------------------------- 1 | # Phrases extraction and D3 Wordcloud 2 | 100% JavaScript solution to extracting ngrams from text and display high frequency in beautiful D3 wordcloud. Phrases (ngrams) extraction are done inside *phrases-extraction-d3-wordcloud-phrases.js*, there are a few params which you could tweak and edit stopwords list. Adjustments to wordcloud can be found in *phrases-extraction-d3-wordcloud-wordcloud.js*. 3 | 4 | ## Examples 5 | View a working example [here](https://jinglescode.github.io/demos/phrases-extraction-d3-wordcloud). 6 | 7 | ## Data 8 | Data belongs to [datafiniti/Hotel Reviews](https://data.world/datafiniti/hotel-reviews). 9 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to demos!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /src/app/components/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HomeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Title } from "@angular/platform-browser"; 3 | import { GlobalService } from "./services/global.service"; 4 | 5 | @Component({ 6 | selector: 'app-root', 7 | templateUrl: './app.component.html', 8 | styleUrls: ['./app.component.css'] 9 | }) 10 | export class AppComponent implements OnInit { 11 | 12 | title = 'Jingles'; 13 | 14 | constructor(private service: GlobalService, private titleService:Title){ 15 | 16 | } 17 | 18 | ngOnInit(){ 19 | this.updatePageTitle(); 20 | } 21 | 22 | updatePageTitle(){ 23 | this.service. 24 | updatePageTitle.subscribe((title:string) => { 25 | this.titleService.setTitle(title); 26 | this.title = title; 27 | }); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/app/components/devt-playground/devt-playground.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DevtPlaygroundComponent } from './devt-playground.component'; 4 | 5 | describe('DevtPlaygroundComponent', () => { 6 | let component: DevtPlaygroundComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ DevtPlaygroundComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DevtPlaygroundComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/rl-value-function-tic-tac-toe/rl-value-function-tic-tac-toe.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TicTacToeComponent } from './tic-tac-toe.component'; 4 | 5 | describe('TicTacToeComponent', () => { 6 | let component: TicTacToeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TicTacToeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TicTacToeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/clustering-d3-force-chart/clustering-d3-force-chart.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { GlobalService } from "../../services/global.service"; 3 | import { ClusteringD3ForceChartMain } from "./clustering-d3-force-chart-main"; 4 | 5 | @Component({ 6 | selector: 'app-clustering-d3-force-chart', 7 | templateUrl: './clustering-d3-force-chart.component.html', 8 | styleUrls: ['./clustering-d3-force-chart.component.css'] 9 | }) 10 | export class ClusteringD3ForceChartComponent implements OnInit { 11 | 12 | api_main: ClusteringD3ForceChartMain; 13 | 14 | constructor(private service: GlobalService) { } 15 | 16 | ngOnInit() { 17 | this.service.changePageTitle('Force Chart'); 18 | this.api_main = new ClusteringD3ForceChartMain(); 19 | 20 | this.api_main.init(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events.json 15 | speed-measure-plugin.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | Thumbs.db 46 | .DS_Store 47 | 48 | package-lock.json 49 | -------------------------------------------------------------------------------- /src/app/components/nlp-sentence-encoder/nlp-sentence-encoder.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NlpSentenceEncoderComponent } from './nlp-sentence-encoder.component'; 4 | 5 | describe('NlpSentenceEncoderComponent', () => { 6 | let component: NlpSentenceEncoderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ NlpSentenceEncoderComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(NlpSentenceEncoderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/tfjs-timeseries-stocks/tfjs-timeseries-stocks.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TfjsTimeseriesStocksComponent } from './tfjs-timeseries-stocks.component'; 4 | 5 | describe('TfjsTimeseriesStocksComponent', () => { 6 | let component: TfjsTimeseriesStocksComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TfjsTimeseriesStocksComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TfjsTimeseriesStocksComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/clustering-d3-force-chart/clustering-d3-force-chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ClusteringD3ForceChartComponent } from './clustering-d3-force-chart.component'; 4 | 5 | describe('ClusteringD3ForceChartComponent', () => { 6 | let component: ClusteringD3ForceChartComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ClusteringD3ForceChartComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ClusteringD3ForceChartComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/standalone_demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 |
12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- 1 | .toolbar { 2 | position: sticky; 3 | position: -webkit-sticky; /* For macOS/iOS Safari */ 4 | top: 0; /* Sets the sticky toolbar to be on top */ 5 | z-index: 1000; /* Ensure that your app's content doesn't overlap the toolbar */ 6 | cursor: default; 7 | } 8 | 9 | .toolbar-icon { 10 | width: 36px; 11 | height: 36px; 12 | font-size: 36px; 13 | } 14 | 15 | .toolbar-spacer { 16 | flex: 1 1 auto; 17 | } 18 | 19 | .toolbar h1 { 20 | display: inline-block; 21 | font: 400 20px/36px Google Sans,sans-serif; 22 | color: rgba(0,0,0,.54); 23 | letter-spacing: 0; 24 | margin: 0; 25 | vertical-align: top; 26 | white-space: nowrap; 27 | } 28 | 29 | .toolbar a { 30 | color: #263238; 31 | } 32 | 33 | .main-container { 34 | max-width: 1400px; 35 | margin: 40px auto; 36 | padding: 0 24px; 37 | position: relative; 38 | } 39 | 40 | .mat-icon svg { 41 | height: 24px; 42 | width: 24px; 43 | } 44 | -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/phrases-extraction-d3-wordcloud.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PhrasesExtractionD3WordcloudComponent } from './phrases-extraction-d3-wordcloud.component'; 4 | 5 | describe('PhrasesExtractionD3WordcloudComponent', () => { 6 | let component: PhrasesExtractionD3WordcloudComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PhrasesExtractionD3WordcloudComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PhrasesExtractionD3WordcloudComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/demos'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

{{title}}

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 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | })); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.debugElement.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'lonedune.github.io'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.debugElement.componentInstance; 26 | expect(app.title).toEqual('lonedune.github.io'); 27 | }); 28 | 29 | it('should render title in a h1 tag', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.debugElement.nativeElement; 33 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to lonedune.github.io!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/app/components/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { GlobalService } from "../../services/global.service"; 3 | 4 | @Component({ 5 | selector: 'app-home', 6 | templateUrl: './home.component.html', 7 | styleUrls: ['./home.component.css'] 8 | }) 9 | export class HomeComponent implements OnInit { 10 | 11 | constructor(private service: GlobalService) { } 12 | 13 | ngOnInit() { 14 | this.service.changePageTitle('JavaScript Exhibits'); 15 | } 16 | 17 | showcases = [ 18 | { 19 | name:'Time Series Forecasting with TensorFlow.js', 20 | link:'./tfjs-timeseries-stocks', 21 | description:'Pull stock prices from online API and perform predictions using Recurrent Neural Network and Long Short-Term Memory (LSTM) with TensorFlow.js framework.' 22 | }, 23 | { 24 | name:'Reinforcement Learning Value Function with Tic Tac Toe', 25 | link:'./rl-value-function-tic-tac-toe', 26 | description:'A simple reinforcement learning algorithm for agents to learn the game tic-tac-toe. This demonstrate the purpose of the value function.' 27 | }, 28 | { 29 | name:'Phrases extraction and D3 Wordcloud', 30 | link:'./phrases-extraction-d3-wordcloud', 31 | description:'Extracting ngrams from text and display high frequency in beautiful D3 wordcloud.' 32 | }, 33 | { 34 | name:'Sentence Similarity With TensorFlow.Js', 35 | link:'./nlp-sentence-encoder', 36 | description:'Encoding sentences into embedding vectors and perform sentence similarity' 37 | } 38 | ]; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/app/components/home/home.component.html: -------------------------------------------------------------------------------- 1 | 15 | 16 | 35 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { HomeComponent } from './components/home/home.component'; 5 | import { TfjsTimeseriesStocksComponent } from './components/tfjs-timeseries-stocks/tfjs-timeseries-stocks.component'; 6 | import { RLValueFunctionTicTacToeComponent } from './components/rl-value-function-tic-tac-toe/rl-value-function-tic-tac-toe.component'; 7 | import { PhrasesExtractionD3WordcloudComponent } from './components/phrases-extraction-d3-wordcloud/phrases-extraction-d3-wordcloud.component'; 8 | import { ClusteringD3ForceChartComponent } from './components/clustering-d3-force-chart/clustering-d3-force-chart.component'; 9 | import { NlpSentenceEncoderComponent } from './components/nlp-sentence-encoder/nlp-sentence-encoder.component'; 10 | import { DevtPlaygroundComponent } from './components/devt-playground/devt-playground.component'; 11 | 12 | const routes: Routes = [ 13 | { path: '', component: HomeComponent }, 14 | { path: 'tfjs-timeseries-stocks', component: TfjsTimeseriesStocksComponent }, 15 | { path: 'phrases-extraction-d3-wordcloud', component: PhrasesExtractionD3WordcloudComponent }, 16 | { path: 'rl-value-function-tic-tac-toe', component: RLValueFunctionTicTacToeComponent }, 17 | { path: 'clustering-d3-force-chart', component: ClusteringD3ForceChartComponent }, 18 | { path: 'nlp-sentence-encoder', component: NlpSentenceEncoderComponent }, 19 | { path: 'devt-playground', component: DevtPlaygroundComponent }, 20 | ]; 21 | 22 | @NgModule({ 23 | imports: [RouterModule.forRoot(routes)], 24 | exports: [RouterModule] 25 | }) 26 | export class AppRoutingModule { } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demos", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e", 11 | "push": "sh ./others/push_git.sh", 12 | "pull": "sh ./others/pull_git.sh", 13 | "ghpage1": "ng build --prod --base-href 'https://jinglescode.github.io/demos/' --source-map --build-optimizer", 14 | "ghpage2": "npx angular-cli-ghpages --dir=dist/demos" 15 | }, 16 | "private": true, 17 | "dependencies": { 18 | "@angular/animations": "^8.0.0", 19 | "@angular/cdk": "^8.0.0", 20 | "@angular/common": "~8.0.0", 21 | "@angular/compiler": "~8.0.0", 22 | "@angular/core": "~8.0.0", 23 | "@angular/flex-layout": "^8.0.0-beta.26", 24 | "@angular/forms": "~8.0.0", 25 | "@angular/material": "^8.0.0", 26 | "@angular/platform-browser": "~8.0.0", 27 | "@angular/platform-browser-dynamic": "~8.0.0", 28 | "@angular/router": "~8.0.0", 29 | "@tensorflow-models/universal-sentence-encoder": "^1.1.1", 30 | "@tensorflow/tfjs": "^1.2.6", 31 | "@tensorflow/tfjs-node": "^1.2.1", 32 | "angular-plotly.js": "^1.3.2", 33 | "hammerjs": "^2.0.8", 34 | "plotly.js": "^1.48.3", 35 | "rxjs": "~6.4.0", 36 | "tslib": "^1.9.0", 37 | "zone.js": "~0.9.1" 38 | }, 39 | "devDependencies": { 40 | "@angular-devkit/build-angular": "~0.800.0", 41 | "@angular/cli": "~8.0.1", 42 | "@angular/compiler-cli": "~8.0.0", 43 | "@angular/language-service": "~8.0.0", 44 | "@types/jasmine": "~3.3.8", 45 | "@types/jasminewd2": "~2.0.3", 46 | "codelyzer": "^5.0.0", 47 | "jasmine-core": "~3.4.0", 48 | "jasmine-spec-reporter": "~4.2.1", 49 | "karma": "~4.1.0", 50 | "karma-chrome-launcher": "~2.2.0", 51 | "karma-coverage-istanbul-reporter": "~2.0.1", 52 | "karma-jasmine": "~2.0.1", 53 | "karma-jasmine-html-reporter": "^1.4.0", 54 | "protractor": "~5.4.0", 55 | "ts-node": "~7.0.0", 56 | "tslint": "~5.15.0", 57 | "typescript": "~3.4.3" 58 | }, 59 | "browser": { 60 | "crypto": false 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/app/components/clustering-d3-force-chart/standalone_demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 26 | 27 | 28 | 29 | 30 |
31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 |
40 | 41 |

42 |
43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "array-type": false, 5 | "arrow-parens": false, 6 | "deprecation": { 7 | "severity": "warn" 8 | }, 9 | "component-class-suffix": true, 10 | "contextual-lifecycle": true, 11 | "directive-class-suffix": true, 12 | "directive-selector": [ 13 | true, 14 | "attribute", 15 | "app", 16 | "camelCase" 17 | ], 18 | "component-selector": [ 19 | true, 20 | "element", 21 | "app", 22 | "kebab-case" 23 | ], 24 | "import-blacklist": [ 25 | true, 26 | "rxjs/Rx" 27 | ], 28 | "interface-name": false, 29 | "max-classes-per-file": false, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-consecutive-blank-lines": false, 47 | "no-console": [ 48 | true, 49 | "debug", 50 | "info", 51 | "time", 52 | "timeEnd", 53 | "trace" 54 | ], 55 | "no-empty": false, 56 | "no-inferrable-types": [ 57 | true, 58 | "ignore-params" 59 | ], 60 | "no-non-null-assertion": true, 61 | "no-redundant-jsdoc": true, 62 | "no-switch-case-fall-through": true, 63 | "no-use-before-declare": true, 64 | "no-var-requires": false, 65 | "object-literal-key-quotes": [ 66 | true, 67 | "as-needed" 68 | ], 69 | "object-literal-sort-keys": false, 70 | "ordered-imports": false, 71 | "quotemark": [ 72 | true, 73 | "single" 74 | ], 75 | "trailing-comma": false, 76 | "no-conflicting-lifecycle": true, 77 | "no-host-metadata-property": true, 78 | "no-input-rename": true, 79 | "no-inputs-metadata-property": true, 80 | "no-output-native": true, 81 | "no-output-on-prefix": true, 82 | "no-output-rename": true, 83 | "no-outputs-metadata-property": true, 84 | "template-banana-in-box": true, 85 | "template-no-negated-async": true, 86 | "use-lifecycle-interface": true, 87 | "use-pipe-transform-interface": true 88 | }, 89 | "rulesDirectory": [ 90 | "codelyzer" 91 | ] 92 | } -------------------------------------------------------------------------------- /src/app/components/tfjs-timeseries-stocks/standalone_demo/model.js: -------------------------------------------------------------------------------- 1 | async function trainModel(inputs, outputs, trainingsize, window_size, n_epochs, learning_rate, n_layers, callback){ 2 | 3 | const input_layer_shape = window_size; 4 | const input_layer_neurons = 100; 5 | 6 | const rnn_input_layer_features = 10; 7 | const rnn_input_layer_timesteps = input_layer_neurons / rnn_input_layer_features; 8 | 9 | const rnn_input_shape = [rnn_input_layer_features, rnn_input_layer_timesteps]; 10 | const rnn_output_neurons = 20; 11 | 12 | const rnn_batch_size = window_size; 13 | 14 | const output_layer_shape = rnn_output_neurons; 15 | const output_layer_neurons = 1; 16 | 17 | const model = tf.sequential(); 18 | 19 | let X = inputs.slice(0, Math.floor(trainingsize / 100 * inputs.length)); 20 | let Y = outputs.slice(0, Math.floor(trainingsize / 100 * outputs.length)); 21 | 22 | const xs = tf.tensor2d(X, [X.length, X[0].length]).div(tf.scalar(10)); 23 | const ys = tf.tensor2d(Y, [Y.length, 1]).reshape([Y.length, 1]).div(tf.scalar(10)); 24 | 25 | model.add(tf.layers.dense({units: input_layer_neurons, inputShape: [input_layer_shape]})); 26 | model.add(tf.layers.reshape({targetShape: rnn_input_shape})); 27 | 28 | let lstm_cells = []; 29 | for (let index = 0; index < n_layers; index++) { 30 | lstm_cells.push(tf.layers.lstmCell({units: rnn_output_neurons})); 31 | } 32 | 33 | model.add(tf.layers.rnn({ 34 | cell: lstm_cells, 35 | inputShape: rnn_input_shape, 36 | returnSequences: false 37 | })); 38 | 39 | model.add(tf.layers.dense({units: output_layer_neurons, inputShape: [output_layer_shape]})); 40 | 41 | model.compile({ 42 | optimizer: tf.train.adam(learning_rate), 43 | loss: 'meanSquaredError' 44 | }); 45 | 46 | const hist = await model.fit(xs, ys, 47 | { batchSize: rnn_batch_size, epochs: n_epochs, callbacks: { 48 | onEpochEnd: async (epoch, log) => { 49 | callback(epoch, log); 50 | } 51 | } 52 | }); 53 | 54 | return { model: model, stats: hist }; 55 | } 56 | 57 | function makePredictions(inputs, size, model) 58 | { 59 | let X = inputs.slice(Math.floor(size / 100 * inputs.length), inputs.length); 60 | const predictedResults = model.predict(tf.tensor2d(X, [X.length, X[0].length]).div(tf.scalar(10))).mul(10); 61 | return Array.from(predictedResults.dataSync()); 62 | } 63 | -------------------------------------------------------------------------------- /src/app/components/rl-value-function-tic-tac-toe/tic-tac-toe-agent.ts: -------------------------------------------------------------------------------- 1 | export class TicTacToeAgent { 2 | 3 | eps = 0.1; 4 | alpha = 0.5; 5 | state_history = []; 6 | name = 0; 7 | V = []; 8 | skill_level = 0; 9 | 10 | constructor(name:number, eps=0.05, alpha=0.5) { 11 | this.eps = eps; // probability of choosing random action instead of greedy 12 | this.alpha = alpha; // learning rate 13 | this.state_history = []; 14 | this.name = name; 15 | } 16 | 17 | set_v(V){ 18 | this.V = V; 19 | } 20 | 21 | set_skilllevel(v){ 22 | this.skill_level = v; 23 | } 24 | 25 | set_eps(v){ 26 | this.eps = v; 27 | } 28 | 29 | take_action(env, return_computation=false){ 30 | 31 | let next_move = -1; 32 | let debug_moves = []; 33 | let strategy = "exploit"; 34 | 35 | if(Math.random() best_value){ 61 | best_value = this.V[state]; 62 | best_state = state; 63 | next_move = i; 64 | } 65 | 66 | } 67 | } 68 | 69 | } 70 | 71 | if(return_computation){ 72 | return [next_move, strategy, debug_moves]; 73 | }else{ 74 | return next_move; 75 | } 76 | 77 | } 78 | 79 | update_state_history(state){ 80 | this.state_history.push(this.copy_obj(state)); 81 | } 82 | 83 | update(env){ 84 | let reward = env.get_reward(this.name); 85 | let target = this.copy_obj(reward); 86 | 87 | for(let i=this.state_history.length-1;i>=0;i--){ 88 | let prev = this.state_history[i]; 89 | let value = this.V[prev] + this.alpha*(target - this.V[prev]); 90 | this.V[prev] = value; 91 | // console.log(this.name, prev, this.V[prev]); 92 | target = this.copy_obj(value); 93 | } 94 | this.reset_history(); 95 | } 96 | 97 | reset_history(){ 98 | this.state_history = []; 99 | } 100 | 101 | copy_obj(obj:any) { 102 | return JSON.parse(JSON.stringify(obj)); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/standalone_demo/make_wordcloud.js: -------------------------------------------------------------------------------- 1 | function make_wordcloud(word_count){ 2 | 3 | var fill_colors = ["#29e8c4", "#29e8d8", "#29e4e8", "#29cbe8"]; 4 | 5 | drawWordCloud(word_count, "#chart"); 6 | 7 | function drawWordCloud(word_count, div_id){ 8 | 9 | var width = $(document).width(); 10 | var height = $(document).height(); 11 | var word_entries = d3.entries(word_count); 12 | 13 | var xScale = d3.scale.linear() 14 | .domain([0, d3.max(word_entries, function(d) { 15 | return d.value; 16 | }) 17 | ]) 18 | .range([10,70]); 19 | 20 | d3.layout.cloud().size([width, height]) 21 | .timeInterval(200) 22 | .words(word_entries) 23 | .fontSize(function(d) { return xScale(+d.value); }) 24 | .text(function(d) { return d.key; }) 25 | .rotate(function() { 26 | // return ~~(Math.random() * 2) * 90; 27 | return 0; // comment this and un-comment above to have 90 degree rotations 28 | }) 29 | .font("'helvetica neue', helvetica, arial, sans-serif") 30 | .on("end", draw) 31 | .start(); 32 | 33 | function draw(words) { 34 | // d3.select(div_id).append("svg") 35 | // .attr("width", width) 36 | // .attr("height", height) 37 | // .append("g") 38 | // .attr("transform", "translate(" + [width >> 1, height >> 1] + ")") 39 | // .selectAll("text") 40 | // .data(words) 41 | // .enter().append("text") 42 | // .style("font-size", function(d) { return xScale(d.value) + "px"; }) 43 | // .style("font-family", "'helvetica neue', helvetica, arial, sans-serif") 44 | // .style("font-weight", 100) 45 | // .style("fill", function(d, i) { return fill_colors[i%4]; }) 46 | // .attr("text-anchor", "middle") 47 | // .attr("transform", function(d) { 48 | // return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; 49 | // }) 50 | // .text(function(d) { return d.key; }) 51 | // ; 52 | 53 | var svg = d3.select(div_id).append("svg") 54 | .attr("width", width) 55 | .attr("height", height) 56 | .append("g") 57 | .attr("transform", "translate(" + [width >> 1, height >> 1] + ")") 58 | ; 59 | 60 | var words = svg.selectAll("text") 61 | .data(words) 62 | .enter().append("text") 63 | .style("font-size", function(d) { return xScale(d.value) + "px"; }) 64 | .style("font-family", "'helvetica neue', helvetica, arial, sans-serif") 65 | .style("font-weight", 100) 66 | .style("fill", function(d, i) { return fill_colors[i%4]; }) 67 | .attr("text-anchor", "middle") 68 | .attr("transform", function(d) { 69 | return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; 70 | }) 71 | .text(function(d) { return d.key; }) 72 | ; 73 | 74 | } 75 | 76 | d3.layout.cloud().stop(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/standalone_demo/assets/space.css: -------------------------------------------------------------------------------- 1 | /* ============================================================================================== 2 | Nick Mkrtchyan 3 | https://www.facebook.com/sonick.pk 4 | http://www.Mkrtchyan.zz.mu 5 | ================================================================================================= */ 6 | * { 7 | margin: 0; 8 | padding: 0; 9 | } 10 | header { 11 | background-color:rgba(33, 33, 33, 0.9); 12 | color:#ffffff; 13 | display:block; 14 | font: 14px/1.3 Arial,sans-serif; 15 | height:50px; 16 | position:relative; 17 | z-index:5; 18 | } 19 | h2{ 20 | margin-top: 30px; 21 | text-align: center; 22 | } 23 | header h2{ 24 | font-size: 22px; 25 | margin: 0 auto; 26 | padding: 10px 0; 27 | width: 80%; 28 | text-align: center; 29 | } 30 | header a, a:visited { 31 | text-decoration:none; 32 | color:#fcfcfc; 33 | } 34 | 35 | @keyframes move-twink-back { 36 | from {background-position:0 0;} 37 | to {background-position:-10000px 5000px;} 38 | } 39 | @-webkit-keyframes move-twink-back { 40 | from {background-position:0 0;} 41 | to {background-position:-10000px 5000px;} 42 | } 43 | @-moz-keyframes move-twink-back { 44 | from {background-position:0 0;} 45 | to {background-position:-10000px 5000px;} 46 | } 47 | @-ms-keyframes move-twink-back { 48 | from {background-position:0 0;} 49 | to {background-position:-10000px 5000px;} 50 | } 51 | 52 | @keyframes move-clouds-back { 53 | from {background-position:0 0;} 54 | to {background-position:10000px 0;} 55 | } 56 | @-webkit-keyframes move-clouds-back { 57 | from {background-position:0 0;} 58 | to {background-position:10000px 0;} 59 | } 60 | @-moz-keyframes move-clouds-back { 61 | from {background-position:0 0;} 62 | to {background-position:10000px 0;} 63 | } 64 | @-ms-keyframes move-clouds-back { 65 | from {background-position: 0;} 66 | to {background-position:10000px 0;} 67 | } 68 | 69 | .stars, .twinkling, .clouds { 70 | position:absolute; 71 | top:0; 72 | left:0; 73 | right:0; 74 | bottom:0; 75 | width:100%; 76 | height:100%; 77 | display:block; 78 | } 79 | 80 | .stars { 81 | background:#000 url(imgs/stars.png) repeat top center; 82 | z-index:0; 83 | } 84 | 85 | .twinkling{ 86 | background:transparent url(imgs/twinkling.png) repeat top center; 87 | z-index:1; 88 | 89 | -moz-animation:move-twink-back 200s linear infinite; 90 | -ms-animation:move-twink-back 200s linear infinite; 91 | -o-animation:move-twink-back 200s linear infinite; 92 | -webkit-animation:move-twink-back 200s linear infinite; 93 | animation:move-twink-back 200s linear infinite; 94 | } 95 | 96 | .clouds{ 97 | background:transparent url(imgs/clouds3.png) repeat top center; 98 | z-index:3; 99 | 100 | -moz-animation:move-clouds-back 200s linear infinite; 101 | -ms-animation:move-clouds-back 200s linear infinite; 102 | -o-animation:move-clouds-back 200s linear infinite; 103 | -webkit-animation:move-clouds-back 200s linear infinite; 104 | animation:move-clouds-back 200s linear infinite; 105 | } -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/phrases-extraction-d3-wordcloud.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Phrases extraction and D3 Wordcloud

4 |
5 | 6 |

7 | 100% JavaScript solution to extracting n-grams from text and display high frequency in beautiful D3 wordcloud. Phrases (n-grams) extraction are done inside d3-wordcloud-phrases.js, there are a few params which you could tweak and edit stopwords list. Adjustments to wordcloud can be found in d3-wordcloud-wordcloud.js. 8 |

9 |

10 | Mock data belongs to datafiniti/Hotel Reviews 11 |

12 |

13 | See repo. 14 |

15 |
16 |
17 | 18 | 19 | 20 |

Demo

21 |
22 | 23 |
24 |
25 | 26 | Input text 27 | 28 | Separate sentences by break line 29 | 30 |
31 |
32 |
33 |
34 | 35 | Number of words in wordcloud 36 | 37 | 38 |
39 |
40 | 41 | Words to remove 42 | 43 | Words you want to deliberately remove 44 | 45 |
46 |
47 | 48 |
49 |
50 | 51 |
52 |
53 |
54 |
55 | 56 |
57 | 58 | 59 |

Word Cloud

60 |
61 | 62 |
63 |
64 |
65 |
66 |
67 |
68 | -------------------------------------------------------------------------------- /src/app/components/nlp-sentence-encoder/nlp-sentence-encoder.component.html: -------------------------------------------------------------------------------- 1 |

Sentence Similarity with TensorFlow.js Sentence Encoder

2 | 3 | 4 | 5 |

Find similar sentences

6 |
7 | 8 | 9 |
10 |
11 |

12 | Have you wondered how search engines understand your queries and match the relevant results? How chatbot extract your intent from your questions and provide the most appropriate response? 13 |

14 |

15 | Universal Sentence Encoder (Cer et al., 2018) is a language model that encodes text into fixed-length embeddings. It aims to convert sentences into semantically-meaningful dense real-valued vectors. 16 |

17 |

18 | Try the demo with your own list of sentences. [read more] 19 |

20 |
21 | 22 | 23 |
24 | 25 | Input Sentences 26 | 27 | Every line is a sentence 28 | 29 | 30 | Threshold 31 | 32 | Sentences with similarity score higher than threshold are grouped together 33 | 34 |
35 |
36 | 40 |
41 |
42 | 43 |
44 |
45 |
46 |
47 | 48 |
49 |
50 | 51 | 52 | 53 |

Grouping Results

54 |
55 | 56 | 57 |
58 |
59 |
60 |
61 |
62 | 63 |
64 |
65 | 66 |
67 |
68 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | //**** theming ****// 2 | 3 | @import '~@angular/material/theming'; 4 | /* // Plus imports for other components in your app. 5 | 6 | // Include the common styles for Angular Material. We include this here so that you only 7 | // have to load a single css file for Angular Material in your app. 8 | // Be sure that you only ever include this mixin once! */ 9 | @include mat-core(); 10 | 11 | $candy-app-primary: mat-palette($mat-blue, A200, A100, A400); 12 | $candy-app-accent: mat-palette($mat-light-blue, 100); 13 | 14 | /* // The warn palette is optional (defaults to red). */ 15 | $candy-app-warn: mat-palette($mat-red); 16 | 17 | /* // Create the theme object (a Sass map containing all of the palettes). */ 18 | $candy-app-theme: mat-light-theme($candy-app-primary, $candy-app-accent, $candy-app-warn); 19 | 20 | /* // Include theme styles for core and each component used in your app. 21 | // Alternatively, you can import and @include the theme mixins for each component 22 | // that you are using. */ 23 | @include angular-material-theme($candy-app-theme); 24 | 25 | 26 | //**** global CSS ****// 27 | body { 28 | // font-family: Roboto, Arial, sans-serif; 29 | // font-family: Google Sans,sans-serif; 30 | font-family: 'San Francisco', -apple-system, BlinkMacSystemFont, '.SFNSText-Regular', Roboto, 'Helvetica Neue', Helvetica, Arial, sans-serif; 31 | color: #263238; 32 | margin: 0; 33 | -webkit-font-smoothing: antialiased; 34 | text-rendering: optimizeLegibility; 35 | background-color: #fafafa; 36 | } 37 | 38 | p, ol { 39 | // font: 400 16px/24px Roboto,sans-serif; 40 | margin-bottom: 1rem; 41 | font-size: 15px; 42 | line-height: 1.6; 43 | text-rendering: optimizeLegibility; 44 | } 45 | 46 | a{ 47 | text-decoration: none; 48 | color: #039be5; 49 | } 50 | 51 | h1, h2, h3, h4, h5, h6 { 52 | /* margin: 20px 0 10px 0; 53 | font-weight: 300; 54 | line-height: 53px; */ 55 | // font-family: linea, avenir, "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; 56 | color: #1D2129; 57 | text-transform: capitalize; 58 | font-weight: normal; 59 | } 60 | 61 | h1 { 62 | font-size: 30px; 63 | } 64 | h2 { 65 | font-size: 22px; 66 | } 67 | h3 { 68 | font-size: 16px; 69 | } 70 | h4 { 71 | font-size: 14px; 72 | } 73 | h5 { 74 | font-size: 12px; 75 | } 76 | h6 { 77 | font-size: 10px; 78 | } 79 | 80 | // h1 { 81 | // // font: 400 32px/40px Google Sans,sans-serif; 82 | // font-family: linea, avenir, "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; 83 | // letter-spacing: 0; 84 | // margin: 0px 0 24px; 85 | // } 86 | // 87 | // h2 { 88 | // border-bottom: 0; 89 | // // font: 400 22px/30px Google Sans,sans-serif; 90 | // font-family: linea, avenir, "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; 91 | // letter-spacing: 0; 92 | // margin: 0px 0 24px; 93 | // padding-bottom: 0; 94 | // } 95 | 96 | .mat-card { 97 | margin-bottom: 30px; 98 | color: #4B4F56; 99 | } 100 | 101 | .page-title { 102 | // font: 400 44px/52px Google Sans,sans-serif; 103 | font-family: linea, avenir, "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; 104 | margin: 40px auto 20px; 105 | min-width: 400px; 106 | text-align: center; 107 | width: 50%; 108 | } 109 | 110 | .page-subtitle { 111 | margin: 0 auto 32px; 112 | min-width: 400px; 113 | width: 80%; 114 | text-align: center; 115 | } 116 | -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/phrases-extraction-d3-wordcloud-wordcloud.js: -------------------------------------------------------------------------------- 1 | const d3 = require("../../../assets/scripts/d3.min.js"); 2 | const cloud = require("../../../assets/scripts/d3.layout.cloud.js"); 3 | 4 | export class D3WordcloucWordcloud { 5 | 6 | constructor() { 7 | } 8 | 9 | make_wordcloud(word_count){ 10 | 11 | var fill_colors = ["#29e8c4", "#29e8d8", "#29e4e8", "#29cbe8"]; 12 | 13 | drawWordCloud(word_count, ".chart_wordcloud"); 14 | 15 | function drawWordCloud(word_count, div_id){ 16 | 17 | var width = window.innerWidth - 200;// $(document).width(); 18 | var height = width * 0.5;//$(document).height(); 19 | var word_entries = d3.entries(word_count); 20 | 21 | var xScale = d3.scale.linear() 22 | .domain([0, d3.max(word_entries, function(d) { 23 | return d.value; 24 | }) 25 | ]) 26 | .range([10,70]); 27 | 28 | cloud().size([width, height]) 29 | .timeInterval(200) 30 | .words(word_entries) 31 | .fontSize(function(d) { return xScale(+d.value); }) 32 | .text(function(d) { return d.key; }) 33 | .rotate(function() { 34 | // return ~~(Math.random() * 2) * 90; 35 | return 0; // comment this and un-comment above to have 90 degree rotations 36 | }) 37 | .font("'helvetica neue', helvetica, arial, sans-serif") 38 | .on("end", draw) 39 | .start(); 40 | 41 | function draw(words) { 42 | // d3.select(div_id).append("svg") 43 | // .attr("width", width) 44 | // .attr("height", height) 45 | // .append("g") 46 | // .attr("transform", "translate(" + [width >> 1, height >> 1] + ")") 47 | // .selectAll("text") 48 | // .data(words) 49 | // .enter().append("text") 50 | // .style("font-size", function(d) { return xScale(d.value) + "px"; }) 51 | // .style("font-family", "'helvetica neue', helvetica, arial, sans-serif") 52 | // .style("font-weight", 100) 53 | // .style("fill", function(d, i) { return fill_colors[i%4]; }) 54 | // .attr("text-anchor", "middle") 55 | // .attr("transform", function(d) { 56 | // return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; 57 | // }) 58 | // .text(function(d) { return d.key; }) 59 | // ; 60 | 61 | d3.select(div_id).html(""); 62 | 63 | var svg = d3.select(div_id).append("svg") 64 | .attr("width", width) 65 | .attr("height", height) 66 | .append("g") 67 | .attr("transform", "translate(" + [width >> 1, height >> 1] + ")") 68 | ; 69 | 70 | var words = svg.selectAll("text") 71 | .data(words) 72 | .enter().append("text") 73 | .style("font-size", function(d) { return xScale(d.value) + "px"; }) 74 | .style("font-family", "'helvetica neue', helvetica, arial, sans-serif") 75 | .style("font-weight", 100) 76 | .style("fill", function(d, i) { return fill_colors[i%4]; }) 77 | .attr("text-anchor", "middle") 78 | .attr("transform", function(d) { 79 | return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; 80 | }) 81 | .text(function(d) { return d.key; }) 82 | ; 83 | 84 | } 85 | 86 | cloud().stop(); 87 | } 88 | } 89 | 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/app/components/devt-playground/devt-playground.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { GlobalService } from "../../services/global.service"; 3 | 4 | import * as tf from '@tensorflow/tfjs'; 5 | import * as use from '@tensorflow-models/universal-sentence-encoder'; 6 | 7 | @Component({ 8 | selector: 'app-devt-playground', 9 | templateUrl: './devt-playground.component.html', 10 | styleUrls: ['./devt-playground.component.css'] 11 | }) 12 | export class DevtPlaygroundComponent implements OnInit { 13 | 14 | list_sentences = []; 15 | plotly_heatmap = {data:[], layout:{}}; 16 | 17 | constructor(private service: GlobalService) { } 18 | 19 | ngOnInit() { 20 | this.service.changePageTitle('Development Playground'); 21 | this.main(); 22 | } 23 | 24 | get_embeddings(list_sentences, callback) { 25 | use.load().then(model => { 26 | model.embed(list_sentences).then(embeddings => { 27 | callback(embeddings); 28 | }); 29 | }); 30 | } 31 | 32 | dot(a, b){ 33 | var hasOwnProperty = Object.prototype.hasOwnProperty; 34 | var sum = 0; 35 | for (var key in a) { 36 | if (hasOwnProperty.call(a, key) && hasOwnProperty.call(b, key)) { 37 | sum += a[key] * b[key] 38 | } 39 | } 40 | return sum 41 | } 42 | 43 | similarity(a, b) { 44 | var magA = Math.sqrt(this.dot(a, a)); 45 | var magB = Math.sqrt(this.dot(b, b)); 46 | if (magA && magB) return this.dot(a, b) / (magA * magB); 47 | else return false 48 | } 49 | 50 | cosine_similarity_matrix(matrix){ 51 | let cosine_similarity_matrix = []; 52 | for(let i=0;i { 124 | // return tokenizer.encode(text); 125 | // }); 126 | // console.log('use 2'); 127 | // } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "demos": { 7 | "projectType": "application", 8 | "schematics": {}, 9 | "root": "", 10 | "sourceRoot": "src", 11 | "prefix": "app", 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/demos", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "tsconfig.app.json", 21 | "assets": [ 22 | "src/favicon.ico", 23 | "src/assets" 24 | ], 25 | "styles": [ 26 | "src/styles.scss" 27 | ], 28 | "scripts": [ 29 | "node_modules/plotly.js/dist/plotly.min.js" 30 | ] 31 | }, 32 | "configurations": { 33 | "production": { 34 | "fileReplacements": [ 35 | { 36 | "replace": "src/environments/environment.ts", 37 | "with": "src/environments/environment.prod.ts" 38 | } 39 | ], 40 | "optimization": true, 41 | "outputHashing": "all", 42 | "sourceMap": false, 43 | "extractCss": true, 44 | "namedChunks": false, 45 | "aot": true, 46 | "extractLicenses": true, 47 | "vendorChunk": true, 48 | "buildOptimizer": false, 49 | "budgets": [ 50 | { 51 | "type": "initial", 52 | "maximumWarning": "2mb", 53 | "maximumError": "10mb" 54 | } 55 | ] 56 | } 57 | } 58 | }, 59 | "serve": { 60 | "builder": "@angular-devkit/build-angular:dev-server", 61 | "options": { 62 | "browserTarget": "demos:build" 63 | }, 64 | "configurations": { 65 | "production": { 66 | "browserTarget": "demos:build:production" 67 | } 68 | } 69 | }, 70 | "extract-i18n": { 71 | "builder": "@angular-devkit/build-angular:extract-i18n", 72 | "options": { 73 | "browserTarget": "demos:build" 74 | } 75 | }, 76 | "test": { 77 | "builder": "@angular-devkit/build-angular:karma", 78 | "options": { 79 | "main": "src/test.ts", 80 | "polyfills": "src/polyfills.ts", 81 | "tsConfig": "tsconfig.spec.json", 82 | "karmaConfig": "karma.conf.js", 83 | "assets": [ 84 | "src/favicon.ico", 85 | "src/assets" 86 | ], 87 | "styles": [ 88 | "src/styles.css" 89 | ], 90 | "scripts": [] 91 | } 92 | }, 93 | "lint": { 94 | "builder": "@angular-devkit/build-angular:tslint", 95 | "options": { 96 | "tsConfig": [ 97 | "tsconfig.app.json", 98 | "tsconfig.spec.json", 99 | "e2e/tsconfig.json" 100 | ], 101 | "exclude": [ 102 | "**/node_modules/**" 103 | ] 104 | } 105 | }, 106 | "e2e": { 107 | "builder": "@angular-devkit/build-angular:protractor", 108 | "options": { 109 | "protractorConfig": "e2e/protractor.conf.js", 110 | "devServerTarget": "demos:serve" 111 | }, 112 | "configurations": { 113 | "production": { 114 | "devServerTarget": "demos:serve:production" 115 | } 116 | } 117 | } 118 | } 119 | }}, 120 | "defaultProject": "demos" 121 | } 122 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { CommonModule } from '@angular/common'; 4 | 5 | import { AppRoutingModule } from './app-routing.module'; 6 | import { AppComponent } from './app.component'; 7 | import { FormsModule } from '@angular/forms'; 8 | import { FlexLayoutModule } from '@angular/flex-layout'; 9 | import { HttpClientModule } from '@angular/common/http'; 10 | 11 | import { PlotlyViaWindowModule } from 'angular-plotly.js'; 12 | 13 | // material 14 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; 15 | import {MatAutocompleteModule, 16 | MatBadgeModule, 17 | MatBottomSheetModule, 18 | MatButtonModule, 19 | MatButtonToggleModule, 20 | MatCardModule, 21 | MatCheckboxModule, 22 | MatChipsModule, 23 | MatDatepickerModule, 24 | MatDialogModule, 25 | MatDividerModule, 26 | MatExpansionModule, 27 | MatGridListModule, 28 | MatIconModule, 29 | MatInputModule, 30 | MatListModule, 31 | MatMenuModule, 32 | MatNativeDateModule, 33 | MatPaginatorModule, 34 | MatProgressBarModule, 35 | MatProgressSpinnerModule, 36 | MatRadioModule, 37 | MatRippleModule, 38 | MatSelectModule, 39 | MatSidenavModule, 40 | MatSliderModule, 41 | MatSlideToggleModule, 42 | MatSnackBarModule, 43 | MatSortModule, 44 | MatStepperModule, 45 | MatTableModule, 46 | MatTabsModule, 47 | MatToolbarModule, 48 | MatTooltipModule, 49 | MatTreeModule} from '@angular/material'; 50 | 51 | // components 52 | import { HomeComponent } from './components/home/home.component'; 53 | import { TfjsTimeseriesStocksComponent } from './components/tfjs-timeseries-stocks/tfjs-timeseries-stocks.component'; 54 | import { RLValueFunctionTicTacToeComponent } from './components/rl-value-function-tic-tac-toe/rl-value-function-tic-tac-toe.component'; 55 | import { PhrasesExtractionD3WordcloudComponent } from './components/phrases-extraction-d3-wordcloud/phrases-extraction-d3-wordcloud.component'; 56 | import { ClusteringD3ForceChartComponent } from './components/clustering-d3-force-chart/clustering-d3-force-chart.component'; 57 | import { NlpSentenceEncoderComponent } from './components/nlp-sentence-encoder/nlp-sentence-encoder.component'; 58 | import { DevtPlaygroundComponent } from './components/devt-playground/devt-playground.component'; 59 | 60 | // directives 61 | 62 | @NgModule({ 63 | declarations: [ 64 | AppComponent, 65 | HomeComponent, 66 | TfjsTimeseriesStocksComponent, 67 | RLValueFunctionTicTacToeComponent, 68 | PhrasesExtractionD3WordcloudComponent, 69 | ClusteringD3ForceChartComponent, 70 | NlpSentenceEncoderComponent, 71 | DevtPlaygroundComponent 72 | ], 73 | imports: [ 74 | BrowserModule, 75 | AppRoutingModule, 76 | CommonModule, 77 | 78 | BrowserAnimationsModule, 79 | MatAutocompleteModule, 80 | MatBadgeModule, 81 | MatBottomSheetModule, 82 | MatButtonModule, 83 | MatButtonToggleModule, 84 | MatCardModule, 85 | MatCheckboxModule, 86 | MatChipsModule, 87 | MatDatepickerModule, 88 | MatDialogModule, 89 | MatDividerModule, 90 | MatExpansionModule, 91 | MatGridListModule, 92 | MatIconModule, 93 | MatInputModule, 94 | MatListModule, 95 | MatMenuModule, 96 | MatNativeDateModule, 97 | MatPaginatorModule, 98 | MatProgressBarModule, 99 | MatProgressSpinnerModule, 100 | MatRadioModule, 101 | MatRippleModule, 102 | MatSelectModule, 103 | MatSidenavModule, 104 | MatSliderModule, 105 | MatSlideToggleModule, 106 | MatSnackBarModule, 107 | MatSortModule, 108 | MatStepperModule, 109 | MatTableModule, 110 | MatTabsModule, 111 | MatToolbarModule, 112 | MatTooltipModule, 113 | MatTreeModule, 114 | 115 | FormsModule, 116 | FlexLayoutModule, 117 | HttpClientModule, 118 | PlotlyViaWindowModule 119 | ], 120 | providers: [], 121 | bootstrap: [AppComponent] 122 | }) 123 | export class AppModule { } 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScript Exhibits 2 | 3 | Here are the list of JavaScript projects in this repo. I work on them during my free time. If you are interested to collaborate on working a cool JavaScript side project together, [reach out to me](https://jinglescode.github.io/), I will be happy to chat! 4 | 5 | ## Depreciated 6 | 7 | This repo has been decommissioned. But here are the updated repos: 8 | - [Time Series Forecasting With TensorFlow.Js](https://github.com/jinglescode/time-series-forecasting-tensorflowjs) 9 | - [Sentence Similarity With TensorFlow.Js Sentence Encoder](https://github.com/jinglescode/textual-similarity-universal-sentence-encoder) 10 | - [Reinforcement Learning Value Function with Tic Tac Toe](https://github.com/jinglescode/reinforcement-learning-tic-tac-toe) 11 | - [Phrases Extraction And D3 Wordcloud](https://github.com/jinglescode/phrases-extraction-wordcloud) 12 | 13 | ## Time Series Forecasting With TensorFlow.Js 14 | 15 | Pull stock prices from online API and perform predictions using Recurrent Neural Network and Long Short-Term Memory (LSTM) with TensorFlow.js framework. 16 | 17 | [Demo](https://jinglescode.github.io/time-series-forecasting-tensorflowjs) | 18 | [Code](https://github.com/jinglescode/time-series-forecasting-tensorflowjs) | 19 | [Article](https://jinglescode.github.io/2019/05/17/time-series-forecasting-with-tensorflow-js/) 20 | 21 | Packages dependencies: 22 | - @tensorflow/tfjs 23 | - @angular/common/http 24 | 25 | ## Reinforcement Learning Value Function with Tic Tac Toe 26 | 27 | Reinforcement learning algorithm for agents to learn the tic-tac-toe, using the value function. Train the agent to play tic-tac-toe, by having 2 agents play against each other through simulation. You can experiment by adjusting 2 parameters, 1) learning rate and 2) probability of exploration of each agent. After training, try playing against the agent. 28 | 29 | [Demo](https://jinglescode.github.io/reinforcement-learning-tic-tac-toe) | 30 | [Code](https://github.com/jinglescode/reinforcement-learning-tic-tac-toe) | 31 | [Article](https://jinglescode.github.io/2019/06/30/reinforcement-learning-value-function/) 32 | 33 | ## Phrases Extraction And D3 Wordcloud 34 | 35 | 100% JavaScript solution to extracting ngrams from text and display high frequency in beautiful D3 wordcloud. Phrases (ngrams) extraction are done inside d3-wordcloud-phrases.js, there are a few params which you could tweak and edit stopwords list. Adjustments to wordcloud can be found in d3-wordcloud-wordcloud.js. 36 | 37 | [Demo](https://jinglescode.github.io/phrases-extraction-wordcloud) | 38 | [Code](https://github.com/jinglescode/phrases-extraction-wordcloud) | 39 | [Article](https://jinglescode.github.io/2017/10/01/extract-phrases-display-wordcloud/) 40 | 41 | Packages dependencies: 42 | - d3 43 | - d3.layout.cloud 44 | 45 | ## Sentence Similarity With TensorFlow.Js Sentence Encoder 46 | 47 | Universal Sentence Encoder [(Cer et al., 2018)](https://arxiv.org/pdf/1803.11175.pdf) is a language model that encodes text into fixed-length embeddings. It aims to convert sentences into semantically-meaningful dense real-valued vectors. 48 | 49 | [Demo](https://jinglescode.github.io/textual-similarity-universal-sentence-encoder) | 50 | [Code](https://github.com/jinglescode/textual-similarity-universal-sentence-encoder) | 51 | [Article](https://jinglescode.github.io/2020/02/10/build-textual-similarity-analysis-web-app/) 52 | 53 | Packages dependencies: 54 | - @tensorflow/tfjs 55 | - @tensorflow-models/universal-sentence-encoder 56 | 57 | # Features 58 | 59 | - packages are shared among all the exhibits, reduces setup time and we can focus on building JavaScript projects 60 | - each project are separated as different [app/components](https://github.com/jinglescode/demos/tree/master/src/app/components), this is neat 61 | 62 | # Install 63 | 64 | With [npm](https://npmjs.org/) installed, run 65 | 66 | ``` 67 | $ npm install 68 | ``` 69 | 70 | That will install all the dependencies listed in `package.json`. 71 | 72 | # Usage 73 | 74 | To start, simply run 75 | 76 | ``` 77 | $ npm start 78 | ``` 79 | 80 | This project is build on [Angular](https://angular.io/), design styles are based on [Material](https://material.angular.io/). 81 | -------------------------------------------------------------------------------- /src/app/components/rl-value-function-tic-tac-toe/tic-tac-toe-environment.ts: -------------------------------------------------------------------------------- 1 | export class TicTacToeEnvironment { 2 | 3 | board = []; 4 | board_length: number; 5 | p1 = 1; 6 | p2 = -1; 7 | winner = 0; 8 | ended = false; 9 | num_states: number; 10 | player_turn = 1; 11 | 12 | constructor(board_length:number) { 13 | this.board_length = board_length; 14 | this.num_states = Math.pow(3,board_length*board_length); 15 | 16 | for(let i=0;i { 63 | model.embed(list_sentences).then(embeddings => { 64 | callback(embeddings); 65 | }); 66 | }); 67 | } 68 | 69 | dot(a, b){ 70 | var hasOwnProperty = Object.prototype.hasOwnProperty; 71 | var sum = 0; 72 | for (var key in a) { 73 | if (hasOwnProperty.call(a, key) && hasOwnProperty.call(b, key)) { 74 | sum += a[key] * b[key] 75 | } 76 | } 77 | return sum 78 | } 79 | 80 | similarity(a, b) { 81 | var magnitudeA = Math.sqrt(this.dot(a, a)); 82 | var magnitudeB = Math.sqrt(this.dot(b, b)); 83 | if (magnitudeA && magnitudeB) 84 | return this.dot(a, b) / (magnitudeA * magnitudeB); 85 | else return false 86 | } 87 | 88 | cosine_similarity_matrix(matrix){ 89 | let cosine_similarity_matrix = []; 90 | for(let i=0;i this.input_threshold){ 115 | 116 | let group_num: number; 117 | 118 | if(!(i in dict_keys_in_group)){ 119 | group_num = groups.length; 120 | dict_keys_in_group[i] = group_num; 121 | }else{ 122 | group_num = dict_keys_in_group[i]; 123 | } 124 | if(!(j in dict_keys_in_group)){ 125 | dict_keys_in_group[j] = group_num; 126 | } 127 | 128 | if(groups.length <= group_num){ 129 | groups.push([]); 130 | } 131 | groups[group_num].push(i); 132 | groups[group_num].push(j); 133 | } 134 | } 135 | } 136 | } 137 | 138 | let return_groups = []; 139 | for(var i in groups){ 140 | return_groups.push(Array.from(new Set(groups[i]))); 141 | } 142 | 143 | console.log(return_groups); 144 | return return_groups; 145 | } 146 | 147 | async get_similarity(list_sentences){ 148 | 149 | let callback = function(embeddings) { 150 | 151 | // console.log("embeddings", embeddings); 152 | 153 | let cosine_similarity_matrix = this.cosine_similarity_matrix(embeddings.arraySync()); 154 | console.log(cosine_similarity_matrix); 155 | 156 | let groups = this.form_groups(cosine_similarity_matrix); 157 | 158 | let html_groups = ""; 159 | for(let i in groups){ 160 | html_groups+="
Group "+String(parseInt(i)+1)+"
"; 161 | for(let j in groups[i]){ 162 | // console.log(groups[i][j], list_sentences[ groups[i][j] ]) 163 | html_groups+= list_sentences[ groups[i][j] ] + "
"; 164 | } 165 | } 166 | 167 | this.output_resultshtml = html_groups; 168 | 169 | // plot heatmap 170 | let colors = []; 171 | let base_color = 54; 172 | for(let i=0;i<=10;i++){ 173 | colors.push([i/10, "rgb(0,"+(base_color+(i*20))+",0)"]); 174 | } 175 | 176 | this.plotly_heatmap = { 177 | data: [ 178 | { 179 | z: cosine_similarity_matrix,// [[1, 20, 30], [20, 1, 60], [30, 60, 1]], 180 | x: list_sentences, 181 | y: list_sentences, 182 | type: 'heatmap', 183 | colorscale: colors 184 | } 185 | ], 186 | layout: {height:1200, title: "Similarity", autosize: true}, 187 | 188 | }; 189 | this.analyzing_text = false 190 | }; 191 | 192 | this.analyzing_text = true; 193 | let embeddings = await this.get_embeddings(list_sentences, callback.bind(this)); 194 | 195 | } 196 | 197 | } 198 | -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/standalone_demo/get_top_phrases.js: -------------------------------------------------------------------------------- 1 | function get_top_phrases(_list_text, top_n, remove_these){ 2 | 3 | var common = "poop,i,me,my,myself,we,us,our,ours,ourselves,you,your,yours,yourself,yourselves,he,him,his,himself,she,her,hers,herself,it,its,itself,they,them,their,theirs,themselves,what,which,who,whom,whose,this,that,these,those,am,is,are,was,were,be,been,being,have,has,had,having,do,does,did,doing,will,would,should,can,could,ought,i'm,you're,he's,she's,it's,we're,they're,i've,you've,we've,they've,i'd,you'd,he'd,she'd,we'd,they'd,i'll,you'll,he'll,she'll,we'll,they'll,isn't,aren't,wasn't,weren't,hasn't,haven't,hadn't,doesn't,don't,didn't,won't,wouldn't,shan't,shouldn't,can't,cannot,couldn't,mustn't,let's,that's,who's,what's,here's,there's,when's,where's,why's,how's,a,an,the,and,but,if,or,because,as,until,while,of,at,by,for,with,about,against,between,into,through,during,before,after,above,below,to,from,up,upon,down,in,out,on,off,over,under,again,further,then,once,here,there,when,where,why,how,all,any,both,each,few,more,most,other,some,such,no,nor,not,only,own,same,so,than,too,very,say,says,said,shall"; 4 | 5 | var text = ""; 6 | for(var i in _list_text){ 7 | text+= _list_text[i]+" "; 8 | } 9 | 10 | var atLeast = 2; // Show results with at least .. occurrences 11 | var numWords = 5; // Show statistics for one to .. words 12 | var ignoreCase = true; // Case-sensitivity 13 | var REallowedChars = /[^a-zA-Z']+/g; 14 | // RE pattern to select valid characters. Invalid characters are replaced with a whitespace 15 | 16 | var i, j, k, textlen, len, s; 17 | // Prepare key hash 18 | var keys = [null]; //"keys[0] = null", a word boundary with length zero is empty 19 | var results = []; 20 | var phrase_count = []; 21 | numWords++; //for human logic, we start counting at 1 instead of 0 22 | for (i=1; i<=numWords; i++) { 23 | keys.push({}); 24 | } 25 | 26 | // Remove all irrelevant characters 27 | text = text.replace(REallowedChars, " ").replace(/^\s+/,"").replace(/\s+$/,""); 28 | 29 | // Create a hash 30 | if (ignoreCase) text = text.toLowerCase(); 31 | text = text.split(/\s+/); 32 | for (i=0, textlen=text.length; i1){ 56 | 57 | }else{ 58 | is_ok = false; 59 | } 60 | }); 61 | 62 | if(is_ok){ 63 | if(key[i] >= atLeast && words.length > 1){ 64 | results[k].push({"word":words.join(" "), "count":key[i]}); 65 | phrase_count.push({"word":words.join(" "), "count":key[i]}); 66 | } 67 | } 68 | 69 | } 70 | } 71 | 72 | var f_sortAscending = function(x,y) {return y.count - x.count;}; 73 | for (k=2; k1){ 61 | 62 | }else{ 63 | is_ok = false; 64 | } 65 | }); 66 | 67 | if(is_ok){ 68 | if(key[i] >= atLeast && words.length > 1){ 69 | results[k].push({"word":words.join(" "), "count":key[i]}); 70 | phrase_count.push({"word":words.join(" "), "count":key[i]}); 71 | } 72 | } 73 | 74 | } 75 | } 76 | 77 | var f_sortAscending = function(x,y) {return y.count - x.count;}; 78 | for (k=2; k nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; 97 | }); 98 | }; 99 | } 100 | 101 | function data_filter(attribute){ 102 | var computer_categories = {}; 103 | var total = 0; 104 | for(i in _data){ 105 | if(!( _data[i][attribute] in computer_categories )){ 106 | computer_categories[_data[i][attribute]] = [Object.keys(computer_categories).length,0]; 107 | } 108 | computer_categories[_data[i][attribute]][1]++; 109 | total++; 110 | } 111 | num_clusters = Object.keys(computer_categories).length; 112 | return [computer_categories,total] 113 | } 114 | 115 | function change_cluster(attribute){ 116 | force.stop(); 117 | 118 | data = data_filter(attribute); 119 | computer_categories = data[0]; 120 | total = data[1]; 121 | 122 | var gravity_point = []; 123 | var num_of_parts = Math.ceil(num_clusters/2); 124 | var at_part = 0; 125 | var at_cluster = 0; 126 | 127 | d3.selectAll(".title").remove(); 128 | //find each cluster gravity point and print its label 129 | for(var i in computer_categories){ 130 | x = ((width/num_of_parts)/2)+((width/num_of_parts)*at_part); 131 | 132 | if(at_part==num_of_parts-1 && num_clusters%2==1){ 133 | gravity_point.push( {x: x, y: ((height-100)/2)+80 } ); 134 | } 135 | else if(at_cluster%2==0 && at_part%2==1){ 136 | gravity_point.push( {x: x, y: ((height-100)/2/2)+100 } ); 137 | }else if(at_cluster%2==1 && at_part%2==1){ 138 | gravity_point.push( {x: x, y: ((height-100)/2)+((height-100)/2/2)+100 } ); 139 | at_part++; 140 | }else if(at_cluster%2==0 && at_part%2==0){ 141 | gravity_point.push( {x: x, y: ((height-100)/2/2)+50 } ); 142 | }else if(at_cluster%2==1 && at_part%2==0){ 143 | gravity_point.push( {x: x, y: ((height-100)/2)+((height-100)/2/2)+50 } ); 144 | at_part++; 145 | } 146 | 147 | at_cluster++; 148 | } 149 | 150 | //update centriod for each nodes 151 | var cluster_count_innerclusters = {}; 152 | for(i in _data){ 153 | nodes[i].cluster_id = computer_categories[ _data[i][attribute] ][0]; 154 | nodes[i].cx = gravity_point[nodes[i].cluster_id].x, 155 | nodes[i].cy = gravity_point[nodes[i].cluster_id].y; 156 | 157 | if(!(nodes[i].cluster_id in cluster_count_innerclusters)){ 158 | cluster_count_innerclusters[nodes[i].cluster_id.toString()] = {}; 159 | } 160 | if(!( nodes[i].color in cluster_count_innerclusters[nodes[i].cluster_id.toString()] )){ 161 | cluster_count_innerclusters[nodes[i].cluster_id.toString()][nodes[i].color.toString()] = 0; 162 | } 163 | cluster_count_innerclusters[nodes[i].cluster_id.toString()][nodes[i].color.toString()]++; 164 | } 165 | 166 | for(var i in computer_categories){ 167 | var this_text = svg.append("text") 168 | .attr("class", "title") 169 | .attr("fill", "#0074D9") 170 | .attr("x", gravity_point[computer_categories[i][0]].x-100) 171 | .attr("y", gravity_point[computer_categories[i][0]].y-50) 172 | .text(i+": "+computer_categories[i][1]+" ("+parseInt(computer_categories[i][1]/total*1000)/10+"%)"); 173 | 174 | for(j in cluster_count_innerclusters[ computer_categories[i][0] ]){ 175 | var percentage = parseInt( cluster_count_innerclusters[ computer_categories[i][0] ][j] / computer_categories[i][1] *1000)/10; 176 | var tspan1 = this_text.append('tspan') 177 | .attr("fill", j) 178 | .attr("dx", -110) 179 | .attr("dy", 20) 180 | .text(cluster_count_innerclusters[ computer_categories[i][0] ][j]+'/'+computer_categories[i][1]+' ('+percentage+'%) '); 181 | 182 | } 183 | } 184 | 185 | document.getElementById('current_selected').innerHTML = attribute; 186 | force.start(); 187 | } 188 | 189 | change_cluster(inital_filter_clustering_colors_by); 190 | -------------------------------------------------------------------------------- /src/assets/foundation-icons/.fontcustom-data: -------------------------------------------------------------------------------- 1 | { 2 | "fonts": [ 3 | "fontcustom_10588e4d0af9f9cd5471c9540658204b.ttf", 4 | "fontcustom_10588e4d0af9f9cd5471c9540658204b.woff", 5 | "fontcustom_10588e4d0af9f9cd5471c9540658204b.eot", 6 | "fontcustom_10588e4d0af9f9cd5471c9540658204b.svg" 7 | ], 8 | "templates": [ 9 | "fontcustom.css", 10 | "fontcustom-preview.html" 11 | ], 12 | "file_name": "fontcustom_10588e4d0af9f9cd5471c9540658204b", 13 | "glyphs": [ 14 | "fi-address-book", 15 | "fi-alert", 16 | "fi-align-center", 17 | "fi-align-justify", 18 | "fi-align-left", 19 | "fi-align-right", 20 | "fi-anchor", 21 | "fi-annotate", 22 | "fi-archive", 23 | "fi-arrow-down", 24 | "fi-arrow-left", 25 | "fi-arrow-right", 26 | "fi-arrow-up", 27 | "fi-arrows-compress", 28 | "fi-arrows-expand", 29 | "fi-arrows-in", 30 | "fi-arrows-out", 31 | "fi-asl", 32 | "fi-asterisk", 33 | "fi-at-sign", 34 | "fi-background-color", 35 | "fi-battery-empty", 36 | "fi-battery-full", 37 | "fi-battery-half", 38 | "fi-bitcoin-circle", 39 | "fi-bitcoin", 40 | "fi-blind", 41 | "fi-bluetooth", 42 | "fi-bold", 43 | "fi-book-bookmark", 44 | "fi-book", 45 | "fi-bookmark", 46 | "fi-braille", 47 | "fi-burst-new", 48 | "fi-burst-sale", 49 | "fi-burst", 50 | "fi-calendar", 51 | "fi-camera", 52 | "fi-check", 53 | "fi-checkbox", 54 | "fi-clipboard-notes", 55 | "fi-clipboard-pencil", 56 | "fi-clipboard", 57 | "fi-clock", 58 | "fi-closed-caption", 59 | "fi-cloud", 60 | "fi-comment-minus", 61 | "fi-comment-quotes", 62 | "fi-comment-video", 63 | "fi-comment", 64 | "fi-comments", 65 | "fi-compass", 66 | "fi-contrast", 67 | "fi-credit-card", 68 | "fi-crop", 69 | "fi-crown", 70 | "fi-css3", 71 | "fi-database", 72 | "fi-die-five", 73 | "fi-die-four", 74 | "fi-die-one", 75 | "fi-die-six", 76 | "fi-die-three", 77 | "fi-die-two", 78 | "fi-dislike", 79 | "fi-dollar-bill", 80 | "fi-dollar", 81 | "fi-download", 82 | "fi-eject", 83 | "fi-elevator", 84 | "fi-euro", 85 | "fi-eye", 86 | "fi-fast-forward", 87 | "fi-female-symbol", 88 | "fi-female", 89 | "fi-filter", 90 | "fi-first-aid", 91 | "fi-flag", 92 | "fi-folder-add", 93 | "fi-folder-lock", 94 | "fi-folder", 95 | "fi-foot", 96 | "fi-foundation", 97 | "fi-graph-bar", 98 | "fi-graph-horizontal", 99 | "fi-graph-pie", 100 | "fi-graph-trend", 101 | "fi-guide-dog", 102 | "fi-hearing-aid", 103 | "fi-heart", 104 | "fi-home", 105 | "fi-html5", 106 | "fi-indent-less", 107 | "fi-indent-more", 108 | "fi-info", 109 | "fi-italic", 110 | "fi-key", 111 | "fi-laptop", 112 | "fi-layout", 113 | "fi-lightbulb", 114 | "fi-like", 115 | "fi-link", 116 | "fi-list-bullet", 117 | "fi-list-number", 118 | "fi-list-thumbnails", 119 | "fi-list", 120 | "fi-lock", 121 | "fi-loop", 122 | "fi-magnifying-glass", 123 | "fi-mail", 124 | "fi-male-female", 125 | "fi-male-symbol", 126 | "fi-male", 127 | "fi-map", 128 | "fi-marker", 129 | "fi-megaphone", 130 | "fi-microphone", 131 | "fi-minus-circle", 132 | "fi-minus", 133 | "fi-mobile-signal", 134 | "fi-mobile", 135 | "fi-monitor", 136 | "fi-mountains", 137 | "fi-music", 138 | "fi-next", 139 | "fi-no-dogs", 140 | "fi-no-smoking", 141 | "fi-page-add", 142 | "fi-page-copy", 143 | "fi-page-csv", 144 | "fi-page-delete", 145 | "fi-page-doc", 146 | "fi-page-edit", 147 | "fi-page-export-csv", 148 | "fi-page-export-doc", 149 | "fi-page-export-pdf", 150 | "fi-page-export", 151 | "fi-page-filled", 152 | "fi-page-multiple", 153 | "fi-page-pdf", 154 | "fi-page-remove", 155 | "fi-page-search", 156 | "fi-page", 157 | "fi-paint-bucket", 158 | "fi-paperclip", 159 | "fi-pause", 160 | "fi-paw", 161 | "fi-paypal", 162 | "fi-pencil", 163 | "fi-photo", 164 | "fi-play-circle", 165 | "fi-play-video", 166 | "fi-play", 167 | "fi-plus", 168 | "fi-pound", 169 | "fi-power", 170 | "fi-previous", 171 | "fi-price-tag", 172 | "fi-pricetag-multiple", 173 | "fi-print", 174 | "fi-prohibited", 175 | "fi-projection-screen", 176 | "fi-puzzle", 177 | "fi-quote", 178 | "fi-record", 179 | "fi-refresh", 180 | "fi-results-demographics", 181 | "fi-results", 182 | "fi-rewind-ten", 183 | "fi-rewind", 184 | "fi-rss", 185 | "fi-safety-cone", 186 | "fi-save", 187 | "fi-share", 188 | "fi-sheriff-badge", 189 | "fi-shield", 190 | "fi-shopping-bag", 191 | "fi-shopping-cart", 192 | "fi-shuffle", 193 | "fi-skull", 194 | "fi-social-500px", 195 | "fi-social-adobe", 196 | "fi-social-amazon", 197 | "fi-social-android", 198 | "fi-social-apple", 199 | "fi-social-behance", 200 | "fi-social-bing", 201 | "fi-social-blogger", 202 | "fi-social-delicious", 203 | "fi-social-designer-news", 204 | "fi-social-deviant-art", 205 | "fi-social-digg", 206 | "fi-social-dribbble", 207 | "fi-social-drive", 208 | "fi-social-dropbox", 209 | "fi-social-evernote", 210 | "fi-social-facebook", 211 | "fi-social-flickr", 212 | "fi-social-forrst", 213 | "fi-social-foursquare", 214 | "fi-social-game-center", 215 | "fi-social-github", 216 | "fi-social-google-plus", 217 | "fi-social-hacker-news", 218 | "fi-social-hi5", 219 | "fi-social-instagram", 220 | "fi-social-joomla", 221 | "fi-social-lastfm", 222 | "fi-social-linkedin", 223 | "fi-social-medium", 224 | "fi-social-myspace", 225 | "fi-social-orkut", 226 | "fi-social-path", 227 | "fi-social-picasa", 228 | "fi-social-pinterest", 229 | "fi-social-rdio", 230 | "fi-social-reddit", 231 | "fi-social-skillshare", 232 | "fi-social-skype", 233 | "fi-social-smashing-mag", 234 | "fi-social-snapchat", 235 | "fi-social-spotify", 236 | "fi-social-squidoo", 237 | "fi-social-stack-overflow", 238 | "fi-social-steam", 239 | "fi-social-stumbleupon", 240 | "fi-social-treehouse", 241 | "fi-social-tumblr", 242 | "fi-social-twitter", 243 | "fi-social-vimeo", 244 | "fi-social-windows", 245 | "fi-social-xbox-20", 246 | "fi-social-yahoo", 247 | "fi-social-yelp", 248 | "fi-social-youtube", 249 | "fi-social-zerply", 250 | "fi-social-zurb", 251 | "fi-sound", 252 | "fi-star", 253 | "fi-stop", 254 | "fi-strikethrough", 255 | "fi-subscript", 256 | "fi-superscript", 257 | "fi-tablet-landscape", 258 | "fi-tablet-portrait", 259 | "fi-target-two", 260 | "fi-target", 261 | "fi-telephone-accessible", 262 | "fi-telephone", 263 | "fi-text-color", 264 | "fi-thumbnails", 265 | "fi-ticket", 266 | "fi-torso-business", 267 | "fi-torso-female", 268 | "fi-torso", 269 | "fi-torsos-all-female", 270 | "fi-torsos-all", 271 | "fi-torsos-female-male", 272 | "fi-torsos-male-female", 273 | "fi-torsos", 274 | "fi-trash", 275 | "fi-trees", 276 | "fi-trophy", 277 | "fi-underline", 278 | "fi-universal-access", 279 | "fi-unlink", 280 | "fi-unlock", 281 | "fi-upload-cloud", 282 | "fi-upload", 283 | "fi-usb", 284 | "fi-video", 285 | "fi-volume-none", 286 | "fi-volume-strike", 287 | "fi-volume", 288 | "fi-web", 289 | "fi-wheelchair", 290 | "fi-widget", 291 | "fi-wrench", 292 | "fi-x-circle", 293 | "fi-x", 294 | "fi-yen", 295 | "fi-zoom-in", 296 | "fi-zoom-out" 297 | ] 298 | } -------------------------------------------------------------------------------- /src/app/components/tfjs-timeseries-stocks/tfjs-timeseries-stocks-main.ts: -------------------------------------------------------------------------------- 1 | import * as tf from '@tensorflow/tfjs'; 2 | 3 | import { HttpClient } from '@angular/common/http'; 4 | 5 | export class TfjsTimeseriesStocksMain { 6 | 7 | input_dataset: number[]; 8 | result: number[]; 9 | data_raw: number[]; 10 | sma_vec: number[]; 11 | window_size: number; 12 | trainingsize: number; 13 | data_temporal_resolutions: string; 14 | 15 | constructor(private httpClient:HttpClient) { 16 | this.input_dataset = []; 17 | this.result = []; 18 | this.data_raw = []; 19 | this.sma_vec = []; 20 | this.window_size = 50; 21 | this.trainingsize = 70; 22 | this.data_temporal_resolutions = 'Weekly'; 23 | } 24 | 25 | async demo_1_fetchData(ticker:string, apikey:string, data_temporal_resolutions:string){ 26 | 27 | return new Promise((resolve, reject) => { 28 | 29 | let output = {}; 30 | 31 | let requestUrl = ""; 32 | if(data_temporal_resolutions == 'Daily'){ 33 | requestUrl = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol="+ticker+"&outputsize=full&apikey="+apikey; 34 | }else{ 35 | requestUrl = "https://www.alphavantage.co/query?function=TIME_SERIES_WEEKLY&symbol="+ticker+"&apikey="+apikey; 36 | } 37 | 38 | this.httpClient.get(requestUrl).subscribe( 39 | data => { 40 | console.log("GET Request is successful ", data); 41 | 42 | let daily = []; 43 | if(data_temporal_resolutions == 'Daily'){ 44 | daily = data['Time Series (Daily)']; 45 | }else{ 46 | daily = data['Weekly Time Series']; 47 | } 48 | 49 | if(daily){ 50 | let symbol = data['Meta Data']['2. Symbol']; 51 | let last_refreshed = data['Meta Data']['3. Last Refreshed']; 52 | 53 | let data_raw = []; 54 | 55 | for(let date in daily){ 56 | data_raw.push({ timestamp: date, price: parseFloat(daily[date]['4. close']) }); 57 | } 58 | 59 | data_raw.reverse(); 60 | 61 | let message = "Symbol: " + symbol + " (last refreshed " + last_refreshed + ")"; 62 | 63 | output['linegraph_title'] = message; 64 | 65 | if(data_raw.length > 0){ 66 | let timestamps = data_raw.map(function (val) { return val['timestamp']; }); 67 | let prices = data_raw.map(function (val) { return val['price']; }); 68 | output['timestamps'] = timestamps; 69 | output['prices'] = prices; 70 | } 71 | 72 | output['data_raw'] = data_raw; 73 | output['success'] = true; 74 | 75 | }else{ 76 | output['success'] = false; 77 | output['error_message'] = data['Information']; 78 | } 79 | 80 | resolve(output); 81 | 82 | }, 83 | error => { 84 | output['success'] = false; 85 | output['error_message'] = error; 86 | 87 | reject(output); 88 | } 89 | ); 90 | 91 | }); 92 | 93 | } 94 | 95 | demo_2_compute_sma(data_raw, input_windowsize){ 96 | let output = {}; 97 | output['data_sma_vec'] = this.computeSMA(data_raw, input_windowsize); 98 | 99 | output['sma'] = output['data_sma_vec'].map(function (val) { return val['avg']; }); 100 | output['prices'] = data_raw.map(function (val) { return val['price']; }); 101 | 102 | output['timestamps_a'] = data_raw.map(function (val) { return val['timestamp']; }); 103 | output['timestamps_b'] = data_raw.map(function (val) { 104 | return val['timestamp']; 105 | }).splice(input_windowsize, data_raw.length); 106 | 107 | // table 108 | // output['demo_2_table'] = []; 109 | // let set = output['data_sma_vec'].map(function (val) { return val['set']; }); 110 | // let data_output = ""; 111 | // for (let index = 0; index < 25; index++){ 112 | // let row = { 113 | // index: (index + 1), 114 | // x: set[index].map(function (val) { 115 | // return (Math.round(val['price'] * 10000) / 10000).toString(); 116 | // }), 117 | // y: output['data_sma_vec'][index]['avg'] 118 | // }; 119 | // output['demo_2_table'].push(row); 120 | // } 121 | 122 | return output; 123 | } 124 | 125 | async trainModel(model_params, callback){ 126 | 127 | console.log(model_params); 128 | 129 | let inputs = model_params['inputs']; 130 | let outputs = model_params['outputs']; 131 | let trainingsize = model_params['input_trainingsize']; 132 | let window_size = model_params['input_windowsize']; 133 | let n_epochs = model_params['input_epochs']; 134 | let learning_rate = model_params['input_learningrate']; 135 | let n_layers = model_params['input_hiddenlayers']; 136 | 137 | const input_layer_shape = window_size; 138 | const input_layer_neurons = 50; 139 | 140 | const rnn_input_layer_features = 10; 141 | const rnn_input_layer_timesteps = input_layer_neurons / rnn_input_layer_features; 142 | 143 | const rnn_input_shape = [rnn_input_layer_features, rnn_input_layer_timesteps]; 144 | const rnn_output_neurons = 20; 145 | 146 | const rnn_batch_size = window_size; 147 | 148 | const output_layer_shape = rnn_output_neurons; 149 | const output_layer_neurons = 1; 150 | 151 | let X = inputs.slice(0, Math.floor(trainingsize / 100 * inputs.length)); 152 | let Y = outputs.slice(0, Math.floor(trainingsize / 100 * outputs.length)); 153 | 154 | const xs = tf.tensor2d(X, [X.length, X[0].length]).div(tf.scalar(10)); 155 | const ys = tf.tensor2d(Y, [Y.length, 1]).reshape([Y.length, 1]).div(tf.scalar(10)); 156 | 157 | const model = tf.sequential(); 158 | 159 | model.add(tf.layers.dense({units: input_layer_neurons, inputShape: [input_layer_shape]})); 160 | model.add(tf.layers.reshape({targetShape: rnn_input_shape})); 161 | 162 | let lstm_cells = []; 163 | for (let index = 0; index < n_layers; index++) { 164 | lstm_cells.push(tf.layers.lstmCell({units: rnn_output_neurons})); 165 | } 166 | 167 | model.add(tf.layers.rnn({ 168 | cell: lstm_cells, 169 | inputShape: rnn_input_shape, 170 | returnSequences: false 171 | })); 172 | 173 | model.add(tf.layers.dense({units: output_layer_neurons, inputShape: [output_layer_shape]})); 174 | 175 | model.compile({ 176 | optimizer: tf.train.adam(learning_rate), 177 | loss: 'meanSquaredError' 178 | }); 179 | 180 | const hist = await model.fit(xs, ys, 181 | { batchSize: rnn_batch_size, epochs: n_epochs, callbacks: { 182 | onEpochEnd: async (epoch, log) => { 183 | callback(epoch, log, model_params); 184 | } 185 | } 186 | }); 187 | 188 | // await model.save('localstorage://tfjs-stocks'); 189 | // const model = await tf.loadLayersModel('localstorage://tfjs-stocks'); 190 | // const hist = {}; 191 | 192 | return { model: model, stats: hist }; 193 | } 194 | 195 | makePredictions(X, model) 196 | { 197 | // let X = inputs.slice(Math.floor(size / 100 * inputs.length), inputs.length); 198 | const predictedResults = model.predict(tf.tensor2d(X, [X.length, X[0].length]).div(tf.scalar(10))).mul(10); 199 | return Array.from(predictedResults.dataSync()); 200 | } 201 | 202 | 203 | computeSMA(data, window_size) 204 | { 205 | let r_avgs = [], avg_prev = 0; 206 | for (let i = 0; i <= data.length - window_size; i++){ 207 | let curr_avg = 0.00, t = i + window_size; 208 | for (let k = i; k < t && k <= data.length; k++){ 209 | curr_avg += data[k]['price'] / window_size; 210 | } 211 | r_avgs.push({ set: data.slice(i, i + window_size), avg: curr_avg }); 212 | avg_prev = curr_avg; 213 | } 214 | return r_avgs; 215 | } 216 | 217 | 218 | } 219 | -------------------------------------------------------------------------------- /src/app/components/rl-value-function-tic-tac-toe/README.md: -------------------------------------------------------------------------------- 1 | # Reinforcement Learning Value Function with Tic Tac Toe 2 | > A reinforcement learning algorithm for agents to learn the tic-tac-toe, using the value function 3 | 4 | ![cover](https://jinglescode.github.io/assets/img/posts/rl-value-func-00.webp) 5 | 6 | [Explore Demo](https://jinglescode.github.io/demos/rl-value-function-tic-tac-toe) 7 | 8 | # Intuition 9 | 10 | After a long day at work, you are deciding between 2 choices: to head home and write a Medium article or hang out with friends at a bar. If you choose to hang out with friends, your friends will make you feel happy; whereas heading home to write an article, you’ll end up feeling tired after a long day at work. In this example, enjoying yourself is a reward and feeling tired is viewed as a negative reward, so why write articles? 11 | 12 | Because in life, we don’t just think about immediate rewards; we plan a course of actions to determine the possible future rewards that may follow. Perhaps writing an article may brush up your understanding of a particular topic really well, get recognised and ultimately lands you that dream job you’ve always wanted. In this scenario, getting your dream job is a delayed reward from a list of actions you took, then we want to assign some value for being at those states (for example “going home and write an article”). In order to determine the value of a state, we call this the “value function”. 13 | 14 | So how do we learn from our past? Let’s say you made some great decisions and are in the best state of your life. Now look back at the various decisions you’ve made to reach this stage: what do you attribute your success to? What are the previous states that led you to this success? What are the actions you did in the past that led you to this state of receiving this reward? How is the action you are doing now related to the potential reward you may receive in the future? 15 | 16 | # Reward vs Value Function 17 | 18 | A reward is immediate. It can be scoring points in a game for collecting coins, winning a match of tic-tac-toe or securing your dream job. This reward is what you (or the agent) wants to acquire. 19 | 20 | In order to acquire the reward, the value function is an efficient way to determine the value of being in a state. Denoted by V(s), this value function measures potential future rewards we may get from being in this state s. 21 | 22 | # Define the Value Function 23 | 24 | ![Fig 1: State A leads to state B or C](https://jinglescode.github.io/assets/img/posts/rl-value-func-01.webp) 25 | 26 | In figure 1, how do we determine the value of state A? There is a 50–50 chance to end up in the next 2 possible states, either state B or C. The value of state A is simply the sum of all next states’ probability multiplied by the reward for reaching that state. The value of state A is 0.5. 27 | 28 | ![Fig 2: One-way future states](https://jinglescode.github.io/assets/img/posts/rl-value-func-02.webp) 29 | 30 | In figure 2, you find yourself in state D with only 1 possible route to state E. Since state E gives a reward of 1, state D’s value is also 1 since the only outcome is to receive the reward. 31 | 32 | If you are in state F (in figure 2), which can only lead to state G, followed by state H. Since state H has a negative reward of -1, state G’s value will also be -1, likewise for state F. 33 | 34 | ![Fig 3: Being in state J brings you closer to state K](https://jinglescode.github.io/assets/img/posts/rl-value-func-03.webp) 35 | 36 | [In this game of tic-tac-toe,](https://jinglescode.github.io/demos/rl-value-function-tic-tac-toe) getting 2 Xs in a row (state J in figure 3) does not win the game, hence there is no reward. But being at state J places you one step closer to reaching state K, completing the row of X to win the game, thus being in state J yields a good value. 37 | 38 | ![Fig 4: State M has a higher value than state N](https://jinglescode.github.io/assets/img/posts/rl-value-func-04.webp) 39 | 40 | In figure 4, you’ll find yourself in state L contemplating where to place your next X. You can place it at the top thus bringing you to state M with 2 Xs in the same row. The other choice would be to place it at the bottom row. State M should have a higher significance and value as compared to state N because it results in a higher possibility of victory. 41 | 42 | Therefore, at any given state, we can perform the action that brings us (or the agent) closer to receiving a reward, by picking the state that yields us the highest value. 43 | 44 | # Tic Tac Toe — Initialise the Value Function 45 | 46 | The Value function V(s) for a tic-tac-toe game is the probability of winning for achieving state s. This initialisation is done to define the winning and losing state. We initialise the states as the following: 47 | - V(s) = 1 — if the agent won the game in state s, it is a terminal state 48 | - V(s) = 0 — if the agent lost or tie the game in state s, it is a terminal state 49 | - V(s) = 0.5 — otherwise 0.5 for non-terminal states, which will be finetuned during training 50 | 51 | # Tic Tac Toe — Update the Value Function 52 | 53 | Updating the value function is how the agent learns from past experiences, by updating the value of those states that have been through in the training process. 54 | 55 | ![Fig 5: Update the value of state s](https://jinglescode.github.io/assets/img/posts/rl-value-func-05.webp) 56 | 57 | State s’ is the next state of the current state s. We can update the value of the current state s by adding the differences in value between state s and s’. α is the learning rate. 58 | 59 | As multiple actions can be taken at any given state, so constantly picking only one action at a state that used to bring success might end up missing other better states to be in. In reinforcement learning, this is the [explore-exploit dilemma](https://towardsdatascience.com/striking-a-balance-between-exploring-and-exploiting-5475d9c1e66e). 60 | 61 | With explore strategy, the agent takes random actions to try unexplored states which may find other ways to win the game. With exploit strategy, the agent is able to increase the confidence of those actions that worked in the past to gain rewards. With a good balance between exploring and exploiting, and by playing infinitely many games, the value for every state will approach its true probability. This good balance between exploring and exploit is determined by the [epsilon greedy parameter](https://towardsdatascience.com/exploration-exploitation-dilemma-c9eee9a460ac). 62 | 63 | We can only update the value of each state that has been played in that particular game by the agent when the game has ended, after knowing if the agent has won (reward = 1) or lost/tie (reward = 0). A terminal state can only be 0 or 1, and we know exactly which are the terminal states as defined in during the initialisation. 64 | 65 | The goal of the agent is to update the value function after a game is played to learn the list of actions that were executed. As every state’s value is updated using the next state’s value, during the end of each game, the update process read the state history of that particular game backwards and finetunes the value for each state. 66 | 67 | # Tic Tac Toe — Exploit the Value Function 68 | 69 | ![Fig 6: Values of various next states](https://jinglescode.github.io/assets/img/posts/rl-value-func-06.webp) 70 | 71 | Given enough training, the agent would have learnt the value (or probability of winning) of any given state. So, when we play a game against our trained agent, the agent uses the exploit strategy to maximise winning rate. [See if you can win against the agent](https://jinglescode.github.io/demos/rl-value-function-tic-tac-toe). 72 | 73 | At each state of the game, the agent loop through every possibility, picking the next state with the highest value, therefore selecting the best course of action. In figure 6, the agent would pick the bottom-right corner to win the game. 74 | 75 | # Conclusion 76 | 77 | At any progression state except the terminal stage (where a win, loss or draw is recorded), the agent takes an action which leads to the next state, which may not yield any reward but would result in the agent a move closer to receiving a reward. 78 | 79 | The value function is the algorithm to determine the value of being in a state, the probability of receiving a future reward. 80 | 81 | The value of each state is updated reversed chronologically through the state history of a game, with enough training using [both explore and exploit strategy](https://towardsdatascience.com/exploration-exploitation-dilemma-c9eee9a460ac), the agent will be able to determine the true value of each state in the game. 82 | 83 | There are many ways to define a value function, this is just one that is suitable for a tic-tac-toe game. 84 | 85 | [Explore the demo on Github](https://jinglescode.github.io/demos/rl-value-function-tic-tac-toe) 86 | -------------------------------------------------------------------------------- /src/app/components/rl-value-function-tic-tac-toe/rl-value-function-tic-tac-toe.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Reinforcement Learning Value Function with Tic Tac Toe

4 |
5 | 6 |

7 | A simple reinforcement learning algorithm for agents to learn the game tic-tac-toe. This demonstrate the purpose of the value function. Read on Medium 8 |

9 |

10 | You begin by training the agent, where 2 agents (agent X and agent O) will be created and trained through simulation. These 2 agents will be playing a number of games determined by 'number of episodes'. You can adjust the 1) learning rate and 2) the probability of exploration of each agent. After training, you can play against agent X. 11 |

12 |

13 | The 9 percentages on the right show the value of each grid at each state. Don't give up when playing against the trained agent! Because as humans, we can actually outsmart them. Try it! The agents are still learning as you play. You will notice the percentages of those grids that used to be very confident dropping over time if the agent didn't manage to win for a few games. 14 |

15 |
16 |
17 | 18 |
19 |
20 | 21 | 22 |

Train Agent

23 |
24 | 25 |
26 | 27 | 28 | Number of Episodes 29 | 30 | Number of times agent play against each other in simulation 31 | 32 | 33 | Agent 1 Explore Probability 34 | 35 | 36 | 37 | 38 | Agent 1 Learning Rate 39 | 40 | 41 | 42 | 43 | Agent 2 Explore Probability 44 | 45 | 46 | 47 | 48 | Agent 2 Learning Rate 49 | 50 | 51 | 52 | 53 |
54 | 55 |
56 | 57 | 58 | 59 | 60 |
61 |
62 |
63 | 64 | 65 |

Play against agent

66 | 67 | Agent skill level: {{agentA.skill_level}} 68 | 69 |
70 | 71 | 72 |
73 |
74 | 75 | 76 | 80 | 81 | 82 |
83 |
84 | 85 | 86 | {{prob}} 87 | 88 | 89 |
90 |
91 | 92 | 93 |
94 | 95 |
96 |
97 | Game ended, player {{environment.winner==1?'X':'O'}} won 98 |
99 |
100 | Tie 101 |
102 |
103 |
104 | Player {{environment.player_turn==1?'X':'O'}}'s turn 105 |
106 | 107 |
108 | 109 |
110 |
111 |
112 |
113 |
114 | 115 | 116 | 117 | 118 |

Evaluate Epsilon Greedy

119 |
120 | 121 |

122 | In order to figure out the most suitable epsilon-greedy value, I will test different epsilon-greedy value. First, initialise agent X with epsilon-greedy of 0.01, means there is 1% probability agent X will choose to explore instead of exploiting. Then, agents will play against each other for 10,000 games, and I will record the number of times agent X wins. After 10,000 games, I will increase the epsilon-greedy value to 0.02 and agents will play another 10,000 games. 123 |

124 |

125 | Agent X (eps increment) vs Agent O (eps 0.05) 126 |

127 |

The blue line is the number of times agent X won against agent O. The winning rate decreases as the epsilon-greedy value increases and peaked at winning 9268 games at the epsilon-greedy value of 0.05 (agent X explores 5% of the time). Agent O begin to win more games as agent X explores more than 50% of the time.

128 |
129 |
130 |
131 | 132 |
133 |
134 |
135 |
136 | 137 |
138 |
139 |
140 |

141 | Agent O (eps increment) vs Agent X (eps 0.05) 142 |

143 |

Let us try something, by experimenting with different epsilon greedy for agent O, challenging agent X with an optimal 5% epsilon greedy.

144 |

Given agent X has optimal epsilon greedy and advantage to start first in the game, agent O lost the game before it is able to learn the game.

145 |
146 |
147 |
148 | 149 |
150 |
151 |
152 |
153 | 154 |
155 |
156 |
157 |

158 | Agent O (eps increment) vs Agent X (eps 1) 159 |

160 |

Let's tweak epsilon greedy of agent X to 100%, where agent X will be playing random actions all the time.

161 |

Agent O is able to learn the game and win against agent X, peaking at 4% epsilon greedy and begin losing at 30%.

162 |
163 |
164 |
165 | 166 |
167 |
168 |
169 |
170 | 171 |
172 |
173 |
174 | 175 |
176 |
177 | -------------------------------------------------------------------------------- /src/app/components/tfjs-timeseries-stocks/README.md: -------------------------------------------------------------------------------- 1 | # Time Series Forecasting with TensorFlow.js 2 | > Pull stock prices from online API and perform predictions using Recurrent Neural Network & Long Short Term Memory (LSTM) with TensorFlow.js framework 3 | 4 | ![cover](https://jinglescode.github.io/assets/img/posts/time-series-00.webp) 5 | 6 | Machine learning is becoming increasingly popular these days and a growing number of the world’s population see it is as a magic crystal ball: predicting when and what will happen in the future. This experiment uses artificial neural networks to reveal stock market trends and demonstrates the ability of time series forecasting to predict future stock prices based on past historical data. 7 | 8 | Disclaimer: As stock markets fluctuation are dynamic and unpredictable owing to multiple factors, this experiment is 100% educational and by no means a trading prediction tool. 9 | 10 | [Explore Demo](https://jinglescode.github.io/demos/tfjs-timeseries-stocks/) 11 | 12 | --- 13 | 14 | # Project Walkthrough 15 | There are 4 parts to this project walkthrough: 16 | 1. Get stocks data from online API 17 | 2. Compute simple moving average for a given time window 18 | 3. Train LSTM neural network 19 | 4. Predict and compare predicted values to the actual values 20 | 21 | # Get Stocks Data 22 | 23 | Before we can train the neural network and make any predictions, we will first require data. The type of data we are looking for is time series: a sequence of numbers in chronological order. A good place to fetch these data are from [alphavantage.co](https://www.alphavantage.co/). This API allows us to retrieve chronological data on specific company stocks prices from the last 20 years. 24 | 25 | The API yields the following fields: 26 | - open price 27 | - the highest price of that day 28 | - the lowest price of that day 29 | - closing price (this is used in this project) 30 | - volume 31 | 32 | To prepare training dataset for our neural network, we will be using closing stocks price. This also means that we will be aiming to predict the future closing price. Below graph shows 20 years of Microsoft Corporation weekly closing prices. 33 | 34 | ![20 years of Microsoft Corporation weekly closing prices data from alphavantage.co](https://jinglescode.github.io/assets/img/posts/time-series-01.webp) 35 | 36 | # Simple Moving Average 37 | 38 | For this experiment, we are using [supervised learning](https://en.wikipedia.org/wiki/Supervised_learning), which means feeding data to the neural network and it learns by mapping input data to the output label. One way to prepare the training dataset is to extract the moving average from that time-series data. 39 | 40 | [Simple Moving Average (SMA)](https://www.investopedia.com/terms/s/sma.asp) is a method to identify trends direction for a certain period of time, by looking at the average of all the values within that time window. The number of prices in a time window is selected experimentally. 41 | 42 | For example, let’s assume the closing prices for the past 5 days were 13, 15, 14, 16, 17, the SMA would be (13+15+14+16+17)/5 = 15. So the input for our training dataset is the set of prices within a single time window, and its label is the computed moving average of those prices. 43 | 44 | Let’s compute the SMA of Microsoft Corporation weekly closing prices data, with a window size of 50. 45 | 46 | ```javascript 47 | function ComputeSMA(data, window_size) 48 | { 49 | let r_avgs = [], avg_prev = 0; 50 | for (let i = 0; i <= data.length - window_size; i++){ 51 | let curr_avg = 0.00, t = i + window_size; 52 | for (let k = i; k < t && k <= data.length; k++){ 53 | curr_avg += data[k]['price'] / window_size; 54 | } 55 | r_avgs.push({ set: data.slice(i, i + window_size), avg: curr_avg }); 56 | avg_prev = curr_avg; 57 | } 58 | return r_avgs; 59 | } 60 | ``` 61 | 62 | And this is what we get, weekly stock closing price in blue, and SMA in orange. Because SMA is the moving average of 50 weeks, it is smoother than the weekly price, which can fluctuate. 63 | 64 | ![Simple Moving Average of Microsoft Corporation closing prices data](https://jinglescode.github.io/assets/img/posts/time-series-02.webp) 65 | 66 | # Training Data 67 | 68 | We can prepare the training data with weekly stock prices and the computed SMA. Given the window size is 50, this means that we will use the closing price of every 50 consecutive weeks as our training features (X), and the SMA of those 50 weeks as our training label (Y). Which [looks like that](https://gist.github.com/jinglescode/60f8f9357b3960a1b3017d7483f8194c). 69 | 70 | Next, we split our data into 2 sets, training and validation set. If 70% of the data is used for training, then 30% for validation. The API returns us approximate 1000 weeks of data, so 700 for training, and 300 for validation. 71 | 72 | # Train Neural Network 73 | 74 | Now that the training data is ready, it is time to create a model for time series prediction, to achieve this we will use [TensorFlow.js](https://www.tensorflow.org/js) framework. TensorFlow.js is a library for developing and training machine learning models in JavaScript, and we can deploy these machine learning capabilities in a web browser. 75 | 76 | [Sequential model](https://js.tensorflow.org/api/latest/#sequential) is selected which simply connects each layer and pass the data from input to the output during the training process. In order for the model to learn time series data which are sequential, [recurrent neural network (RNN)](https://js.tensorflow.org/api/latest/#layers.rnn) layer is created and a number of [LSTM cells](https://js.tensorflow.org/api/latest/#layers.lstmCell) are added to the RNN. 77 | 78 | The model will be trained using [Adam](https://js.tensorflow.org/api/latest/#train.adam) ([research paper](https://arxiv.org/abs/1412.6980)), a popular optimisation algorithm for machine learning. [Root mean square error](https://js.tensorflow.org/api/latest/#losses.meanSquaredError) which will determine the difference between predicted values and the actual values, so the model is able to learn by minimising the error during the training process. 79 | 80 | Here is a code snippet of the model described above, [full code on Github](https://github.com/jinglescode/demos/tree/master/src/app/components/tfjs-timeseries-stocks). 81 | 82 | ``` 83 | async function trainModel(inputs, outputs, trainingsize, window_size, n_epochs, learning_rate, n_layers, callback){ 84 | 85 | const input_layer_shape = window_size; 86 | const input_layer_neurons = 100; 87 | 88 | const rnn_input_layer_features = 10; 89 | const rnn_input_layer_timesteps = input_layer_neurons / rnn_input_layer_features; 90 | 91 | const rnn_input_shape = [rnn_input_layer_features, rnn_input_layer_timesteps]; 92 | const rnn_output_neurons = 20; 93 | 94 | const rnn_batch_size = window_size; 95 | 96 | const output_layer_shape = rnn_output_neurons; 97 | const output_layer_neurons = 1; 98 | 99 | const model = tf.sequential(); 100 | 101 | let X = inputs.slice(0, Math.floor(trainingsize / 100 * inputs.length)); 102 | let Y = outputs.slice(0, Math.floor(trainingsize / 100 * outputs.length)); 103 | 104 | const xs = tf.tensor2d(X, [X.length, X[0].length]).div(tf.scalar(10)); 105 | const ys = tf.tensor2d(Y, [Y.length, 1]).reshape([Y.length, 1]).div(tf.scalar(10)); 106 | 107 | model.add(tf.layers.dense({units: input_layer_neurons, inputShape: [input_layer_shape]})); 108 | model.add(tf.layers.reshape({targetShape: rnn_input_shape})); 109 | 110 | let lstm_cells = []; 111 | for (let index = 0; index < n_layers; index++) { 112 | lstm_cells.push(tf.layers.lstmCell({units: rnn_output_neurons})); 113 | } 114 | 115 | model.add(tf.layers.rnn({ 116 | cell: lstm_cells, 117 | inputShape: rnn_input_shape, 118 | returnSequences: false 119 | })); 120 | 121 | model.add(tf.layers.dense({units: output_layer_neurons, inputShape: [output_layer_shape]})); 122 | 123 | model.compile({ 124 | optimizer: tf.train.adam(learning_rate), 125 | loss: 'meanSquaredError' 126 | }); 127 | 128 | const hist = await model.fit(xs, ys, 129 | { batchSize: rnn_batch_size, epochs: n_epochs, callbacks: { 130 | onEpochEnd: async (epoch, log) => { 131 | callback(epoch, log); 132 | } 133 | } 134 | }); 135 | 136 | return { model: model, stats: hist }; 137 | } 138 | ``` 139 | 140 | These are the [hyper-parameters](https://en.wikipedia.org/wiki/Hyperparameter_(machine_learning)) (parameters used in the training process) available for tweaking in the [frontend](https://jinglescode.github.io/demos/tfjs-timeseries-stocks): 141 | - Training Dataset Size (%): the amount of data used for training, and remaining data will be used for validation 142 | - Epochs: number of times the dataset is used to train the model ([learn more](https://machinelearningmastery.com/difference-between-a-batch-and-an-epoch/)) 143 | - Learning Rate: the amount of change in the weights during training in each step ([learn more](https://machinelearningmastery.com/learning-rate-for-deep-learning-neural-networks/)) 144 | - Hidden LSTM Layers: to increase the model complexity to learn in higher dimensional space ([learn more](https://machinelearningmastery.com/how-to-configure-the-number-of-layers-and-nodes-in-a-neural-network/)) 145 | 146 | ![Web frontend, showing parameters available for tweaking](https://jinglescode.github.io/assets/img/posts/time-series-03.webp) 147 | 148 | Click the Begin Training Model button… 149 | 150 | ![User interface showing training model progress](https://jinglescode.github.io/assets/img/posts/time-series-04.webp) 151 | 152 | The model seems to converge at around 15 epoch. 153 | 154 | # Validation 155 | 156 | Now that the model is trained, it is time to use it for predicting future values, for our case, it is the moving average. We will use the model.predict function from TFJS. 157 | 158 | The data has been split into 2 sets, training and validation set. The training set has been used for training the model, thus will be using the validation set to validate the model. Since the model has not seen the validation dataset, it will be good if the model is able to predict values that are close to the true values. 159 | 160 | So let us use the remaining data for prediction which allow us to see how closely our predicted values are compared to the actual values. 161 | 162 | ![The green line denotes the prediction of the validation data, from web demo](https://jinglescode.github.io/assets/img/posts/time-series-05.webp) 163 | 164 | Looks like the model predicted (green line) does a good job plotting closely to the actual price (blue line). This means that the model is able to predict the last 30% of the data which was unseen by the model. 165 | 166 | Other algorithms can be applied and uses the [Root Mean Square Error](https://www.statisticshowto.datasciencecentral.com/rmse/) to compare 2 or more models performance. 167 | 168 | # Prediction 169 | 170 | Finally, the model has been validated and the predicted values map closely to its true values, we shall use it to predict the future. We will apply the same model.predict function and use the last 50 data points as the input, because our window size is 50. Since our training data is increment daily, we will use the past 50 days as input, to predict the 51st day. 171 | 172 | ![Predict the 51st day](https://jinglescode.github.io/assets/img/posts/time-series-06.webp) 173 | 174 | # Conclusion 175 | 176 | There are many ways to do time series prediction other than using a simple moving average. Possible future work is to implement this with more data from various sources. 177 | 178 | With TensorFlow.js, machine learning on a web browser is possible, and it is actually pretty cool. 179 | 180 | [Explore the demo on Github](https://jinglescode.github.io/demos/tfjs-timeseries-stocks), this experiment is 100% educational and by no means a trading prediction tool. 181 | -------------------------------------------------------------------------------- /src/assets/scripts/d3.layout.cloud.js: -------------------------------------------------------------------------------- 1 | // Word cloud layout by Jason Davies, http://www.jasondavies.com/word-cloud/ 2 | // Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf 3 | (function() { 4 | function cloud() { 5 | var size = [256, 256], 6 | text = cloudText, 7 | font = cloudFont, 8 | fontSize = cloudFontSize, 9 | fontStyle = cloudFontNormal, 10 | fontWeight = cloudFontNormal, 11 | rotate = cloudRotate, 12 | padding = cloudPadding, 13 | spiral = archimedeanSpiral, 14 | words = [], 15 | timeInterval = Infinity, 16 | event = d3.dispatch("word", "end"), 17 | timer = null, 18 | cloud = {}; 19 | 20 | cloud.start = function() { 21 | var board = zeroArray((size[0] >> 5) * size[1]), 22 | bounds = null, 23 | n = words.length, 24 | i = -1, 25 | tags = [], 26 | data = words.map(function(d, i) { 27 | d.text = text.call(this, d, i); 28 | d.font = font.call(this, d, i); 29 | d.style = fontStyle.call(this, d, i); 30 | d.weight = fontWeight.call(this, d, i); 31 | d.rotate = rotate.call(this, d, i); 32 | d.size = ~~fontSize.call(this, d, i); 33 | d.padding = padding.call(this, d, i); 34 | return d; 35 | }).sort(function(a, b) { return b.size - a.size; }); 36 | 37 | if (timer) clearInterval(timer); 38 | timer = setInterval(step, 0); 39 | step(); 40 | 41 | return cloud; 42 | 43 | function step() { 44 | var start = +new Date, 45 | d; 46 | while (+new Date - start < timeInterval && ++i < n && timer) { 47 | d = data[i]; 48 | d.x = (size[0] * (Math.random() + .5)) >> 1; 49 | d.y = (size[1] * (Math.random() + .5)) >> 1; 50 | cloudSprite(d, data, i); 51 | if (d.hasText && place(board, d, bounds)) { 52 | tags.push(d); 53 | event.word(d); 54 | if (bounds) cloudBounds(bounds, d); 55 | else bounds = [{x: d.x + d.x0, y: d.y + d.y0}, {x: d.x + d.x1, y: d.y + d.y1}]; 56 | // Temporary hack 57 | d.x -= size[0] >> 1; 58 | d.y -= size[1] >> 1; 59 | } 60 | } 61 | if (i >= n) { 62 | cloud.stop(); 63 | event.end(tags, bounds); 64 | } 65 | } 66 | }; 67 | 68 | cloud.stop = function() { 69 | if (timer) { 70 | clearInterval(timer); 71 | timer = null; 72 | } 73 | return cloud; 74 | }; 75 | 76 | cloud.timeInterval = function(x) { 77 | if (!arguments.length) return timeInterval; 78 | timeInterval = x == null ? Infinity : x; 79 | return cloud; 80 | }; 81 | 82 | function place(board, tag, bounds) { 83 | var perimeter = [{x: 0, y: 0}, {x: size[0], y: size[1]}], 84 | startX = tag.x, 85 | startY = tag.y, 86 | maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]), 87 | s = spiral(size), 88 | dt = Math.random() < .5 ? 1 : -1, 89 | t = -dt, 90 | dxdy, 91 | dx, 92 | dy; 93 | 94 | while (dxdy = s(t += dt)) { 95 | dx = ~~dxdy[0]; 96 | dy = ~~dxdy[1]; 97 | 98 | if (Math.min(dx, dy) > maxDelta) break; 99 | 100 | tag.x = startX + dx; 101 | tag.y = startY + dy; 102 | 103 | if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 || 104 | tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue; 105 | // TODO only check for collisions within current bounds. 106 | if (!bounds || !cloudCollide(tag, board, size[0])) { 107 | if (!bounds || collideRects(tag, bounds)) { 108 | var sprite = tag.sprite, 109 | w = tag.width >> 5, 110 | sw = size[0] >> 5, 111 | lx = tag.x - (w << 4), 112 | sx = lx & 0x7f, 113 | msx = 32 - sx, 114 | h = tag.y1 - tag.y0, 115 | x = (tag.y + tag.y0) * sw + (lx >> 5), 116 | last; 117 | for (var j = 0; j < h; j++) { 118 | last = 0; 119 | for (var i = 0; i <= w; i++) { 120 | board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0); 121 | } 122 | x += sw; 123 | } 124 | delete tag.sprite; 125 | return true; 126 | } 127 | } 128 | } 129 | return false; 130 | } 131 | 132 | cloud.words = function(x) { 133 | if (!arguments.length) return words; 134 | words = x; 135 | return cloud; 136 | }; 137 | 138 | cloud.size = function(x) { 139 | if (!arguments.length) return size; 140 | size = [+x[0], +x[1]]; 141 | return cloud; 142 | }; 143 | 144 | cloud.font = function(x) { 145 | if (!arguments.length) return font; 146 | font = d3.functor(x); 147 | return cloud; 148 | }; 149 | 150 | cloud.fontStyle = function(x) { 151 | if (!arguments.length) return fontStyle; 152 | fontStyle = d3.functor(x); 153 | return cloud; 154 | }; 155 | 156 | cloud.fontWeight = function(x) { 157 | if (!arguments.length) return fontWeight; 158 | fontWeight = d3.functor(x); 159 | return cloud; 160 | }; 161 | 162 | cloud.rotate = function(x) { 163 | if (!arguments.length) return rotate; 164 | rotate = d3.functor(x); 165 | return cloud; 166 | }; 167 | 168 | cloud.text = function(x) { 169 | if (!arguments.length) return text; 170 | text = d3.functor(x); 171 | return cloud; 172 | }; 173 | 174 | cloud.spiral = function(x) { 175 | if (!arguments.length) return spiral; 176 | spiral = spirals[x + ""] || x; 177 | return cloud; 178 | }; 179 | 180 | cloud.fontSize = function(x) { 181 | if (!arguments.length) return fontSize; 182 | fontSize = d3.functor(x); 183 | return cloud; 184 | }; 185 | 186 | cloud.padding = function(x) { 187 | if (!arguments.length) return padding; 188 | padding = d3.functor(x); 189 | return cloud; 190 | }; 191 | 192 | return d3.rebind(cloud, event, "on"); 193 | } 194 | 195 | function cloudText(d) { 196 | return d.text; 197 | } 198 | 199 | function cloudFont() { 200 | return "serif"; 201 | } 202 | 203 | function cloudFontNormal() { 204 | return "normal"; 205 | } 206 | 207 | function cloudFontSize(d) { 208 | return Math.sqrt(d.value); 209 | } 210 | 211 | function cloudRotate() { 212 | return (~~(Math.random() * 6) - 3) * 30; 213 | } 214 | 215 | function cloudPadding() { 216 | return 1; 217 | } 218 | 219 | // Fetches a monochrome sprite bitmap for the specified text. 220 | // Load in batches for speed. 221 | function cloudSprite(d, data, di) { 222 | if (d.sprite) return; 223 | c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio); 224 | var x = 0, 225 | y = 0, 226 | maxh = 0, 227 | n = data.length; 228 | --di; 229 | while (++di < n) { 230 | d = data[di]; 231 | c.save(); 232 | c.font = d.style + " " + d.weight + " " + ~~((d.size + 1) / ratio) + "px " + d.font; 233 | var w = c.measureText(d.text + "m").width * ratio, 234 | h = d.size << 1; 235 | if (d.rotate) { 236 | var sr = Math.sin(d.rotate * cloudRadians), 237 | cr = Math.cos(d.rotate * cloudRadians), 238 | wcr = w * cr, 239 | wsr = w * sr, 240 | hcr = h * cr, 241 | hsr = h * sr; 242 | w = (Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f) >> 5 << 5; 243 | h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr)); 244 | } else { 245 | w = (w + 0x1f) >> 5 << 5; 246 | } 247 | if (h > maxh) maxh = h; 248 | if (x + w >= (cw << 5)) { 249 | x = 0; 250 | y += maxh; 251 | maxh = 0; 252 | } 253 | if (y + h >= ch) break; 254 | c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio); 255 | if (d.rotate) c.rotate(d.rotate * cloudRadians); 256 | c.fillText(d.text, 0, 0); 257 | if (d.padding) c.lineWidth = 2 * d.padding, c.strokeText(d.text, 0, 0); 258 | c.restore(); 259 | d.width = w; 260 | d.height = h; 261 | d.xoff = x; 262 | d.yoff = y; 263 | d.x1 = w >> 1; 264 | d.y1 = h >> 1; 265 | d.x0 = -d.x1; 266 | d.y0 = -d.y1; 267 | d.hasText = true; 268 | x += w; 269 | } 270 | var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data, 271 | sprite = []; 272 | while (--di >= 0) { 273 | d = data[di]; 274 | if (!d.hasText) continue; 275 | var w = d.width, 276 | w32 = w >> 5, 277 | h = d.y1 - d.y0; 278 | // Zero the buffer 279 | for (var i = 0; i < h * w32; i++) sprite[i] = 0; 280 | x = d.xoff; 281 | if (x == null) return; 282 | y = d.yoff; 283 | var seen = 0, 284 | seenRow = -1; 285 | for (var j = 0; j < h; j++) { 286 | for (var i = 0; i < w; i++) { 287 | var k = w32 * j + (i >> 5), 288 | m = pixels[((y + j) * (cw << 5) + (x + i)) << 2] ? 1 << (31 - (i % 32)) : 0; 289 | sprite[k] |= m; 290 | seen |= m; 291 | } 292 | if (seen) seenRow = j; 293 | else { 294 | d.y0++; 295 | h--; 296 | j--; 297 | y++; 298 | } 299 | } 300 | d.y1 = d.y0 + seenRow; 301 | d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32); 302 | } 303 | } 304 | 305 | // Use mask-based collision detection. 306 | function cloudCollide(tag, board, sw) { 307 | sw >>= 5; 308 | var sprite = tag.sprite, 309 | w = tag.width >> 5, 310 | lx = tag.x - (w << 4), 311 | sx = lx & 0x7f, 312 | msx = 32 - sx, 313 | h = tag.y1 - tag.y0, 314 | x = (tag.y + tag.y0) * sw + (lx >> 5), 315 | last; 316 | for (var j = 0; j < h; j++) { 317 | last = 0; 318 | for (var i = 0; i <= w; i++) { 319 | if (((last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0)) 320 | & board[x + i]) return true; 321 | } 322 | x += sw; 323 | } 324 | return false; 325 | } 326 | 327 | function cloudBounds(bounds, d) { 328 | var b0 = bounds[0], 329 | b1 = bounds[1]; 330 | if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0; 331 | if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0; 332 | if (d.x + d.x1 > b1.x) b1.x = d.x + d.x1; 333 | if (d.y + d.y1 > b1.y) b1.y = d.y + d.y1; 334 | } 335 | 336 | function collideRects(a, b) { 337 | return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y; 338 | } 339 | 340 | function archimedeanSpiral(size) { 341 | var e = size[0] / size[1]; 342 | return function(t) { 343 | return [e * (t *= .1) * Math.cos(t), t * Math.sin(t)]; 344 | }; 345 | } 346 | 347 | function rectangularSpiral(size) { 348 | var dy = 4, 349 | dx = dy * size[0] / size[1], 350 | x = 0, 351 | y = 0; 352 | return function(t) { 353 | var sign = t < 0 ? -1 : 1; 354 | // See triangular numbers: T_n = n * (n + 1) / 2. 355 | switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) { 356 | case 0: x += dx; break; 357 | case 1: y += dy; break; 358 | case 2: x -= dx; break; 359 | default: y -= dy; break; 360 | } 361 | return [x, y]; 362 | }; 363 | } 364 | 365 | // TODO reuse arrays? 366 | function zeroArray(n) { 367 | var a = [], 368 | i = -1; 369 | while (++i < n) a[i] = 0; 370 | return a; 371 | } 372 | 373 | var cloudRadians = Math.PI / 180, 374 | cw = 1 << 11 >> 5, 375 | ch = 1 << 11, 376 | canvas, 377 | ratio = 1; 378 | 379 | if (typeof document !== "undefined") { 380 | canvas = document.createElement("canvas"); 381 | canvas.width = 1; 382 | canvas.height = 1; 383 | ratio = Math.sqrt(canvas.getContext("2d").getImageData(0, 0, 1, 1).data.length >> 2); 384 | canvas.width = (cw << 5) / ratio; 385 | canvas.height = ch / ratio; 386 | } else { 387 | // Attempt to use node-canvas. 388 | canvas = new Canvas(cw << 5, ch); 389 | } 390 | 391 | var c = canvas.getContext("2d"), 392 | spirals = { 393 | archimedean: archimedeanSpiral, 394 | rectangular: rectangularSpiral 395 | }; 396 | c.fillStyle = c.strokeStyle = "red"; 397 | c.textAlign = "center"; 398 | 399 | if (typeof module === "object" && module.exports) module.exports = cloud; 400 | else (d3.layout || (d3.layout = {})).cloud = cloud; 401 | })(); 402 | -------------------------------------------------------------------------------- /src/app/components/phrases-extraction-d3-wordcloud/standalone_demo/assets/cloud.js: -------------------------------------------------------------------------------- 1 | // Word cloud layout by Jason Davies, http://www.jasondavies.com/word-cloud/ 2 | // Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf 3 | (function() { 4 | function cloud() { 5 | var size = [256, 256], 6 | text = cloudText, 7 | font = cloudFont, 8 | fontSize = cloudFontSize, 9 | fontStyle = cloudFontNormal, 10 | fontWeight = cloudFontNormal, 11 | rotate = cloudRotate, 12 | padding = cloudPadding, 13 | spiral = archimedeanSpiral, 14 | words = [], 15 | timeInterval = Infinity, 16 | event = d3.dispatch("word", "end"), 17 | timer = null, 18 | cloud = {}; 19 | 20 | cloud.start = function() { 21 | var board = zeroArray((size[0] >> 5) * size[1]), 22 | bounds = null, 23 | n = words.length, 24 | i = -1, 25 | tags = [], 26 | data = words.map(function(d, i) { 27 | d.text = text.call(this, d, i); 28 | d.font = font.call(this, d, i); 29 | d.style = fontStyle.call(this, d, i); 30 | d.weight = fontWeight.call(this, d, i); 31 | d.rotate = rotate.call(this, d, i); 32 | d.size = ~~fontSize.call(this, d, i); 33 | d.padding = padding.call(this, d, i); 34 | return d; 35 | }).sort(function(a, b) { return b.size - a.size; }); 36 | 37 | if (timer) clearInterval(timer); 38 | timer = setInterval(step, 0); 39 | step(); 40 | 41 | return cloud; 42 | 43 | function step() { 44 | var start = +new Date, 45 | d; 46 | while (+new Date - start < timeInterval && ++i < n && timer) { 47 | d = data[i]; 48 | d.x = (size[0] * (Math.random() + .5)) >> 1; 49 | d.y = (size[1] * (Math.random() + .5)) >> 1; 50 | cloudSprite(d, data, i); 51 | if (d.hasText && place(board, d, bounds)) { 52 | tags.push(d); 53 | event.word(d); 54 | if (bounds) cloudBounds(bounds, d); 55 | else bounds = [{x: d.x + d.x0, y: d.y + d.y0}, {x: d.x + d.x1, y: d.y + d.y1}]; 56 | // Temporary hack 57 | d.x -= size[0] >> 1; 58 | d.y -= size[1] >> 1; 59 | } 60 | } 61 | if (i >= n) { 62 | cloud.stop(); 63 | event.end(tags, bounds); 64 | } 65 | } 66 | }; 67 | 68 | cloud.stop = function() { 69 | if (timer) { 70 | clearInterval(timer); 71 | timer = null; 72 | } 73 | return cloud; 74 | }; 75 | 76 | cloud.timeInterval = function(x) { 77 | if (!arguments.length) return timeInterval; 78 | timeInterval = x == null ? Infinity : x; 79 | return cloud; 80 | }; 81 | 82 | function place(board, tag, bounds) { 83 | var perimeter = [{x: 0, y: 0}, {x: size[0], y: size[1]}], 84 | startX = tag.x, 85 | startY = tag.y, 86 | maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]), 87 | s = spiral(size), 88 | dt = Math.random() < .5 ? 1 : -1, 89 | t = -dt, 90 | dxdy, 91 | dx, 92 | dy; 93 | 94 | while (dxdy = s(t += dt)) { 95 | dx = ~~dxdy[0]; 96 | dy = ~~dxdy[1]; 97 | 98 | if (Math.min(dx, dy) > maxDelta) break; 99 | 100 | tag.x = startX + dx; 101 | tag.y = startY + dy; 102 | 103 | if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 || 104 | tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue; 105 | // TODO only check for collisions within current bounds. 106 | if (!bounds || !cloudCollide(tag, board, size[0])) { 107 | if (!bounds || collideRects(tag, bounds)) { 108 | var sprite = tag.sprite, 109 | w = tag.width >> 5, 110 | sw = size[0] >> 5, 111 | lx = tag.x - (w << 4), 112 | sx = lx & 0x7f, 113 | msx = 32 - sx, 114 | h = tag.y1 - tag.y0, 115 | x = (tag.y + tag.y0) * sw + (lx >> 5), 116 | last; 117 | for (var j = 0; j < h; j++) { 118 | last = 0; 119 | for (var i = 0; i <= w; i++) { 120 | board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0); 121 | } 122 | x += sw; 123 | } 124 | delete tag.sprite; 125 | return true; 126 | } 127 | } 128 | } 129 | return false; 130 | } 131 | 132 | cloud.words = function(x) { 133 | if (!arguments.length) return words; 134 | words = x; 135 | return cloud; 136 | }; 137 | 138 | cloud.size = function(x) { 139 | if (!arguments.length) return size; 140 | size = [+x[0], +x[1]]; 141 | return cloud; 142 | }; 143 | 144 | cloud.font = function(x) { 145 | if (!arguments.length) return font; 146 | font = d3.functor(x); 147 | return cloud; 148 | }; 149 | 150 | cloud.fontStyle = function(x) { 151 | if (!arguments.length) return fontStyle; 152 | fontStyle = d3.functor(x); 153 | return cloud; 154 | }; 155 | 156 | cloud.fontWeight = function(x) { 157 | if (!arguments.length) return fontWeight; 158 | fontWeight = d3.functor(x); 159 | return cloud; 160 | }; 161 | 162 | cloud.rotate = function(x) { 163 | if (!arguments.length) return rotate; 164 | rotate = d3.functor(x); 165 | return cloud; 166 | }; 167 | 168 | cloud.text = function(x) { 169 | if (!arguments.length) return text; 170 | text = d3.functor(x); 171 | return cloud; 172 | }; 173 | 174 | cloud.spiral = function(x) { 175 | if (!arguments.length) return spiral; 176 | spiral = spirals[x + ""] || x; 177 | return cloud; 178 | }; 179 | 180 | cloud.fontSize = function(x) { 181 | if (!arguments.length) return fontSize; 182 | fontSize = d3.functor(x); 183 | return cloud; 184 | }; 185 | 186 | cloud.padding = function(x) { 187 | if (!arguments.length) return padding; 188 | padding = d3.functor(x); 189 | return cloud; 190 | }; 191 | 192 | return d3.rebind(cloud, event, "on"); 193 | } 194 | 195 | function cloudText(d) { 196 | return d.text; 197 | } 198 | 199 | function cloudFont() { 200 | return "serif"; 201 | } 202 | 203 | function cloudFontNormal() { 204 | return "normal"; 205 | } 206 | 207 | function cloudFontSize(d) { 208 | return Math.sqrt(d.value); 209 | } 210 | 211 | function cloudRotate() { 212 | return (~~(Math.random() * 6) - 3) * 30; 213 | } 214 | 215 | function cloudPadding() { 216 | return 1; 217 | } 218 | 219 | // Fetches a monochrome sprite bitmap for the specified text. 220 | // Load in batches for speed. 221 | function cloudSprite(d, data, di) { 222 | if (d.sprite) return; 223 | c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio); 224 | var x = 0, 225 | y = 0, 226 | maxh = 0, 227 | n = data.length; 228 | --di; 229 | while (++di < n) { 230 | d = data[di]; 231 | c.save(); 232 | c.font = d.style + " " + d.weight + " " + ~~((d.size + 1) / ratio) + "px " + d.font; 233 | var w = c.measureText(d.text + "m").width * ratio, 234 | h = d.size << 1; 235 | if (d.rotate) { 236 | var sr = Math.sin(d.rotate * cloudRadians), 237 | cr = Math.cos(d.rotate * cloudRadians), 238 | wcr = w * cr, 239 | wsr = w * sr, 240 | hcr = h * cr, 241 | hsr = h * sr; 242 | w = (Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f) >> 5 << 5; 243 | h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr)); 244 | } else { 245 | w = (w + 0x1f) >> 5 << 5; 246 | } 247 | if (h > maxh) maxh = h; 248 | if (x + w >= (cw << 5)) { 249 | x = 0; 250 | y += maxh; 251 | maxh = 0; 252 | } 253 | if (y + h >= ch) break; 254 | c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio); 255 | if (d.rotate) c.rotate(d.rotate * cloudRadians); 256 | c.fillText(d.text, 0, 0); 257 | if (d.padding) c.lineWidth = 2 * d.padding, c.strokeText(d.text, 0, 0); 258 | c.restore(); 259 | d.width = w; 260 | d.height = h; 261 | d.xoff = x; 262 | d.yoff = y; 263 | d.x1 = w >> 1; 264 | d.y1 = h >> 1; 265 | d.x0 = -d.x1; 266 | d.y0 = -d.y1; 267 | d.hasText = true; 268 | x += w; 269 | } 270 | var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data, 271 | sprite = []; 272 | while (--di >= 0) { 273 | d = data[di]; 274 | if (!d.hasText) continue; 275 | var w = d.width, 276 | w32 = w >> 5, 277 | h = d.y1 - d.y0; 278 | // Zero the buffer 279 | for (var i = 0; i < h * w32; i++) sprite[i] = 0; 280 | x = d.xoff; 281 | if (x == null) return; 282 | y = d.yoff; 283 | var seen = 0, 284 | seenRow = -1; 285 | for (var j = 0; j < h; j++) { 286 | for (var i = 0; i < w; i++) { 287 | var k = w32 * j + (i >> 5), 288 | m = pixels[((y + j) * (cw << 5) + (x + i)) << 2] ? 1 << (31 - (i % 32)) : 0; 289 | sprite[k] |= m; 290 | seen |= m; 291 | } 292 | if (seen) seenRow = j; 293 | else { 294 | d.y0++; 295 | h--; 296 | j--; 297 | y++; 298 | } 299 | } 300 | d.y1 = d.y0 + seenRow; 301 | d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32); 302 | } 303 | } 304 | 305 | // Use mask-based collision detection. 306 | function cloudCollide(tag, board, sw) { 307 | sw >>= 5; 308 | var sprite = tag.sprite, 309 | w = tag.width >> 5, 310 | lx = tag.x - (w << 4), 311 | sx = lx & 0x7f, 312 | msx = 32 - sx, 313 | h = tag.y1 - tag.y0, 314 | x = (tag.y + tag.y0) * sw + (lx >> 5), 315 | last; 316 | for (var j = 0; j < h; j++) { 317 | last = 0; 318 | for (var i = 0; i <= w; i++) { 319 | if (((last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0)) 320 | & board[x + i]) return true; 321 | } 322 | x += sw; 323 | } 324 | return false; 325 | } 326 | 327 | function cloudBounds(bounds, d) { 328 | var b0 = bounds[0], 329 | b1 = bounds[1]; 330 | if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0; 331 | if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0; 332 | if (d.x + d.x1 > b1.x) b1.x = d.x + d.x1; 333 | if (d.y + d.y1 > b1.y) b1.y = d.y + d.y1; 334 | } 335 | 336 | function collideRects(a, b) { 337 | return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y; 338 | } 339 | 340 | function archimedeanSpiral(size) { 341 | var e = size[0] / size[1]; 342 | return function(t) { 343 | return [e * (t *= .1) * Math.cos(t), t * Math.sin(t)]; 344 | }; 345 | } 346 | 347 | function rectangularSpiral(size) { 348 | var dy = 4, 349 | dx = dy * size[0] / size[1], 350 | x = 0, 351 | y = 0; 352 | return function(t) { 353 | var sign = t < 0 ? -1 : 1; 354 | // See triangular numbers: T_n = n * (n + 1) / 2. 355 | switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) { 356 | case 0: x += dx; break; 357 | case 1: y += dy; break; 358 | case 2: x -= dx; break; 359 | default: y -= dy; break; 360 | } 361 | return [x, y]; 362 | }; 363 | } 364 | 365 | // TODO reuse arrays? 366 | function zeroArray(n) { 367 | var a = [], 368 | i = -1; 369 | while (++i < n) a[i] = 0; 370 | return a; 371 | } 372 | 373 | var cloudRadians = Math.PI / 180, 374 | cw = 1 << 11 >> 5, 375 | ch = 1 << 11, 376 | canvas, 377 | ratio = 1; 378 | 379 | if (typeof document !== "undefined") { 380 | canvas = document.createElement("canvas"); 381 | canvas.width = 1; 382 | canvas.height = 1; 383 | ratio = Math.sqrt(canvas.getContext("2d").getImageData(0, 0, 1, 1).data.length >> 2); 384 | canvas.width = (cw << 5) / ratio; 385 | canvas.height = ch / ratio; 386 | } else { 387 | // Attempt to use node-canvas. 388 | canvas = new Canvas(cw << 5, ch); 389 | } 390 | 391 | var c = canvas.getContext("2d"), 392 | spirals = { 393 | archimedean: archimedeanSpiral, 394 | rectangular: rectangularSpiral 395 | }; 396 | c.fillStyle = c.strokeStyle = "red"; 397 | c.textAlign = "center"; 398 | 399 | if (typeof module === "object" && module.exports) module.exports = cloud; 400 | else (d3.layout || (d3.layout = {})).cloud = cloud; 401 | })(); -------------------------------------------------------------------------------- /src/app/components/rl-value-function-tic-tac-toe/rl-value-function-tic-tac-toe.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { GlobalService } from "../../services/global.service"; 3 | import { TicTacToeAgent } from "./tic-tac-toe-agent"; 4 | import { TicTacToeEnvironment } from "./tic-tac-toe-environment"; 5 | 6 | @Component({ 7 | selector: 'app-tic-tac-toe', 8 | templateUrl: './rl-value-function-tic-tac-toe.component.html', 9 | styleUrls: ['./rl-value-function-tic-tac-toe.component.css'] 10 | }) 11 | export class RLValueFunctionTicTacToeComponent implements OnInit { 12 | 13 | constructor(private service: GlobalService) { 14 | this.service.changePageTitle('Tic Tac Toe'); 15 | } 16 | 17 | agent: TicTacToeAgent; 18 | environment: TicTacToeEnvironment; 19 | 20 | agentA: TicTacToeAgent; 21 | agentB: TicTacToeAgent; 22 | 23 | input_episodes: number; 24 | input_agent1_explore_probability = 0; 25 | input_agent1_learning_rate = 0; 26 | input_agent2_explore_probability = 0; 27 | input_agent2_learning_rate = 0; 28 | 29 | strategy: String; 30 | agent_probability = []; 31 | 32 | demo_agentx_graph_1 = {data:[], layout:{}}; 33 | demo_agentx_graph_2 = {data:[], layout:{}}; 34 | demo_agento_graph_1 = {data:[], layout:{}}; 35 | demo_agento_graph_2 = {data:[], layout:{}}; 36 | demo_agento_graph_1_zero = {data:[], layout:{}}; 37 | demo_agento_graph_2_zero = {data:[], layout:{}}; 38 | 39 | 40 | ngOnInit() { 41 | this.environment = new TicTacToeEnvironment(3); 42 | this.agentA = new TicTacToeAgent(1); 43 | this.agentB = new TicTacToeAgent(-1); 44 | this.input_episodes = 1; 45 | this.input_agent1_explore_probability = 0.05; 46 | this.input_agent1_learning_rate = 0.5; 47 | this.input_agent2_explore_probability = 0.05; 48 | this.input_agent2_learning_rate = 0.5; 49 | 50 | this.generate_epsilon_greedy_charts(); 51 | 52 | this.input_episodes = 10000; 53 | this.train_agents(); 54 | } 55 | 56 | play_again(){ 57 | this.environment.reset_game(); 58 | this.play_with_agent(); 59 | } 60 | 61 | async play_game(p1, p2, simulation=false){ 62 | 63 | let current_agent = p1; 64 | 65 | for(let i=0;i<9;i++){ 66 | let action = current_agent.take_action(this.environment); 67 | 68 | // console.log(current_agent.name, action, this.environment.get_state()); 69 | this.environment.grid_select(action); 70 | 71 | p1.update_state_history(this.environment.get_state()); 72 | p2.update_state_history(this.environment.get_state()); 73 | 74 | if(this.environment.ended){ 75 | break; 76 | } 77 | 78 | if(current_agent == p1){ 79 | current_agent = p2; 80 | }else{ 81 | current_agent = p1; 82 | } 83 | 84 | if(simulation){ 85 | await this.sleep(1000); 86 | } 87 | } 88 | 89 | p1.update(this.environment); 90 | p2.update(this.environment); 91 | 92 | } 93 | 94 | train_agents(){ 95 | 96 | this.agentA = new TicTacToeAgent(1, this.input_agent1_explore_probability, this.input_agent1_learning_rate); 97 | this.agentB = new TicTacToeAgent(-1, this.input_agent2_explore_probability, this.input_agent2_learning_rate); 98 | 99 | let episode = this.input_episodes; 100 | 101 | let state_winner_triples = this.get_state_hash_and_winner(this.environment); 102 | 103 | let V_list = this.initial_values(this.environment, state_winner_triples, this.agentA.name, this.agentB.name); 104 | this.agentA.set_v(V_list[0]); 105 | this.agentB.set_v(V_list[1]); 106 | 107 | for(let i=0;i setTimeout(resolve, ms)); 227 | } 228 | 229 | 230 | generate_epsilon_greedy_charts(){ 231 | let chartdata_agent_x = JSON.parse('[{"eps": 0, "counter": [9017, 241]}, {"eps": 0.01, "counter": [9181, 262]}, {"eps": 0.02, "counter": [8864, 428]}, {"eps": 0.03, "counter": [9112, 353]}, {"eps": 0.04, "counter": [9080, 420]}, {"eps": 0.05, "counter": [9268, 359]}, {"eps": 0.06, "counter": [8773, 634]}, {"eps": 0.07, "counter": [8748, 691]}, {"eps": 0.08, "counter": [8772, 731]}, {"eps": 0.09, "counter": [8569, 858]}, {"eps": 0.1, "counter": [8527, 916]}, {"eps": 0.11, "counter": [8400, 1015]}, {"eps": 0.12, "counter": [8231, 1172]}, {"eps": 0.13, "counter": [8221, 1144]}, {"eps": 0.14, "counter": [8021, 1350]}, {"eps": 0.15, "counter": [8048, 1329]}, {"eps": 0.16, "counter": [7855, 1454]}, {"eps": 0.17, "counter": [7790, 1528]}, {"eps": 0.18, "counter": [7815, 1533]}, {"eps": 0.19, "counter": [7712, 1615]}, {"eps": 0.2, "counter": [7665, 1681]}, {"eps": 0.3, "counter": [6655, 2592]}, {"eps": 0.4, "counter": [5982, 3244]}, {"eps": 0.5, "counter": [5128, 4087]}, {"eps": 0.6, "counter": [4127, 5146]}, {"eps": 0.7, "counter": [3436, 5880]}, {"eps": 0.8, "counter": [2583, 6840]}, {"eps": 0.9, "counter": [1984, 7532]}, {"eps": 1.0, "counter": [1454, 8180]}]'); 232 | let chartdata_agent_o = JSON.parse('[{"eps": 0, "counter": [535, 8993]}, {"eps": 0.01, "counter": [628, 8887]}, {"eps": 0.02, "counter": [627, 8790]}, {"eps": 0.03, "counter": [582, 8898]}, {"eps": 0.04, "counter": [591, 8855]}, {"eps": 0.05, "counter": [603, 8856]}, {"eps": 0.06, "counter": [598, 8879]}, {"eps": 0.07, "counter": [603, 8832]}, {"eps": 0.08, "counter": [516, 8946]}, {"eps": 0.09, "counter": [476, 9107]}, {"eps": 0.1, "counter": [473, 9069]}, {"eps": 0.11, "counter": [499, 9008]}, {"eps": 0.12, "counter": [534, 8772]}, {"eps": 0.13, "counter": [477, 8918]}, {"eps": 0.14, "counter": [498, 9009]}, {"eps": 0.15, "counter": [538, 8957]}, {"eps": 0.16, "counter": [505, 8978]}, {"eps": 0.17, "counter": [457, 9028]}, {"eps": 0.18, "counter": [430, 9133]}, {"eps": 0.19, "counter": [501, 8975]}, {"eps": 0.2, "counter": [503, 8921]}, {"eps": 0.3, "counter": [445, 9106]}, {"eps": 0.4, "counter": [433, 9083]}, {"eps": 0.5, "counter": [475, 9073]}, {"eps": 0.6, "counter": [583, 8946]}, {"eps": 0.7, "counter": [479, 9144]}, {"eps": 0.8, "counter": [421, 9317]}, {"eps": 0.9, "counter": [291, 9513]}, {"eps": 1.0, "counter": [232, 9662]}]'); 233 | let chartdata_agent_o_zero = JSON.parse('[{"eps": 0, "counter": [7927, 1563]}, {"eps": 0.01, "counter": [8010, 1846]}, {"eps": 0.02, "counter": [8256, 1619]}, {"eps": 0.03, "counter": [7841, 2028]}, {"eps": 0.04, "counter": [8272, 1596]}, {"eps": 0.05, "counter": [8246, 1618]}, {"eps": 0.06, "counter": [7821, 2059]}, {"eps": 0.07, "counter": [7290, 2584]}, {"eps": 0.08, "counter": [7102, 2775]}, {"eps": 0.09, "counter": [7201, 2665]}, {"eps": 0.1, "counter": [7605, 2294]}, {"eps": 0.11, "counter": [7210, 2667]}, {"eps": 0.12, "counter": [6321, 3529]}, {"eps": 0.13, "counter": [6991, 2886]}, {"eps": 0.14, "counter": [6654, 3215]}, {"eps": 0.15, "counter": [6441, 3415]}, {"eps": 0.16, "counter": [6606, 3254]}, {"eps": 0.17, "counter": [6505, 3358]}, {"eps": 0.18, "counter": [6092, 3761]}, {"eps": 0.19, "counter": [6139, 3715]}, {"eps": 0.2, "counter": [5906, 3955]}, {"eps": 0.3, "counter": [4985, 4856]}, {"eps": 0.4, "counter": [3934, 5900]}, {"eps": 0.5, "counter": [3935, 5855]}, {"eps": 0.6, "counter": [2712, 7086]}, {"eps": 0.7, "counter": [1933, 7848]}, {"eps": 0.8, "counter": [1438, 8338]}, {"eps": 0.9, "counter": [1045, 8715]}, {"eps": 1.0, "counter": [758, 9010]}]'); 234 | 235 | let x_all = []; 236 | let x_initial = []; 237 | let agentx_graph_1_win=[]; 238 | let agentx_graph_1_lost=[]; 239 | let agentx_graph_2_win=[]; 240 | let agento_graph_1_win=[]; 241 | let agento_graph_1_lost=[]; 242 | let agento_graph_2_win=[]; 243 | let agento_zero_graph_1_win=[]; 244 | let agento_zero_graph_1_lost=[]; 245 | let agento_zero_graph_2_win=[]; 246 | 247 | for(let i=0; i 2 | 3 | 4 | Stocks Prediction (TensorFlow.js) 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 |
28 |

Time Series Forecasting with TensorFlow.js

29 |

30 | Pull stock prices from online API and perform predictions using Recurrent Neural Network and Long Short-Term Memory (LSTM) with TensorFlow.js framework 31 |

32 |
33 |

34 | 35 | Machine learning is becoming increasingly popular these days and a growing number of the world’s population see it is as a magic crystal ball: predicting when and what will happen in the future. This experiment uses artificial neural networks to reveal stock market trends and demonstrates the ability of time series forecasting to predict future stock prices based on past historical data. 36 |

37 |

38 | 39 | Disclaimer: As stock markets fluctuation are dynamic and unpredictable owing to multiple factors, this experiment is 100% educational and by no means a trading prediction tool. 40 |

41 |

42 | 43 | There are 4 parts to this experiment: 44 |

    45 |
  1. get historical stocks prices data
  2. 46 |
  3. prepare training data for our neural network model
  4. 47 |
  5. training the neural network
  6. 48 |
  7. do some prediction
  8. 49 |
50 | Begin by scrolling down to explore each step or hit the Load Snapshot Demo button! 51 |

52 | 55 | 58 |
59 |
60 | 61 | 62 |
63 |
64 |

Get Stocks Data

65 |

66 | 67 |

68 |

69 | 70 | Before we can train our neural network and make any predictions, we will first require data. The type of data we are looking for is time series: a sequence of numbers in chronological order. A good starting place to fetch these data is from alphavantage.co. This API allows us to retrieve chronological data on specific company stocks prices from the last 20 years. 71 |

72 |

73 | The API yields the following fields: 74 |

    75 |
  1. open price
  2. 76 |
  3. highest price of that day
  4. 77 |
  5. lowest price of that day
  6. 78 |
  7. closing price
  8. 79 |
  9. volume
  10. 80 |
81 |

82 |

83 | To prepare training dataset for our neural network, we will be using closing stocks price; which also means that we will be aiming to predict future closing price. 84 |

85 |

86 | 87 | Use demo API key to fetch Microsoft Corporation prices or get your own API key for other stocks. 88 |

89 |
90 | 91 |
92 | 93 |
94 |
95 |
96 | 97 | 98 | Demo API key only allows 'MSFT' 99 |
100 |
101 |
102 |
103 | 104 | 105 | You can claim your API key from alphavantage.co 106 |
107 |
108 |
109 | 110 |
111 | 115 | 116 |
117 | 118 | 130 |
131 |
132 | 133 | 134 | 135 | 146 | 147 |
148 |
149 | 150 | 162 | 163 |
164 |
165 | 166 | 167 |
168 |
169 |

Simple Moving Average

170 |

171 |

172 | 173 | For this experiment, we are using supervised learning, which means feeding data to the neural network and it learns by mapping input data to the output label. One way to prepare the training dataset is to extract Simple Moving Average from that time series data. 174 |

175 |

176 | Simple Moving Average (SMA) is a method to identify trends direction for a certain period of time, by looking at the average of all the values within that time window. The number of prices in a time window is selected experimentally. 177 | 178 | For example, let's assume the closing prices for past 5 days were 13, 15, 14, 16, 17, the SMA would be (13+15+14+16+17)/5 = 15. So the input for our training dataset is the set of prices within a single time window, and label is the computed moving average of those prices. 179 |

180 |
181 | 182 |
183 | 184 |
185 |
186 |

But first, fetch stocks data from the previous step.

187 |
188 |
189 | 190 | 209 | 210 | 220 | 231 | 232 |
233 |
234 | 235 | 236 |
237 |
238 |

Train Neural Network

239 |

240 |

241 | 242 | Now that you have the training data, it is time to create a model for time series prediction, to achieve this we will use TensorFlow.js framework. 243 |

244 |

245 | Sequential model is selected which simply connects each layer and pass the data from input to the output during the training process. In order for the model to learn time series data which are sequential, recurrent neural network (RNN) layer layer is created and a number of LSTM cells are added to the RNN. 246 |

247 |

248 | The model will be trained using Adam (read more), a popular optimisation algorithm for machine learning. Root-means-squared error which determine the difference between predicted values and the actual values, so model is able to learn by minimising the error during the training process. 249 |

250 |

251 | 252 | These are the hyperparameters (parameters used in the training process) available for tweaking: 253 |

    254 |
  1. Training Dataset Size (%): the amount of data used for training, and remaining data will be used for prediction
  2. 255 |
  3. Epochs: number of times the dataset is used to train the model (learn more)
  4. 256 |
  5. Learning Rate: amount of change in the weights during training in each step (learn more)
  6. 257 |
  7. Hidden LSTM Layers: to increase the model complexity to learn in higher dimensional space (learn more)
  8. 258 |
259 |

260 |
261 | 262 |
263 | 264 |
265 |
266 |

Need training data? Explore the previous section to prepare training data.

267 |
268 |
269 | 270 | 311 | 312 | 334 |
335 |
336 | 337 | 338 |
339 |
340 |

Prediction

341 |

342 |

343 | 344 | Now that you have trained your model, it is time to use it for predicting future values, for our case, it is the moving average. We are actually using the remaining data for prediction which allow us to see how closely our predicted values are compared to the actual values. 345 |

346 |
347 | 348 |
349 | 350 |
351 |
352 |

Don’t have a model to perform prediction? Train your model.

353 |
354 |
355 | 356 | 368 | 378 | 379 |
380 |
381 | 382 | 396 | 397 | 398 | 399 | --------------------------------------------------------------------------------