Full Code of ngfelixl/nodeplotlib for AI

main 3f7c89b398a0 cached
113 files
85.2 KB
27.3k tokens
55 symbols
1 requests
Download .txt
Repository: ngfelixl/nodeplotlib
Branch: main
Commit: 3f7c89b398a0
Files: 113
Total size: 85.2 KB

Directory structure:
gitextract_d23cn4mt/

├── .editorconfig
├── .eslintrc.json
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode/
│   └── extensions.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── NOTES.md
├── README.md
├── angular.json
├── apps/
│   ├── .gitkeep
│   ├── dev-server/
│   │   ├── .eslintrc.json
│   │   ├── jest.config.ts
│   │   ├── project.json
│   │   ├── src/
│   │   │   ├── assets/
│   │   │   │   └── .gitkeep
│   │   │   ├── data/
│   │   │   │   ├── 2d-histogram.ts
│   │   │   │   ├── bar.ts
│   │   │   │   ├── candlestick.ts
│   │   │   │   ├── line-stream.ts
│   │   │   │   ├── sankey.ts
│   │   │   │   ├── scatter.ts
│   │   │   │   └── table.ts
│   │   │   ├── environments/
│   │   │   │   ├── environment.prod.ts
│   │   │   │   └── environment.ts
│   │   │   └── main.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   └── tsconfig.spec.json
│   ├── web/
│   │   ├── .browserslistrc
│   │   ├── .eslintrc.json
│   │   ├── jest.config.ts
│   │   ├── project.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── app-routing.module.ts
│   │   │   │   ├── app.module.ts
│   │   │   │   ├── components/
│   │   │   │   │   ├── app/
│   │   │   │   │   │   ├── app.component.css
│   │   │   │   │   │   ├── app.component.html
│   │   │   │   │   │   ├── app.component.spec.ts
│   │   │   │   │   │   └── app.component.ts
│   │   │   │   │   ├── plot/
│   │   │   │   │   │   ├── plot.component.css
│   │   │   │   │   │   ├── plot.component.html
│   │   │   │   │   │   └── plot.component.ts
│   │   │   │   │   ├── plots/
│   │   │   │   │   │   ├── plots.component.css
│   │   │   │   │   │   ├── plots.component.html
│   │   │   │   │   │   ├── plots.component.spec.ts
│   │   │   │   │   │   └── plots.component.ts
│   │   │   │   │   └── tutorial/
│   │   │   │   │       ├── tutorial.component.css
│   │   │   │   │       ├── tutorial.component.html
│   │   │   │   │       └── tutorial.component.ts
│   │   │   │   └── services/
│   │   │   │       ├── plots.service.ts
│   │   │   │       └── socket.service.ts
│   │   │   ├── assets/
│   │   │   │   └── .gitkeep
│   │   │   ├── custom-theme.scss
│   │   │   ├── environments/
│   │   │   │   ├── environment.prod.ts
│   │   │   │   └── environment.ts
│   │   │   ├── index.html
│   │   │   ├── main.ts
│   │   │   ├── polyfills.ts
│   │   │   ├── styles.css
│   │   │   └── test-setup.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.editor.json
│   │   ├── tsconfig.json
│   │   └── tsconfig.spec.json
│   └── web-e2e/
│       ├── .eslintrc.json
│       ├── cypress.json
│       ├── project.json
│       ├── src/
│       │   ├── fixtures/
│       │   │   └── example.json
│       │   ├── integration/
│       │   │   └── app.spec.ts
│       │   └── support/
│       │       ├── app.po.ts
│       │       ├── commands.ts
│       │       └── index.ts
│       └── tsconfig.json
├── decorate-angular-cli.js
├── jest.config.ts
├── jest.preset.js
├── libs/
│   └── nodeplotlib/
│       ├── .babelrc
│       ├── .eslintrc.json
│       ├── README.md
│       ├── jest.config.ts
│       ├── package.json
│       ├── project.json
│       ├── src/
│       │   ├── index.ts
│       │   └── lib/
│       │       ├── interfaces/
│       │       │   ├── index.ts
│       │       │   └── plot.ts
│       │       ├── nodeplotlib.ts
│       │       ├── server/
│       │       │   ├── plots/
│       │       │   │   ├── plots.gateway.ts
│       │       │   │   └── plots.service.ts
│       │       │   ├── server.module.ts
│       │       │   └── services/
│       │       │       ├── bridge-service.spec.ts
│       │       │       └── bridge.service.ts
│       │       └── utils/
│       │           ├── get-port.spec.ts
│       │           ├── get-port.ts
│       │           ├── open-window.spec.ts
│       │           └── open-window.ts
│       ├── tsconfig.json
│       ├── tsconfig.lib.json
│       └── tsconfig.spec.json
├── nx.json
├── package.json
├── tools/
│   ├── demo/
│   │   ├── README.md
│   │   ├── candlestick.js
│   │   ├── scatter.js
│   │   ├── scatter.ts
│   │   └── stream.ts
│   ├── generators/
│   │   └── .gitkeep
│   ├── tsconfig.tools.json
│   └── util/
│       └── copy-files.ts
└── tsconfig.base.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# Editor configuration, see http://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
max_line_length = off
trim_trailing_whitespace = false


================================================
FILE: .eslintrc.json
================================================
{
  "root": true,
  "ignorePatterns": ["**/*"],
  "plugins": ["@nrwl/nx"],
  "overrides": [
    {
      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
      "rules": {
        "@nrwl/nx/enforce-module-boundaries": [
          "error",
          {
            "enforceBuildableLibDependency": true,
            "allow": [],
            "depConstraints": [
              {
                "sourceTag": "*",
                "onlyDependOnLibsWithTags": ["*"]
              }
            ]
          }
        ]
      },
      "plugins": [],
      "extends": []
    },
    {
      "files": ["*.ts", "*.tsx"],
      "extends": ["plugin:@nrwl/nx/typescript"],
      "rules": {},
      "plugins": []
    },
    {
      "files": ["*.js", "*.jsx"],
      "extends": ["plugin:@nrwl/nx/javascript"],
      "rules": {}
    }
  ]
}


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
 - OS: [e.g. iOS]
 - Browser [e.g. chrome, safari]
 - Version [e.g. 22]

**Smartphone (please complete the following information):**
 - Device: [e.g. iPhone6]
 - OS: [e.g. iOS8.1]
 - Browser [e.g. stock browser, safari]
 - Version [e.g. 22]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/workflows/ci.yml
================================================
name: Node.js CI

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - uses: nrwl/nx-set-shas@v2
      - run: npm ci
      - run: npx nx workspace-lint
      - run: npx nx format:check
      - run: npx nx run-many --target=lint --all
      - run: npx nx run-many --target=test --all
      - run: npx nx run dev-server:build
      - run: npm run build:prod
        env:
          CI: true


================================================
FILE: .gitignore
================================================
# See http://help.github.com/ignore-files/ for more about ignoring files.

# compiled output
/dist
/tmp
/out-tsc

# dependencies
/node_modules

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

# misc
/.angular/cache
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings

# System Files
.DS_Store
Thumbs.db


================================================
FILE: .prettierignore
================================================
# Add files here to ignore them from prettier formatting

/dist
/coverage


================================================
FILE: .prettierrc
================================================
{
  "singleQuote": true
}


================================================
FILE: .vscode/extensions.json
================================================
{
  "recommendations": [
    "angular.ng-template",
    "nrwl.angular-console",
    "esbenp.prettier-vscode",
    "firsttris.vscode-jest-runner",
    "dbaeumer.vscode-eslint"
  ]
}


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
 advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
 address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
 professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at flemke.dev@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq


================================================
FILE: CONTRIBUTING.md
================================================
## Contribution guidelines

Contributions are very welcome. Please stick to the [code of conduct](./CODE_OF_CONDUCT.md) and, if possible, follow the issue templates.


### Commit message guidelines

Please use the following template for your commit messages.

```
type(scope): message

message-body

BREAKING CHANGE
Closes #4746
```

The message body can be multiple lines without any empty lines in between. If there is a breaking change please add the `BREAKING CHANGE` note.
If there is a related issue to this commit, please add a line containing `Closes/Fixes/Related to #ISSUENUMBER`. The type may be
one of the following

- feature (if new features are introduced)
- fix (if a bug was fixed and no features are introduced)
- package (for changes related to npm/travis configuration)
- misc (anything that does not fit in the above)


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2022 Felix Lemke

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: NOTES.md
================================================
These are notes for the stream implementation of Nodeplotlib.

## General

- A plot window (**apps/web**) tries to connect to the server via a realtime api (e.g. websockets).
- The server recognizes the count of connected apps.
- If the user executes the `plot` function several times, it will only open a window if there is no
  open connection to a **apps/web**.

## Server lifecycle

- The server starts with the execution of the `plot` function if there is no active server running.
- The server stops if all **apps/web** are disconnected (and there were connections before).

## The plot function

- The plot function can either handle a `Plot` or an `Observable<Plot>`.
  - It creates an `Observable<Plot>` by using Rxjs' `of` observable constructor.
- The plot streams are saved in a Plots Set.
- If there is an active **apps/web** that listens to the server, it subscribes to all Plots in the Set.
- It does not submit a whole "plots" object, but rather submits all plots one by one. The reason is
  realtime data, for which only the updated plot should be transmitted.
- If all **apps/web** are disconnected, it should close the observable subscriptions of the plots and close
  the server as mentioned in the **server lifecycle** section.

## The stack function

- Is the `stack` function really needed? Stack served the purpose that only one window opens which
  could display several plots.

## The clear function

- The `clear` function is also probably not needed. Just close all windows and it should close the
  subscriptions to the plots and streams.

## Backlog

- The user can remove plots from the frontend. If that happened it submits a message to the
  backend so that the subscription can be cancelled and the plot stream can be removed from the plots set.

## Frontend only

- The user has the possibility to rearrange plots per drag and drop.
- The user can resize the individual plot windows.

## Development

To start the app for development purposes run

```
npm run build web -- --watch
npm start dev-server
```


================================================
FILE: README.md
================================================
# <img src="./img/nodeplotlib_64x64.png" width="22px" height="22px"> NodePlotLib

[![NodeJS CI](https://github.com/ngfelixl/nodeplotlib/workflows/Node.js%20CI/badge.svg)](https://github.com/ngfelixl/nodeplotlib/actions?query=workflow%3A%22Node.js+CI%22)
[![npm](https://img.shields.io/npm/v/nodeplotlib?color=#00f800)](https://npmjs.com/package/nodeplotlib)
[![npm](https://img.shields.io/npm/dt/nodeplotlib.svg)](https://npmjs.com/package/nodeplotlib)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)

[![Animation (View on Github)](https://raw.githubusercontent.com/ngfelixl/nodeplotlib/master/img/animation-next.gif)](https://raw.githubusercontent.com/ngfelixl/nodeplotlib/master/img/animation-next.gif)

This readme contains all the necessary information for the development.

## [Go to the user docs](./libs/nodeplotlib/README.md)

## Installation

### Npmjs

```sh
npm install nodeplotlib
# or
yarn add nodeplotlib
```

### Repository

Create a fork of this repository. Then clone it

```
git clone https://github.com/{{USERNAME}}/nodeplotlib
cd nodeplotlib
npm i
```

## Serving the app for development

Serving in development mode prevents the app to open a new browser window on changes.
You can open the app at the specified port, e.g. `http://localhost:4201`.

```
npx nx run web:build -- --watch

NODEPLOTLIB_PORT=4201 npx nx run dev-server:serve
// or on Windows cmd
set "NODEPLOTLIB_PORT=4201" && npx nx run dev-server:serve
// or on Windows Powershell
$env:NODEPLOTLIB_PORT = "4201" ; npx nx run dev-server:serve
```

## Build for production

To build for production three steps are necessary. Build the web app, build
the library, and finally copy the web app files to the libraries dist folder.
All steps are bundled in the following script:

```
npm run build:prod
```

All dist files are located in **/dist/libs/nodeplotlib**

## Release Guide

This is a note for maintainers only. There are several steps to follow before you
can publish the new version to npm.

1. Bump the version number using semver. Use "rc" for release candidates as the _preid_, e.g.
   `1.0.0-rc1`. Update the version number in the root [package.json](./package.json)
   and in the libs [package.json](./libs/nodeplotlib/package.json).
2. If everything is committed and in place on "master" for non-release candidates,
   or on "release/..." for release candidates. Create a tag with that version number,
   e.g. `v1.0.0-rc1` or `v1.0.1`, and push it to the repository.
3. Run `npm run build:prod`
4. Navigate to **/dist/libs/nodeplotlib**
5. Run `npm pack`
6. Make sure to be logged in to npmjs. Then run
   - `npm publish {{filename}}.tgz` or
   - `npm publish {{filename}}.tgz --tag test` for release candidates.
7. Create a release on Github for non-release cadidate versions.

## Behind the scenes

The lib launches a webserver and opens new tabs for every plot located at
`http://localhost:{{PORT}}`, where `PORT` is a free port determined by the express
server itself. At this address the Angular application will be served temporarily.
The server and the app set up a connection via socket.io. This way a realtime
transmission is possible.

## Contributing

Contributions in all forms are welcome.

## Contributors

<a href="https://github.com/ngfelixl"><img src="https://avatars2.githubusercontent.com/u/24190530" title="ngfelixl" width="100" height="100"></a>
<a href="https://github.com/mitsos1os"><img src="https://avatars3.githubusercontent.com/u/8208733" title="mitsos1os" width="100" height="100"></a>
<a href="https://github.com/medved-nsk"><img src="https://avatars1.githubusercontent.com/u/6310906" title="medved-nsk" width="100" height="100"></a>
<a href="https://github.com/Moumouls"><img src="https://avatars.githubusercontent.com/u/27959372" title="Moumouls" width="100" height="100"></a>
<a href="https://github.com/grgr-dkrk"><img src="https://avatars.githubusercontent.com/u/40130327" title="guruguru-dekiruko" width="100" height="100"></a>


================================================
FILE: angular.json
================================================
{
  "$schema": "./node_modules/nx/schemas/workspace-schema.json",
  "version": 2,
  "projects": {
    "dev-server": "apps/dev-server",
    "nodeplotlib": "libs/nodeplotlib",
    "web": "apps/web",
    "web-e2e": "apps/web-e2e"
  }
}


================================================
FILE: apps/.gitkeep
================================================


================================================
FILE: apps/dev-server/.eslintrc.json
================================================
{
  "extends": ["../../.eslintrc.json"],
  "ignorePatterns": ["!**/*"],
  "overrides": [
    {
      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
      "rules": {}
    },
    {
      "files": ["*.ts", "*.tsx"],
      "rules": {}
    },
    {
      "files": ["*.js", "*.jsx"],
      "rules": {}
    }
  ]
}


================================================
FILE: apps/dev-server/jest.config.ts
================================================
/* eslint-disable */
export default {
  displayName: 'dev-server',
  preset: '../../jest.preset.js',
  globals: {
    'ts-jest': {
      tsconfig: '<rootDir>/tsconfig.spec.json',
    },
  },
  testEnvironment: 'node',
  transform: {
    '^.+\\.[tj]s$': 'ts-jest',
  },
  moduleFileExtensions: ['ts', 'js', 'html'],
  coverageDirectory: '../../coverage/apps/dev-server',
};


================================================
FILE: apps/dev-server/project.json
================================================
{
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "apps/dev-server/src",
  "projectType": "application",
  "architect": {
    "build": {
      "executor": "@nrwl/node:webpack",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "dist/apps/dev-server",
        "main": "apps/dev-server/src/main.ts",
        "tsConfig": "apps/dev-server/tsconfig.app.json",
        "assets": [
          "apps/dev-server/src/assets",
          {
            "glob": "**/*",
            "input": "dist/apps/web",
            "output": "web"
          }
        ]
      },
      "configurations": {
        "production": {
          "optimization": true,
          "extractLicenses": true,
          "inspect": false,
          "fileReplacements": [
            {
              "replace": "apps/dev-server/src/environments/environment.ts",
              "with": "apps/dev-server/src/environments/environment.prod.ts"
            }
          ]
        }
      }
    },
    "serve": {
      "executor": "@nrwl/node:node",
      "options": {
        "buildTarget": "dev-server:build"
      }
    },
    "lint": {
      "executor": "@nrwl/linter:eslint",
      "outputs": ["{options.outputFile}"],
      "options": {
        "lintFilePatterns": ["apps/dev-server/**/*.ts"]
      }
    },
    "test": {
      "executor": "@nrwl/jest:jest",
      "outputs": ["coverage/apps/dev-server"],
      "options": {
        "jestConfig": "apps/dev-server/jest.config.ts",
        "passWithNoTests": true
      }
    }
  },
  "implicitDependencies": ["web"]
}


================================================
FILE: apps/dev-server/src/assets/.gitkeep
================================================


================================================
FILE: apps/dev-server/src/data/2d-histogram.ts
================================================
import { Layout, Plot } from '@npl/nodeplotlib';

function normal() {
  let x = 0,
    y = 0,
    rds;
  do {
    x = Math.random() * 2 - 1;
    y = Math.random() * 2 - 1;
    rds = x * x + y * y;
  } while (rds == 0 || rds > 1);
  const c = Math.sqrt((-2 * Math.log(rds)) / rds); // Box-Muller transform
  return x * c; // throw away extra sample y * c
}

const N = 2000;
const a = -1;
const b = 1.2;

const step = (b - a) / (N - 1);
const t = new Array(N),
  x = new Array(N),
  y = new Array(N);

for (let i = 0; i < N; i++) {
  t[i] = a + step * i;
  x[i] = Math.pow(t[i], 3) + 0.3 * normal();
  y[i] = Math.pow(t[i], 6) + 0.3 * normal();
}

const trace1: Plot = {
  x: x,
  y: y,
  mode: 'markers',
  name: 'points',
  marker: {
    color: 'rgb(102,0,0)',
    size: 2,
    opacity: 0.4,
  },
  type: 'scatter',
};
const trace2: Plot = {
  x: x,
  y: y,
  name: 'density',
  ncontours: 20,
  colorscale: 'Hot',
  reversescale: true,
  showscale: false,
  type: 'histogram2dcontour',
} as Plot;
const trace3: Plot = {
  x: x,
  name: 'x density',
  marker: { color: 'rgb(102,0,0)' },
  yaxis: 'y2',
  type: 'histogram',
};
const trace4: Plot = {
  y: y,
  name: 'y density',
  marker: { color: 'rgb(102,0,0)' },
  xaxis: 'x2',
  type: 'histogram',
};
export const data = [trace1, trace2, trace3, trace4];
export const layout: Layout = {
  showlegend: false,
  autosize: false,
  width: 600,
  height: 550,
  margin: { t: 50 },
  hovermode: 'closest',
  bargap: 0,
  xaxis: {
    domain: [0, 0.85],
    showgrid: false,
    zeroline: false,
  },
  yaxis: {
    domain: [0, 0.85],
    showgrid: false,
    zeroline: false,
  },
  xaxis2: {
    domain: [0.85, 1],
    showgrid: false,
    zeroline: false,
  },
  yaxis2: {
    domain: [0.85, 1],
    showgrid: false,
    zeroline: false,
  },
};


================================================
FILE: apps/dev-server/src/data/bar.ts
================================================
import { Plot } from '@npl/nodeplotlib';

export const data: Plot[] = [
  {
    type: 'bar',
    x: [20, 14, 23],
    y: ['giraffes', 'orangutans', 'monkeys'],
    orientation: 'h',
  },
];


================================================
FILE: apps/dev-server/src/data/candlestick.ts
================================================
import { Plot } from '@npl/nodeplotlib';

const trace1 = {
  x: [
    '2017-01-04',
    '2017-01-05',
    '2017-01-06',
    '2017-01-09',
    '2017-01-10',
    '2017-01-11',
    '2017-01-12',
    '2017-01-13',
    '2017-01-17',
    '2017-01-18',
    '2017-01-19',
    '2017-01-20',
    '2017-01-23',
    '2017-01-24',
    '2017-01-25',
    '2017-01-26',
    '2017-01-27',
    '2017-01-30',
    '2017-01-31',
    '2017-02-01',
    '2017-02-02',
    '2017-02-03',
    '2017-02-06',
    '2017-02-07',
    '2017-02-08',
    '2017-02-09',
    '2017-02-10',
    '2017-02-13',
    '2017-02-14',
    '2017-02-15',
  ],
  close: [
    116.019997, 116.610001, 117.910004, 118.989998, 119.110001, 119.75, 119.25,
    119.040001, 120, 119.989998, 119.779999, 120, 120.080002, 119.970001,
    121.879997, 121.940002, 121.949997, 121.629997, 121.349998, 128.75,
    128.529999, 129.080002, 130.289993, 131.529999, 132.039993, 132.419998,
    132.119995, 133.289993, 135.020004, 135.509995,
  ],
  decreasing: { line: { color: '#7F7F7F' } },
  high: [
    116.510002, 116.860001, 118.160004, 119.43, 119.379997, 119.93, 119.300003,
    119.620003, 120.239998, 120.5, 120.089996, 120.449997, 120.809998,
    120.099998, 122.099998, 122.440002, 122.349998, 121.629997, 121.389999,
    130.490005, 129.389999, 129.190002, 130.5, 132.089996, 132.220001,
    132.449997, 132.940002, 133.820007, 135.089996, 136.270004,
  ],
  increasing: { line: { color: '#17BECF' } },
  line: { color: 'rgba(31,119,180,1)' },
  low: [
    115.75, 115.809998, 116.470001, 117.940002, 118.300003, 118.599998,
    118.209999, 118.809998, 118.220001, 119.709999, 119.370003, 119.730003,
    119.769997, 119.5, 120.279999, 121.599998, 121.599998, 120.660004,
    120.620003, 127.010002, 127.779999, 128.160004, 128.899994, 130.449997,
    131.220001, 131.119995, 132.050003, 132.75, 133.25, 134.619995,
  ],
  open: [
    115.849998, 115.919998, 116.779999, 117.949997, 118.769997, 118.739998,
    118.900002, 119.110001, 118.339996, 120, 119.400002, 120.449997, 120,
    119.550003, 120.419998, 121.669998, 122.139999, 120.93, 121.150002,
    127.029999, 127.980003, 128.309998, 129.130005, 130.539993, 131.350006,
    131.649994, 132.460007, 133.080002, 133.470001, 135.520004,
  ],
  type: 'candlestick',
  xaxis: 'x',
  yaxis: 'y',
} as Plot;

export const data = [trace1];

export const layout = {
  dragmode: 'zoom',
  margin: {
    r: 10,
    t: 25,
    b: 40,
    l: 60,
  },
  showlegend: false,
  xaxis: {
    autorange: true,
    domain: [0, 1],
    range: ['2017-01-03 12:00', '2017-02-15 12:00'],
    rangeslider: { range: ['2017-01-03 12:00', '2017-02-15 12:00'] },
    title: 'Date',
    type: 'date',
  },
  yaxis: {
    autorange: true,
    domain: [0, 1],
    range: [114.609999778, 137.410004222],
    type: 'linear',
  },
};


================================================
FILE: apps/dev-server/src/data/line-stream.ts
================================================
import { Plot } from '@npl/nodeplotlib';
import { interval, Observable, map } from 'rxjs';

export const stream$: Observable<Plot[]> = interval(100).pipe(
  map((index) => {
    const data: Plot = {
      x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
      y: Array(10)
        .fill(0)
        .map((_, i) => Math.sin(index + i)),
      type: 'scatter',
    };
    return [data];
  })
);


================================================
FILE: apps/dev-server/src/data/sankey.ts
================================================
import { Plot } from '@npl/nodeplotlib';

export const data = [
  {
    type: 'sankey',
    orientation: 'h',
    node: {
      pad: 15,
      thickness: 30,
      line: {
        color: 'black',
        width: 0.5,
      },
      label: ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'],
      color: ['blue', 'blue', 'blue', 'blue', 'blue', 'blue'],
    },

    link: {
      source: [0, 1, 0, 2, 3, 3],
      target: [2, 3, 3, 4, 4, 5],
      value: [8, 4, 2, 8, 4, 2],
    },
  } as Plot,
];

export const layout = {
  title: 'Basic Sankey',
  font: {
    size: 10,
  },
};


================================================
FILE: apps/dev-server/src/data/scatter.ts
================================================
import { Plot } from '@npl/nodeplotlib';

const trace1: Plot = {
  x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
  y: [1, 2, 1, 2, 1, 2, 1, 2, 1, 2],
  type: 'scatter',
};
export const data = [trace1];
export const layout = {};


================================================
FILE: apps/dev-server/src/data/table.ts
================================================
import { Plot } from '@npl/nodeplotlib';

const values = [
  ['Salaries', 'Office', 'Merchandise', 'Legal', '<b>TOTAL</b>'],
  [1200000, 20000, 80000, 2000, 12120000],
  [1300000, 20000, 70000, 2000, 130902000],
  [1300000, 20000, 120000, 2000, 131222000],
  [1400000, 20000, 90000, 2000, 14102000],
];

const headerColor = 'grey';
const rowEvenColor = 'lightgrey';
const rowOddColor = 'white';

export const data = [
  {
    type: 'table',
    header: {
      values: [
        ['<b>EXPENSES</b>'],
        ['<b>Q1</b>'],
        ['<b>Q2</b>'],
        ['<b>Q3</b>'],
        ['<b>Q4</b>'],
      ],
      align: 'center',
      line: { width: 1, color: 'black' },
      fill: { color: headerColor },
      font: { family: 'Arial', size: 12, color: 'white' },
    },
    cells: {
      values: values,
      align: 'center',
      line: { color: 'black', width: 1 },
      fill: {
        color: [
          [rowOddColor, rowEvenColor, rowOddColor, rowEvenColor, rowOddColor],
        ],
      },
      font: { family: 'Arial', size: 11, color: ['black'] },
    },
  } as Plot,
];


================================================
FILE: apps/dev-server/src/environments/environment.prod.ts
================================================
export const environment = {
  production: true,
};


================================================
FILE: apps/dev-server/src/environments/environment.ts
================================================
export const environment = {
  production: false,
};


================================================
FILE: apps/dev-server/src/main.ts
================================================
/**
 * This is not a production server yet!
 * This is only a minimal backend to get started.
 */

import { plot } from '@npl/nodeplotlib';
import {
  data as histogram,
  layout as histogramLayout,
} from './data/2d-histogram';
import { data as bar } from './data/bar';
import { stream$ } from './data/line-stream';
import { data as sankey, layout as sankeyLayout } from './data/sankey';
import { data as scatter, layout as scatterPlotLayout } from './data/scatter';
import { data as table } from './data/table';

plot(stream$);
plot(scatter, scatterPlotLayout);
plot(bar);
plot(sankey, sankeyLayout);
plot(histogram, histogramLayout);
plot(table);


================================================
FILE: apps/dev-server/tsconfig.app.json
================================================
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "module": "commonjs",
    "types": ["node"],
    "emitDecoratorMetadata": true,
    "target": "es2015"
  },
  "exclude": ["**/*.spec.ts", "**/*.test.ts"],
  "include": ["**/*.ts"]
}


================================================
FILE: apps/dev-server/tsconfig.json
================================================
{
  "extends": "../../tsconfig.base.json",
  "files": [],
  "include": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
  ]
}


================================================
FILE: apps/dev-server/tsconfig.spec.json
================================================
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "module": "commonjs",
    "types": ["jest", "node"]
  },
  "include": ["**/*.spec.ts", "**/*.test.ts", "**/*.d.ts"]
}


================================================
FILE: apps/web/.browserslistrc
================================================
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries

# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support

# You can see what browsers were selected by your queries by running:
#   npx browserslist

last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.


================================================
FILE: apps/web/.eslintrc.json
================================================
{
  "extends": ["../../.eslintrc.json"],
  "ignorePatterns": ["!**/*"],
  "overrides": [
    {
      "files": ["*.ts"],
      "extends": [
        "plugin:@nrwl/nx/angular",
        "plugin:@angular-eslint/template/process-inline-templates"
      ],
      "rules": {
        "@angular-eslint/directive-selector": [
          "error",
          {
            "type": "attribute",
            "prefix": "npl",
            "style": "camelCase"
          }
        ],
        "@angular-eslint/component-selector": [
          "error",
          {
            "type": "element",
            "prefix": "npl",
            "style": "kebab-case"
          }
        ]
      }
    },
    {
      "files": ["*.html"],
      "extends": ["plugin:@nrwl/nx/angular-template"],
      "rules": {}
    }
  ]
}


================================================
FILE: apps/web/jest.config.ts
================================================
/* eslint-disable */
export default {
  displayName: 'web',
  preset: '../../jest.preset.js',
  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
  globals: {
    'ts-jest': {
      tsconfig: '<rootDir>/tsconfig.spec.json',
      stringifyContentPathRegex: '\\.(html|svg)$',
    },
  },
  coverageDirectory: '../../coverage/apps/web',
  transform: {
    '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular',
  },
  transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
  snapshotSerializers: [
    'jest-preset-angular/build/serializers/no-ng-attributes',
    'jest-preset-angular/build/serializers/ng-snapshot',
    'jest-preset-angular/build/serializers/html-comment',
  ],
};


================================================
FILE: apps/web/project.json
================================================
{
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "projectType": "application",
  "sourceRoot": "apps/web/src",
  "prefix": "npl",
  "targets": {
    "build": {
      "executor": "@angular-devkit/build-angular:browser",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "dist/apps/web",
        "index": "apps/web/src/index.html",
        "main": "apps/web/src/main.ts",
        "polyfills": "apps/web/src/polyfills.ts",
        "tsConfig": "apps/web/tsconfig.app.json",
        "assets": ["apps/web/src/favicon.ico", "apps/web/src/assets"],
        "styles": ["apps/web/src/custom-theme.scss", "apps/web/src/styles.css"],
        "scripts": []
      },
      "configurations": {
        "production": {
          "budgets": [
            {
              "type": "initial",
              "maximumWarning": "500kb",
              "maximumError": "1mb"
            },
            {
              "type": "anyComponentStyle",
              "maximumWarning": "2kb",
              "maximumError": "4kb"
            }
          ],
          "fileReplacements": [
            {
              "replace": "apps/web/src/environments/environment.ts",
              "with": "apps/web/src/environments/environment.prod.ts"
            }
          ],
          "outputHashing": "none"
        },
        "development": {
          "buildOptimizer": false,
          "optimization": false,
          "vendorChunk": true,
          "extractLicenses": false,
          "sourceMap": true,
          "namedChunks": true
        }
      },
      "defaultConfiguration": "production"
    },
    "serve": {
      "executor": "@angular-devkit/build-angular:dev-server",
      "configurations": {
        "production": {
          "browserTarget": "web:build:production"
        },
        "development": {
          "browserTarget": "web:build:development"
        }
      },
      "defaultConfiguration": "development"
    },
    "extract-i18n": {
      "executor": "@angular-devkit/build-angular:extract-i18n",
      "options": {
        "browserTarget": "web:build"
      }
    },
    "lint": {
      "executor": "@nrwl/linter:eslint",
      "options": {
        "lintFilePatterns": ["apps/web/src/**/*.ts", "apps/web/src/**/*.html"]
      }
    },
    "test": {
      "executor": "@nrwl/jest:jest",
      "outputs": ["coverage/apps/web"],
      "options": {
        "jestConfig": "apps/web/jest.config.ts",
        "passWithNoTests": true
      }
    }
  }
}


================================================
FILE: apps/web/src/app/app-routing.module.ts
================================================
import { NgModule } from '@angular/core';
import {
  ActivatedRouteSnapshot,
  BaseRouteReuseStrategy,
  DetachedRouteHandle,
  Route,
  RouteReuseStrategy,
  RouterModule,
} from '@angular/router';
import { PlotsComponent } from './components/plots/plots.component';
import { TutorialComponent } from './components/tutorial/tutorial.component';

const routes: Route[] = [
  { path: 'plots', component: PlotsComponent },
  { path: 'tutorial', component: TutorialComponent },
  { path: '**', redirectTo: 'plots' },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

export class AppRoutesReuseStrategy implements RouteReuseStrategy {
  private cache: { [key: string]: DetachedRouteHandle } = {};

  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return true;
  }

  store(route: ActivatedRouteSnapshot, handler: DetachedRouteHandle): void {
    if (handler) {
      this.cache[this.getUrl(route)] = handler;
    }
  }

  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    return !!this.cache[this.getUrl(route)];
  }

  shouldReuseRoute(
    future: ActivatedRouteSnapshot,
    current: ActivatedRouteSnapshot
  ): boolean {
    return future.routeConfig === current.routeConfig;
  }

  retrieve(route: ActivatedRouteSnapshot) {
    if (!route.routeConfig || route.routeConfig.loadChildren) {
      return null;
    }
    return this.cache[this.getUrl(route)];
  }

  private getUrl(route: ActivatedRouteSnapshot): string {
    return route.routeConfig?.path ?? '';
  }
}


================================================
FILE: apps/web/src/app/app.module.ts
================================================
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AppRoutesReuseStrategy, AppRoutingModule } from './app-routing.module';
import { AppComponent } from './components/app/app.component';
import { TutorialComponent } from './components/tutorial/tutorial.component';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatListModule } from '@angular/material/list';
import { PlotComponent } from './components/plot/plot.component';
import { PlotsComponent } from './components/plots/plots.component';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { RouteReuseStrategy } from '@angular/router';

@NgModule({
  declarations: [
    AppComponent,
    TutorialComponent,
    PlotComponent,
    PlotsComponent,
  ],
  imports: [
    AppRoutingModule,
    BrowserAnimationsModule,
    BrowserModule,
    MatButtonModule,
    MatToolbarModule,
    HttpClientModule,
    MatSidenavModule,
    MatListModule,
    DragDropModule,
    MatCardModule,
    MatIconModule,
    MatTooltipModule,
  ],
  providers: [
    { provide: RouteReuseStrategy, useClass: AppRoutesReuseStrategy },
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}


================================================
FILE: apps/web/src/app/components/app/app.component.css
================================================
:host {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  justify-content: stretch;
  align-items: stretch;
}

main {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: stretch;
}

mat-toolbar {
  flex: 0 0 auto;
  justify-content: space-between;
}

.info-icons {
  display: flex;
  gap: 8px;
}

.info-icons img {
  width: 24px;
  height: 24px;
}

.green {
  color: #00ff2a;
}


================================================
FILE: apps/web/src/app/components/app/app.component.html
================================================
<mat-toolbar color="primary" class="mat-elevation-z4">
  <span class="brand" routerLink="/">
    <button mat-button>
      <img
        src="./assets/nodeplotlib_64x64_transparent.png"
        alt="NodePlotLib Brand Icon"
        height="32px"
        width="32px"
      />
      <span>
        <span class="green">N</span>ode<span class="green">P</span>lot<span
          class="green"
          >L</span
        >ib
      </span>
    </button>
  </span>
  <span class="info-icons">
    <button mat-icon-button routerLink="tutorial" matTooltip="Tutorial">
      <mat-icon>tips_and_updates</mat-icon>
    </button>
    <a href="https://plotly.com/javascript/" target="_blank" rel="noreferrer"
      ><button mat-icon-button matTooltip="Plotly.js Documentation">
        <img src="/assets/plotly.svg" alt="Plotly.js Icon" /></button
    ></a>
    <a
      href="https://github.com/ngfelixl/nodeplotlib"
      target="_blank"
      rel="noreferrer"
      ><button mat-icon-button>
        <img src="/assets/github-light-32px.png" alt="Github Icon" /></button
    ></a>
  </span>
</mat-toolbar>
<main>
  <router-outlet></router-outlet>
</main>


================================================
FILE: apps/web/src/app/components/app/app.component.spec.ts
================================================
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SocketService } from '../../services/socket.service';
import { AppComponent } from './app.component';

describe('AppComponent', () => {
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [AppComponent],
      imports: [],
      providers: [{ provide: SocketService, useValue: {} }],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
    }).compileComponents();

    fixture = TestBed.createComponent(AppComponent);
  });

  it('should create', () => {
    expect(fixture).toBeTruthy();
  });
});


================================================
FILE: apps/web/src/app/components/app/app.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { SocketService } from '../../services/socket.service';

@Component({
  selector: 'npl-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
  constructor(private socketService: SocketService) {}
}


================================================
FILE: apps/web/src/app/components/plot/plot.component.css
================================================


================================================
FILE: apps/web/src/app/components/plot/plot.component.html
================================================
<div #plotContainer></div>


================================================
FILE: apps/web/src/app/components/plot/plot.component.ts
================================================
import {
  AfterViewInit,
  ChangeDetectionStrategy,
  Component,
  ElementRef,
  Input,
  OnChanges,
  SimpleChanges,
  ViewChild,
} from '@angular/core';
import { PlotData } from '@npl/nodeplotlib';

// eslint-disable-next-line
declare const Plotly: any;

@Component({
  selector: 'npl-plot',
  templateUrl: './plot.component.html',
  styleUrls: ['./plot.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PlotComponent implements AfterViewInit, OnChanges {
  @Input() plotData!: PlotData;
  @ViewChild('plotContainer', { static: false }) plotContainer!: ElementRef;

  ngAfterViewInit() {
    Plotly.newPlot(
      this.plotContainer.nativeElement,
      this.plotData.data,
      { ...(this.plotData.layout ?? {}), autosize: true },
      { ...(this.plotData.config ?? {}), responsive: true }
    );
  }

  ngOnChanges(simpleChanges: SimpleChanges) {
    if (simpleChanges.plotData) {
      Plotly.react(
        this.plotContainer.nativeElement,
        this.plotData.data,
        { ...(this.plotData.layout ?? {}), autosize: true },
        { ...(this.plotData.config ?? {}), responsive: true }
      );
    }
  }
}


================================================
FILE: apps/web/src/app/components/plots/plots.component.css
================================================
:host {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
  grid-gap: 8px;
  margin: 12px;
  grid-template-rows: auto;
}


================================================
FILE: apps/web/src/app/components/plots/plots.component.html
================================================
<mat-card *ngFor="let plot of plots$ | async; trackBy: trackById">
  <npl-plot [plotData]="plot"></npl-plot>
</mat-card>


================================================
FILE: apps/web/src/app/components/plots/plots.component.spec.ts
================================================
import { Component, CUSTOM_ELEMENTS_SCHEMA, Input } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { PlotData } from '@npl/nodeplotlib';
import { Subject } from 'rxjs';
import { PlotsService } from '../../services/plots.service';
import { PlotsComponent } from './plots.component';

const PLOTS: PlotData[] = [
  {
    id: 1,
    data: [{ x: [1, 2, 3], y: [2, 3, 4] }],
    layout: {
      title: 'Test Plot 1',
    },
  },
  {
    id: 2,
    data: [{ x: [1, 2, 3], y: [2, 3, 4] }],
    layout: {
      title: 'Test Plot 2',
    },
  },
];

@Component({
  selector: 'npl-plot',
  template: '',
})
export class PlotComponent {
  @Input() plotData!: PlotData;
}

describe('PlotsComponent', () => {
  let component: PlotsComponent;
  let fixture: ComponentFixture<PlotsComponent>;
  let plotsServiceMock: PlotsService;
  let plots$: Subject<PlotData[]>;

  beforeEach(async () => {
    plots$ = new Subject();
    plotsServiceMock = {
      plots$,
    } as unknown as PlotsService;

    await TestBed.configureTestingModule({
      declarations: [PlotsComponent, PlotComponent],
      providers: [{ provide: PlotsService, useValue: plotsServiceMock }],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
    }).compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(PlotsComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should render a empty list if there are no emitted values', () => {
    const plots = fixture.debugElement.queryAll(By.directive(PlotComponent));

    expect(plots.length).toBe(0);
  });

  it('should render a plot if there is one element', () => {
    plots$.next([PLOTS[0]]);

    fixture.detectChanges();

    const plots = fixture.debugElement.queryAll(By.directive(PlotComponent));
    expect(plots.length).toBe(1);
  });

  it('should render several plots', () => {
    plots$.next(PLOTS);

    fixture.detectChanges();

    const plots = fixture.debugElement.queryAll(By.directive(PlotComponent));
    expect(plots.length).toBe(2);
  });
});


================================================
FILE: apps/web/src/app/components/plots/plots.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { PlotData } from '@npl/nodeplotlib';
import { PlotsService } from '../../services/plots.service';

@Component({
  selector: 'npl-plots',
  templateUrl: './plots.component.html',
  styleUrls: ['./plots.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PlotsComponent {
  plots$ = this.plotsService.plots$;

  constructor(private plotsService: PlotsService) {}

  trackById(_: number, plot: PlotData) {
    return plot.id;
  }
}


================================================
FILE: apps/web/src/app/components/tutorial/tutorial.component.css
================================================
:host {
  display: block;
  margin: 18px;
}


================================================
FILE: apps/web/src/app/components/tutorial/tutorial.component.html
================================================
<h1>Tutorials</h1>

The tutorials sections will be tackled once the application is done. It will
contain the following topics:

<ul>
  <li>Basic plot commands</li>
  <li>The Plot and the Layout interfaces</li>
  <li>How to plot streams in realtime</li>
</ul>


================================================
FILE: apps/web/src/app/components/tutorial/tutorial.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
  selector: 'npl-tutorial',
  templateUrl: './tutorial.component.html',
  styleUrls: ['./tutorial.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TutorialComponent {}


================================================
FILE: apps/web/src/app/services/plots.service.ts
================================================
import { Injectable } from '@angular/core';
import { PlotData } from '@npl/nodeplotlib';
import { BehaviorSubject } from 'rxjs';
import { map } from 'rxjs/operators';
import { SocketService } from './socket.service';

@Injectable({ providedIn: 'root' })
export class PlotsService {
  private plotDataMap$ = new BehaviorSubject<Map<number, PlotData>>(new Map());
  plots$ = this.plotDataMap$.pipe(
    map((plotDataMap) => Array.from(plotDataMap.values()))
  );

  constructor(private socketService: SocketService) {
    this.socketService.listen<PlotData>('plotdata', (data) => {
      const plots = this.plotDataMap$.value;
      plots.set(data.id, data);
      this.plotDataMap$.next(plots);
    });
    this.socketService.emit('readplots');
  }
}


================================================
FILE: apps/web/src/app/services/socket.service.ts
================================================
import { Injectable, OnDestroy } from '@angular/core';
import { io, Socket } from 'socket.io-client';
import { environment } from '../../environments/environment';

@Injectable({ providedIn: 'root' })
export class SocketService implements OnDestroy {
  private socket: Socket;

  constructor() {
    this.socket = io(environment.socketIoEndpoint, { transports: ['polling'] });

    this.socket.on('connect', () => {
      console.log('[Nodeplotlib] connected');
    });

    this.socket.on('disconnect', () => {
      console.log('[Nodeplotlib] disconnected');
    });
  }

  listen<T>(eventName: string, cb: (data: T) => void) {
    return this.socket.on(eventName, cb);
  }

  emit<T>(eventName: string, data?: T) {
    this.socket.emit(eventName, data);
  }

  ngOnDestroy() {
    this.socket?.disconnect();
  }
}


================================================
FILE: apps/web/src/assets/.gitkeep
================================================


================================================
FILE: apps/web/src/custom-theme.scss
================================================
// Custom Theming for Angular Material
// For more information: https://material.angular.io/guide/theming
@use '@angular/material' as mat;
// Plus imports for other components in your app.

// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat.core();

// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue. Available color palettes: https://material.io/design/color/
$web-primary: mat.define-palette(mat.$blue-grey-palette, 900);
$web-accent: mat.define-palette(mat.$light-green-palette, A200, A100, A400);

// The warn palette is optional (defaults to red).
$web-warn: mat.define-palette(mat.$red-palette);

// Create the theme object. A theme consists of configurations for individual
// theming systems such as "color" or "typography".
$web-theme: mat.define-light-theme(
  (
    color: (
      primary: $web-primary,
      accent: $web-accent,
      warn: $web-warn,
    ),
  )
);

// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include mat.all-component-themes($web-theme);


================================================
FILE: apps/web/src/environments/environment.prod.ts
================================================
export const environment = {
  production: true,
  socketIoEndpoint: '',
};


================================================
FILE: apps/web/src/environments/environment.ts
================================================
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.

export const environment = {
  production: false,
  socketIoEndpoint: '',
};

/*
 * For easier debugging in development mode, you can import the following file
 * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
 *
 * This import should be commented out in production mode because it will have a negative impact
 * on performance if an error is thrown.
 */
// import 'zone.js/plugins/zone-error';  // Included with Angular CLI.


================================================
FILE: apps/web/src/index.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <base href="/" />
    <title>Nodeplotlib</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="preconnect" href="https://fonts.gstatic.com" />
    <link
      href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap"
      rel="stylesheet"
    />
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />
  </head>
  <body class="mat-typography">
    <npl-root></npl-root>
    <script
      type="text/javascript"
      src="https://cdn.plot.ly/plotly-1.58.4.min.js"
      defer
    ></script>
  </body>
</html>


================================================
FILE: apps/web/src/main.ts
================================================
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch((err) => console.error(err));


================================================
FILE: apps/web/src/polyfills.ts
================================================
/**
 * This file includes polyfills needed by Angular and is loaded before the app.
 * You can add your own extra polyfills to this file.
 *
 * This file is divided into 2 sections:
 *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
 *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
 *      file.
 *
 * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
 * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
 * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
 *
 * Learn more in https://angular.io/guide/browser-support
 */

/***************************************************************************************************
 * BROWSER POLYFILLS
 */

/**
 * By default, zone.js will patch all possible macroTask and DomEvents
 * user can disable parts of macroTask/DomEvents patch by setting following flags
 * because those flags need to be set before `zone.js` being loaded, and webpack
 * will put import in the top of bundle, so user need to create a separate file
 * in this directory (for example: zone-flags.ts), and put the following flags
 * into that file, and then add the following code before importing zone.js.
 * import './zone-flags';
 *
 * The flags allowed in zone-flags.ts are listed here.
 *
 * The following flags will work for all browsers.
 *
 * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
 * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
 * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
 *
 *  in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
 *  with the following flag, it will bypass `zone.js` patch for IE/Edge
 *
 *  (window as any).__Zone_enable_cross_context_check = true;
 *
 */

/***************************************************************************************************
 * Zone JS is required by default for Angular itself.
 */
import 'zone.js'; // Included with Angular CLI.

/***************************************************************************************************
 * APPLICATION IMPORTS
 */


================================================
FILE: apps/web/src/styles.css
================================================
/* You can add global styles to this file, and also import other style files */

html,
body {
  height: 100%;
}
body {
  margin: 0;
  font-family: Roboto, 'Helvetica Neue', sans-serif;
}

.brand .mat-button-wrapper {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 1.2em;
}


================================================
FILE: apps/web/src/test-setup.ts
================================================
import 'jest-preset-angular/setup-jest';

import { getTestBed } from '@angular/core/testing';
import {
  BrowserDynamicTestingModule,
  platformBrowserDynamicTesting,
} from '@angular/platform-browser-dynamic/testing';

getTestBed().resetTestEnvironment();
getTestBed().initTestEnvironment(
  BrowserDynamicTestingModule,
  platformBrowserDynamicTesting(),
  { teardown: { destroyAfterEach: false } }
);


================================================
FILE: apps/web/tsconfig.app.json
================================================
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "types": []
  },
  "files": ["src/main.ts", "src/polyfills.ts"],
  "include": ["src/**/*.d.ts"]
}


================================================
FILE: apps/web/tsconfig.editor.json
================================================
{
  "extends": "./tsconfig.json",
  "include": ["**/*.ts"],
  "compilerOptions": {
    "types": ["jest", "node"]
  }
}


================================================
FILE: apps/web/tsconfig.json
================================================
{
  "extends": "../../tsconfig.base.json",
  "files": [],
  "include": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.spec.json"
    },
    {
      "path": "./tsconfig.editor.json"
    }
  ],
  "compilerOptions": {
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "target": "es2020"
  },
  "angularCompilerOptions": {
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}


================================================
FILE: apps/web/tsconfig.spec.json
================================================
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "module": "commonjs",
    "types": ["jest", "node"]
  },
  "files": ["src/test-setup.ts"],
  "include": ["**/*.spec.ts", "**/*.test.ts", "**/*.d.ts"]
}


================================================
FILE: apps/web-e2e/.eslintrc.json
================================================
{
  "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"],
  "ignorePatterns": ["!**/*"],
  "overrides": [
    {
      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
      "rules": {}
    },
    {
      "files": ["src/plugins/index.js"],
      "rules": {
        "@typescript-eslint/no-var-requires": "off",
        "no-undef": "off"
      }
    }
  ]
}


================================================
FILE: apps/web-e2e/cypress.json
================================================
{
  "fileServerFolder": ".",
  "fixturesFolder": "./src/fixtures",
  "integrationFolder": "./src/integration",
  "modifyObstructiveCode": false,
  "supportFile": "./src/support/index.ts",
  "pluginsFile": false,
  "video": true,
  "videosFolder": "../../dist/cypress/apps/web-e2e/videos",
  "screenshotsFolder": "../../dist/cypress/apps/web-e2e/screenshots",
  "chromeWebSecurity": false
}


================================================
FILE: apps/web-e2e/project.json
================================================
{
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "apps/web-e2e/src",
  "projectType": "application",
  "architect": {
    "e2e": {
      "executor": "@nrwl/cypress:cypress",
      "options": {
        "cypressConfig": "apps/web-e2e/cypress.json",
        "devServerTarget": "web:serve:development",
        "tsConfig": "apps/web-e2e/tsconfig.json"
      },
      "configurations": {
        "production": {
          "devServerTarget": "web:serve:production"
        }
      }
    },
    "lint": {
      "executor": "@nrwl/linter:eslint",
      "outputs": ["{options.outputFile}"],
      "options": {
        "lintFilePatterns": ["apps/web-e2e/**/*.{js,ts}"]
      }
    }
  },
  "tags": [],
  "implicitDependencies": ["web"]
}


================================================
FILE: apps/web-e2e/src/fixtures/example.json
================================================
{
  "name": "Using fixtures to represent data",
  "email": "hello@cypress.io"
}


================================================
FILE: apps/web-e2e/src/integration/app.spec.ts
================================================
import { getGreeting } from '../support/app.po';

describe('web', () => {
  beforeEach(() => cy.visit('/'));

  it('should display welcome message', () => {
    // Custom command example, see `../support/commands.ts` file
    cy.login('my-email@something.com', 'myPassword');

    // Function helper example, see `../support/app.po.ts` file
    getGreeting().contains('Welcome to web!');
  });
});


================================================
FILE: apps/web-e2e/src/support/app.po.ts
================================================
export const getGreeting = () => cy.get('h1');


================================================
FILE: apps/web-e2e/src/support/commands.ts
================================================
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************

// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace Cypress {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  interface Chainable<Subject> {
    login(email: string, password: string): void;
  }
}
//
// -- This is a parent command --
Cypress.Commands.add('login', (email, password) => {
  console.log('Custom command example: Login', email, password);
});
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })


================================================
FILE: apps/web-e2e/src/support/index.ts
================================================
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import './commands';


================================================
FILE: apps/web-e2e/tsconfig.json
================================================
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "sourceMap": false,
    "outDir": "../../dist/out-tsc",
    "allowJs": true,
    "types": ["cypress", "node"],
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src/**/*.ts", "src/**/*.js"],
  "angularCompilerOptions": {
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}


================================================
FILE: decorate-angular-cli.js
================================================
/**
 * This file decorates the Angular CLI with the Nx CLI to enable features such as computation caching
 * and faster execution of tasks.
 *
 * It does this by:
 *
 * - Patching the Angular CLI to warn you in case you accidentally use the undecorated ng command.
 * - Symlinking the ng to nx command, so all commands run through the Nx CLI
 * - Updating the package.json postinstall script to give you control over this script
 *
 * The Nx CLI decorates the Angular CLI, so the Nx CLI is fully compatible with it.
 * Every command you run should work the same when using the Nx CLI, except faster.
 *
 * Because of symlinking you can still type `ng build/test/lint` in the terminal. The ng command, in this case,
 * will point to nx, which will perform optimizations before invoking ng. So the Angular CLI is always invoked.
 * The Nx CLI simply does some optimizations before invoking the Angular CLI.
 *
 * To opt out of this patch:
 * - Replace occurrences of nx with ng in your package.json
 * - Remove the script from your postinstall script in your package.json
 * - Delete and reinstall your node_modules
 */

const fs = require('fs');
const os = require('os');
const cp = require('child_process');
const isWindows = os.platform() === 'win32';
let output;
try {
  output = require('@nrwl/workspace').output;
} catch (e) {
  console.warn(
    'Angular CLI could not be decorated to enable computation caching. Please ensure @nrwl/workspace is installed.'
  );
  process.exit(0);
}

/**
 * Symlink of ng to nx, so you can keep using `ng build/test/lint` and still
 * invoke the Nx CLI and get the benefits of computation caching.
 */
function symlinkNgCLItoNxCLI() {
  try {
    const ngPath = './node_modules/.bin/ng';
    const nxPath = './node_modules/.bin/nx';
    if (isWindows) {
      /**
       * This is the most reliable way to create symlink-like behavior on Windows.
       * Such that it works in all shells and works with npx.
       */
      ['', '.cmd', '.ps1'].forEach((ext) => {
        if (fs.existsSync(nxPath + ext))
          fs.writeFileSync(ngPath + ext, fs.readFileSync(nxPath + ext));
      });
    } else {
      // If unix-based, symlink
      cp.execSync(`ln -sf ./nx ${ngPath}`);
    }
  } catch (e) {
    output.error({
      title:
        'Unable to create a symlink from the Angular CLI to the Nx CLI:' +
        e.message,
    });
    throw e;
  }
}

try {
  symlinkNgCLItoNxCLI();
  require('nx/src/adapter/decorate-cli').decorateCli();
  output.log({
    title: 'Angular CLI has been decorated to enable computation caching.',
  });
} catch (e) {
  output.error({
    title: 'Decoration of the Angular CLI did not complete successfully',
  });
}


================================================
FILE: jest.config.ts
================================================
import { getJestProjects } from '@nrwl/jest';

export default {
  projects: getJestProjects(),
};


================================================
FILE: jest.preset.js
================================================
const nxPreset = require('@nrwl/jest/preset').default;

module.exports = { ...nxPreset };


================================================
FILE: libs/nodeplotlib/.babelrc
================================================
{
  "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]]
}


================================================
FILE: libs/nodeplotlib/.eslintrc.json
================================================
{
  "extends": ["../../.eslintrc.json"],
  "ignorePatterns": ["!**/*"],
  "overrides": [
    {
      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
      "rules": {}
    },
    {
      "files": ["*.ts", "*.tsx"],
      "rules": {}
    },
    {
      "files": ["*.js", "*.jsx"],
      "rules": {}
    }
  ]
}


================================================
FILE: libs/nodeplotlib/README.md
================================================
# <img src="https://raw.githubusercontent.com/ngfelixl/nodeplotlib/master/img/nodeplotlib_64x64.png" width="28px" height="28px"> NodePlotLib

[![NodeJS CI](https://github.com/ngfelixl/nodeplotlib/workflows/Node.js%20CI/badge.svg)](https://github.com/ngfelixl/nodeplotlib/actions?query=workflow%3A%22Node.js+CI%22)
[![npm](https://img.shields.io/npm/v/nodeplotlib?color=#00f800)](https://npmjs.com/package/nodeplotlib)
[![npm](https://img.shields.io/npm/dt/nodeplotlib.svg)](https://npmjs.com/package/nodeplotlib)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)

[![Animation (View on Github)](https://raw.githubusercontent.com/ngfelixl/nodeplotlib/master/img/animation-next.gif)](https://raw.githubusercontent.com/ngfelixl/nodeplotlib/master/img/animation-next.gif)

Library to create plots directly in TypeScript or JavaScript in NodeJS on top of [plotly.js](https://plot.ly/javascript/)
without any front-end preparations. Inspired by matplotlib.

## Installation

```sh
npm install nodeplotlib
# or
yarn add nodeplotlib
```

## Usage

### Creating a simple plot

Use with TypeScript/JavaScript:

```typescript
import { plot, Plot } from 'nodeplotlib';

const data: Plot[] = [
  {
    x: [1, 3, 4, 5],
    y: [3, 12, 1, 4],
    type: 'scatter',
  },
];

plot(data);
```

### Creating a stream that plots data in realtime

NodePlotLib makes use of the popular [RxJS](https://rxjs.dev) library,
which provides functionality for streams, stream creator functions (e.g. from interval or from event),
and tons of operators to modify your stream.

In this example we create a stream based on an interval which triggers every 100ms. Then we modify
the output of the interval (which is just a counter) to be an actual `Plot` using RxJS' `map` operator.
The output will be a `sin` function.

```typescript
import { plot, Plot } from 'nodeplotlib';
import { interval, map } from 'rxjs';

const stream$: Observable<Plot[]> = interval(100).pipe(
  map(createSinusPlotFromNumber)
);

function createSinusPlotFromNumber(num: number): Plot[] {
  const data: Plot[] = [
    {
      x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
      y: Array(10)
        .fill(0)
        .map((_, i) => Math.sin(num + i)),
      type: 'scatter',
    },
  ];
  return data;
}
```

As you can see, providing a function for a dynamic plot seems to be a good idea.
The functions content looks almost the same as the "non-stream" version. Simple as
that, you can just put the created Observable as an argument in the plot function:

```typescript
plot(stream$);
```

### API overview

There are three exports. The `plot` function and types for the Plot and for the Layout.

```typescript
import { plot, Plot, Layout, Config } from 'nodeplotlib';
```

The `plot` function has the following structure

```typescript
function plot(
  data: Plot[] | Observable<Plot[]>,
  layout?: Layout,
  config?: Config
): void;
```

It does not return a Subscription for the Observables because you just need to close
the listening browser window to unsubscribe from all Obserables.

## Examples

In this section there are some examples to getting started. See the full plotly
[cheatsheet](https://images.plot.ly/plotly-documentation/images/plotly_js_cheat_sheet.pdf?_ga=2.2676214.711017137.1550402185-1513144731.1549064935).

#### Line Plots

```typescript
const trace1: Plot = { x: [1, 2], y: [1, 2], type: 'scatter' };
const trace2: Plot = { x: [3, 4], y: [9, 16], type: 'scatter' };
plot([trace1, trace2]);
```

#### Bar Charts

```typescript
const trace: Plot = { x: [1, 2], y: [1, 2], type: 'bar' };
plot([trace]);
```

#### 3D Line Plots

```typescript
const trace: Plot = {
  x: [9, 8, 5, 1],
  y: [1, 2, 4, 8],
  z: [11, 8, 15, 3],
  type: 'scatter3d',
};
plot([trace]);
```

#### 3D Surface Plots

```typescript
const trace: Plot = {
  colorscale: 'Viridis',
  z: [
    [3, 5, 7, 9],
    [21, 13, 8, 5],
  ],
};
plot([trace]);
```

#### Radial Plots

In order to style the plot, one is able to pass in the `layout` parameter, which internally
is typeof `Partial<Layout>` from plotly's `Layout`. See the full layout documentation
[here](https://plot.ly/javascript/#layout-options).

With this parameter one is able to define styles like _title_, _axis labels_,
_subplots_ and many more.

```typescript
const data: Plot[] = [
  {
    type: 'scatterpolar',
    r: [1.5, 10, 39, 31, 15, 1.5],
    theta: ['A', 'B', 'C', 'D', 'E', 'A'],
    fill: 'toself',
    name: 'Group B',
  },
];

const layout: Layout = {
  polar: {
    radialaxis: {
      visible: true,
      range: [0, 50],
    },
  },
};

plot(data, layout);
```

## Plot types

| Simple charts   | Advanced charts  | 3D Plots |
| --------------- | ---------------- | -------- |
| Scatter         | 2d density plots | Scatter  |
| Line            | Histograms       | Surface  |
| Bar             | Box-plots        | Lines    |
| Pie charts      | Contour plots    |          |
| Sankey diagrams | Heatmaps         |          |
| Tables          | Radar charts     |          |

## Contributing

Contributions in all forms are welcome.

## Developers guide

You can find the developers guide in the repositories root
[README.md](https://github.com/ngfelixl/nodeplotlib).

## Contributors

<a href="https://github.com/ngfelixl"><img src="https://avatars2.githubusercontent.com/u/24190530" title="ngfelixl" width="100" height="100"></a>
<a href="https://github.com/mitsos1os"><img src="https://avatars3.githubusercontent.com/u/8208733" title="mitsos1os" width="100" height="100"></a>
<a href="https://github.com/medved-nsk"><img src="https://avatars1.githubusercontent.com/u/6310906" title="medved-nsk" width="100" height="100"></a>
<a href="https://github.com/Moumouls"><img src="https://avatars.githubusercontent.com/u/27959372" title="Moumouls" width="100" height="100"></a>
<a href="https://github.com/grgr-dkrk"><img src="https://avatars.githubusercontent.com/u/40130327" title="guruguru-dekiruko" width="100" height="100"></a>
<a href="https://github.com/nathanbabcock"><img src="https://avatars.githubusercontent.com/u/9583103" title="nathanbabcock" width="100" height="100"></a>


================================================
FILE: libs/nodeplotlib/jest.config.ts
================================================
/* eslint-disable */
export default {
  displayName: 'nodeplotlib',
  preset: '../../jest.preset.js',
  globals: {
    'ts-jest': {
      tsconfig: '<rootDir>/tsconfig.spec.json',
    },
  },
  testEnvironment: 'node',
  transform: {
    '^.+\\.[tj]sx?$': 'ts-jest',
  },
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
  coverageDirectory: '../../coverage/libs/nodeplotlib',
};


================================================
FILE: libs/nodeplotlib/package.json
================================================
{
  "name": "nodeplotlib",
  "version": "1.1.3",
  "description": "NodeJS frontend-less plotting lib using plotly.js inspired by matplotlib",
  "author": "Felix Lemke <flemke.dev@gmail.com> (https://felixlemke.dev)",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/ngfelixl/nodeplotlib.git"
  },
  "bugs": {
    "url": "https://github.com/ngfelixl/nodeplotlib/issues"
  },
  "homepage": "https://github.com/ngfelixl/nodeplotlib#readme",
  "keywords": [
    "plot",
    "nodejs",
    "plotlyjs",
    "science",
    "easy-to-use",
    "statistics",
    "browser",
    "localhost"
  ],
  "dependencies": {
    "@types/plotly.js": "^1.54.17",
    "@nestjs/platform-express": "^9.0.0",
    "@nestjs/platform-socket.io": "^9.0.0"
  },
  "peerDependencies": {}
}


================================================
FILE: libs/nodeplotlib/project.json
================================================
{
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "root": "libs/nodeplotlib",
  "sourceRoot": "libs/nodeplotlib/src",
  "projectType": "library",
  "architect": {
    "build": {
      "builder": "@nrwl/js:tsc",
      "outputs": ["{options.outputPath}"],
      "options": {
        "main": "libs/nodeplotlib/src/index.ts",
        "outputPath": "dist/libs/nodeplotlib",
        "tsConfig": "libs/nodeplotlib/tsconfig.lib.json",
        "generatePackageJson": true,
        "extractLicenses": true
      }
    },
    "lint": {
      "builder": "@nrwl/linter:eslint",
      "outputs": ["{options.outputFile}"],
      "options": {
        "lintFilePatterns": ["libs/nodeplotlib/**/*.ts"]
      }
    },
    "test": {
      "builder": "@nrwl/jest:jest",
      "outputs": ["coverage/libs/nodeplotlib"],
      "options": {
        "jestConfig": "libs/nodeplotlib/jest.config.ts",
        "passWithNoTests": true
      }
    }
  },
  "tags": []
}


================================================
FILE: libs/nodeplotlib/src/index.ts
================================================
// Exports required for the actual nodeplotlib
export { Plot, Layout, Config } from './lib/interfaces/plot';
export { plot } from './lib/nodeplotlib';

// Exports required for the web app
export { PlotData } from './lib/interfaces/plot';


================================================
FILE: libs/nodeplotlib/src/lib/interfaces/index.ts
================================================
export { Layout, Plot, PlotData, PlotDataStream } from './plot';


================================================
FILE: libs/nodeplotlib/src/lib/interfaces/plot.ts
================================================
import {
  Layout as PlotlyLayout,
  PlotData as PlotlyPlotData,
  Config as PlotlyConfig,
} from 'plotly.js';
import { Observable } from 'rxjs';

export type Plot = Partial<PlotlyPlotData>;
export type Layout = Partial<PlotlyLayout>;
export type Config = Partial<PlotlyConfig>;

export interface PlotDataStream {
  id: number;
  data: Observable<Plot[]>;
  layout: Observable<Layout | undefined>;
  config: Config | undefined;
}

export interface PlotData {
  id: number;
  data: Plot[];
  layout?: Layout;
  config?: Config;
}


================================================
FILE: libs/nodeplotlib/src/lib/nodeplotlib.ts
================================================
import { INestApplication } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { Layout, Plot, PlotDataStream } from './interfaces';
import { BehaviorSubject, Observable, of, Subscription } from 'rxjs';
import { PlotsService } from './server/plots/plots.service';
import { ServerModule } from './server/server.module';
import { BridgeService } from './server/services/bridge.service';
import { getPort } from './utils/get-port';
import { Config } from './interfaces/plot';
let app: INestApplication | null = null;
let plotsService: PlotsService;
let bridgeService: BridgeService;

// This variable is used to determine if the nestjs app is running
// or starting. Because it is "async" and the plot function is not,
// we need to make sure that we do not bootstrap the app twice in the
// same macro-task.
let appRuns = false;
let shutdownSubscription: Subscription;
const plotsBuffer$ = new BehaviorSubject<Omit<PlotDataStream, 'id'>[]>([]);
const port = getPort();

/**
 * Plots the given data with the given layout. This function
 * starts a server if one is not already running.
 * @param data
 * @param layout
 * @param cb
 */
export function plot(
  data: Plot[] | Observable<Plot[]>,
  layout?: Layout,
  config?: Config
) {
  bootstrap(port);
  const bufferedPlots = plotsBuffer$.value;

  const streamData$: Observable<Plot[]> =
    data instanceof Observable ? data : of(data);
  plotsBuffer$.next([
    ...bufferedPlots,
    { data: streamData$, layout: of(layout), config },
  ]);
}

async function bootstrap(port: number) {
  if (appRuns) {
    console.log('[Nodeplotlib] App is already up and running');
    return;
  }
  appRuns = true;
  app = await NestFactory.create(ServerModule);
  plotsService = app.get(PlotsService);
  bridgeService = app.get(BridgeService);
  await app.listen(port);

  const actualPort = app.getHttpServer().address().port;
  bridgeService.setPort(actualPort);
  plotsService.setBuffer(plotsBuffer$);
  console.log(
    '[Nodeplotlib] Server running at',
    `http://localhost:${actualPort}`
  );

  shutdownSubscription = bridgeService.shutdown$.subscribe(shutdown);
}

async function shutdown() {
  console.log('[Nodeplotlib] Server shutting down');
  shutdownSubscription?.unsubscribe();
  appRuns = false;

  if (app) {
    await app.close();
  }
}


================================================
FILE: libs/nodeplotlib/src/lib/server/plots/plots.gateway.ts
================================================
import {
  OnGatewayConnection,
  OnGatewayDisconnect,
  SubscribeMessage,
  WebSocketGateway,
} from '@nestjs/websockets';
import { PlotData } from '../../interfaces';
import { combineLatest, merge, Observable } from 'rxjs';
import { map, share, switchMap } from 'rxjs/operators';
import { BridgeService } from '../services/bridge.service';
import { PlotsService } from './plots.service';

@WebSocketGateway({ transports: ['polling'] })
export class PlotsGateway implements OnGatewayConnection, OnGatewayDisconnect {
  private clientMap = new Map<WebSocket, number>();
  private plotDataStream$: Observable<PlotData>;

  constructor(
    private bridgeService: BridgeService,
    private plotsService: PlotsService
  ) {
    this.plotDataStream$ = this.plotsService.plotIds$.pipe(
      switchMap((plotIds) =>
        merge(
          ...Array.from(plotIds).map((id) => {
            const plotDataStream = this.plotsService.plotEntities.get(id);
            if (!plotDataStream) {
              return new Observable<PlotData>();
            }
            return combineLatest([
              plotDataStream.data,
              plotDataStream.layout,
            ]).pipe(
              map(([data, layout]) => ({
                id,
                data,
                layout,
                config: plotDataStream.config,
              }))
            );
          })
        )
      ),
      share()
    );
  }

  @SubscribeMessage('readplots')
  handleEvent() {
    return this.plotDataStream$.pipe(
      map((plotData) => ({
        event: 'plotdata',
        data: plotData,
      }))
    );
  }

  handleConnection(client: WebSocket) {
    console.log('[Nodeplotlib] client connected');
    this.clientMap.set(client, Date.now());
  }

  handleDisconnect(client: WebSocket) {
    console.log('[Nodeplotlib] client disconnected');
    this.clientMap.delete(client);

    if (this.clientMap.size === 0) {
      this.bridgeService.shutdown$.next(null);
    }
  }
}


================================================
FILE: libs/nodeplotlib/src/lib/server/plots/plots.service.ts
================================================
import { Injectable } from '@nestjs/common';
import { PlotDataStream } from '../../interfaces';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';

@Injectable()
export class PlotsService {
  plotEntities = new Map<number, PlotDataStream>();
  plotIds$ = new BehaviorSubject<Set<number>>(new Set());
  private currentPlotId = 0;
  private bufferSubscription?: Subscription;

  setBuffer(buffer$: Observable<Omit<PlotDataStream, 'id'>[]>) {
    this.bufferSubscription?.unsubscribe();
    this.bufferSubscription = buffer$
      .pipe(filter((buffer) => buffer.length > 0))
      .subscribe((buffer) => this.readBuffer(buffer));
  }

  addPlot(plotData: Omit<PlotDataStream, 'id'>) {
    const plot: PlotDataStream = {
      id: this.currentPlotId++,
      data: plotData.data,
      layout: plotData.layout,
      config: plotData.config,
    };

    this.plotEntities.set(plot.id, plot);
    const plotIds = this.plotIds$.value;
    plotIds.add(plot.id);
    this.plotIds$.next(plotIds);
  }

  /**
   * Function gets executed on the main process and makes the service read
   * the buffered plot data.
   * @param buffer
   */
  readBuffer(buffer: Omit<PlotDataStream, 'id'>[]) {
    for (const plot of buffer) {
      this.addPlot(plot);
    }
  }
}


================================================
FILE: libs/nodeplotlib/src/lib/server/server.module.ts
================================================
import { Module } from '@nestjs/common';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';
import { PlotsGateway } from './plots/plots.gateway';
import { PlotsService } from './plots/plots.service';
import { BridgeService } from './services/bridge.service';

@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, 'web'),
    }),
  ],
  providers: [PlotsGateway, PlotsService, BridgeService],
})
export class ServerModule {}


================================================
FILE: libs/nodeplotlib/src/lib/server/services/bridge-service.spec.ts
================================================
import { BridgeService } from './bridge.service';
import { openWindow } from '../../utils/open-window';
jest.mock('../../utils/open-window');

describe('BridgeService', () => {
  it('should emit a shutdown$ event if the shutdown function is called', (done) => {
    const bridgeService = new BridgeService();
    bridgeService.shutdown$.subscribe(() => {
      done();
    });
    bridgeService.shutdown();
  });

  it('call the openWindow function with the url if a port is set', () => {
    const bridgeService = new BridgeService();
    bridgeService.setPort(1234);
    expect(openWindow).toHaveBeenCalledWith(`http://localhost:1234`);
  });
});


================================================
FILE: libs/nodeplotlib/src/lib/server/services/bridge.service.ts
================================================
import { Injectable } from '@nestjs/common';
import { Subject } from 'rxjs';
import { openWindow } from '../../utils/open-window';

/**
 * The BridgeService is used to build a bridge between the
 * NestJS server and the outside of the NestJS server.
 * The two purposes are to get the port of the express server
 * inside of the NestJS server and to provide a shutdown$
 * steam so that the NestJS server can trigger a full shutdown.
 *
 * @see nodeplotlib.ts
 */
@Injectable()
export class BridgeService {
  shutdown$ = new Subject();
  port$ = new Subject<number>();

  constructor() {
    this.port$.subscribe((port) => {
      openWindow(`http://localhost:${port}`);
    });
  }

  setPort(port: number) {
    this.port$.next(port);
  }

  shutdown() {
    this.shutdown$.next(null);
  }
}


================================================
FILE: libs/nodeplotlib/src/lib/utils/get-port.spec.ts
================================================
import { getPort } from './get-port';

describe('getPort', () => {
  it('should return 0 if NODEPLOTLIB_PORT is undefined', () => {
    process.env.NODEPLOTLIB_PORT = undefined;
    expect(getPort()).toBe(0);
  });

  it('should return 0 if NODEPLOTLIB_PORT is null', () => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    process.env.NODEPLOTLIB_PORT = null as any;
    expect(getPort()).toBe(0);
  });

  it('should return 0 if NODEPLOTLIB_PORT is empty string', () => {
    process.env.NODEPLOTLIB_PORT = '';
    expect(getPort()).toBe(0);
  });

  it('should return 0 if NODEPLOTLIB_PORT is 0', () => {
    process.env.NODEPLOTLIB_PORT = '0';
    expect(getPort()).toBe(0);
  });

  it('should return the number if NODEPLOTLIB_PORT is a number and not 0', () => {
    process.env.NODEPLOTLIB_PORT = '123';
    expect(getPort()).toBe(123);
  });
});


================================================
FILE: libs/nodeplotlib/src/lib/utils/get-port.ts
================================================
export function getPort(): number {
  const portAsString = process.env.NODEPLOTLIB_PORT;
  const port = Number(portAsString);
  if (isNaN(port)) {
    return 0;
  }
  return port;
}


================================================
FILE: libs/nodeplotlib/src/lib/utils/open-window.spec.ts
================================================
import { openWindow } from './open-window';
import { exec } from 'child_process';
import { type } from 'os';
jest.mock('child_process');
jest.mock('os');

describe('openWindow', () => {
  let execMock: jest.MockedFunction<typeof exec>;
  let typeMock: jest.MockedFunction<typeof type>;

  beforeEach(() => {
    execMock = exec as jest.MockedFunction<typeof exec>;
    typeMock = type as jest.MockedFunction<typeof type>;
  });

  afterEach(() => {
    delete process.env.NODEPLOTLIB_PORT;
  });

  it('should not call the exec function if NODEPLOTLIB_PORT is set', () => {
    process.env.NODEPLOTLIB_PORT = '123';
    openWindow('location');
    expect(execMock).not.toBeCalled();
  });

  it('should not call the exec function if NODEPLOTLIB_PORT is set to ""', () => {
    process.env.NODEPLOTLIB_PORT = '';
    openWindow('location');
    expect(execMock).not.toBeCalled();
  });

  it('should call the exec function for linux correctly', () => {
    typeMock.mockImplementation(() => 'Linux');
    openWindow('location');
    expect(execMock).toBeCalledWith('xdg-open location');
  });

  it('should call the exec function for windows correctly', () => {
    typeMock.mockImplementation(() => 'Windows_NT');
    openWindow('location');
    expect(execMock).toBeCalledWith('start location');
  });

  it('should call the exec function for mac correctly', () => {
    typeMock.mockImplementation(() => 'Darwin');
    openWindow('location');
    expect(execMock).toBeCalledWith('open location');
  });
});


================================================
FILE: libs/nodeplotlib/src/lib/utils/open-window.ts
================================================
import { exec } from 'child_process';
import { type } from 'os';

export function openWindow(location: string) {
  if (process.env.NODEPLOTLIB_PORT) {
    return;
  }

  switch (type()) {
    case 'Linux':
      exec(`xdg-open ${location}`);
      break;
    case 'Darwin':
      exec(`open ${location}`);
      break;
    case 'Windows_NT':
      exec(`start ${location}`);
      break;
  }
}


================================================
FILE: libs/nodeplotlib/tsconfig.json
================================================
{
  "extends": "../../tsconfig.base.json",
  "files": [],
  "include": [],
  "references": [
    {
      "path": "./tsconfig.lib.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
  ],
  "compilerOptions": {
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  }
}


================================================
FILE: libs/nodeplotlib/tsconfig.lib.json
================================================
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs",
    "outDir": "../../dist/out-tsc",
    "declaration": true,
    "types": ["node"]
  },
  "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"],
  "include": ["**/*.ts"]
}


================================================
FILE: libs/nodeplotlib/tsconfig.spec.json
================================================
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "module": "commonjs",
    "types": ["jest", "node"]
  },
  "include": [
    "**/*.test.ts",
    "**/*.spec.ts",
    "**/*.test.tsx",
    "**/*.spec.tsx",
    "**/*.test.js",
    "**/*.spec.js",
    "**/*.test.jsx",
    "**/*.spec.jsx",
    "**/*.d.ts"
  ]
}


================================================
FILE: nx.json
================================================
{
  "$schema": "./node_modules/nx/schemas/nx-schema.json",
  "npmScope": "npl",
  "affected": {
    "defaultBase": "main"
  },
  "implicitDependencies": {
    "package.json": {
      "dependencies": "*",
      "devDependencies": "*"
    },
    ".eslintrc.json": "*"
  },
  "tasksRunnerOptions": {
    "default": {
      "runner": "nx/tasks-runners/default",
      "options": {
        "cacheableOperations": ["build", "lint", "test", "e2e"]
      }
    }
  },
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"]
    }
  },
  "generators": {
    "@nrwl/angular:application": {
      "style": "css",
      "linter": "eslint",
      "unitTestRunner": "jest",
      "e2eTestRunner": "cypress"
    },
    "@nrwl/angular:library": {
      "linter": "eslint",
      "unitTestRunner": "jest"
    },
    "@nrwl/angular:component": {
      "style": "css"
    }
  },
  "defaultProject": "web"
}


================================================
FILE: package.json
================================================
{
  "name": "nodeplotlib",
  "version": "1.1.3",
  "license": "MIT",
  "scripts": {
    "ng": "nx",
    "postinstall": "node ./decorate-angular-cli.js && ngcc --properties es2020 browser module main",
    "format:write": "nx format:write",
    "build": "nx build",
    "build:prod": "nx run web:build && nx run nodeplotlib:build && ts-node ./tools/util/copy-files.ts",
    "demo": "node ./tools/demo/candlestick.js"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "14.1.1",
    "@angular/cdk": "14.1.1",
    "@angular/common": "14.1.1",
    "@angular/compiler": "14.1.1",
    "@angular/core": "14.1.1",
    "@angular/forms": "14.1.1",
    "@angular/material": "14.1.1",
    "@angular/platform-browser": "14.1.1",
    "@angular/platform-browser-dynamic": "14.1.1",
    "@angular/router": "14.1.1",
    "@nestjs/common": "9.0.8",
    "@nestjs/core": "9.0.8",
    "@nestjs/microservices": "9.0.8",
    "@nestjs/platform-express": "9.0.8",
    "@nestjs/platform-socket.io": "9.0.8",
    "@nestjs/serve-static": "3.0.0",
    "@nestjs/websockets": "9.0.8",
    "@ngrx/effects": "~14.0.1",
    "@ngrx/entity": "~14.0.1",
    "@ngrx/store": "~14.0.1",
    "@nrwl/angular": "14.5.4",
    "@types/plotly.js": "^1.54.17",
    "express": "^4.17.1",
    "reflect-metadata": "^0.1.13",
    "rxjs": "^7.4.0",
    "socket.io-client": "^4.4.0",
    "tslib": "^2.0.0",
    "zone.js": "~0.11.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "14.1.1",
    "@angular-eslint/eslint-plugin": "~14.0.0",
    "@angular-eslint/eslint-plugin-template": "~14.0.0",
    "@angular-eslint/template-parser": "~14.0.0",
    "@angular/cli": "~14.1.0",
    "@angular/compiler-cli": "14.1.1",
    "@angular/language-service": "14.1.1",
    "@nestjs/schematics": "9.0.1",
    "@nestjs/testing": "9.0.8",
    "@ngrx/eslint-plugin": "^14.0.1",
    "@nrwl/cli": "14.5.4",
    "@nrwl/cypress": "14.5.4",
    "@nrwl/eslint-plugin-nx": "14.5.4",
    "@nrwl/jest": "14.5.4",
    "@nrwl/linter": "14.5.4",
    "@nrwl/nest": "14.5.4",
    "@nrwl/node": "14.5.4",
    "@nrwl/workspace": "14.5.4",
    "@types/express": "^4.17.13",
    "@types/jest": "27.4.1",
    "@types/node": "16.11.7",
    "@types/request": "^2.48.7",
    "@typescript-eslint/eslint-plugin": "^5.29.0",
    "@typescript-eslint/parser": "^5.29.0",
    "copy-webpack-plugin": "^6.3.2",
    "cypress": "^9.1.0",
    "eslint": "~8.15.0",
    "eslint-config-prettier": "8.1.0",
    "eslint-plugin-cypress": "^2.10.3",
    "fs-extra": "^10.0.0",
    "jest": "27.5.1",
    "jest-preset-angular": "~11.1.2",
    "nx": "14.5.4",
    "plotly.js-dist": "^2.5.1",
    "prettier": "^2.6.2",
    "request": "^2.88.2",
    "ts-jest": "27.1.4",
    "ts-node": "~10.8.0",
    "typescript": "~4.7.2"
  }
}


================================================
FILE: tools/demo/README.md
================================================
# Demo plots

These plots are meant to run with the compiled version of nodeplotlib. You can run them
with the following commands:

```
node ./tools/demo/scatter.js
node ./tools/demo/candlestick.js
npx ts-node ./tools/demo/scatter.ts
```

For further demos you can have a look at the **dev-server** app. In the _/data_ folder
you'll find demos for several plot types.


================================================
FILE: tools/demo/candlestick.js
================================================
const npl = require('../../dist/libs/nodeplotlib');

const trace1 = {
  x: [
    '2017-01-04',
    '2017-01-05',
    '2017-01-06',
    '2017-01-09',
    '2017-01-10',
    '2017-01-11',
    '2017-01-12',
    '2017-01-13',
    '2017-01-17',
    '2017-01-18',
    '2017-01-19',
    '2017-01-20',
    '2017-01-23',
    '2017-01-24',
    '2017-01-25',
    '2017-01-26',
    '2017-01-27',
    '2017-01-30',
    '2017-01-31',
    '2017-02-01',
    '2017-02-02',
    '2017-02-03',
    '2017-02-06',
    '2017-02-07',
    '2017-02-08',
    '2017-02-09',
    '2017-02-10',
    '2017-02-13',
    '2017-02-14',
    '2017-02-15',
  ],
  close: [
    116.019997, 116.610001, 117.910004, 118.989998, 119.110001, 119.75, 119.25,
    119.040001, 120, 119.989998, 119.779999, 120, 120.080002, 119.970001,
    121.879997, 121.940002, 121.949997, 121.629997, 121.349998, 128.75,
    128.529999, 129.080002, 130.289993, 131.529999, 132.039993, 132.419998,
    132.119995, 133.289993, 135.020004, 135.509995,
  ],
  decreasing: { line: { color: '#7F7F7F' } },
  high: [
    116.510002, 116.860001, 118.160004, 119.43, 119.379997, 119.93, 119.300003,
    119.620003, 120.239998, 120.5, 120.089996, 120.449997, 120.809998,
    120.099998, 122.099998, 122.440002, 122.349998, 121.629997, 121.389999,
    130.490005, 129.389999, 129.190002, 130.5, 132.089996, 132.220001,
    132.449997, 132.940002, 133.820007, 135.089996, 136.270004,
  ],
  increasing: { line: { color: '#17BECF' } },
  line: { color: 'rgba(31,119,180,1)' },
  low: [
    115.75, 115.809998, 116.470001, 117.940002, 118.300003, 118.599998,
    118.209999, 118.809998, 118.220001, 119.709999, 119.370003, 119.730003,
    119.769997, 119.5, 120.279999, 121.599998, 121.599998, 120.660004,
    120.620003, 127.010002, 127.779999, 128.160004, 128.899994, 130.449997,
    131.220001, 131.119995, 132.050003, 132.75, 133.25, 134.619995,
  ],
  open: [
    115.849998, 115.919998, 116.779999, 117.949997, 118.769997, 118.739998,
    118.900002, 119.110001, 118.339996, 120, 119.400002, 120.449997, 120,
    119.550003, 120.419998, 121.669998, 122.139999, 120.93, 121.150002,
    127.029999, 127.980003, 128.309998, 129.130005, 130.539993, 131.350006,
    131.649994, 132.460007, 133.080002, 133.470001, 135.520004,
  ],
  type: 'candlestick',
  xaxis: 'x',
  yaxis: 'y',
};

const data = [trace1];

const layout = {
  dragmode: 'zoom',
  margin: {
    r: 10,
    t: 25,
    b: 40,
    l: 60,
  },
  showlegend: false,
  xaxis: {
    autorange: true,
    domain: [0, 1],
    range: ['2017-01-03 12:00', '2017-02-15 12:00'],
    rangeslider: { range: ['2017-01-03 12:00', '2017-02-15 12:00'] },
    title: 'Date',
    type: 'date',
  },
  yaxis: {
    autorange: true,
    domain: [0, 1],
    range: [114.609999778, 137.410004222],
    type: 'linear',
  },
};

npl.plot(data, layout);


================================================
FILE: tools/demo/scatter.js
================================================
import npl from '../../dist/libs/nodeplotlib';
npl.plot([{ x: [0], y: [1], type: 'scatter' }]);


================================================
FILE: tools/demo/scatter.ts
================================================
import npl from '../../dist/libs/nodeplotlib';

npl.plot([{ x: [0, 1], y: [1, 1], type: 'scatter' }]);


================================================
FILE: tools/demo/stream.ts
================================================
import { plot, Plot } from '../../dist/libs/nodeplotlib';
import { interval, map, Observable } from 'rxjs';

const stream$: Observable<Plot[]> = interval(100).pipe(
  map(createSinusPlotFromNumber)
);

function createSinusPlotFromNumber(num: number): Plot[] {
  const data: Plot[] = [
    {
      x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
      y: Array(10)
        .fill(0)
        .map((_, i) => Math.sin(num + i)),
      type: 'scatter',
    },
  ];
  return data;
}

plot(stream$);


================================================
FILE: tools/generators/.gitkeep
================================================


================================================
FILE: tools/tsconfig.tools.json
================================================
{
  "extends": "../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "../dist/out-tsc/tools",
    "rootDir": ".",
    "module": "commonjs",
    "target": "es5",
    "types": ["node"],
    "importHelpers": false
  },
  "include": ["**/*.ts"]
}


================================================
FILE: tools/util/copy-files.ts
================================================
import { copySync } from 'fs-extra';

copySync('dist/apps/web', 'dist/libs/nodeplotlib/src/lib/server/web');
copySync('libs/nodeplotlib/README.md', 'dist/libs/nodeplotlib/README.md');
copySync('LICENSE', 'dist/libs/nodeplotlib/LICENSE');


================================================
FILE: tsconfig.base.json
================================================
{
  "compileOnSave": false,
  "compilerOptions": {
    "rootDir": ".",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "importHelpers": true,
    "target": "es2015",
    "module": "esnext",
    "lib": ["es2017", "dom"],
    "skipLibCheck": true,
    "skipDefaultLibCheck": true,
    "baseUrl": ".",
    "paths": {
      "@npl/nodeplotlib": ["libs/nodeplotlib/src/index.ts"]
    }
  },
  "exclude": ["node_modules", "tmp"]
}
Download .txt
gitextract_d23cn4mt/

├── .editorconfig
├── .eslintrc.json
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode/
│   └── extensions.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── NOTES.md
├── README.md
├── angular.json
├── apps/
│   ├── .gitkeep
│   ├── dev-server/
│   │   ├── .eslintrc.json
│   │   ├── jest.config.ts
│   │   ├── project.json
│   │   ├── src/
│   │   │   ├── assets/
│   │   │   │   └── .gitkeep
│   │   │   ├── data/
│   │   │   │   ├── 2d-histogram.ts
│   │   │   │   ├── bar.ts
│   │   │   │   ├── candlestick.ts
│   │   │   │   ├── line-stream.ts
│   │   │   │   ├── sankey.ts
│   │   │   │   ├── scatter.ts
│   │   │   │   └── table.ts
│   │   │   ├── environments/
│   │   │   │   ├── environment.prod.ts
│   │   │   │   └── environment.ts
│   │   │   └── main.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   └── tsconfig.spec.json
│   ├── web/
│   │   ├── .browserslistrc
│   │   ├── .eslintrc.json
│   │   ├── jest.config.ts
│   │   ├── project.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── app-routing.module.ts
│   │   │   │   ├── app.module.ts
│   │   │   │   ├── components/
│   │   │   │   │   ├── app/
│   │   │   │   │   │   ├── app.component.css
│   │   │   │   │   │   ├── app.component.html
│   │   │   │   │   │   ├── app.component.spec.ts
│   │   │   │   │   │   └── app.component.ts
│   │   │   │   │   ├── plot/
│   │   │   │   │   │   ├── plot.component.css
│   │   │   │   │   │   ├── plot.component.html
│   │   │   │   │   │   └── plot.component.ts
│   │   │   │   │   ├── plots/
│   │   │   │   │   │   ├── plots.component.css
│   │   │   │   │   │   ├── plots.component.html
│   │   │   │   │   │   ├── plots.component.spec.ts
│   │   │   │   │   │   └── plots.component.ts
│   │   │   │   │   └── tutorial/
│   │   │   │   │       ├── tutorial.component.css
│   │   │   │   │       ├── tutorial.component.html
│   │   │   │   │       └── tutorial.component.ts
│   │   │   │   └── services/
│   │   │   │       ├── plots.service.ts
│   │   │   │       └── socket.service.ts
│   │   │   ├── assets/
│   │   │   │   └── .gitkeep
│   │   │   ├── custom-theme.scss
│   │   │   ├── environments/
│   │   │   │   ├── environment.prod.ts
│   │   │   │   └── environment.ts
│   │   │   ├── index.html
│   │   │   ├── main.ts
│   │   │   ├── polyfills.ts
│   │   │   ├── styles.css
│   │   │   └── test-setup.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.editor.json
│   │   ├── tsconfig.json
│   │   └── tsconfig.spec.json
│   └── web-e2e/
│       ├── .eslintrc.json
│       ├── cypress.json
│       ├── project.json
│       ├── src/
│       │   ├── fixtures/
│       │   │   └── example.json
│       │   ├── integration/
│       │   │   └── app.spec.ts
│       │   └── support/
│       │       ├── app.po.ts
│       │       ├── commands.ts
│       │       └── index.ts
│       └── tsconfig.json
├── decorate-angular-cli.js
├── jest.config.ts
├── jest.preset.js
├── libs/
│   └── nodeplotlib/
│       ├── .babelrc
│       ├── .eslintrc.json
│       ├── README.md
│       ├── jest.config.ts
│       ├── package.json
│       ├── project.json
│       ├── src/
│       │   ├── index.ts
│       │   └── lib/
│       │       ├── interfaces/
│       │       │   ├── index.ts
│       │       │   └── plot.ts
│       │       ├── nodeplotlib.ts
│       │       ├── server/
│       │       │   ├── plots/
│       │       │   │   ├── plots.gateway.ts
│       │       │   │   └── plots.service.ts
│       │       │   ├── server.module.ts
│       │       │   └── services/
│       │       │       ├── bridge-service.spec.ts
│       │       │       └── bridge.service.ts
│       │       └── utils/
│       │           ├── get-port.spec.ts
│       │           ├── get-port.ts
│       │           ├── open-window.spec.ts
│       │           └── open-window.ts
│       ├── tsconfig.json
│       ├── tsconfig.lib.json
│       └── tsconfig.spec.json
├── nx.json
├── package.json
├── tools/
│   ├── demo/
│   │   ├── README.md
│   │   ├── candlestick.js
│   │   ├── scatter.js
│   │   ├── scatter.ts
│   │   └── stream.ts
│   ├── generators/
│   │   └── .gitkeep
│   ├── tsconfig.tools.json
│   └── util/
│       └── copy-files.ts
└── tsconfig.base.json
Download .txt
SYMBOL INDEX (55 symbols across 21 files)

FILE: apps/dev-server/src/data/2d-histogram.ts
  function normal (line 3) | function normal() {

FILE: apps/web-e2e/src/support/commands.ts
  type Chainable (line 14) | interface Chainable<Subject> {

FILE: apps/web/src/app/app-routing.module.ts
  class AppRoutingModule (line 23) | class AppRoutingModule {}
  class AppRoutesReuseStrategy (line 25) | class AppRoutesReuseStrategy implements RouteReuseStrategy {
    method shouldDetach (line 28) | shouldDetach(route: ActivatedRouteSnapshot): boolean {
    method store (line 32) | store(route: ActivatedRouteSnapshot, handler: DetachedRouteHandle): vo...
    method shouldAttach (line 38) | shouldAttach(route: ActivatedRouteSnapshot): boolean {
    method shouldReuseRoute (line 42) | shouldReuseRoute(
    method retrieve (line 49) | retrieve(route: ActivatedRouteSnapshot) {
    method getUrl (line 56) | private getUrl(route: ActivatedRouteSnapshot): string {

FILE: apps/web/src/app/app.module.ts
  class AppModule (line 46) | class AppModule {}

FILE: apps/web/src/app/components/app/app.component.ts
  class AppComponent (line 10) | class AppComponent {
    method constructor (line 11) | constructor(private socketService: SocketService) {}

FILE: apps/web/src/app/components/plot/plot.component.ts
  class PlotComponent (line 22) | class PlotComponent implements AfterViewInit, OnChanges {
    method ngAfterViewInit (line 26) | ngAfterViewInit() {
    method ngOnChanges (line 35) | ngOnChanges(simpleChanges: SimpleChanges) {

FILE: apps/web/src/app/components/plots/plots.component.spec.ts
  constant PLOTS (line 9) | const PLOTS: PlotData[] = [
  class PlotComponent (line 30) | class PlotComponent {

FILE: apps/web/src/app/components/plots/plots.component.ts
  class PlotsComponent (line 11) | class PlotsComponent {
    method constructor (line 14) | constructor(private plotsService: PlotsService) {}
    method trackById (line 16) | trackById(_: number, plot: PlotData) {

FILE: apps/web/src/app/components/tutorial/tutorial.component.ts
  class TutorialComponent (line 9) | class TutorialComponent {}

FILE: apps/web/src/app/services/plots.service.ts
  class PlotsService (line 8) | class PlotsService {
    method constructor (line 14) | constructor(private socketService: SocketService) {

FILE: apps/web/src/app/services/socket.service.ts
  class SocketService (line 6) | class SocketService implements OnDestroy {
    method constructor (line 9) | constructor() {
    method listen (line 21) | listen<T>(eventName: string, cb: (data: T) => void) {
    method emit (line 25) | emit<T>(eventName: string, data?: T) {
    method ngOnDestroy (line 29) | ngOnDestroy() {

FILE: decorate-angular-cli.js
  function symlinkNgCLItoNxCLI (line 42) | function symlinkNgCLItoNxCLI() {

FILE: libs/nodeplotlib/src/lib/interfaces/plot.ts
  type Plot (line 8) | type Plot = Partial<PlotlyPlotData>;
  type Layout (line 9) | type Layout = Partial<PlotlyLayout>;
  type Config (line 10) | type Config = Partial<PlotlyConfig>;
  type PlotDataStream (line 12) | interface PlotDataStream {
  type PlotData (line 19) | interface PlotData {

FILE: libs/nodeplotlib/src/lib/nodeplotlib.ts
  function plot (line 30) | function plot(
  function bootstrap (line 46) | async function bootstrap(port: number) {
  function shutdown (line 68) | async function shutdown() {

FILE: libs/nodeplotlib/src/lib/server/plots/plots.gateway.ts
  class PlotsGateway (line 14) | class PlotsGateway implements OnGatewayConnection, OnGatewayDisconnect {
    method constructor (line 18) | constructor(
    method handleEvent (line 49) | handleEvent() {
    method handleConnection (line 58) | handleConnection(client: WebSocket) {
    method handleDisconnect (line 63) | handleDisconnect(client: WebSocket) {

FILE: libs/nodeplotlib/src/lib/server/plots/plots.service.ts
  class PlotsService (line 7) | class PlotsService {
    method setBuffer (line 13) | setBuffer(buffer$: Observable<Omit<PlotDataStream, 'id'>[]>) {
    method addPlot (line 20) | addPlot(plotData: Omit<PlotDataStream, 'id'>) {
    method readBuffer (line 39) | readBuffer(buffer: Omit<PlotDataStream, 'id'>[]) {

FILE: libs/nodeplotlib/src/lib/server/server.module.ts
  class ServerModule (line 16) | class ServerModule {}

FILE: libs/nodeplotlib/src/lib/server/services/bridge.service.ts
  class BridgeService (line 15) | class BridgeService {
    method constructor (line 19) | constructor() {
    method setPort (line 25) | setPort(port: number) {
    method shutdown (line 29) | shutdown() {

FILE: libs/nodeplotlib/src/lib/utils/get-port.ts
  function getPort (line 1) | function getPort(): number {

FILE: libs/nodeplotlib/src/lib/utils/open-window.ts
  function openWindow (line 4) | function openWindow(location: string) {

FILE: tools/demo/stream.ts
  function createSinusPlotFromNumber (line 8) | function createSinusPlotFromNumber(num: number): Plot[] {
Condensed preview — 113 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (99K chars).
[
  {
    "path": ".editorconfig",
    "chars": 245,
    "preview": "# Editor configuration, see http://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = "
  },
  {
    "path": ".eslintrc.json",
    "chars": 816,
    "preview": "{\n  \"root\": true,\n  \"ignorePatterns\": [\"**/*\"],\n  \"plugins\": [\"@nrwl/nx\"],\n  \"overrides\": [\n    {\n      \"files\": [\"*.ts\""
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 834,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 595,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 526,
    "preview": "name: Node.js CI\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n   "
  },
  {
    "path": ".gitignore",
    "chars": 519,
    "preview": "# See http://help.github.com/ignore-files/ for more about ignoring files.\n\n# compiled output\n/dist\n/tmp\n/out-tsc\n\n# depe"
  },
  {
    "path": ".prettierignore",
    "chars": 74,
    "preview": "# Add files here to ignore them from prettier formatting\n\n/dist\n/coverage\n"
  },
  {
    "path": ".prettierrc",
    "chars": 26,
    "preview": "{\n  \"singleQuote\": true\n}\n"
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 181,
    "preview": "{\n  \"recommendations\": [\n    \"angular.ng-template\",\n    \"nrwl.angular-console\",\n    \"esbenp.prettier-vscode\",\n    \"first"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3352,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 839,
    "preview": "## Contribution guidelines\n\nContributions are very welcome. Please stick to the [code of conduct](./CODE_OF_CONDUCT.md) "
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2022 Felix Lemke\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "NOTES.md",
    "chars": 2041,
    "preview": "These are notes for the stream implementation of Nodeplotlib.\n\n## General\n\n- A plot window (**apps/web**) tries to conne"
  },
  {
    "path": "README.md",
    "chars": 4036,
    "preview": "# <img src=\"./img/nodeplotlib_64x64.png\" width=\"22px\" height=\"22px\"> NodePlotLib\n\n[![NodeJS CI](https://github.com/ngfel"
  },
  {
    "path": "angular.json",
    "chars": 233,
    "preview": "{\n  \"$schema\": \"./node_modules/nx/schemas/workspace-schema.json\",\n  \"version\": 2,\n  \"projects\": {\n    \"dev-server\": \"app"
  },
  {
    "path": "apps/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "apps/dev-server/.eslintrc.json",
    "chars": 306,
    "preview": "{\n  \"extends\": [\"../../.eslintrc.json\"],\n  \"ignorePatterns\": [\"!**/*\"],\n  \"overrides\": [\n    {\n      \"files\": [\"*.ts\", \""
  },
  {
    "path": "apps/dev-server/jest.config.ts",
    "chars": 373,
    "preview": "/* eslint-disable */\nexport default {\n  displayName: 'dev-server',\n  preset: '../../jest.preset.js',\n  globals: {\n    't"
  },
  {
    "path": "apps/dev-server/project.json",
    "chars": 1591,
    "preview": "{\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"sourceRoot\": \"apps/dev-server/src\",\n  \"projectTyp"
  },
  {
    "path": "apps/dev-server/src/assets/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "apps/dev-server/src/data/2d-histogram.ts",
    "chars": 1796,
    "preview": "import { Layout, Plot } from '@npl/nodeplotlib';\n\nfunction normal() {\n  let x = 0,\n    y = 0,\n    rds;\n  do {\n    x = Ma"
  },
  {
    "path": "apps/dev-server/src/data/bar.ts",
    "chars": 190,
    "preview": "import { Plot } from '@npl/nodeplotlib';\n\nexport const data: Plot[] = [\n  {\n    type: 'bar',\n    x: [20, 14, 23],\n    y:"
  },
  {
    "path": "apps/dev-server/src/data/candlestick.ts",
    "chars": 2805,
    "preview": "import { Plot } from '@npl/nodeplotlib';\n\nconst trace1 = {\n  x: [\n    '2017-01-04',\n    '2017-01-05',\n    '2017-01-06',\n"
  },
  {
    "path": "apps/dev-server/src/data/line-stream.ts",
    "chars": 378,
    "preview": "import { Plot } from '@npl/nodeplotlib';\nimport { interval, Observable, map } from 'rxjs';\n\nexport const stream$: Observ"
  },
  {
    "path": "apps/dev-server/src/data/sankey.ts",
    "chars": 565,
    "preview": "import { Plot } from '@npl/nodeplotlib';\n\nexport const data = [\n  {\n    type: 'sankey',\n    orientation: 'h',\n    node: "
  },
  {
    "path": "apps/dev-server/src/data/scatter.ts",
    "chars": 217,
    "preview": "import { Plot } from '@npl/nodeplotlib';\n\nconst trace1: Plot = {\n  x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n  y: [1, 2, 1, 2, "
  },
  {
    "path": "apps/dev-server/src/data/table.ts",
    "chars": 1082,
    "preview": "import { Plot } from '@npl/nodeplotlib';\n\nconst values = [\n  ['Salaries', 'Office', 'Merchandise', 'Legal', '<b>TOTAL</b"
  },
  {
    "path": "apps/dev-server/src/environments/environment.prod.ts",
    "chars": 52,
    "preview": "export const environment = {\n  production: true,\n};\n"
  },
  {
    "path": "apps/dev-server/src/environments/environment.ts",
    "chars": 53,
    "preview": "export const environment = {\n  production: false,\n};\n"
  },
  {
    "path": "apps/dev-server/src/main.ts",
    "chars": 650,
    "preview": "/**\n * This is not a production server yet!\n * This is only a minimal backend to get started.\n */\n\nimport { plot } from "
  },
  {
    "path": "apps/dev-server/tsconfig.app.json",
    "chars": 279,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"module\": \"commonjs\",\n "
  },
  {
    "path": "apps/dev-server/tsconfig.json",
    "chars": 197,
    "preview": "{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"files\": [],\n  \"include\": [],\n  \"references\": [\n    {\n      \"path\": \"./tsco"
  },
  {
    "path": "apps/dev-server/tsconfig.spec.json",
    "chars": 215,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"module\": \"commonjs\",\n "
  },
  {
    "path": "apps/web/.browserslistrc",
    "chars": 703,
    "preview": "# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.\n# For addit"
  },
  {
    "path": "apps/web/.eslintrc.json",
    "chars": 792,
    "preview": "{\n  \"extends\": [\"../../.eslintrc.json\"],\n  \"ignorePatterns\": [\"!**/*\"],\n  \"overrides\": [\n    {\n      \"files\": [\"*.ts\"],\n"
  },
  {
    "path": "apps/web/jest.config.ts",
    "chars": 681,
    "preview": "/* eslint-disable */\nexport default {\n  displayName: 'web',\n  preset: '../../jest.preset.js',\n  setupFilesAfterEnv: ['<r"
  },
  {
    "path": "apps/web/project.json",
    "chars": 2494,
    "preview": "{\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"application\",\n  \"sourceRoot\": \"app"
  },
  {
    "path": "apps/web/src/app/app-routing.module.ts",
    "chars": 1563,
    "preview": "import { NgModule } from '@angular/core';\nimport {\n  ActivatedRouteSnapshot,\n  BaseRouteReuseStrategy,\n  DetachedRouteHa"
  },
  {
    "path": "apps/web/src/app/app.module.ts",
    "chars": 1659,
    "preview": "import { HttpClientModule } from '@angular/common/http';\nimport { NgModule } from '@angular/core';\nimport { MatButtonMod"
  },
  {
    "path": "apps/web/src/app/components/app/app.component.css",
    "chars": 490,
    "preview": ":host {\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  display: flex;\n  flex-direction: column;\n "
  },
  {
    "path": "apps/web/src/app/components/app/app.component.html",
    "chars": 1141,
    "preview": "<mat-toolbar color=\"primary\" class=\"mat-elevation-z4\">\n  <span class=\"brand\" routerLink=\"/\">\n    <button mat-button>\n   "
  },
  {
    "path": "apps/web/src/app/components/app/app.component.spec.ts",
    "chars": 694,
    "preview": "import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing"
  },
  {
    "path": "apps/web/src/app/components/app/app.component.ts",
    "chars": 385,
    "preview": "import { ChangeDetectionStrategy, Component } from '@angular/core';\nimport { SocketService } from '../../services/socket"
  },
  {
    "path": "apps/web/src/app/components/plot/plot.component.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "apps/web/src/app/components/plot/plot.component.html",
    "chars": 27,
    "preview": "<div #plotContainer></div>\n"
  },
  {
    "path": "apps/web/src/app/components/plot/plot.component.ts",
    "chars": 1156,
    "preview": "import {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  Input,\n  OnChanges,\n  SimpleChanges,\n "
  },
  {
    "path": "apps/web/src/app/components/plots/plots.component.css",
    "chars": 152,
    "preview": ":host {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));\n  grid-gap: 8px;\n  margin: 12px"
  },
  {
    "path": "apps/web/src/app/components/plots/plots.component.html",
    "chars": 121,
    "preview": "<mat-card *ngFor=\"let plot of plots$ | async; trackBy: trackById\">\n  <npl-plot [plotData]=\"plot\"></npl-plot>\n</mat-card>"
  },
  {
    "path": "apps/web/src/app/components/plots/plots.component.spec.ts",
    "chars": 2207,
    "preview": "import { Component, CUSTOM_ELEMENTS_SCHEMA, Input } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@an"
  },
  {
    "path": "apps/web/src/app/components/plots/plots.component.ts",
    "chars": 537,
    "preview": "import { ChangeDetectionStrategy, Component } from '@angular/core';\nimport { PlotData } from '@npl/nodeplotlib';\nimport "
  },
  {
    "path": "apps/web/src/app/components/tutorial/tutorial.component.css",
    "chars": 44,
    "preview": ":host {\n  display: block;\n  margin: 18px;\n}\n"
  },
  {
    "path": "apps/web/src/app/components/tutorial/tutorial.component.html",
    "chars": 259,
    "preview": "<h1>Tutorials</h1>\n\nThe tutorials sections will be tackled once the application is done. It will\ncontain the following t"
  },
  {
    "path": "apps/web/src/app/components/tutorial/tutorial.component.ts",
    "chars": 285,
    "preview": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\n@Component({\n  selector: 'npl-tutorial',\n  template"
  },
  {
    "path": "apps/web/src/app/services/plots.service.ts",
    "chars": 750,
    "preview": "import { Injectable } from '@angular/core';\nimport { PlotData } from '@npl/nodeplotlib';\nimport { BehaviorSubject } from"
  },
  {
    "path": "apps/web/src/app/services/socket.service.ts",
    "chars": 817,
    "preview": "import { Injectable, OnDestroy } from '@angular/core';\nimport { io, Socket } from 'socket.io-client';\nimport { environme"
  },
  {
    "path": "apps/web/src/assets/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "apps/web/src/custom-theme.scss",
    "chars": 1429,
    "preview": "// Custom Theming for Angular Material\n// For more information: https://material.angular.io/guide/theming\n@use '@angular"
  },
  {
    "path": "apps/web/src/environments/environment.prod.ts",
    "chars": 76,
    "preview": "export const environment = {\n  production: true,\n  socketIoEndpoint: '',\n};\n"
  },
  {
    "path": "apps/web/src/environments/environment.ts",
    "chars": 683,
    "preview": "// This file can be replaced during build by using the `fileReplacements` array.\n// `ng build` replaces `environment.ts`"
  },
  {
    "path": "apps/web/src/index.html",
    "chars": 670,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <base href=\"/\" />\n    <title>Nodeplotlib</title>\n    <meta name=\"viewport\" content=\""
  },
  {
    "path": "apps/web/src/main.ts",
    "chars": 377,
    "preview": "import { enableProdMode } from '@angular/core';\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynami"
  },
  {
    "path": "apps/web/src/polyfills.ts",
    "chars": 2338,
    "preview": "/**\n * This file includes polyfills needed by Angular and is loaded before the app.\n * You can add your own extra polyfi"
  },
  {
    "path": "apps/web/src/styles.css",
    "chars": 292,
    "preview": "/* You can add global styles to this file, and also import other style files */\n\nhtml,\nbody {\n  height: 100%;\n}\nbody {\n "
  },
  {
    "path": "apps/web/src/test-setup.ts",
    "chars": 404,
    "preview": "import 'jest-preset-angular/setup-jest';\n\nimport { getTestBed } from '@angular/core/testing';\nimport {\n  BrowserDynamicT"
  },
  {
    "path": "apps/web/tsconfig.app.json",
    "chars": 195,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"types\": []\n  },\n  \"fil"
  },
  {
    "path": "apps/web/tsconfig.editor.json",
    "chars": 119,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"**/*.ts\"],\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  }\n}\n"
  },
  {
    "path": "apps/web/tsconfig.json",
    "chars": 579,
    "preview": "{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"files\": [],\n  \"include\": [],\n  \"references\": [\n    {\n      \"path\": \"./tsco"
  },
  {
    "path": "apps/web/tsconfig.spec.json",
    "chars": 249,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"module\": \"commonjs\",\n "
  },
  {
    "path": "apps/web-e2e/.eslintrc.json",
    "chars": 364,
    "preview": "{\n  \"extends\": [\"plugin:cypress/recommended\", \"../../.eslintrc.json\"],\n  \"ignorePatterns\": [\"!**/*\"],\n  \"overrides\": [\n "
  },
  {
    "path": "apps/web-e2e/cypress.json",
    "chars": 390,
    "preview": "{\n  \"fileServerFolder\": \".\",\n  \"fixturesFolder\": \"./src/fixtures\",\n  \"integrationFolder\": \"./src/integration\",\n  \"modify"
  },
  {
    "path": "apps/web-e2e/project.json",
    "chars": 763,
    "preview": "{\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"sourceRoot\": \"apps/web-e2e/src\",\n  \"projectType\":"
  },
  {
    "path": "apps/web-e2e/src/fixtures/example.json",
    "chars": 80,
    "preview": "{\n  \"name\": \"Using fixtures to represent data\",\n  \"email\": \"hello@cypress.io\"\n}\n"
  },
  {
    "path": "apps/web-e2e/src/integration/app.spec.ts",
    "chars": 398,
    "preview": "import { getGreeting } from '../support/app.po';\n\ndescribe('web', () => {\n  beforeEach(() => cy.visit('/'));\n\n  it('shou"
  },
  {
    "path": "apps/web-e2e/src/support/app.po.ts",
    "chars": 47,
    "preview": "export const getGreeting = () => cy.get('h1');\n"
  },
  {
    "path": "apps/web-e2e/src/support/commands.ts",
    "chars": 1133,
    "preview": "// ***********************************************\n// This example commands.js shows you how to\n// create various custom"
  },
  {
    "path": "apps/web-e2e/src/support/index.ts",
    "chars": 599,
    "preview": "// ***********************************************************\n// This example support/index.js is processed and\n// load"
  },
  {
    "path": "apps/web-e2e/tsconfig.json",
    "chars": 510,
    "preview": "{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"sourceMap\": false,\n    \"outDir\": \"../../dist/out-"
  },
  {
    "path": "decorate-angular-cli.js",
    "chars": 2690,
    "preview": "/**\n * This file decorates the Angular CLI with the Nx CLI to enable features such as computation caching\n * and faster "
  },
  {
    "path": "jest.config.ts",
    "chars": 98,
    "preview": "import { getJestProjects } from '@nrwl/jest';\n\nexport default {\n  projects: getJestProjects(),\n};\n"
  },
  {
    "path": "jest.preset.js",
    "chars": 90,
    "preview": "const nxPreset = require('@nrwl/jest/preset').default;\n\nmodule.exports = { ...nxPreset };\n"
  },
  {
    "path": "libs/nodeplotlib/.babelrc",
    "chars": 67,
    "preview": "{\n  \"presets\": [[\"@nrwl/web/babel\", { \"useBuiltIns\": \"usage\" }]]\n}\n"
  },
  {
    "path": "libs/nodeplotlib/.eslintrc.json",
    "chars": 306,
    "preview": "{\n  \"extends\": [\"../../.eslintrc.json\"],\n  \"ignorePatterns\": [\"!**/*\"],\n  \"overrides\": [\n    {\n      \"files\": [\"*.ts\", \""
  },
  {
    "path": "libs/nodeplotlib/README.md",
    "chars": 6167,
    "preview": "# <img src=\"https://raw.githubusercontent.com/ngfelixl/nodeplotlib/master/img/nodeplotlib_64x64.png\" width=\"28px\" height"
  },
  {
    "path": "libs/nodeplotlib/jest.config.ts",
    "chars": 383,
    "preview": "/* eslint-disable */\nexport default {\n  displayName: 'nodeplotlib',\n  preset: '../../jest.preset.js',\n  globals: {\n    '"
  },
  {
    "path": "libs/nodeplotlib/package.json",
    "chars": 800,
    "preview": "{\n  \"name\": \"nodeplotlib\",\n  \"version\": \"1.1.3\",\n  \"description\": \"NodeJS frontend-less plotting lib using plotly.js ins"
  },
  {
    "path": "libs/nodeplotlib/project.json",
    "chars": 959,
    "preview": "{\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"root\": \"libs/nodeplotlib\",\n  \"sourceRoot\": \"libs/"
  },
  {
    "path": "libs/nodeplotlib/src/index.ts",
    "chars": 238,
    "preview": "// Exports required for the actual nodeplotlib\nexport { Plot, Layout, Config } from './lib/interfaces/plot';\nexport { pl"
  },
  {
    "path": "libs/nodeplotlib/src/lib/interfaces/index.ts",
    "chars": 65,
    "preview": "export { Layout, Plot, PlotData, PlotDataStream } from './plot';\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/interfaces/plot.ts",
    "chars": 529,
    "preview": "import {\n  Layout as PlotlyLayout,\n  PlotData as PlotlyPlotData,\n  Config as PlotlyConfig,\n} from 'plotly.js';\nimport { "
  },
  {
    "path": "libs/nodeplotlib/src/lib/nodeplotlib.ts",
    "chars": 2318,
    "preview": "import { INestApplication } from '@nestjs/common';\nimport { NestFactory } from '@nestjs/core';\nimport { Layout, Plot, Pl"
  },
  {
    "path": "libs/nodeplotlib/src/lib/server/plots/plots.gateway.ts",
    "chars": 1974,
    "preview": "import {\n  OnGatewayConnection,\n  OnGatewayDisconnect,\n  SubscribeMessage,\n  WebSocketGateway,\n} from '@nestjs/websocket"
  },
  {
    "path": "libs/nodeplotlib/src/lib/server/plots/plots.service.ts",
    "chars": 1309,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { PlotDataStream } from '../../interfaces';\nimport { BehaviorSubject"
  },
  {
    "path": "libs/nodeplotlib/src/lib/server/server.module.ts",
    "chars": 494,
    "preview": "import { Module } from '@nestjs/common';\nimport { ServeStaticModule } from '@nestjs/serve-static';\nimport { join } from "
  },
  {
    "path": "libs/nodeplotlib/src/lib/server/services/bridge-service.spec.ts",
    "chars": 649,
    "preview": "import { BridgeService } from './bridge.service';\nimport { openWindow } from '../../utils/open-window';\njest.mock('../.."
  },
  {
    "path": "libs/nodeplotlib/src/lib/server/services/bridge.service.ts",
    "chars": 794,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { Subject } from 'rxjs';\nimport { openWindow } from '../../utils/ope"
  },
  {
    "path": "libs/nodeplotlib/src/lib/utils/get-port.spec.ts",
    "chars": 877,
    "preview": "import { getPort } from './get-port';\n\ndescribe('getPort', () => {\n  it('should return 0 if NODEPLOTLIB_PORT is undefine"
  },
  {
    "path": "libs/nodeplotlib/src/lib/utils/get-port.ts",
    "chars": 182,
    "preview": "export function getPort(): number {\n  const portAsString = process.env.NODEPLOTLIB_PORT;\n  const port = Number(portAsStr"
  },
  {
    "path": "libs/nodeplotlib/src/lib/utils/open-window.spec.ts",
    "chars": 1509,
    "preview": "import { openWindow } from './open-window';\nimport { exec } from 'child_process';\nimport { type } from 'os';\njest.mock('"
  },
  {
    "path": "libs/nodeplotlib/src/lib/utils/open-window.ts",
    "chars": 394,
    "preview": "import { exec } from 'child_process';\nimport { type } from 'os';\n\nexport function openWindow(location: string) {\n  if (p"
  },
  {
    "path": "libs/nodeplotlib/tsconfig.json",
    "chars": 361,
    "preview": "{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"files\": [],\n  \"include\": [],\n  \"references\": [\n    {\n      \"path\": \"./tsco"
  },
  {
    "path": "libs/nodeplotlib/tsconfig.lib.json",
    "chars": 263,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"outDir\": \"../../dist/out-tsc\",\n "
  },
  {
    "path": "libs/nodeplotlib/tsconfig.spec.json",
    "chars": 355,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"module\": \"commonjs\",\n "
  },
  {
    "path": "nx.json",
    "chars": 899,
    "preview": "{\n  \"$schema\": \"./node_modules/nx/schemas/nx-schema.json\",\n  \"npmScope\": \"npl\",\n  \"affected\": {\n    \"defaultBase\": \"main"
  },
  {
    "path": "package.json",
    "chars": 2754,
    "preview": "{\n  \"name\": \"nodeplotlib\",\n  \"version\": \"1.1.3\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"ng\": \"nx\",\n    \"postinstall\": \""
  },
  {
    "path": "tools/demo/README.md",
    "chars": 368,
    "preview": "# Demo plots\n\nThese plots are meant to run with the compiled version of nodeplotlib. You can run them\nwith the following"
  },
  {
    "path": "tools/demo/candlestick.js",
    "chars": 2819,
    "preview": "const npl = require('../../dist/libs/nodeplotlib');\n\nconst trace1 = {\n  x: [\n    '2017-01-04',\n    '2017-01-05',\n    '20"
  },
  {
    "path": "tools/demo/scatter.js",
    "chars": 96,
    "preview": "import npl from '../../dist/libs/nodeplotlib';\nnpl.plot([{ x: [0], y: [1], type: 'scatter' }]);\n"
  },
  {
    "path": "tools/demo/scatter.ts",
    "chars": 103,
    "preview": "import npl from '../../dist/libs/nodeplotlib';\n\nnpl.plot([{ x: [0, 1], y: [1, 1], type: 'scatter' }]);\n"
  },
  {
    "path": "tools/demo/stream.ts",
    "chars": 479,
    "preview": "import { plot, Plot } from '../../dist/libs/nodeplotlib';\nimport { interval, map, Observable } from 'rxjs';\n\nconst strea"
  },
  {
    "path": "tools/generators/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tools/tsconfig.tools.json",
    "chars": 251,
    "preview": "{\n  \"extends\": \"../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../dist/out-tsc/tools\",\n    \"rootDir\": \".\""
  },
  {
    "path": "tools/util/copy-files.ts",
    "chars": 238,
    "preview": "import { copySync } from 'fs-extra';\n\ncopySync('dist/apps/web', 'dist/libs/nodeplotlib/src/lib/server/web');\ncopySync('l"
  },
  {
    "path": "tsconfig.base.json",
    "chars": 532,
    "preview": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"rootDir\": \".\",\n    \"sourceMap\": true,\n    \"declaration\": false,\n"
  }
]

About this extraction

This page contains the full source code of the ngfelixl/nodeplotlib GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 113 files (85.2 KB), approximately 27.3k tokens, and a symbol index with 55 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!