Merged Plotly repository

This commit is contained in:
Alexander Nozik 2024-06-04 22:47:56 +03:00
parent 42e98f0bcc
commit 6fd719b9ee
246 changed files with 27959 additions and 56 deletions

2
.gitignore vendored
View File

@ -8,6 +8,8 @@ build/
data/
.kotlin/
jcef-bundle/
!gradle-wrapper.jar
/kotlin-js-store/yarn.lock

View File

@ -3,8 +3,11 @@
## Unreleased
### Added
- Moved plotly-kt repo inside this one
### Changed
- Kotlin 2.0
- DataForge 0.9
### Deprecated

View File

@ -3,14 +3,15 @@ import space.kscience.gradle.useSPCTeam
plugins {
id("space.kscience.gradle.project")
id("org.jetbrains.kotlinx.kover") version "0.5.0"
alias(spclibs.plugins.kotlinx.kover)
}
val dataforgeVersion by extra("0.8.0")
val dataforgeVersion by extra("0.9.0")
val plotlyVersion by extra("2.29.0")
allprojects {
group = "space.kscience"
version = "0.4.2-dev-2"
version = "0.5.0-dev-1"
}
subprojects {

View File

@ -1,6 +1,7 @@
plugins {
id("space.kscience.gradle.mpp")
alias(spclibs.plugins.compose)
alias(spclibs.plugins.compose.compiler)
alias(spclibs.plugins.compose.jb)
}
kscience {

View File

@ -1,6 +1,7 @@
plugins {
id("space.kscience.gradle.mpp")
alias(spclibs.plugins.compose)
alias(spclibs.plugins.compose.compiler)
alias(spclibs.plugins.compose.jb)
}
group = "demo"

View File

@ -1,6 +1,7 @@
plugins {
id("space.kscience.gradle.mpp")
alias(spclibs.plugins.compose)
alias(spclibs.plugins.compose.compiler)
alias(spclibs.plugins.compose.jb)
}
kscience {

View File

@ -1,6 +1,7 @@
plugins {
id("space.kscience.gradle.mpp")
alias(spclibs.plugins.compose)
alias(spclibs.plugins.compose.compiler)
alias(spclibs.plugins.compose.jb)
// alias(spclibs.plugins.ktor)
application
}

View File

@ -43,9 +43,9 @@ kotlin {
val commonMain by getting {
dependencies {
implementation(projects.visionforgeSolid)
implementation(projects.visionforgePlotly)
// implementation(projects.visionforgePlotly)
implementation(projects.visionforgeMarkdown)
implementation(projects.visionforgeTables)
// implementation(projects.visionforgeTables)
implementation(projects.cernRootLoader)
api(projects.visionforgeJupyter.visionforgeJupyterCommon)
}

View File

@ -18,7 +18,6 @@ Before we start, we have to load necessary dependencies:
```kotlin
repositories {
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven")
// Add either the line below:
maven("https://repo.kotlin.link")

View File

@ -4,4 +4,4 @@ kotlin.mpp.stability.nowarn=true
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx4G
toolsVersion=0.15.2-kotlin-2.0.0-RC1
toolsVersion=0.15.4-kotlin-2.0.0

221
plotly/CHANGELOG.md Normal file
View File

@ -0,0 +1,221 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
### Changed
### Deprecated
### Removed
### Fixed
### Security
## 0.7.1 - 2024-02-22
### Added
- Compose demo
### Changed
- Migrated to DF 0.8
### Removed
- Grid view
### Fixed
- Fixed rendering for Jupyter lab
## 0.6.0 - 2023-07-29
### Added
- Add experimental support for events on JS
### Changed
- DataForge 0.6.2
- Use a self-made Plotly-js bundle instead of one from CDN
## 0.5.3 - 2023-04-01
### Added
- API for background images (https://github.com/SciProgCentre/plotly.kt/issues/49)
- API for multiple Y axis (https://github.com/SciProgCentre/plotly.kt/issues/92)
- Native support
- `plotlykt module` with basic Geo API
- DataSourceHost/DataSourcePost to configure custom networks
### Changed
- Kotlin 1.8.20
- Moved renderers to JVM to avoid confusion with JS direct element rendering.
- DataForge 0.6
- Replaced krangl by Kotlin-DataFrame in examples
- Plotly server uses push strategy by default
- Renderers moved to common
- Moved to Ktor 2.0
### Deprecated
- Page layout. Use VisionForge for that.
### Removed
- Moved CORS to `Plotly.serve`
### Fixed
- Added a protective copy on reading doubleArray from TraceValues
- #85
- Rendering in JS that used backend HTML generation
## 0.5.0
### Changed
- Switch to DataForge 0.5
-
## 0.4.4
### Added
- Candlestick support
- Range builders for axis
### Changed
- build tools 0.10.0
- demo projects moved to examples
### Deprecated
- Direct usage of `range` in axis
### Fixed
- #80
- Plotly coordinate array wrap is moved to the server side
## 0.4.3
### Fixed
- Proper deserialization of single plot.
- A bug in jupyter lab visualization
## 0.4.2
### Added
- `automargin` property to `Axis` according to https://plotly.com/python/reference/layout/xaxis/#layout-xaxis-automargin
### Fixed
- Remove unnecessary `kotlinx-css` dependency.
- Added compatibility mode for legacy notebooks. Use `Plotly.jupyter.notebook()` call to enable legacy mode.
## 0.4.0
### Added
- Jupyter integration plugin for server
- Separate static plot integration module in `plotlykt-jupyter`
- Expanded JS demo
- Jupyter support goes beta
### Changed
- Package change (again) to `space.kscience`
- Build tools `0.9.5`
- Kotlin `1.5.0`
- HtmlFragment renamed to PlotlyHtmlFragment
### Removed
- Local bootstrap
### Fixed
- Incomplete coverage in JS (#70)
## 0.3.1
### Added
- Table widget implementation by @ArtificialPB
- Mathjax header promoted to stable
- Tabbed plots layout (experimental)
- Trace value builders for functions and ranges (experimental)
### Changed
- **Breaking API change!** Trace `text` replaced by `TraceValues`
- Moved to DataForge 0.3 API
- Kotlin 1.4.30
- **JVM-IR**
- Plot `Config` moved to constructor
- Replaced direct color accessor by a delegate
### Fixed
- https://github.com/mipt-npm/plotly.kt/issues/53
- Add JQuery to Bootstrap headers
## 0.3.0
### Changed
- Serialization API is encapsulated (not longer exposed) in order to provide compatibility with new serialization.
- Migration to Kotlin 1.4
- Minor breaking change in Plot to encapsulate serialization usage
- JS supports IR. LEGACY is not supported anymore.
### Fixed
- https://github.com/mipt-npm/plotly.kt/issues/51
## 0.2.0
### Added
- Experimental scripting support
- Static export via Orca
- Experimental Jupyter support
- Color palettes (T10 and XKCD)
- New parameters and classes in Trace, Legend, Layout
- Parameters description
- naming.md with decisions about parameters and methods names
- Error bars
- New scatter, contour, error plots examples
- Interfaces with common parameters for some plots (Histogram, Contour, Heatmap)
- New parameters for different plots
- Add Z axis
- Tutorial about drawing sinus
- Loading resources using krangl
- TraceValues extension for krangl columns
### Changed
- Migrated from `scientifik` to `kscience`
- Refactored packages to better suit star import style
- Removed bootstrap dependency
- Examples colors changed and more cases for each example added
- Different types of plots were inherited from Trace
- Unnecessary constructors removed
- Change Title methods
- Project structure updated
- Removed other Plot functions
- Plot2D renamed to Plot

126
plotly/README.md Normal file
View File

@ -0,0 +1,126 @@
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![DOI](https://zenodo.org/badge/186020000.svg)](https://zenodo.org/badge/latestdoi/186020000)
![Gradle build](https://github.com/mipt-npm/plotly.kt/workflows/Gradle%20build/badge.svg)
[![Kotlin JS IR supported](https://img.shields.io/badge/Kotlin%2FJS-IR%20supported-yellow)](https://kotl.in/jsirsupported)
![Plotlykt logo](./docs/logo_text.svg)
## Artifact details
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/plotlykt-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22%20AND%20a:%22plotlykt-core%22)
Dev builds and intermediate artifacts are available via `https://repo.kotlin.link` maven repository.
## Compatibility note
The current `$version` version of the library is compatible with kotlin 1.4 with JS-IR and kotlinx-serialization 1.1.0. The JVM part requires JVM 11 to run.
# TL;DR
See [examples](./examples/src/main/kotlin).
See [original library samples](https://plotly.com/javascript/) to understand capabilities.
# Description
This project is developed to allow simple access to plotly functionality from kotlin-multiplatform. The API allows to create plotly configuration and render it as a plotly chart.
The library supports three drawable plot objects:
* `Plot` itself stands for a stand-alone plot frame. It requires external infrastructure to load appropriate JavaScript libraries.
* `PlotFragment` is an HTML fragment possibly including several plots. The API for html is provided by [kotlinx-html](https://github.com/Kotlin/kotlinx.html) library.
* `PlotlyPage` is a complete page, including body fragment and page headers (needed to load JavaScript part of Plotly).
The work with plotly graphs could be rendered in following modes:
## HTML page export
(JVM and native) Export plot or page in a standalone html file, using CDN distribution or local JS file (JVM only). This mode does not support updates.
See [staticPlot](./examples/src/main/kotlin/staticPlot.kt) and
[customPage](./examples/src/main/kotlin/customPage.kt) for examples.
## Ktor-based server with dynamic updates
(JVM only) A Ktor CIO server with full multi-page and update capabilities.
See [simpleServer](./examples/src/main/kotlin/simpleServer.kt) and
[dynamicServer](./examples/src/main/kotlin/dynamicServer.kt) for examples.
## Kotlin-JS
Plotly is a JavaScript library, yet it is convenient to have a type-safe API when using in with Kotlin-JS. The sample application is available in [js-demo](./js-demo) module. One should node that Plotly.kt for JS is not a zero-cost wrapper like TypeScript definitions, it maintains its own object structure, could generate stand-alone models and some internal optimizations.
## JavaFX browser
Plotly.kt could be run in a JavaFX browser. An example project is presented in [fx-demo](./fx-demo).
## Kotlin jupyter kernel
Plotly.kt comes with (beta-version) support for integration with [Kotlin Jupyter kernel](https://github.com/Kotlin/kotlin-jupyter). See details [here](./docs/tutorials/jupyter.md).
The examples of the notebooks are shown in [notebooks](./examples/notebooks) directory. Plotly.kt uses Kotlin jupyter notebook API for integration (available in kernel version `0.8.3.236` and later). In order to load the library together with automatic imports one need to simply load a library in a following way:
```kotlin
@file:Repository("https://repo.kotlin.link")
@file:DependsOn("space.kscience:plotlykt-jupyter:$version")
//@file:DependsOn("space.kscience:plotlykt-server:$version") // Use this one for sever integration.
```
The module `plotly` allows rendering static plots in Jupyter. Jupyter lab is currently supported. Jupyter notebook (classic) is able to render only `PlotlyPage` objects, so one must convert plots to pages to be able to use notebook (see [demo notebook](./notebooks/plotlykt-demo-classic.ipynb)).
The module `plotly-server` adds server capabilities and allows to render dynamic plots in notebooks (see [demo notebook](./notebooks/plotlykt-server-demo.ipynb)). One must note that for dynamic pages, one must pass `renderer` parameter explicitly to plot like it is done in examples.
**IMPORTANT:** By default, Plotly-kt jupyter integration is configured to work with Jupyter Lab frontend, which renders all cells in the same page. Jupyter classic notebook and DataLore use cell isolation with iframes, so you will see blanks instead of plots. It could be fixed by switching into a notebook mode by running `Plotly.jupyter.notebook()` in a cell after plotly library is loaded.
## Direct image render via Orca (experimental)
[Plotly Orca](https://github.com/plotly/orca) application allows direct rendering of plots (not fragments or pages) to raster of vector images.
`Plot.export` extension could be used to call it. It requires for orca to be installed in the system and available on the system path.
## Kotlin-scripting (experimental)
It is possible to separate script logic into stand-alone `plotly.kts` script file and generate an html from the command line. See [plotlykt-script](./plotlykt-script) module for details.
## Kotlin/Native (experimental)
Plotly model now fully supports Kotlin/Native. It means that you can use it to create a proper Plotly-based HTML file. You will still need browser to view it. You can use [native-demo](./examples/native-demo) example.
# The feature I need is not implemented!
There are three ways to solve it:
1. Contribute! It is easy! Just add a model you need.
2. Create a model you need in your project or add an extension. Since the inner model is dynamic, you can add features on flight.
3. You can dynamically add missing features directly into configuration
like it done in [unsupportedFeature](./examples/src/main/kotlin/unsupportedFeature.kt) example.
# Build and usage
In order to use the library, one needs to use following `gradle.kts` configuration:
```kotlin
plugins {
kotlin("jvm")
}
repositories {
maven("https://repo.kotlin.link")
}
dependencies {
implementation("space.kscience:plotlykt-server:$version")
}
```
If you do not need the server, then use plotlykt-core instead.
# Naming
The library keeps original Plotly API naming wherever it is possible. There are some usability shortcuts, usually provided via kotlin extensions, included in order to simplify user interaction. For example, `text` and `shape` extensions in the top level API.
Keeping the original naming sometimes causes clashes with Kotlin code style. For example enum names are unorthodox.
# Planned features
* Table widgets
* Serverside plot events
* Online plot editor
* Dynamic data
* Mathjax and latex support
# Contributions and thanks
* [Vasily Chernov](https://research.jetbrains.org/researchers/vchernov) - initial project foundation
* [Alexander Nozik](https://research.jetbrains.org/researchers/altavir) - dynamic core and server
* [Mikhail Zeleniy](https://research.jetbrains.org/researchers/gama_sennin) - basic models
* [Ekaterina Samorodova](https://github.com/ebsamorodova) (JBR-2020 summer internship) - Model refactoring, tutorials and `0.2` release.
The project was partially founded by JetBrains Research grant.

8
plotly/build.gradle.kts Normal file
View File

@ -0,0 +1,8 @@
allprojects {
group = "space.kscience"
version = "0.7.2"
}
readme {
readmeTemplate = file("docs/templates/README-TEMPLATE.md")
}

Binary file not shown.

BIN
plotly/docs/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

250
plotly/docs/logo.svg Normal file
View File

@ -0,0 +1,250 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="logo_2.svg"
inkscape:version="1.0 (6e3e5246a0, 2020-05-07)"
id="svg8"
version="1.1"
viewBox="0 0 29.104165 29.104156"
height="29.104156mm"
width="29.104164mm">
<defs
id="defs2">
<linearGradient
id="linearGradient1618"
inkscape:collect="always">
<stop
id="stop1614"
offset="0"
style="stop-color:#806ee3;stop-opacity:1" />
<stop
id="stop1616"
offset="1"
style="stop-color:#00c3d5;stop-opacity:1" />
</linearGradient>
<rect
id="rect1524"
height="15.875"
width="48.947916"
y="7.9604866"
x="37.06465" />
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow1Lstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1122" />
</marker>
<linearGradient
gradientTransform="rotate(90,10.606316,10.60632)"
gradientUnits="userSpaceOnUse"
y2="21.189653"
x2="21.18965"
y1="0.022986634"
x1="21.18965"
id="linearGradient1620"
xlink:href="#linearGradient1618"
inkscape:collect="always" />
<linearGradient
gradientTransform="rotate(90,10.606316,10.60632)"
gradientUnits="userSpaceOnUse"
y2="21.189653"
x2="0.022983"
y1="0.022986634"
x1="0.022983"
id="linearGradient1638"
xlink:href="#linearGradient1618"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
inkscape:window-maximized="1"
inkscape:window-y="34"
inkscape:window-x="67"
inkscape:window-height="1018"
inkscape:window-width="1853"
showgrid="true"
inkscape:document-rotation="0"
inkscape:current-layer="layer2"
inkscape:document-units="mm"
inkscape:cy="50.040837"
inkscape:cx="61.969517"
inkscape:zoom="5.9388735"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base">
<inkscape:grid
originy="-125.67708"
originx="-59.531251"
id="grid843"
type="xygrid" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(3.945766,3.9457667)"
inkscape:label="Слой 2"
id="layer2"
inkscape:groupmode="layer">
<rect
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
ry="1.0272725e-05"
rx="1.0272725e-05"
y="-3.9457667"
x="-3.945766"
height="29.104156"
width="29.104164"
id="rect1494"
style="fill:#ffffff;fill-rule:evenodd;stroke-width:0.264583" />
<path
id="path1612"
d="M 21.189649,21.189653 H 0.02298279 V 0.02298679 Z"
style="fill:url(#linearGradient1620);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path1630"
d="M 21.189649,0.02298679 0.02298279,21.189653 V 0.02298679 Z"
style="fill:url(#linearGradient1638);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<g
transform="translate(-59.531252,-125.67708)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Слой 1">
<rect
transform="rotate(-89.858546)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
y="63.831543"
x="-150.6329"
height="21.166674"
width="21.166664"
id="rect845"
style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ellipse
transform="matrix(0.00254488,-0.99999676,0.99999713,0.00239507,0,0)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
ry="1.3434278"
rx="1.2960323"
cy="83.69519"
cx="-134.73538"
id="path853"
style="fill:#00c3d5;fill-opacity:1;stroke:#00c3d5;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ellipse
transform="matrix(0.00251442,-0.99999684,0.99999706,0.00242408,0,0)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="fill:#00c3d5;fill-opacity:1;stroke:none;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path853-3"
cx="-145.31732"
cy="83.716812"
rx="1.323424"
ry="1.3351575" />
<ellipse
transform="matrix(0.0024009,-0.99999712,0.99999678,0.00253869,0,0)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="fill:#00c3d5;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path853-6"
cx="-140.06395"
cy="83.702271"
rx="1.3443971"
ry="1.2951746" />
<ellipse
transform="matrix(-0.00258022,0.99999667,-0.99999721,-0.00236228,0,0)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="fill:#00c3d5;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path853-7"
cx="140.02629"
cy="-79.456383"
rx="1.3054924"
ry="1.3265911" />
<rect
transform="rotate(0.141454)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
rx="1.3229166"
ry="1.3228887"
y="146.68326"
x="65.185257"
height="2.6457775"
width="14.552083"
id="rect1120-6-2"
style="mix-blend-mode:normal;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264999;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke" />
<rect
transform="rotate(0.141454)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
rx="1.3229166"
ry="1.3228887"
y="130.77238"
x="65.146019"
height="2.6457775"
width="14.552083"
id="rect1120-6-9"
style="mix-blend-mode:normal;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264999;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke" />
<rect
transform="rotate(0.141454)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="mix-blend-mode:normal;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264999;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke"
id="rect1120-6-9-9"
width="10.583334"
height="2.6457775"
x="65.155861"
y="134.77705"
ry="1.3228887"
rx="1.3229166" />
<rect
transform="rotate(0.141454)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="mix-blend-mode:normal;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264999;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke"
id="rect1120-6-9-3"
width="10.583334"
height="2.6457775"
x="65.175453"
y="142.71452"
ry="1.3228887"
rx="1.3229166" />
<rect
transform="rotate(0.141454)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="mix-blend-mode:normal;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264998;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke"
id="rect1120-6-9-6"
width="6.6145844"
height="2.6458383"
x="65.165657"
y="138.74579"
ry="1.3228886"
rx="1.3229166" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.3 KiB

263
plotly/docs/logo_text.svg Normal file
View File

@ -0,0 +1,263 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/home/katsam/plotly_pictures/logo_text.png"
sodipodi:docname="logo_text.svg"
inkscape:version="1.0 (6e3e5246a0, 2020-05-07)"
id="svg8"
version="1.1"
viewBox="0 0 144.19792 41.010418"
height="41.010418mm"
width="144.19791mm">
<defs
id="defs2">
<rect
x="27.804234"
y="-1.29993"
width="110.37238"
height="34.123283"
id="rect40" />
<linearGradient
id="linearGradient1618"
inkscape:collect="always">
<stop
id="stop1614"
offset="0"
style="stop-color:#806ee3;stop-opacity:1" />
<stop
id="stop1616"
offset="1"
style="stop-color:#00c3d5;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientTransform="rotate(90,10.606316,10.60632)"
gradientUnits="userSpaceOnUse"
y2="21.189653"
x2="21.18965"
y1="0.022986634"
x1="21.18965"
id="linearGradient1620"
xlink:href="#linearGradient1618"
inkscape:collect="always" />
<linearGradient
gradientTransform="rotate(90,10.606316,10.60632)"
gradientUnits="userSpaceOnUse"
y2="21.189653"
x2="0.022983"
y1="0.022986634"
x1="0.022983"
id="linearGradient1638"
xlink:href="#linearGradient1618"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
inkscape:window-maximized="1"
inkscape:window-y="34"
inkscape:window-x="67"
inkscape:window-height="1018"
inkscape:window-width="1853"
showgrid="true"
inkscape:document-rotation="0"
inkscape:current-layer="layer3"
inkscape:document-units="mm"
inkscape:cy="-28.867052"
inkscape:cx="373.38531"
inkscape:zoom="1.7069031"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
inkscape:snap-text-baseline="false">
<inkscape:grid
originy="-121.70833"
originx="-55.562519"
id="grid843"
type="xygrid" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Слой 3"
transform="translate(3.9687517,3.9687471)">
<rect
style="fill:#ffffff;fill-rule:evenodd;stroke-width:0.264584"
id="rect873"
width="144.19791"
height="41.010418"
x="-3.9687517"
y="-3.9687471" />
</g>
<g
transform="translate(7.9145176,7.9145034)"
inkscape:label="Слой 2"
id="layer2"
inkscape:groupmode="layer">
<rect
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
ry="1.0272725e-05"
rx="1.0272725e-05"
y="-3.9457667"
x="-3.945766"
height="29.104156"
width="29.104164"
id="rect1494"
style="fill:#ffffff;fill-rule:evenodd;stroke-width:0.264583" />
<path
id="path1612"
d="M 21.189649,21.189653 H 0.02298279 V 0.02298679 Z"
style="fill:url(#linearGradient1620);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path1630"
d="M 21.189649,0.02298679 0.02298279,21.189653 V 0.02298679 Z"
style="fill:url(#linearGradient1638);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<text
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
xml:space="preserve"
id="text38"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.4px;line-height:1.25;font-family:Norasi;-inkscape-font-specification:'Norasi, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;white-space:pre;shape-inside:url(#rect40);fill:#5e4cbf;fill-opacity:1;stroke:#5e3a93;stroke-width:0.402811;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;"
transform="matrix(1.2597546,0,0,1.223073,-10.154695,-6.4045632)"><tspan
x="27.804688"
y="22.194218"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.4px;font-family:Norasi;-inkscape-font-specification:'Norasi, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#5e4cbf;fill-opacity:1;stroke:#5e4cbf;stroke-width:0.402811;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill">Plotly.kt</tspan></tspan></text>
</g>
<g
transform="translate(-55.5625,-121.70834)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Слой 1">
<rect
transform="rotate(-89.858546)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
y="63.831543"
x="-150.6329"
height="21.166674"
width="21.166664"
id="rect845"
style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ellipse
transform="matrix(0.00254488,-0.99999676,0.99999713,0.00239507,-4.0844967e-8,0)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
ry="1.3434278"
rx="1.2960323"
cy="83.69519"
cx="-134.73538"
id="path853"
style="fill:#00c3d5;fill-opacity:1;stroke:#00c3d5;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ellipse
transform="matrix(0.00251442,-0.99999684,0.99999706,0.00242408,-4.0844967e-8,0)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="fill:#00c3d5;fill-opacity:1;stroke:none;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path853-3"
cx="-145.31732"
cy="83.716812"
rx="1.323424"
ry="1.3351575" />
<ellipse
transform="matrix(0.0024009,-0.99999712,0.99999678,0.00253869,-4.0844967e-8,0)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="fill:#00c3d5;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path853-6"
cx="-140.06395"
cy="83.702271"
rx="1.3443971"
ry="1.2951746" />
<ellipse
transform="matrix(-0.00258022,0.99999667,-0.99999721,-0.00236228,-4.0844967e-8,0)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="fill:#00c3d5;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path853-7"
cx="140.02629"
cy="-79.456383"
rx="1.3054924"
ry="1.3265911" />
<rect
transform="rotate(0.141454)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
rx="1.3229166"
ry="1.3228887"
y="146.68326"
x="65.185257"
height="2.6457775"
width="14.552083"
id="rect1120-6-2"
style="mix-blend-mode:normal;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264999;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke" />
<rect
transform="rotate(0.141454)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
rx="1.3229166"
ry="1.3228887"
y="130.77238"
x="65.146019"
height="2.6457775"
width="14.552083"
id="rect1120-6-9"
style="mix-blend-mode:normal;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264999;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke" />
<rect
transform="rotate(0.141454)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="mix-blend-mode:normal;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264999;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke"
id="rect1120-6-9-9"
width="10.583334"
height="2.6457775"
x="65.155861"
y="134.77705"
ry="1.3228887"
rx="1.3229166" />
<rect
transform="rotate(0.141454)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="mix-blend-mode:normal;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264999;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke"
id="rect1120-6-9-3"
width="10.583334"
height="2.6457775"
x="65.175453"
y="142.71452"
ry="1.3228887"
rx="1.3229166" />
<rect
transform="rotate(0.141454)"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
style="mix-blend-mode:normal;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264998;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke"
id="rect1120-6-9-6"
width="6.6145844"
height="2.6458383"
x="65.165657"
y="138.74579"
ry="1.3228886"
rx="1.3229166" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.8 KiB

259
plotly/docs/models.uml Normal file
View File

@ -0,0 +1,259 @@
<?xml version="1.0" encoding="UTF-8"?>
<Diagram>
<ID>JAVA</ID>
<OriginalElement>kscience.plotly.models</OriginalElement>
<nodes>
<node x="1679.0" y="1764.0">kscience.plotly.models.Contours</node>
<node x="294.0" y="2467.0">kscience.plotly.models.ShapeType</node>
<node x="840.0" y="2393.0">kscience.plotly.models.TextPosition</node>
<node x="1645.0" y="2393.0">kscience.plotly.models.MeasureMode</node>
<node x="0.0" y="2541.0">kscience.plotly.models.BoxMode</node>
<node x="1127.0" y="2541.0">kscience.plotly.models.Ticks</node>
<node x="868.0" y="2251.0">kscience.plotly.models.Cumulative</node>
<node x="1591.0" y="2251.0">kscience.plotly.models.LegendOrientation</node>
<node x="1001.0" y="2393.0">kscience.plotly.models.ViolinPoints</node>
<node x="1896.0" y="1764.0">kscience.plotly.models.Margin</node>
<node x="242.0" y="2251.0">kscience.plotly.models.SelectMarker</node>
<node x="0.0" y="2393.0">kscience.plotly.models.VerticalAlign</node>
<node x="168.0" y="2393.0">kscience.plotly.models.ShapeSizeMode</node>
<node x="126.0" y="2541.0">kscience.plotly.models.BoxMean</node>
<node x="1510.0" y="1764.0">kscience.plotly.models.Title</node>
<node x="117.0" y="1764.0">kscience.plotly.models.Line</node>
<node x="1578.75" y="1211.0">kscience.plotly.models.Heatmap</node>
<node x="1060.0" y="2251.0">kscience.plotly.models.SelectPoints</node>
<node x="1414.0" y="2467.0">kscience.plotly.models.AxisType</node>
<node x="1341.1291666666666" y="440.0">kscience.plotly.models.HeatmapContour</node>
<node x="434.0" y="2467.0">kscience.plotly.models.GroupNorm</node>
<node x="712.1125" y="0.0">kscience.plotly.models.Trace</node>
<node x="1547.0" y="2467.0">kscience.plotly.models.FillType</node>
<node x="574.0" y="2467.0">kscience.plotly.models.StackGaps</node>
<node x="2261.0" y="2393.0">kscience.plotly.models.ShapeLayer</node>
<node x="1273.0" y="1764.0">kscience.plotly.models.Legend</node>
<node x="2408.0" y="2393.0">kscience.plotly.models.BoxHoveron</node>
<node x="2621.25" y="0.0">kscience.plotly.models.Shape</node>
<node x="336.0" y="2393.0">kscience.plotly.models.ShapeFillRule</node>
<node x="1680.0" y="2467.0">kscience.plotly.models.TickMode</node>
<node x="252.0" y="2541.0">kscience.plotly.models.YAnchor</node>
<node x="520.0" y="1167.0">kscience.plotly.models.Bar</node>
<node x="1207.3625" y="1233.0">kscience.plotly.models.ContourSpec</node>
<node x="1162.0" y="2393.0">kscience.plotly.models.GradientType</node>
<node x="332.5" y="1634.0">kscience.plotly.models.ScatterGL</node>
<node x="1388.0" y="2251.0">kscience.plotly.models.HistogramDirection</node>
<node x="1084.4208333333333" y="1578.0">kscience.plotly.models.Contour</node>
<node x="1323.0" y="2393.0">kscience.plotly.models.PieDirection</node>
<node x="1246.0" y="2251.0">kscience.plotly.models.Color</node>
<node x="1484.0" y="2393.0">kscience.plotly.models.ContoursType</node>
<node x="2555.0" y="2393.0">kscience.plotly.models.CurrentBin</node>
<node x="2225.25" y="0.0">kscience.plotly.models.Layout</node>
<node x="2083.0" y="1764.0">kscience.plotly.models.TraceValues</node>
<node x="260.0" y="1167.0">kscience.plotly.models.Scatter</node>
<node x="234.0" y="1977.0">kscience.plotly.models.LayoutLine</node>
<node x="2340.0" y="2251.0">kscience.plotly.models.ScatterHoveron</node>
<node x="202.36249999999995" y="429.0">kscience.plotly.models.SelectedPoints</node>
<node x="714.0" y="2467.0">kscience.plotly.models.ErrorType</node>
<node x="854.0" y="2467.0">kscience.plotly.models.HoverMode</node>
<node x="2702.0" y="2393.0">kscience.plotly.models.ViolinSide</node>
<node x="493.0" y="1764.0">kscience.plotly.models.ColorBar</node>
<node x="378.0" y="2541.0">kscience.plotly.models.BarNorm</node>
<node x="2614.0" y="1764.0">kscience.plotly.models.Domain</node>
<node x="0.0" y="1035.0">kscience.plotly.models.Box</node>
<node x="0.0" y="1911.0">kscience.plotly.models.MarkerLine</node>
<node x="504.0" y="2393.0">kscience.plotly.models.ConstrainText</node>
<node x="1285.7375" y="1600.0">kscience.plotly.models.Histogram2DContour</node>
<node x="405.0" y="2251.0">kscience.plotly.models.ViolinBox</node>
<node x="0.0" y="2467.0">kscience.plotly.models.TraceOrder</node>
<node x="1677.0875" y="1600.0">kscience.plotly.models.Histogram2D</node>
<node x="1799.0" y="2393.0">kscience.plotly.models.Orientation</node>
<node x="1919.25" y="0.0">kscience.plotly.models.Axis</node>
<node x="504.0" y="2541.0">kscience.plotly.models.TraceKt</node>
<node x="1002.0" y="1764.0">kscience.plotly.models.Error</node>
<node x="1953.0" y="2393.0">kscience.plotly.models.ZsmoothType</node>
<node x="630.0" y="2541.0">kscience.plotly.models.XAnchor</node>
<node x="727.0" y="1764.0">kscience.plotly.models.Marker</node>
<node x="1239.0" y="2541.0">kscience.plotly.models.Dash</node>
<node x="756.0" y="2541.0">kscience.plotly.models.BarMode</node>
<node x="1005.0" y="1156.0">kscience.plotly.models.Violin</node>
<node x="1976.0" y="2251.0">kscience.plotly.models.ViolinScaleMode</node>
<node x="994.0" y="2467.0">kscience.plotly.models.TraceType</node>
<node x="1787.0" y="2251.0">kscience.plotly.models.ContoursColoring</node>
<node x="1008.0" y="2541.0">kscience.plotly.models.Symbol</node>
<node x="1813.0" y="2467.0">kscience.plotly.models.Calendar</node>
<node x="781.0" y="1167.0">kscience.plotly.models.Pie</node>
<node x="1134.0" y="2467.0">kscience.plotly.models.BoxPoints</node>
<node x="1344.0" y="2541.0">kscience.plotly.models.Ref</node>
<node x="147.0" y="2467.0">kscience.plotly.models.ViolinMode</node>
<node x="882.0" y="2541.0">kscience.plotly.models.Visible</node>
<node x="0.0" y="2251.0">kscience.plotly.models.Gradient</node>
<node x="562.0" y="2251.0">kscience.plotly.models.MeanLine</node>
<node x="2430.25" y="0.0">kscience.plotly.models.Text</node>
<node x="1562.0875" y="1634.0">kscience.plotly.models.HeatmapGL</node>
<node x="1722.25" y="429.0">kscience.plotly.models.Table2D</node>
<node x="1373.75" y="1145.0">kscience.plotly.models.Histogram</node>
<node x="1946.0" y="2467.0">kscience.plotly.models.SizeMode</node>
<node x="2515.0" y="2251.0">kscience.plotly.models.QuartileMethod</node>
<node x="1274.0" y="2467.0">kscience.plotly.models.LineShape</node>
<node x="2158.0" y="2251.0">kscience.plotly.models.HorizontalAlign</node>
<node x="2361.0" y="1764.0">kscience.plotly.models.Font</node>
<node x="2079.0" y="2467.0">kscience.plotly.models.HistFunc</node>
<node x="2107.0" y="2393.0">kscience.plotly.models.ScatterMode</node>
<node x="719.0" y="2251.0">kscience.plotly.models.Bins</node>
<node x="672.0" y="2393.0">kscience.plotly.models.ViolinHoveron</node>
<node x="2212.0" y="2467.0">kscience.plotly.models.HistNorm</node>
<node x="2345.0" y="2467.0">kscience.plotly.models.TextInfo</node>
<node x="2478.0" y="2467.0">kscience.plotly.models.DataType</node>
<node x="2611.0" y="2467.0">kscience.plotly.models.SpanMode</node>
</nodes>
<notes />
<edges>
<edge source="kscience.plotly.models.LayoutLine" target="kscience.plotly.models.Line">
<point x="0.0" y="-81.5" />
<point x="341.0" y="1886.0" />
<point x="277.5" y="1886.0" />
<point x="53.5" y="48.5" />
</edge>
<edge source="kscience.plotly.models.Contour" target="kscience.plotly.models.Trace">
<point x="-47.33333333333337" y="-70.5" />
<point x="1108.0875" y="1558.0" />
<point x="770.5" y="1558.0" />
<point x="770.5" y="1015.0" />
<point x="814.4875" y="1015.0" />
<point x="-14.625" y="477.5" />
</edge>
<edge source="kscience.plotly.models.Histogram" target="kscience.plotly.models.Trace">
<point x="0.0" y="-136.5" />
<point x="1466.25" y="995.0" />
<point x="902.2375000000002" y="995.0" />
<point x="73.12500000000011" y="477.5" />
</edge>
<edge source="kscience.plotly.models.Scatter" target="kscience.plotly.models.Trace">
<point x="60.0" y="-114.5" />
<point x="440.0" y="995.0" />
<point x="755.9875" y="995.0" />
<point x="-73.125" y="477.5" />
</edge>
<edge source="kscience.plotly.models.Contour" target="kscience.plotly.models.HeatmapContour">
<point x="0.0" y="-70.5" />
<point x="1155.4208333333333" y="1558.0" />
<point x="1194.5" y="1558.0" />
<point x="1194.5" y="1015.0" />
<point x="1373.6291666666666" y="1015.0" />
<point x="-32.5" y="37.5" />
</edge>
<edge source="kscience.plotly.models.Histogram2D" target="kscience.plotly.models.Histogram">
<point x="-38.0" y="-48.5" />
<point x="1715.0875" y="1548.0" />
<point x="1512.5" y="1548.0" />
<point x="46.25" y="136.5" />
</edge>
<edge source="kscience.plotly.models.Pie" target="kscience.plotly.models.Trace">
<point x="0.0" y="-114.5" />
<point x="883.0" y="1015.0" />
<point x="843.7375" y="1015.0" />
<point x="14.625" y="477.5" />
</edge>
<edge source="kscience.plotly.models.Bar" target="kscience.plotly.models.Trace">
<point x="60.0" y="-114.5" />
<point x="700.0" y="1005.0" />
<point x="785.2375" y="1005.0" />
<point x="-43.875" y="477.5" />
</edge>
<edge source="kscience.plotly.models.Histogram2DContour" target="kscience.plotly.models.ContourSpec">
<point x="-39.5" y="-48.5" />
<point x="1325.2375" y="1558.0" />
<point x="1313.8625" y="1558.0" />
<point x="35.5" y="48.5" />
</edge>
<edge source="kscience.plotly.models.Histogram2DContour" target="kscience.plotly.models.Histogram">
<point x="39.5" y="-48.5" />
<point x="1404.2375" y="1558.0" />
<point x="1420.0" y="1558.0" />
<point x="-46.25" y="136.5" />
</edge>
<edge source="kscience.plotly.models.Box" target="kscience.plotly.models.SelectedPoints">
<point x="-60.0" y="-246.5" />
<point x="60.0" y="975.0" />
<point x="242.36249999999995" y="975.0" />
<point x="-80.0" y="48.5" />
</edge>
<edge source="kscience.plotly.models.Heatmap" target="kscience.plotly.models.HeatmapContour">
<point x="0.0" y="-70.5" />
<point x="1654.75" y="975.0" />
<point x="1438.6291666666666" y="975.0" />
<point x="32.5" y="37.5" />
</edge>
<edge source="kscience.plotly.models.Histogram2D" target="kscience.plotly.models.Table2D">
<point x="38.0" y="-48.5" />
<point x="1791.0875" y="1558.0" />
<point x="1832.9875" y="1558.0" />
<point x="1832.9875" y="1015.0" />
<point x="1836.25" y="1015.0" />
<point x="38.0" y="48.5" />
</edge>
<edge source="kscience.plotly.models.Scatter" target="kscience.plotly.models.SelectedPoints">
<point x="-60.0" y="-114.5" />
<point x="320.0" y="975.0" />
<point x="322.36249999999995" y="975.0" />
<point x="0.0" y="48.5" />
</edge>
<edge source="kscience.plotly.models.Box" target="kscience.plotly.models.Trace">
<point x="60.0" y="-246.5" />
<point x="180.0" y="985.0" />
<point x="726.7375" y="985.0" />
<point x="-102.375" y="477.5" />
</edge>
<edge source="kscience.plotly.models.Contour" target="kscience.plotly.models.ContourSpec">
<point x="47.33333333333337" y="-70.5" />
<point x="1202.7541666666666" y="1558.0" />
<point x="1242.8625" y="1558.0" />
<point x="-35.5" y="48.5" />
</edge>
<edge source="kscience.plotly.models.MarkerLine" target="kscience.plotly.models.Line">
<point x="0.0" y="-147.5" />
<point x="107.0" y="1886.0" />
<point x="170.5" y="1886.0" />
<point x="-53.5" y="48.5" />
</edge>
<edge source="kscience.plotly.models.Bar" target="kscience.plotly.models.SelectedPoints">
<point x="-60.0" y="-114.5" />
<point x="580.0" y="975.0" />
<point x="402.36249999999995" y="975.0" />
<point x="80.0" y="48.5" />
</edge>
<edge source="kscience.plotly.models.ScatterGL" target="kscience.plotly.models.Scatter">
<point x="0.0" y="-14.5" />
<point x="0.0" y="114.5" />
</edge>
<edge source="kscience.plotly.models.Heatmap" target="kscience.plotly.models.Table2D">
<point x="50.666666666666686" y="-70.5" />
<point x="1705.4166666666667" y="1015.0" />
<point x="1760.25" y="1015.0" />
<point x="-38.0" y="48.5" />
</edge>
<edge source="kscience.plotly.models.Violin" target="kscience.plotly.models.Trace">
<point x="1.1368683772161603E-13" y="-125.5" />
<point x="1094.5" y="1005.0" />
<point x="872.9875" y="1005.0" />
<point x="43.875" y="477.5" />
</edge>
<edge source="kscience.plotly.models.Heatmap" target="kscience.plotly.models.Trace">
<point x="-50.66666666666666" y="-70.5" />
<point x="1604.0833333333335" y="985.0" />
<point x="931.4875000000002" y="985.0" />
<point x="102.37500000000011" y="477.5" />
</edge>
<edge source="kscience.plotly.models.HeatmapGL" target="kscience.plotly.models.Heatmap">
<point x="0.0" y="-14.5" />
<point x="1609.5875" y="1558.0" />
<point x="1654.75" y="1558.0" />
<point x="0.0" y="70.5" />
</edge>
</edges>
<settings layout="Hierarchic Group" zoom="0.8575289575289575" x="848.7753264295362" y="519.9234579018461" />
<SelectedNodes />
<Categories>
<Category>Properties</Category>
</Categories>
<SCOPE>All</SCOPE>
<VISIBILITY>private</VISIBILITY>
</Diagram>

467
plotly/docs/overview.html Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,29 @@
> #### Artifact:
>
> This module artifact: `${group}:${name}:${version}`.
>
>
> [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/${name}.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22%20AND%20a:%22${name}%22)
>
> **Gradle:**
>
> ```gradle
> repositories {
> maven { url 'https://repo.kotlin.link' }
> }
>
> dependencies {
> implementation '${group}:${name}:${version}'
> }
> ```
> **Gradle Kotlin DSL:**
>
> ```kotlin
> repositories {
> maven("https://https://repo.kotlin.link")
> }
>
> dependencies {
> implementation("${group}:${name}:${version}")
> }
> ```

126
plotly/docs/templates/README-TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,126 @@
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![DOI](https://zenodo.org/badge/186020000.svg)](https://zenodo.org/badge/latestdoi/186020000)
![Gradle build](https://github.com/mipt-npm/plotly.kt/workflows/Gradle%20build/badge.svg)
[![Kotlin JS IR supported](https://img.shields.io/badge/Kotlin%2FJS-IR%20supported-yellow)](https://kotl.in/jsirsupported)
![Plotlykt logo](./docs/logo_text.svg)
## Artifact details
[![Maven Central](https://img.shields.io/maven-central/v/space.kscience/plotlykt-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22%20AND%20a:%22plotlykt-core%22)
Dev builds and intermediate artifacts are available via `https://repo.kotlin.link` maven repository.
## Compatibility note
The current `$version` version of the library is compatible with kotlin 1.4 with JS-IR and kotlinx-serialization 1.1.0. The JVM part requires JVM 11 to run.
# TL;DR
See [examples](./examples/src/main/kotlin).
See [original library samples](https://plotly.com/javascript/) to understand capabilities.
# Description
This project is developed to allow simple access to plotly functionality from kotlin-multiplatform. The API allows to create plotly configuration and render it as a plotly chart.
The library supports three drawable plot objects:
* `Plot` itself stands for a stand-alone plot frame. It requires external infrastructure to load appropriate JavaScript libraries.
* `PlotFragment` is an HTML fragment possibly including several plots. The API for html is provided by [kotlinx-html](https://github.com/Kotlin/kotlinx.html) library.
* `PlotlyPage` is a complete page, including body fragment and page headers (needed to load JavaScript part of Plotly).
The work with plotly graphs could be rendered in following modes:
## HTML page export
(JVM and native) Export plot or page in a standalone html file, using CDN distribution or local JS file (JVM only). This mode does not support updates.
See [staticPlot](./examples/src/main/kotlin/staticPlot.kt) and
[customPage](./examples/src/main/kotlin/customPage.kt) for examples.
## Ktor-based server with dynamic updates
(JVM only) A Ktor CIO server with full multi-page and update capabilities.
See [simpleServer](./examples/src/main/kotlin/simpleServer.kt) and
[dynamicServer](./examples/src/main/kotlin/dynamicServer.kt) for examples.
## Kotlin-JS
Plotly is a JavaScript library, yet it is convenient to have a type-safe API when using in with Kotlin-JS. The sample application is available in [js-demo](./js-demo) module. One should node that Plotly.kt for JS is not a zero-cost wrapper like TypeScript definitions, it maintains its own object structure, could generate stand-alone models and some internal optimizations.
## JavaFX browser
Plotly.kt could be run in a JavaFX browser. An example project is presented in [fx-demo](./fx-demo).
## Kotlin jupyter kernel
Plotly.kt comes with (beta-version) support for integration with [Kotlin Jupyter kernel](https://github.com/Kotlin/kotlin-jupyter). See details [here](./docs/tutorials/jupyter.md).
The examples of the notebooks are shown in [notebooks](./examples/notebooks) directory. Plotly.kt uses Kotlin jupyter notebook API for integration (available in kernel version `0.8.3.236` and later). In order to load the library together with automatic imports one need to simply load a library in a following way:
```kotlin
@file:Repository("https://repo.kotlin.link")
@file:DependsOn("space.kscience:plotlykt-jupyter:$version")
//@file:DependsOn("space.kscience:plotlykt-server:$version") // Use this one for sever integration.
```
The module `plotly` allows rendering static plots in Jupyter. Jupyter lab is currently supported. Jupyter notebook (classic) is able to render only `PlotlyPage` objects, so one must convert plots to pages to be able to use notebook (see [demo notebook](./notebooks/plotlykt-demo-classic.ipynb)).
The module `plotly-server` adds server capabilities and allows to render dynamic plots in notebooks (see [demo notebook](./notebooks/plotlykt-server-demo.ipynb)). One must note that for dynamic pages, one must pass `renderer` parameter explicitly to plot like it is done in examples.
**IMPORTANT:** By default, Plotly-kt jupyter integration is configured to work with Jupyter Lab frontend, which renders all cells in the same page. Jupyter classic notebook and DataLore use cell isolation with iframes, so you will see blanks instead of plots. It could be fixed by switching into a notebook mode by running `Plotly.jupyter.notebook()` in a cell after plotly library is loaded.
## Direct image render via Orca (experimental)
[Plotly Orca](https://github.com/plotly/orca) application allows direct rendering of plots (not fragments or pages) to raster of vector images.
`Plot.export` extension could be used to call it. It requires for orca to be installed in the system and available on the system path.
## Kotlin-scripting (experimental)
It is possible to separate script logic into stand-alone `plotly.kts` script file and generate an html from the command line. See [plotlykt-script](./plotlykt-script) module for details.
## Kotlin/Native (experimental)
Plotly model now fully supports Kotlin/Native. It means that you can use it to create a proper Plotly-based HTML file. You will still need browser to view it. You can use [native-demo](./examples/native-demo) example.
# The feature I need is not implemented!
There are three ways to solve it:
1. Contribute! It is easy! Just add a model you need.
2. Create a model you need in your project or add an extension. Since the inner model is dynamic, you can add features on flight.
3. You can dynamically add missing features directly into configuration
like it done in [unsupportedFeature](./examples/src/main/kotlin/unsupportedFeature.kt) example.
# Build and usage
In order to use the library, one needs to use following `gradle.kts` configuration:
```kotlin
plugins {
kotlin("jvm")
}
repositories {
maven("https://repo.kotlin.link")
}
dependencies {
implementation("space.kscience:plotlykt-server:$version")
}
```
If you do not need the server, then use plotlykt-core instead.
# Naming
The library keeps original Plotly API naming wherever it is possible. There are some usability shortcuts, usually provided via kotlin extensions, included in order to simplify user interaction. For example, `text` and `shape` extensions in the top level API.
Keeping the original naming sometimes causes clashes with Kotlin code style. For example enum names are unorthodox.
# Planned features
* Table widgets
* Serverside plot events
* Online plot editor
* Dynamic data
* Mathjax and latex support
# Contributions and thanks
* [Vasily Chernov](https://research.jetbrains.org/researchers/vchernov) - initial project foundation
* [Alexander Nozik](https://research.jetbrains.org/researchers/altavir) - dynamic core and server
* [Mikhail Zeleniy](https://research.jetbrains.org/researchers/gama_sennin) - basic models
* [Ekaterina Samorodova](https://github.com/ebsamorodova) (JBR-2020 summer internship) - Model refactoring, tutorials and `0.2` release.
The project was partially founded by JetBrains Research grant.

View File

@ -0,0 +1,220 @@
### How To Draw A Sinus?
In data visualization tasks, quite often there is a need to depict mathematical
functions - for example, to compare the convergence rate of a model
with ideal one or to find an approximation for a given time series. Such charts
have a number of features that are not inherent in most other charts: for example,
visualizing the perpendicular axes (OX, OY) from (0, 0) and a large number of
additional information. This can be the expected value of the function, its extremum
points, deviation at various points, etc.
This article will tell you how to depict an ordinary sinus using the library `Plotly.kt`
so that in the end you will get a visual and informative plot.
1. Let's start with drawing perpendicular OX and OY axes. This requires to do a few things:
hide default axes lines, hide zero lines (it's impossible to draw an arrow on the end of it),
add perpendicular arrows using annotations (`Text`) with visible arrows on the end, but without
text. After that, let's sign the axes themselves. It is also important to specify the required
chart sizes (`width`,` height`) so that after saving the graph will look the same as in the browser.
```kotlin
Plotly.page { // making new html page with plot
layout {
width = 900 // width of the plot (in px.)
height = 500 // height of the plot (in px.)
text { // vertical axis
x = Value.of(0) // position of the top end of the arrow = (0, 1+eps)
y = Value.of(1 + eps)
ax = Value.of(0) // ax, ay means the offset of the bottom edge relative to the top
ay = Value.of(430) // positive (negative) value is the arrow length
// upwards (top down) and from right to left (from left to right)
}
text { // horizontal axis
y = Value.of(0) // arrow left position = (2PI + eps, 0)
x = Value.of(2 * PI + eps)
ax = Value.of(-800) // position of the left end of the arrow
ay = Value.of(0)
}
xaxis { // OX parameters
showline = false // hide OX line
zeroline = false // hide zero line
}
yaxis { // OY parameters
showline = false // hide OY line
zeroline = false // hide zero line
}
}
}.makeFile() // making temporary file and visualing plot in the browser
```
2. Now we will draw the sinus function itself - for its visualization let's choose a bright blue color,
contrasting with both the white background and the black ticks on the axes. After that using
the variation of the `mode` parameter (` ScatterMode: lines, markers`) the intersection points with the OY axis
will be marked with a slightly darker shade of the same color.
```kotlin
x1 = (-410..410).map{ it / 200 * PI } // function domain (-2PI - eps, 2PI + eps)
y1 = sin(x1) // function values
Plotly.page {
scatter { // making Scatter plot (sinus)
x.set(x1) // assigning OX values
y.set(y1) // assigning OY values
line { color(XKCD.CERULEAN) } // color of the line is cerulean
}
scatter { // making Scatter plot (OX axis dots)
mode = ScatterMode.markers // visualizing only dots
x(-2* PI, -PI, PI, 2* PI) // points of intersection of sinus with OX (values along the X axis)
y(0, 0, 0, 0) // points of intersection of sinus with OX (values along the Y axis)
line { color(XKCD.CERULEAN_BLUE) } // color of the dots is darker cerulean
marker { size = 8 } // dot's diameter is 8 px.
}
layout { ... }
}.makeFile()
```
3. Let's draw horizontal dashed lines on the chart, corresponding to values equal to -1, 1 (extremum lines) and 1/2.
This requires changing `line.dash` parameter to `Dash.dash` value. The specified values will be plotted after that
on the OY axis using the `tickvals` and` ticklabels` parameters.
```kotlin
...
Plotly.page {
...
layout {
shape { // adding new figure (line y = 1)
x0 = Value.of(-2*PI) // (-2PI, 1) and (2PI, 1) coordinates
x1 = Value.of(2*PI) // will be connected by a line
y0 = Value.of(1)
y1 = Value.of(1)
line { dash = Dash.dash } // dashed type of the line
}
shape { // adding new figure (line y = 1/2)
x0 = Value.of(-2*PI) // coordinates (-2PI, 1/2) and (2PI, 1/2)
x1 = Value.of(2*PI) // will be connected by a line
y0 = Value.of(0.5)
y1 = Value.of(0.5)
line {
color("red") // red color of the line
dash = Dash.dash // dashed type of the line
}
}
shape { // adding new figure (line y = -1)
x0 = Value.of(-2*PI) // coordinates (-2PI, -1) and (2PI, -1)
x1 = Value.of(2*PI) // will be connected by a line
y0 = Value.of(-1)
y1 = Value.of(-1)
line { dash = Dash.dash } // dashed type of the line
}
...
}
}.makeFile()
```
4. After that, it is worth adding vertical lines connecting points on OX, the values in
which equals 1/2, and the value itself in LaTeX format. Shapes are used again for this - an array
values of type `Shape.line`. To use LaTeX format you need to include the `MathJax` header.
```kotlin
...
val sub = PI / 6
val xElems = listOf(-2PI + sub, -PI - sub, 0 + sub, PI - sub)
// points, where sinus equals 1/2
val shapesList = mutableListOf<Shape>() // making list of lines
for (x: xElems) {
val shape = Shape {
x0 = Value.of(x) // (x, 0) and (x, 0.5) will be connected
y0 = Value.of(0)
x1 = Value.of(x)
y0 = Value.of(1/2)
line { color("red") } // red color of the line
}
shapesList.add(shape) // adding new figure to the list
}
Plotly.page(mathJaxHeader, cdnPlotlyHeader) {
scatter { // add string "1/2"
mode = ScatterMode.text // visualing only text
x(-0.35) // text position on the OX axis
y(0.56) // text position on the OX axis
text = listOf("$\Large{1/2}$") // increasing font size with ТеХ
textfont { color("red") } // red color of the font
showlegend = false // do not show this trace in the legend
hoverinfo = "none" // do not show anything on hover
}
...
layout { // adding figure list to the plot
shapes = shapesList
...
}
}.makeFile()
```
5. It remains to add labels on OX corresponding to the intersections of the sinus with the axis. It
is done in a similar way, using axis labels (`tickvals`,` ticktext`) and writing text in LaTeX format.
```kotlin
...
Plolty.page(mathJaxHeader, cdnPlotlyHeader) {
...
layout {
xaxis { // OX axis parameters
...
anchor = "free" // axis position is set manually
position = 0.43 // assigning axis position
tickvals(listOf(-2 * PI-0.05, -PI - 0.15, PI - 0.05, 2 * PI + 0.1))
ticktext(listOf("\$\\huge{-2\\pi}\$", "\$\\huge{-\\pi}\$", "\$\\huge{\\pi}\$", "\$\\huge{2\\pi}\$"))
// ticks positions and text
}
yaxis { // OY axis parameters
...
anchor = "free" // axis position is set manually
position = 0.485 // assigning axis position
tickvals(listOf(-0.91, 0.09, 1.09))
ticktext(listOf("\$\\Large{-1}\$", "\$\\Large{0}\$", "\$\\Large{1}\$"))
// ticks positions and text
}
...
}
}.makeFile()
```
6. As a final improvement, let's add a legend to the plot, which will be placed in upper right corner of the graph.
First you need to set the name of the corresponding line, after which with using the parameters `xanchor = right`
and` yanchor = top` set the position of the legend so that the coordinates specified by the parameters
`x = 1`,` y = 1` correspond to the position in the upper right corner of the image.
```kotlin
...
Plotly.page(mathJaxHeader, cdnPlotlyHeader) {
scatter { // sinus Scatter trace
...
name = "\$\\Large{y = \\mathrm{sin}\\,x}\$"
// the name of the plot displayed in the legend
}
layout {
legend { // legend parameters
x = 0.97 // horizontal position of the legend
y = 1 // vertical position of the legend
borderwidth = 1 // width of the legend border
font { size = 32 } // size of the legend font
xanchor = XAnchor.right // "anchoring" the position of the legend to the right corner
yanchor = YAnchor.top // "anchoring" the position of the legend to the bottom of the graph
}
...
}
}.makeFile()
```
7. Final picture:
![Картинка](https://i.ibb.co/wKTCp4H/newplot-17.png)
Source code is available at: https://github.com/mipt-npm/plotly.kt/tree/dev/examples/src/main/kotlin/tutorials/SinusPicture.kt

View File

@ -0,0 +1,50 @@
# Plotly.kt Jupyter kernel integration
Being a JavaScript library with a Kotlin-JVM backend, Plotly.kt is ideally suited for [Jupyter kotlin kernel](https://github.com/Kotlin/kotlin-jupyter) integration. The integration is supported in two modes:
* Static rendering in [plotlykt-jupyter](../../plotlykt-jupyter) module.
* Dynamic updates processing via [plotlykt-server](../../plotlykt-server) module.
## Loading the library
* Install or update [Jupyter kotlin kernel](https://github.com/Kotlin/kotlin-jupyter) to version `0.9` or later.
* Launch kotlin kernel in `jupyter lab` (classic jupyter notebook is not supported).
* Use `@file:DependsOn("space.kscience:plotlykt-jupyter:$plotlyVersion")` annotation directive to load library, where `$plotlyVersion` is the required version of the library. This approach uses [Kotlin jupyter notebook API](https://github.com/Kotlin/kotlin-jupyter/blob/master/docs/libraries.md#Integration-using-Kotlin-API). For dynamic version one should replace `plotlykt-server` instead of `plotlykr-jupyter`.
* Alternatively one could use `%use plotly` [directive](https://github.com/Kotlin/kotlin-jupyter#supported-libraries). For dynamic version one should replace `plotly-server` instead of `plotly`.
## Automatic rendering
The integration automatically imports `space.kscience.plotlykt.*` and `space.kscience.plotlykt.models.*` and provides automatic rendering for three basic plotly objects: `Plot`, `PlotlyFragment` and `PlotlyPage`. One needs to return those object as result of last expressions in a cell in order to automatically render them.
## Dynamic update server
The dynamic server uses three-way communication to provide updates for the jupyter cell content:
* Jupyter kernel server
* Browser Plotly API (websockets)
* Ktor server which provides both static data and updates via web-sockets.
When the plot is placed into the page, its initial data is embedded into the page as plotly-compatible JSON alongside the path to data server and updates server.
The resulting HTML looks like this:
```html
<div id="space.kscience.plotly.Plot@502ed4cc">
<script>
makePlot(
'space.kscience.plotly.Plot@502ed4cc',
[/*plot data*/],
{/*layout*/},
{}
);
startPush('space.kscience.plotly.Plot@502ed4cc', 'ws://127.0.0.1:3872//ws/space.kscience.plotly.Plot@502ed4cc');
</script>
</div>
```
The changes in the back-end model are automatically collected and sent to the notebook with fixed intervals (if present).
The interval is `100 ms` by default and could be changed via `plotly.updateInterval = 200` line. The server is restarted on interval change.
The local port used for the server (default is `8882`) also could be changed via configuration object (`plotly.port = 8884`). After port change, all plots that use dynamic updates must be re-created to ensure they use correct update location.
## What about classic notebook?
At this moment only Jupyter lab is supported. Classic notebook does not work well because it does not allow loading JS resources globally after the notebook is started. We will research the possibility to support classic notebook as well as other IPython kernels in the future.

View File

@ -0,0 +1,4 @@
# Module examples

View File

@ -0,0 +1,44 @@
plugins {
kotlin("jvm")
}
repositories {
maven("https://repo.kotlin.link")
mavenCentral()
}
dependencies {
implementation(projects.plotly.plotlyktServer)
implementation(projects.plotly.plotlyktJupyter)
implementation(projects.plotly.plotlyktGeo)
implementation(projects.plotly.plotlyktScript)
implementation(kotlin("script-runtime"))
implementation("org.jetbrains.kotlinx:dataframe:0.13.1")
}
kotlin{
jvmToolchain(11)
}
// A workaround for https://youtrack.jetbrains.com/issue/KT-44101
val copyPlotlyResources by tasks.creating(Copy::class){
dependsOn(":plotly:plotlykt-core:jvmProcessResources")
mustRunAfter(":plotly:plotlykt-core:jvmTestProcessResources")
from(project(":plotly:plotlykt-core").layout.buildDirectory.file("processedResources/jvm"))
into(layout.buildDirectory.file("resources"))
}
tasks.getByName("classes").dependsOn(copyPlotlyResources)
//val runDynamicServer by tasks.creating(JavaExec::class){
// group = "run"
// classpath = sourceSets["main"].runtimeClasspath
// main = "DynamicServerKt"
//}
//
//val runCustomPage by tasks.creating(JavaExec::class){
// group = "run"
// classpath = sourceSets["main"].runtimeClasspath
// main = "CustomPageKt"
//}

View File

@ -0,0 +1,4 @@
# Module compose-demo

View File

@ -0,0 +1,26 @@
public final class space/kscience/plotly/compose/AppKt {
public static final fun App (Landroidx/compose/runtime/Composer;I)V
public static final fun main ()V
public static synthetic fun main ([Ljava/lang/String;)V
}
public final class space/kscience/plotly/compose/ComposableSingletons$AppKt {
public static final field INSTANCE Lspace/kscience/plotly/compose/ComposableSingletons$AppKt;
public static field lambda-1 Lkotlin/jvm/functions/Function3;
public static field lambda-2 Lkotlin/jvm/functions/Function3;
public static field lambda-3 Lkotlin/jvm/functions/Function2;
public static field lambda-4 Lkotlin/jvm/functions/Function3;
public static field lambda-5 Lkotlin/jvm/functions/Function3;
public fun <init> ()V
public final fun getLambda-1$compose_demo ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-2$compose_demo ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-3$compose_demo ()Lkotlin/jvm/functions/Function2;
public final fun getLambda-4$compose_demo ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-5$compose_demo ()Lkotlin/jvm/functions/Function3;
}
public final class space/kscience/plotly/compose/ServerKt {
public static final fun servePlots (Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/flow/StateFlow;)Lio/ktor/server/engine/ApplicationEngine;
public static final fun staticPlot ()Ljava/lang/String;
}

View File

@ -0,0 +1,43 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("multiplatform")
alias(spclibs.plugins.compose.compiler)
alias(spclibs.plugins.compose.jb)
}
repositories {
mavenCentral()
maven("https://repo.kotlin.link")
maven("https://jogamp.org/deployment/maven")
}
kotlin {
jvm()
jvmToolchain(17)
sourceSets {
jvmMain {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.desktop.currentOs)
implementation("io.github.kevinnzou:compose-webview-multiplatform:1.9.8")
implementation(projects.plotly.plotlyktServer)
implementation(spclibs.logback.classic)
}
}
}
}
tasks.withType<KotlinCompile> {
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
}
compose {
desktop {
application {
mainClass = "space.kscience.plotly.compose.AppKt"
}
}
}

View File

@ -0,0 +1,86 @@
package space.kscience.plotly.compose
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import com.multiplatform.webview.web.LoadingState
import com.multiplatform.webview.web.WebView
import com.multiplatform.webview.web.rememberWebViewNavigator
import com.multiplatform.webview.web.rememberWebViewStateWithHTMLData
import dev.datlag.kcef.KCEF
import kotlinx.coroutines.flow.MutableStateFlow
private val allowedPages = listOf(
"Static",
"Dynamic"
)
@Composable
fun App() {
val scaleFlow = remember { MutableStateFlow(1f) }
val scale by scaleFlow.collectAsState()
val scope = rememberCoroutineScope()
val server = remember {
scope.servePlots(scaleFlow)
}
val state = rememberWebViewStateWithHTMLData(staticPlot())
val navigator = rememberWebViewNavigator()
val loadingState = state.loadingState
if (loadingState is LoadingState.Loading) {
LinearProgressIndicator(
progress = loadingState.progress,
modifier = Modifier.fillMaxWidth()
)
}
Row(Modifier.fillMaxSize()) {
Column(Modifier.width(300.dp)) {
Button({ navigator.loadHtml(staticPlot()) }, modifier = Modifier.fillMaxWidth()) {
Text("Static")
}
Button({ navigator.loadUrl("http://localhost:7778/Dynamic") }, modifier = Modifier.fillMaxWidth()) {
Text("Dynamic")
}
Slider(
scale,
{ scaleFlow.value = it },
valueRange = 0.1f..10f,
modifier = Modifier.fillMaxWidth()
)
}
Column(Modifier.fillMaxSize()) {
WebView(
state = state,
navigator = navigator,
modifier = Modifier.fillMaxSize()
)
}
}
}
fun main() = application {
KCEF.initBlocking(
builder = {
progress {
onDownloading {
println("Download progress: $it%")
}
}
release(true)
}
)
Window(onCloseRequest = ::exitApplication) {
MaterialTheme {
App()
}
}
}

View File

@ -0,0 +1,92 @@
package space.kscience.plotly.compose
import io.ktor.server.engine.ApplicationEngine
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import space.kscience.plotly.*
import space.kscience.plotly.models.Scatter
import space.kscience.plotly.models.invoke
import space.kscience.plotly.server.pushUpdates
import space.kscience.plotly.server.serve
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
fun staticPlot(): String = Plotly.page {
val x = (0..100).map { it.toDouble() / 100.0 }.toDoubleArray()
val y1 = x.map { sin(2.0 * PI * it) }.toDoubleArray()
val y2 = x.map { cos(2.0 * PI * it) }.toDoubleArray()
val trace1 = Scatter(x, y1) {
name = "sin"
}
val trace2 = Scatter(x, y2) {
name = "cos"
}
plot(config = PlotlyConfig { responsive = true }) {//static plot
traces(trace1, trace2)
layout {
title = "First graph, row: 1, size: 8/12"
xaxis.title = "x axis name"
yaxis { title = "y axis name" }
}
}
}.render()
fun CoroutineScope.servePlots(scale: StateFlow<Number>): ApplicationEngine = Plotly.serve(this, port = 7778) {
page("Static") { container ->
val x = (0..100).map { it.toDouble() / 100.0 }.toDoubleArray()
val y1 = x.map { sin(2.0 * PI * it) }.toDoubleArray()
val y2 = x.map { cos(2.0 * PI * it) }.toDoubleArray()
val trace1 = Scatter(x, y1) {
name = "sin"
}
val trace2 = Scatter(x, y2) {
name = "cos"
}
plot(renderer = container) {//static plot
traces(trace1, trace2)
layout {
title = "First graph, row: 1, size: 8/12"
xaxis.title = "x axis name"
yaxis { title = "y axis name" }
}
}
}
page("Dynamic") { container ->
val x = (0..100).map { it.toDouble() / 100.0 }
val y = x.map { sin(2.0 * PI * it) }
val trace = Scatter(x, y) { name = "sin" }
val plot = plot("dynamic", config = PlotlyConfig { responsive = true }, renderer = container) {
traces(trace)
layout {
title = "Dynamic plot"
xaxis.title = "x axis name"
yaxis.title = "y axis name"
}
}
launch {
var time: Long = 0
while (isActive) {
delay(10)
time += 10
val frequency = scale.value.toDouble()
val dynamicY = x.map { sin(2.0 * PI * frequency * (it + time.toDouble() / 1000.0)) }
//trace.y.numbers = dynamicY
plot.data[0].y.numbers = dynamicY
plot.layout {
xaxis.title = "x axis name (t = $time)"
}
}
}
}
pushUpdates(100)
}

View File

@ -0,0 +1,4 @@
# Module fx-demo

View File

@ -0,0 +1,35 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
application
id("org.openjfx.javafxplugin") version "0.0.10"
}
repositories {
mavenCentral()
maven("https://repo.kotlin.link")
}
dependencies {
implementation(project(":plotly:plotlykt-server"))
implementation("no.tornado:tornadofx:1.7.20")
implementation(spclibs.logback.classic)
}
javafx{
modules("javafx.web")
version = "11"
}
application {
mainClass.set("space.kscience.plotly.fx.PlotlyFXAppKt")
}
kotlin{
jvmToolchain(11)
}
tasks.withType<KotlinCompile> {
kotlinOptions.freeCompilerArgs = kotlinOptions.freeCompilerArgs +"-Xopt-in=kotlin.RequiresOptIn"
}

View File

@ -0,0 +1,71 @@
package space.kscience.plotly.fx
import javafx.beans.property.SimpleBooleanProperty
import javafx.scene.control.SelectionMode
import tornadofx.*
class PlotlyApp : App(PlotlyView::class)
fun main(args: Array<String>) {
launch<PlotlyApp>(args)
}
class PlotlyView : View("Hello PlotlyFX") {
private val controller: PlotlyFXController by inject()
private val hide = SimpleBooleanProperty(false)
override val root = hbox {
listview(controller.pages) {
selectionModel.selectionMode = SelectionMode.SINGLE
selectionModel.selectedItemProperty().addListener(
ChangeListener { _, _, value ->
hide.value = value != "Dynamic"
controller.displayPage(value)
}
)
}
vbox {
stackpane {
webview {
engine.isJavaScriptEnabled = true
engine.loadWorker.stateProperty().onChange {
log.info("WebEngine worker state: $it")
}
engine.loadWorker.exceptionProperty().onChange {
log.severe(it?.stackTraceToString())
}
engine.loadWorker.workDoneProperty().onChange {
log.info("Work done: $it")
}
engine.setOnError {
log.warning(it.message)
}
engine.setOnAlert {
log.info(it.data)
}
controller.address.onChange {
if (it != null) {
log.info("Displaying $it")
engine.load(it.replace("localhost", "127.0.0.1"))
}
}
}
progressindicator {
hiddenWhen(controller.address.isNotEmpty)
}
}
slider(1.0, 100.0, 1.0) {
hiddenWhen(hide)
isShowTickLabels = true
isShowTickMarks = true
controller.scale.bind(valueProperty())
}
}
}
init {
controller.startServer()
}
}

View File

@ -0,0 +1,45 @@
package space.kscience.plotly.fx
import io.ktor.server.engine.ApplicationEngine
import javafx.beans.property.SimpleIntegerProperty
import javafx.beans.property.SimpleStringProperty
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import tornadofx.*
import java.net.URI
class PlotlyFXController : Controller() {
val scale = SimpleIntegerProperty(1)
private var server: ApplicationEngine? = null
@OptIn(DelicateCoroutinesApi::class)
fun startServer() {
GlobalScope.launch(Dispatchers.Default) {
log.info("Starting server")
server = serve(scale)
log.info("Server started")
runLater {
displayPage(pages.first())
}
}
}
val pages = observableListOf(
"Dynamic",
"Static"
)
val address = SimpleStringProperty()
fun displayPage(page: String) {
server?.let {
val connector = it.environment.connectors.first()
val uri = URI("http", null, connector.host, connector.port, null, null, null)
address.set("$uri/$page")
}
}
}

View File

@ -0,0 +1,73 @@
package space.kscience.plotly.fx
import javafx.beans.value.ObservableIntegerValue
import kotlinx.coroutines.*
import space.kscience.plotly.Plotly
import space.kscience.plotly.layout
import space.kscience.plotly.models.Trace
import space.kscience.plotly.models.invoke
import space.kscience.plotly.plot
import space.kscience.plotly.server.pushUpdates
import space.kscience.plotly.server.serve
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
@OptIn(DelicateCoroutinesApi::class)
fun serve(scale: ObservableIntegerValue) = Plotly.serve(port = 7778) {
embedData = true //Should be set this way to avoid FX browser bug
page("Static") {
val x = (0..100).map { it.toDouble() / 100.0 }.toDoubleArray()
val y1 = x.map { sin(2.0 * PI * it) }.toDoubleArray()
val y2 = x.map { cos(2.0 * PI * it) }.toDoubleArray()
val trace1 = Trace(x, y1) {
name = "sin"
}
val trace2 = Trace(x, y2) {
name = "cos"
}
plot {//static plot
traces(trace1, trace2)
layout {
title = "First graph, row: 1, size: 8/12"
xaxis.title = "x axis name"
yaxis { title = "y axis name" }
}
}
}
page("Dynamic") { container ->
val x = (0..100).map { it.toDouble() / 100.0 }
val y = x.map { sin(2.0 * PI * it) }
val trace = Trace(x, y) { name = "sin" }
val plot = plot("dynamic", renderer = container) {
traces(trace)
layout {
title = "Dynamic plot"
xaxis.title = "x axis name"
yaxis.title = "y axis name"
}
}
GlobalScope.launch {
var time: Long = 0
while (isActive) {
delay(10)
time += 10
val frequency = scale.get().toDouble()
val dynamicY = x.map { sin(2.0 * PI * frequency * (it + time.toDouble() / 1000.0)) }
//trace.y.numbers = dynamicY
plot.data[0].y.numbers = dynamicY
plot.layout{
xaxis.title = "x axis name (t = $time)"
}
}
}
}
pushUpdates(100)
}

View File

@ -0,0 +1,4 @@
# Module js-demo

View File

@ -0,0 +1,27 @@
plugins {
kotlin("multiplatform")
}
repositories {
mavenCentral()
maven("https://repo.kotlin.link")
}
kotlin {
js(IR) {
browser()
binaries.executable()
}
sourceSets{
jsMain{
dependencies{
implementation(projects.plotly.plotlyktCore)
implementation(spclibs.kotlinx.coroutines.core)
}
}
}
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
}

View File

@ -0,0 +1,142 @@
package space.kscience.plotly.jsdemo
import kotlinx.browser.document
import kotlinx.coroutines.*
import kotlinx.html.TagConsumer
import kotlinx.html.dom.append
import kotlinx.html.h1
import kotlinx.html.js.div
import kotlinx.html.style
import kotlinx.serialization.json.Json
import org.w3c.dom.HTMLElement
import org.w3c.dom.events.Event
import space.kscience.dataforge.meta.MetaSerializer
import space.kscience.plotly.*
import space.kscience.plotly.events.PlotlyEventListenerType
import space.kscience.plotly.models.ScatterMode
import space.kscience.plotly.models.TraceType
import kotlin.random.Random
private fun onDomLoaded(block: (Event) -> Unit) {
document.addEventListener("DOMContentLoaded", block)
}
private fun withCanvas(block: TagConsumer<HTMLElement>.() -> Unit) = onDomLoaded {
val element = document.getElementById("canvas") as? HTMLElement
?: error("Element with id 'app' not found on page")
console.log("element loaded")
element.append { block() }
}
@OptIn(DelicateCoroutinesApi::class)
fun main(): Unit = withCanvas {
div {
style = "height:50%; width=100%;"
h1 { +"Histogram demo" }
plotDiv {
val rnd = Random(222)
histogram {
name = "Random data"
GlobalScope.launch {
while (isActive) {
x.numbers = List(500) { rnd.nextDouble() }
delay(300)
}
}
}
layout {
bargap = 0.1
title {
text = "Basic Histogram"
font {
size = 20
color("black")
}
}
xaxis {
title {
text = "Value"
font {
size = 16
}
}
}
yaxis {
title {
text = "Count"
font {
size = 16
}
}
}
}
}
}
div {
style = "height:50%; width=100%;"
h1 { +"Dynamic trace demo" }
plotDiv {
scatter {
x(1, 2, 3, 4)
y(10, 15, 13, 17)
mode = ScatterMode.markers
type = TraceType.scatter
}
scatter {
x(2, 3, 4, 5)
y(10, 15, 13, 17)
mode = ScatterMode.lines
type = TraceType.scatter
GlobalScope.launch {
while (isActive) {
delay(500)
marker {
if (Random.nextBoolean()) {
color("magenta")
} else {
color("blue")
}
}
}
}
}
scatter {
x(1, 2, 3, 4)
y(12, 5, 2, 12)
mode = ScatterMode.`lines+markers`
type = TraceType.scatter
marker {
color("red")
}
}
layout {
title = "Line and Scatter Plot"
}
}
}
div {
style = "height:50%; width=100%;"
h1 { +"Deserialization" }
val plot = Plotly.plot {
scatter {
x(1, 2, 3, 4)
y(10, 15, 13, 17)
mode = ScatterMode.markers
type = TraceType.scatter
}
}
val serialized = plot.toJsonString()
console.log(serialized)
val deserialized = Plot(Json.decodeFromString(MetaSerializer, serialized))
plotDiv(plot = deserialized).on(PlotlyEventListenerType.CLICK){
console.info(it.toString())
}
}
}

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Plotly.kt js demo</title>
<script type="text/javascript" src="js-demo.js"></script>
</head>
<body id="application">
<div id="canvas"></div>
</body>
</html>

View File

@ -0,0 +1,4 @@
# Module native-demo

View File

@ -0,0 +1,30 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("multiplatform")
}
repositories {
mavenCentral()
maven("https://repo.kotlin.link")
}
kotlin {
linuxX64{
binaries{
executable()
}
}
sourceSets{
commonMain {
dependencies {
implementation(project(":plotly:plotlykt-core"))
}
}
}
}
tasks.withType<KotlinCompile> {
kotlinOptions.freeCompilerArgs = kotlinOptions.freeCompilerArgs +"-Xopt-in=kotlin.RequiresOptIn"
}

View File

@ -0,0 +1,47 @@
import kotlinx.html.div
import kotlinx.html.h1
import kotlinx.html.hr
import space.kscience.plotly.*
import space.kscience.plotly.models.Trace
import space.kscience.plotly.models.invoke
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
/**
* Creates a renderable plotly html
*/
@OptIn(UnstablePlotlyAPI::class)
fun main() {
val x1 = (0..100).map { it.toDouble() / 100.0 }
val y1 = x1.map { sin(2.0 * PI * it) }
val y2 = x1.map { cos(2.0 * PI * it) }
val trace1 = Trace(x1, y1) { name = "sin" }
val trace2 = Trace(x1, y2) { name = "cos" }
Plotly.page { container ->
h1 { +"This is a plotly page" }
plot(renderer = container) {
traces(trace1, trace2)
layout {
title = "The plot above"
xaxis.title = "x axis name"
yaxis.title = "y axis name"
}
}
hr()
h1 { +"A custom separator" }
hr()
div {
plot {
traces(trace1, trace2)
layout {
title = "The plot below"
xaxis.title = "x axis name"
yaxis.title = "y axis name"
}
}
}
}.makeFile("plotly.html")
}

View File

@ -0,0 +1,298 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%use plotly"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# API"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"enum class Severity(val penalty: Double){\n",
" MINOR(1.0),\n",
" MAJOR(2.0),\n",
" CRITICAL(3.0)\n",
"}\n",
"\n",
"enum class State{\n",
" OPEN,\n",
" ASSIGNED,\n",
" RESOLVED\n",
"}\n",
"\n",
"data class Issue(val id: String, val dayCreated: Int, val severity: Severity, val complexity: Int, \n",
" var state: State = State.OPEN, var dayAssigned: Int? = null, var dayResolved: Int? = null){\n",
" fun activate(day: Int){ \n",
" state = State.ASSIGNED\n",
" dayAssigned = day\n",
" }\n",
" \n",
" fun resolve(day: Int){\n",
" state = State.RESOLVED\n",
" dayResolved = day\n",
" }\n",
" \n",
" internal fun tryResolve(day: Int){\n",
" if(state == State.ASSIGNED && day >= (dayAssigned ?: 0) + complexity ){\n",
" resolve(day)\n",
" }\n",
" }\n",
"}\n",
"\n",
"class Worker(val name: String){\n",
" var currentIssue: Issue? = null\n",
" private set\n",
" \n",
" fun isBusy(): Boolean = currentIssue != null\n",
" \n",
" fun update(day: Int){\n",
" currentIssue?.tryResolve(day)\n",
" if(currentIssue?.state == State.RESOLVED){\n",
" currentIssue = null\n",
" }\n",
" }\n",
" \n",
" fun assign(day: Int, issue: Issue){\n",
" if(currentIssue != null) error(\"Can't assign work to a worker which is busy\")\n",
" issue.activate(day)\n",
" currentIssue = issue\n",
" }\n",
"}\n",
"\n",
"interface IssueGenerator{\n",
" fun generate(day: Int): List<Issue>\n",
"}\n",
"\n",
"interface Strategy{\n",
" fun selectIssue(day: Int, issues: List<Issue>): Issue?\n",
"}\n",
"\n",
"class WorkResult(val issues: List<Issue>, val workers: Int, val days: Int)\n",
"\n",
"@OptIn(kotlin.ExperimentalStdlibApi::class)\n",
"fun simulate(generator: IssueGenerator, strategy: Strategy, numWorkers: Int = 10, days: Int = 100): WorkResult{\n",
" val workers = (0 until numWorkers).map{Worker(\"worker $it\")}\n",
" val issues = buildList<Issue>{\n",
" for(day in 0 until days){\n",
" //update all workers\n",
" workers.forEach { it.update(day) }\n",
" //generate new issues\n",
" val newIssues = generator.generate(day)\n",
" addAll(newIssues)\n",
" //Select all free workers\n",
" workers.filter { !it.isBusy() }.forEach { worker->\n",
" val unasigned = filter { it.state == State.OPEN }\n",
" val anIssue = strategy.selectIssue(day, unasigned) //select an issue to assign from all unassigned issues\n",
" if(anIssue != null){\n",
" worker.assign(day, anIssue)\n",
" }\n",
" }\n",
" }\n",
" }\n",
" return WorkResult(issues, numWorkers, days)\n",
"}\n",
"\n",
"fun WorkResult.computeLoss(): Double = issues.sumByDouble { ((it.dayResolved ?: days) - it.dayCreated)*it.severity.penalty } / days / workers / issues.size"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Implementations"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import kotlin.random.Random\n",
"import kotlin.math.pow\n",
"\n",
"/**\n",
"* Generate one random issue per day\n",
"*/\n",
"class RandomIssueGenerator(seed: Long, val issuesPerDay: Int = 4 ) : IssueGenerator{\n",
" private val random = Random(seed)\n",
" override fun generate(day: Int): List<Issue>{\n",
" return List(issuesPerDay){\n",
" val severity = Severity.values()[random.nextInt(3)]\n",
" val complexity = random.nextInt(15)\n",
" Issue(\"${day}_${it}\", day, severity, complexity)\n",
" }\n",
" }\n",
"}\n",
"\n",
"object TakeOldest: Strategy{\n",
" override fun selectIssue(day: Int, issues: List<Issue>): Issue?{\n",
" return issues.minByOrNull { it.dayCreated }\n",
" }\n",
"}\n",
"\n",
"class TakeRandom(seed: Long): Strategy{\n",
" private val random = Random(seed)\n",
" override fun selectIssue(day: Int, issues: List<Issue>): Issue?{\n",
" if(issues.isEmpty()) return null\n",
" return issues.random(random)\n",
" }\n",
"}\n",
"\n",
"object TakeCritical: Strategy{\n",
" override fun selectIssue(day: Int, issues: List<Issue>): Issue?{\n",
" return issues.maxByOrNull { it.severity.penalty*(day - it.dayCreated) }\n",
" }\n",
"}\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Simulate lossseverity"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"val seed = 89L\n",
"val days = 100\n",
"val workers = 10"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Take oldest"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"val result = simulate(RandomIssueGenerator(seed, workers),TakeOldest, days = days)\n",
"//result.issues.forEach { println(it)}\n",
"result.computeLoss()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Take random"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"simulate(RandomIssueGenerator(seed, workers),TakeRandom(seed), days = days).computeLoss()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Take critical"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"simulate(RandomIssueGenerator(seed, workers), TakeCritical, days = days).computeLoss()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"val seeds = List(1000){Random.nextLong()}\n",
"\n",
"Plotly.plot{\n",
" trace{\n",
" x.numbers = seeds.map{ seed -> simulate(RandomIssueGenerator(seed, workers), TakeOldest, days = days).computeLoss()}\n",
" name = \"oldest\"\n",
" type = TraceType.histogram\n",
" }\n",
" trace{\n",
" x.numbers = seeds.map{ seed -> simulate(RandomIssueGenerator(seed, workers), TakeRandom(seed), days = days).computeLoss()}\n",
" name = \"random\"\n",
" type = TraceType.histogram\n",
" }\n",
" trace{\n",
" x.numbers = seeds.map{ seed -> simulate(RandomIssueGenerator(seed, workers), TakeCritical, days = days).computeLoss()}\n",
" name = \"critical\"\n",
" type = TraceType.histogram\n",
" }\n",
" layout{\n",
" title = \"Loss distribtution\"\n",
" xaxis {\n",
" title = \"Loss\"\n",
" }\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "1.5.30-dev-598"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,334 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"21:08:36.601 [DefaultDispatcher-worker-1] INFO ktor.application - No ktor.deployment.watch patterns specified, automatic reload is not active\n",
"21:08:36.645 [DefaultDispatcher-worker-1] INFO ktor.application - Responding at http://0.0.0.0:8882\n"
]
},
{
"data": {
"text/html": [
"<div id=\"plotly-load-scripts\"></div>\n",
"<script type=\"text/javascript\">(function() {\n",
" console.log(\"Starting up plotly script loader\");\n",
" //initialize LaTeX for Jupyter\n",
" window.PlotlyConfig = {MathJaxConfig: 'local'};\n",
"\n",
" window.startupPlotly = function (){\n",
" if (window.MathJax){ \n",
" MathJax.Hub.Config({\n",
" SVG: {\n",
" font: \"STIX-Web\"\n",
" }\n",
" });\n",
" } \n",
" console.info(\"Calling deferred operations in Plotly queue.\")\n",
" window.plotlyCallQueue.forEach(function(theCall) {theCall();});\n",
" window.plotlyCallQueue = []; \n",
" }\n",
"})();</script>\n",
"<script type=\"text/javascript\" src=\"//localhost:8882/js/plotly.min.js\"></script>\n",
"<script type=\"text/javascript\">/**\r\n",
" * Use existing plotly or load it from the CDN if it is not available\r\n",
" * @param action\r\n",
" */\r\n",
"function withPlotly(action) {\r\n",
" if (typeof Plotly !== \"undefined\") {\r\n",
" action(Plotly);\r\n",
" } else if (typeof window.promiseOfPlotly !== \"undefined\") {\r\n",
" window.promiseOfPlotly.then(plotly => action(plotly));\r\n",
" } else {\r\n",
" console.warn(\"Plotly not defined. Loading the script from CDN\")\r\n",
" window.promiseOfPlotly = new Promise((accept, reject) => {\r\n",
" let plotlyLoaderScript = document.createElement(\"script\");\r\n",
" plotlyLoaderScript.src = \"https://cdnjs.cloudflare.com/ajax/libs/plotly.js/1.54.6/plotly.min.js\";\r\n",
" plotlyLoaderScript.type = 'text/javascript';\r\n",
" plotlyLoaderScript.onload = () => {\r\n",
" accept(Plotly);\r\n",
" }\r\n",
" plotlyLoaderScript.onerror = (error) => {\r\n",
" console.error(error);\r\n",
" reject(error)\r\n",
" }\r\n",
" document.head.appendChild(plotlyLoaderScript);\r\n",
" });\r\n",
" }\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Request and parse json from given address\r\n",
" * @param url {URL}\r\n",
" * @param callback\r\n",
" * @return Promise<Json>\r\n",
" */\r\n",
"function getJSON(url, callback) {\r\n",
"\r\n",
" function handleErrors(response) {\r\n",
" if (!response.ok) {\r\n",
" throw Error(response.statusText);\r\n",
" }\r\n",
" return response;\r\n",
" }\r\n",
"\r\n",
" try {\r\n",
" fetch(url, {\r\n",
" method: 'GET',\r\n",
" headers: {\r\n",
" Accept: 'application/json',\r\n",
" }\r\n",
" })\r\n",
" .then(handleErrors)\r\n",
" .then(response => response.json())\r\n",
" .then(json => callback(json))\r\n",
" .catch(error => console.log(error));\r\n",
" } catch (e) {\r\n",
" alert(\"Fetch of plot data failed with error: \" + e)\r\n",
" }\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Safe call for Plotly.newPlot\r\n",
" * @param id\r\n",
" * @param data\r\n",
" * @param layout\r\n",
" * @param config\r\n",
" */\r\n",
"function makePlot(id, data, layout, config) {\r\n",
" withPlotly(plotly => plotly.newPlot(id, data, layout, config))\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Create a plot taking data from given url\r\n",
" * @param id {string} element id for plot\r\n",
" * @param from {URL} json server url\r\n",
" * @param config {object} plotly configuration\r\n",
" * @return {JSON}\r\n",
" */\r\n",
"function createPlotFrom(id, from, config = {}) {\r\n",
" getJSON(from, json => withPlotly(plotly => {\r\n",
" plotly.newPlot(id, json.data, json.layout, config)\r\n",
" }));\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Update a plot taking data from given url\r\n",
" * @param id {string} element id for plot\r\n",
" * @param from {URL} json server url\r\n",
" * @return {JSON}\r\n",
" */\r\n",
"function updatePlotFrom(id, from) {\r\n",
" getJSON(from, json => withPlotly(plotly => plotly.react(id, json.data, json.layout)));\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Start pull updates with regular requests from client side\r\n",
" * @param id {string}\r\n",
" * @param from\r\n",
" * @param millis\r\n",
" */\r\n",
"function startPull(id, from, millis) {\r\n",
" let action = function () {\r\n",
" updatePlotFrom(id, from)\r\n",
" };\r\n",
" window.setInterval(action, millis)\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Start push updates via websocket\r\n",
" * @param id {string} element id for plot\r\n",
" * @param ws {URL} a websocket address\r\n",
" */\r\n",
"function startPush(id, ws) {\r\n",
" let socket = new WebSocket(ws);\r\n",
"\r\n",
" socket.onopen = function () {\r\n",
" console.log(\"[Plotly.kt] A connection for plot with id = \" + id + \" with server established on \" + ws);\r\n",
" };\r\n",
"\r\n",
" socket.onclose = function (event) {\r\n",
" if (event.wasClean) {\r\n",
" console.log(\"The connection with server is closed\");\r\n",
" } else {\r\n",
" console.log(\"The connection with server is broken\"); // Server process is dead\r\n",
" }\r\n",
" console.log('Code: ' + event.code + ' case: ' + event.reason);\r\n",
" };\r\n",
"\r\n",
" socket.onerror = function (error) {\r\n",
" console.error(\"Ploty push update error: \" + error.message);\r\n",
" socket.close()\r\n",
" };\r\n",
"\r\n",
" socket.onmessage = function (event) {\r\n",
" //console.log('got message: ' + event.data);\r\n",
" let json = JSON.parse(event.data);\r\n",
" //TODO check if plotly is initialized in a cell\r\n",
" if (json.plotId === id) {\r\n",
" if (json.contentType === \"layout\") {\r\n",
" withPlotly(plotly => plotly.relayout(id, json.content));\r\n",
" } else if (json.contentType === \"trace\") {\r\n",
" let content = json.content;\r\n",
" //This is done to satisfy plotly requirements of arrays-in-arrays for data\r\n",
" if (content.hasOwnProperty('x')) {\r\n",
" content.x = [content.x];\r\n",
" }\r\n",
" if (content.hasOwnProperty('y')) {\r\n",
" content.y = [content.y];\r\n",
" }\r\n",
" if (content.hasOwnProperty('z')) {\r\n",
" content.z = [content.z];\r\n",
" }\r\n",
" withPlotly(plotly => plotly.restyle(id, content, json['trace']));\r\n",
" }\r\n",
" }\r\n",
" };\r\n",
"\r\n",
" //gracefully close socket just in case\r\n",
" window.onbeforeunload = function () {\r\n",
" console.log(\"Gracefully closing socket\");\r\n",
" socket.onclose = function () {\r\n",
" }; // disable onclose handler first\r\n",
" socket.close();\r\n",
" };\r\n",
"}\r\n",
"\r\n",
"\r\n",
"window.startupPlotly()</script>\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%use plotly"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-07T11:08+0300",
"start_time": "2020-08-07T11:08+0300"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
" <div id=\"scientifik.plotly.Plot@122c8b64\">\n",
" <script>\n",
"let theCall = function(){\n",
" makePlot(\n",
" 'scientifik.plotly.Plot@122c8b64',\n",
" [{\"x\":[2,3,4,5],\"y\":[10,15,13,17],\"type\":\"scatter\"}],\n",
" {\"annotations\":[{\"@index\":\"0\",\"x\":2,\"y\":10,\"text\":\"$\\\\alpha$\",\"font\":{\"size\":18}},{\"@index\":\"1\",\"x\":5,\"y\":17,\"text\":\"$\\\\Omega$\",\"font\":{\"size\":18}}],\"title\":{\"text\":\"$\\\\text{Plot with annotations } \\\\alpha~and~\\\\Omega$\"}},\n",
" {\"responsive\":true}\n",
" ); \n",
"};\n",
"\n",
"if(typeof Plotly === 'undefined'){\n",
" if(!window.plotlyCallQueue) {\n",
" window.plotlyCallQueue = [];\n",
" } \n",
" window.plotlyCallQueue.push(theCall)\n",
" window.plotlyCall(theCall);\n",
"} else {\n",
" theCall();\n",
"}\n",
"</script>\n",
" <script id=\"scientifik.plotly.Plot@122c8b64-push\">\n",
" \n",
" startPush('scientifik.plotly.Plot@122c8b64', 'ws://localhost:8882/ws/scientifik.plotly.Plot@122c8b64');\n",
" \n",
" </script>\n",
" </div>\n",
"</div>\n"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Plotly.plot {\n",
" scatter {\n",
" x(2, 3, 4, 5)\n",
" y(10, 15, 13, 17)\n",
" }\n",
"\n",
" text {\n",
" position(2, 10)\n",
" font {\n",
" size = 18\n",
" }\n",
" text = \"\\$\\\\alpha\\$\"\n",
" }\n",
"\n",
" text {\n",
" position(5, 17)\n",
" font {\n",
" size = 18\n",
" }\n",
" text = \"\\$\\\\Omega\\$\"\n",
" }\n",
"\n",
" layout {\n",
" title {\n",
" text = \"\\$\\\\text{Plot with annotations } \\\\alpha~and~\\\\Omega\\$\"\n",
" }\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"hide_input": false,
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"pygments_lexer": "kotlin",
"version": "1.4.20-dev-2342"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": false,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": false,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,44 @@
{
"imports": [
"kscience.plotly.*",
"kscience.plotly.models.*",
"kscience.plotly.JupyterPlotly",
"space.kscience.dataforge.meta.*",
"kotlinx.html.*"
],
"repositories": [
"*mavenLocal",
"https://dl.bintray.com/mipt-npm/dataforge",
"https://dl.bintray.com/mipt-npm/kscience",
"https://dl.bintray.com/mipt-npm/dev"
],
"properties": {
"v": "0.2.0"
},
"link": "https://github.com/mipt-npm/plotly.kt",
"dependencies": [
"kscience.plotlykt:plotlykt-core-jvm:$v"
],
"resources": [
{
"type": "JS",
"name": "Plotly",
"locations": [
{
"path": "https://cdn.plot.ly/plotly-latest.min.js",
"type": "URL"
},
{
"path": "js/plotly.min.js",
"type": "CLASSPATH_PATH"
}
]
}
],
"renderers": {
"kscience.plotly.HtmlFragment": "HTML($it.toString())",
"kscience.plotly.Plot": "HTML(JupyterPlotly.renderPlot($it))",
"kscience.plotly.PlotlyFragment": "HTML(JupyterPlotly.renderFragment($it))",
"kscience.plotly.PlotlyPage": "HTML(JupyterPlotly.renderPage($it), true)"
}
}

View File

@ -0,0 +1,99 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"start_time": "2021-04-29T19:06:33.505Z"
}
},
"outputs": [],
"source": [
"%use plotly"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"start_time": "2021-04-29T19:05:34.298Z"
},
"tags": []
},
"outputs": [],
"source": [
"import kotlin.math.*\n",
"\n",
"val x1 = (0..100).map { it.toDouble() / 100.0 }\n",
"val y1 = x1.map { sin(2.0 * PI * it) }\n",
"val y2 = x1.map { cos(2.0 * PI * it) }\n",
"\n",
"val trace1 = Trace(x1, y1) { name = \"sin\" }\n",
"val trace2 = Trace(x1, y2) { name = \"cos\" }\n",
"\n",
"Plotly.page { renderer ->\n",
" val plotConfig = PlotlyConfig{\n",
" responsive = true\n",
" imageFormat = \"svg\"\n",
" } \n",
" h1 { +\"A custom separator\" }\n",
" hr()\n",
" plot(\"below\", renderer = renderer) {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot below\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
" }\n",
"\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"@webio": {
"lastCommId": null,
"lastKernelId": null
},
"hide_input": false,
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "1.5.30-dev-598"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": false,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": false,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,225 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-13T17:37+0300",
"start_time": "2020-08-13T17:37+0300"
}
},
"outputs": [],
"source": [
"%use plotly"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Line_4.jupyter-kts (1:8 - 15) Unresolved reference: jupyter"
]
}
],
"source": [
"Plotly.jupyter.notebook()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-13T17:37+0300",
"start_time": "2020-08-13T17:37+0300"
},
"tags": []
},
"outputs": [
{
"data": {
"text/html": [
"<html>\n",
" <head>\n",
" <meta charset=\"utf-8\">\n",
" <title>Plotly.kt</title>\n",
" <script type=\"text/javascript\" src=\"https://cdn.plot.ly/plotly-1.54.6.min.js\"></script>\n",
" </head>\n",
" <body>\n",
" <div id=\"space.kscience.plotly.Plot@246f69fb\">\n",
" <script>Plotly.react(\n",
" 'space.kscience.plotly.Plot@246f69fb',\n",
" [{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"sin\",\"y\":[0.0,0.06279051952931337,0.12533323356430426,0.1873813145857246,0.2486898871648548,0.3090169943749474,0.3681245526846779,0.4257792915650727,0.4817536741017153,0.5358267949789967,0.5877852522924731,0.6374239897486896,0.6845471059286886,0.7289686274214116,0.7705132427757893,0.8090169943749475,0.8443279255020151,0.8763066800438637,0.9048270524660196,0.9297764858882513,0.9510565162951535,0.9685831611286311,0.9822872507286886,0.9921147013144779,0.9980267284282716,1.0,0.9980267284282716,0.9921147013144778,0.9822872507286886,0.9685831611286312,0.9510565162951536,0.9297764858882513,0.9048270524660195,0.8763066800438635,0.844327925502015,0.8090169943749475,0.7705132427757893,0.7289686274214114,0.6845471059286888,0.6374239897486899,0.5877852522924732,0.535826794978997,0.4817536741017156,0.4257792915650729,0.36812455268467814,0.3090169943749475,0.24868988716485482,0.18738131458572502,0.12533323356430454,0.06279051952931358,1.2246467991473532E-16,-0.06279051952931335,-0.12533323356430429,-0.18738131458572477,-0.24868988716485502,-0.30901699437494773,-0.3681245526846783,-0.42577929156507227,-0.481753674101715,-0.5358267949789964,-0.587785252292473,-0.6374239897486896,-0.6845471059286887,-0.7289686274214113,-0.7705132427757894,-0.8090169943749473,-0.8443279255020153,-0.8763066800438636,-0.9048270524660198,-0.9297764858882511,-0.9510565162951535,-0.968583161128631,-0.9822872507286887,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286887,-0.9685831611286311,-0.9510565162951536,-0.9297764858882512,-0.9048270524660199,-0.8763066800438638,-0.8443279255020155,-0.8090169943749476,-0.7705132427757896,-0.7289686274214116,-0.684547105928689,-0.6374239897486896,-0.5877852522924734,-0.5358267949789963,-0.4817536741017153,-0.4257792915650722,-0.3681245526846787,-0.3090169943749476,-0.24868988716485535,-0.18738131458572468,-0.12533323356430465,-0.06279051952931326,-2.4492935982947064E-16]},{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"cos\",\"y\":[1.0,0.9980267284282716,0.9921147013144779,0.9822872507286887,0.9685831611286311,0.9510565162951535,0.9297764858882515,0.9048270524660195,0.8763066800438636,0.8443279255020151,0.8090169943749475,0.7705132427757893,0.7289686274214116,0.6845471059286886,0.6374239897486896,0.5877852522924731,0.5358267949789965,0.48175367410171516,0.42577929156507266,0.3681245526846781,0.30901699437494745,0.24868988716485496,0.18738131458572474,0.12533323356430426,0.06279051952931353,6.123233995736766E-17,-0.0627905195293134,-0.12533323356430437,-0.18738131458572482,-0.24868988716485463,-0.30901699437494734,-0.368124552684678,-0.4257792915650727,-0.48175367410171543,-0.5358267949789969,-0.587785252292473,-0.6374239897486897,-0.6845471059286887,-0.7289686274214113,-0.7705132427757891,-0.8090169943749473,-0.8443279255020149,-0.8763066800438634,-0.9048270524660194,-0.9297764858882513,-0.9510565162951535,-0.9685831611286311,-0.9822872507286886,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286886,-0.9685831611286311,-0.9510565162951535,-0.9297764858882512,-0.9048270524660197,-0.8763066800438637,-0.8443279255020152,-0.8090169943749476,-0.7705132427757893,-0.7289686274214116,-0.684547105928689,-0.6374239897486895,-0.5877852522924732,-0.5358267949789963,-0.48175367410171527,-0.42577929156507216,-0.3681245526846786,-0.30901699437494756,-0.2486898871648553,-0.18738131458572463,-0.1253332335643046,-0.06279051952931321,-1.8369701987210297E-16,0.06279051952931283,0.12533323356430423,0.18738131458572427,0.24868988716485493,0.30901699437494723,0.36812455268467825,0.4257792915650718,0.48175367410171493,0.535826794978996,0.5877852522924729,0.6374239897486893,0.6845471059286886,0.7289686274214112,0.7705132427757894,0.8090169943749473,0.8443279255020153,0.8763066800438636,0.9048270524660197,0.9297764858882511,0.9510565162951535,0.968583161128631,0.9822872507286887,0.9921147013144778,0.9980267284282716,1.0]}],\n",
" {\"xaxis\":{\"title\":\"x axis name\"},\"title\":{\"text\":\"The plot above\"},\"yaxis\":{\"title\":\"y axis name\"}},\n",
" {\"toImageButtonOptions\":{\"format\":\"svg\"},\"responsive\":true}\n",
");</script>\n",
" </div>\n",
" <hr>\n",
" <h1>A custom separator</h1>\n",
" <hr>\n",
" <div>\n",
" <div id=\"space.kscience.plotly.Plot@386c48c3\">\n",
" <script>Plotly.react(\n",
" 'space.kscience.plotly.Plot@386c48c3',\n",
" [{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"sin\",\"y\":[0.0,0.06279051952931337,0.12533323356430426,0.1873813145857246,0.2486898871648548,0.3090169943749474,0.3681245526846779,0.4257792915650727,0.4817536741017153,0.5358267949789967,0.5877852522924731,0.6374239897486896,0.6845471059286886,0.7289686274214116,0.7705132427757893,0.8090169943749475,0.8443279255020151,0.8763066800438637,0.9048270524660196,0.9297764858882513,0.9510565162951535,0.9685831611286311,0.9822872507286886,0.9921147013144779,0.9980267284282716,1.0,0.9980267284282716,0.9921147013144778,0.9822872507286886,0.9685831611286312,0.9510565162951536,0.9297764858882513,0.9048270524660195,0.8763066800438635,0.844327925502015,0.8090169943749475,0.7705132427757893,0.7289686274214114,0.6845471059286888,0.6374239897486899,0.5877852522924732,0.535826794978997,0.4817536741017156,0.4257792915650729,0.36812455268467814,0.3090169943749475,0.24868988716485482,0.18738131458572502,0.12533323356430454,0.06279051952931358,1.2246467991473532E-16,-0.06279051952931335,-0.12533323356430429,-0.18738131458572477,-0.24868988716485502,-0.30901699437494773,-0.3681245526846783,-0.42577929156507227,-0.481753674101715,-0.5358267949789964,-0.587785252292473,-0.6374239897486896,-0.6845471059286887,-0.7289686274214113,-0.7705132427757894,-0.8090169943749473,-0.8443279255020153,-0.8763066800438636,-0.9048270524660198,-0.9297764858882511,-0.9510565162951535,-0.968583161128631,-0.9822872507286887,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286887,-0.9685831611286311,-0.9510565162951536,-0.9297764858882512,-0.9048270524660199,-0.8763066800438638,-0.8443279255020155,-0.8090169943749476,-0.7705132427757896,-0.7289686274214116,-0.684547105928689,-0.6374239897486896,-0.5877852522924734,-0.5358267949789963,-0.4817536741017153,-0.4257792915650722,-0.3681245526846787,-0.3090169943749476,-0.24868988716485535,-0.18738131458572468,-0.12533323356430465,-0.06279051952931326,-2.4492935982947064E-16]},{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"cos\",\"y\":[1.0,0.9980267284282716,0.9921147013144779,0.9822872507286887,0.9685831611286311,0.9510565162951535,0.9297764858882515,0.9048270524660195,0.8763066800438636,0.8443279255020151,0.8090169943749475,0.7705132427757893,0.7289686274214116,0.6845471059286886,0.6374239897486896,0.5877852522924731,0.5358267949789965,0.48175367410171516,0.42577929156507266,0.3681245526846781,0.30901699437494745,0.24868988716485496,0.18738131458572474,0.12533323356430426,0.06279051952931353,6.123233995736766E-17,-0.0627905195293134,-0.12533323356430437,-0.18738131458572482,-0.24868988716485463,-0.30901699437494734,-0.368124552684678,-0.4257792915650727,-0.48175367410171543,-0.5358267949789969,-0.587785252292473,-0.6374239897486897,-0.6845471059286887,-0.7289686274214113,-0.7705132427757891,-0.8090169943749473,-0.8443279255020149,-0.8763066800438634,-0.9048270524660194,-0.9297764858882513,-0.9510565162951535,-0.9685831611286311,-0.9822872507286886,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286886,-0.9685831611286311,-0.9510565162951535,-0.9297764858882512,-0.9048270524660197,-0.8763066800438637,-0.8443279255020152,-0.8090169943749476,-0.7705132427757893,-0.7289686274214116,-0.684547105928689,-0.6374239897486895,-0.5877852522924732,-0.5358267949789963,-0.48175367410171527,-0.42577929156507216,-0.3681245526846786,-0.30901699437494756,-0.2486898871648553,-0.18738131458572463,-0.1253332335643046,-0.06279051952931321,-1.8369701987210297E-16,0.06279051952931283,0.12533323356430423,0.18738131458572427,0.24868988716485493,0.30901699437494723,0.36812455268467825,0.4257792915650718,0.48175367410171493,0.535826794978996,0.5877852522924729,0.6374239897486893,0.6845471059286886,0.7289686274214112,0.7705132427757894,0.8090169943749473,0.8443279255020153,0.8763066800438636,0.9048270524660197,0.9297764858882511,0.9510565162951535,0.968583161128631,0.9822872507286887,0.9921147013144778,0.9980267284282716,1.0]}],\n",
" {\"xaxis\":{\"title\":\"x axis name\"},\"width\":450,\"title\":{\"text\":\"The plot below\"},\"yaxis\":{\"title\":\"y axis name\"}},\n",
" {}\n",
");</script>\n",
" </div>\n",
" </div>\n",
" </body>\n",
"</html>\n"
]
},
"execution_count": 7,
"metadata": {
"text/html": {
"isolated": true
}
},
"output_type": "execute_result"
}
],
"source": [
"val x1 = (0..100).map { it.toDouble() / 100.0 }\n",
"val y1 = x1.map { sin(2.0 * PI * it) }\n",
"val y2 = x1.map { cos(2.0 * PI * it) }\n",
"\n",
"val trace1 = Trace(x1, y1) { name = \"sin\" }\n",
"val trace2 = Trace(x1, y2) { name = \"cos\" }\n",
"\n",
"val fragment = Plotly.fragment {\n",
" val plotConfig = PlotlyConfig{\n",
" responsive = true\n",
" set(\"toImageButtonOptions.format\", \"svg\")\n",
" }\n",
" \n",
" plot(config = plotConfig) {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot above\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
" }\n",
" hr()\n",
" h1 { +\"A custom separator\" }\n",
" hr()\n",
" div {\n",
" plot{\n",
" traces(trace1, trace2)\n",
" layout {\n",
" width = 450\n",
" title = \"The plot below\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
" }\n",
" }\n",
"}\n",
"fragment.toPage()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-12T22:35+0300",
"start_time": "2020-08-12T22:35+0300"
}
},
"outputs": [
{
"data": {
"text/html": [
"<html>\n",
" <head>\n",
" <meta charset=\"utf-8\">\n",
" <title>Plotly.kt</title>\n",
" <script type=\"text/javascript\" src=\"https://cdn.plot.ly/plotly-1.54.6.min.js\"></script>\n",
" </head>\n",
" <body>\n",
" <div id=\"space.kscience.plotly.Plot@6713105b\">\n",
" <script>Plotly.react(\n",
" 'space.kscience.plotly.Plot@6713105b',\n",
" [{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"sin\",\"y\":[0.0,0.06279051952931337,0.12533323356430426,0.1873813145857246,0.2486898871648548,0.3090169943749474,0.3681245526846779,0.4257792915650727,0.4817536741017153,0.5358267949789967,0.5877852522924731,0.6374239897486896,0.6845471059286886,0.7289686274214116,0.7705132427757893,0.8090169943749475,0.8443279255020151,0.8763066800438637,0.9048270524660196,0.9297764858882513,0.9510565162951535,0.9685831611286311,0.9822872507286886,0.9921147013144779,0.9980267284282716,1.0,0.9980267284282716,0.9921147013144778,0.9822872507286886,0.9685831611286312,0.9510565162951536,0.9297764858882513,0.9048270524660195,0.8763066800438635,0.844327925502015,0.8090169943749475,0.7705132427757893,0.7289686274214114,0.6845471059286888,0.6374239897486899,0.5877852522924732,0.535826794978997,0.4817536741017156,0.4257792915650729,0.36812455268467814,0.3090169943749475,0.24868988716485482,0.18738131458572502,0.12533323356430454,0.06279051952931358,1.2246467991473532E-16,-0.06279051952931335,-0.12533323356430429,-0.18738131458572477,-0.24868988716485502,-0.30901699437494773,-0.3681245526846783,-0.42577929156507227,-0.481753674101715,-0.5358267949789964,-0.587785252292473,-0.6374239897486896,-0.6845471059286887,-0.7289686274214113,-0.7705132427757894,-0.8090169943749473,-0.8443279255020153,-0.8763066800438636,-0.9048270524660198,-0.9297764858882511,-0.9510565162951535,-0.968583161128631,-0.9822872507286887,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286887,-0.9685831611286311,-0.9510565162951536,-0.9297764858882512,-0.9048270524660199,-0.8763066800438638,-0.8443279255020155,-0.8090169943749476,-0.7705132427757896,-0.7289686274214116,-0.684547105928689,-0.6374239897486896,-0.5877852522924734,-0.5358267949789963,-0.4817536741017153,-0.4257792915650722,-0.3681245526846787,-0.3090169943749476,-0.24868988716485535,-0.18738131458572468,-0.12533323356430465,-0.06279051952931326,-2.4492935982947064E-16]},{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"cos\",\"y\":[1.0,0.9980267284282716,0.9921147013144779,0.9822872507286887,0.9685831611286311,0.9510565162951535,0.9297764858882515,0.9048270524660195,0.8763066800438636,0.8443279255020151,0.8090169943749475,0.7705132427757893,0.7289686274214116,0.6845471059286886,0.6374239897486896,0.5877852522924731,0.5358267949789965,0.48175367410171516,0.42577929156507266,0.3681245526846781,0.30901699437494745,0.24868988716485496,0.18738131458572474,0.12533323356430426,0.06279051952931353,6.123233995736766E-17,-0.0627905195293134,-0.12533323356430437,-0.18738131458572482,-0.24868988716485463,-0.30901699437494734,-0.368124552684678,-0.4257792915650727,-0.48175367410171543,-0.5358267949789969,-0.587785252292473,-0.6374239897486897,-0.6845471059286887,-0.7289686274214113,-0.7705132427757891,-0.8090169943749473,-0.8443279255020149,-0.8763066800438634,-0.9048270524660194,-0.9297764858882513,-0.9510565162951535,-0.9685831611286311,-0.9822872507286886,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286886,-0.9685831611286311,-0.9510565162951535,-0.9297764858882512,-0.9048270524660197,-0.8763066800438637,-0.8443279255020152,-0.8090169943749476,-0.7705132427757893,-0.7289686274214116,-0.684547105928689,-0.6374239897486895,-0.5877852522924732,-0.5358267949789963,-0.48175367410171527,-0.42577929156507216,-0.3681245526846786,-0.30901699437494756,-0.2486898871648553,-0.18738131458572463,-0.1253332335643046,-0.06279051952931321,-1.8369701987210297E-16,0.06279051952931283,0.12533323356430423,0.18738131458572427,0.24868988716485493,0.30901699437494723,0.36812455268467825,0.4257792915650718,0.48175367410171493,0.535826794978996,0.5877852522924729,0.6374239897486893,0.6845471059286886,0.7289686274214112,0.7705132427757894,0.8090169943749473,0.8443279255020153,0.8763066800438636,0.9048270524660197,0.9297764858882511,0.9510565162951535,0.968583161128631,0.9822872507286887,0.9921147013144778,0.9980267284282716,1.0]}],\n",
" {\"xaxis\":{\"title\":\"x axis name\"},\"title\":{\"text\":\"The plot below\"},\"yaxis\":{\"title\":\"y axis name\"}},\n",
" {}\n",
");</script>\n",
" </div>\n",
" </body>\n",
"</html>\n"
]
},
"execution_count": 8,
"metadata": {
"text/html": {
"isolated": true
}
},
"output_type": "execute_result"
}
],
"source": [
"Plotly.plot {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot below\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
"}.toPage()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"@webio": {
"lastCommId": null,
"lastKernelId": null
},
"hide_input": false,
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "1.5.30-dev-598"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": false,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": false,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,402 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"ExecuteTime": {
"end_time": "2020-07-31T11:42+0300",
"start_time": "2020-07-31T11:42+0300"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div style=\"color: blue;\">The server is already running on 8882. It must be shut down first to be restarted.</div>\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%use plotly\n",
"import kotlin.math.*"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"ExecuteTime": {
"end_time": "2020-07-31T11:42+0300",
"start_time": "2020-07-31T11:42+0300"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
" <div id=\"kscience.plotly.Plot@11b65246\">\n",
" <script>\n",
"require([\"plotly\"], plotly =>{\n",
" plotly.react(\n",
" 'kscience.plotly.Plot@11b65246',\n",
" [{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"sin\",\"y\":[0.0,0.06279051952931337,0.12533323356430426,0.1873813145857246,0.2486898871648548,0.3090169943749474,0.3681245526846779,0.4257792915650727,0.4817536741017153,0.5358267949789967,0.5877852522924731,0.6374239897486896,0.6845471059286886,0.7289686274214116,0.7705132427757893,0.8090169943749475,0.8443279255020151,0.8763066800438637,0.9048270524660196,0.9297764858882513,0.9510565162951535,0.9685831611286311,0.9822872507286886,0.9921147013144779,0.9980267284282716,1.0,0.9980267284282716,0.9921147013144778,0.9822872507286886,0.9685831611286312,0.9510565162951536,0.9297764858882513,0.9048270524660195,0.8763066800438635,0.844327925502015,0.8090169943749475,0.7705132427757893,0.7289686274214114,0.6845471059286888,0.6374239897486899,0.5877852522924732,0.535826794978997,0.4817536741017156,0.4257792915650729,0.36812455268467814,0.3090169943749475,0.24868988716485482,0.18738131458572502,0.12533323356430454,0.06279051952931358,1.2246467991473532E-16,-0.06279051952931335,-0.12533323356430429,-0.18738131458572477,-0.24868988716485502,-0.30901699437494773,-0.3681245526846783,-0.42577929156507227,-0.481753674101715,-0.5358267949789964,-0.587785252292473,-0.6374239897486896,-0.6845471059286887,-0.7289686274214113,-0.7705132427757894,-0.8090169943749473,-0.8443279255020153,-0.8763066800438636,-0.9048270524660198,-0.9297764858882511,-0.9510565162951535,-0.968583161128631,-0.9822872507286887,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286887,-0.9685831611286311,-0.9510565162951536,-0.9297764858882512,-0.9048270524660199,-0.8763066800438638,-0.8443279255020155,-0.8090169943749476,-0.7705132427757896,-0.7289686274214116,-0.684547105928689,-0.6374239897486896,-0.5877852522924734,-0.5358267949789963,-0.4817536741017153,-0.4257792915650722,-0.3681245526846787,-0.3090169943749476,-0.24868988716485535,-0.18738131458572468,-0.12533323356430465,-0.06279051952931326,-2.4492935982947064E-16]},{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"cos\",\"y\":[1.0,0.9980267284282716,0.9921147013144779,0.9822872507286887,0.9685831611286311,0.9510565162951535,0.9297764858882515,0.9048270524660195,0.8763066800438636,0.8443279255020151,0.8090169943749475,0.7705132427757893,0.7289686274214116,0.6845471059286886,0.6374239897486896,0.5877852522924731,0.5358267949789965,0.48175367410171516,0.42577929156507266,0.3681245526846781,0.30901699437494745,0.24868988716485496,0.18738131458572474,0.12533323356430426,0.06279051952931353,6.123233995736766E-17,-0.0627905195293134,-0.12533323356430437,-0.18738131458572482,-0.24868988716485463,-0.30901699437494734,-0.368124552684678,-0.4257792915650727,-0.48175367410171543,-0.5358267949789969,-0.587785252292473,-0.6374239897486897,-0.6845471059286887,-0.7289686274214113,-0.7705132427757891,-0.8090169943749473,-0.8443279255020149,-0.8763066800438634,-0.9048270524660194,-0.9297764858882513,-0.9510565162951535,-0.9685831611286311,-0.9822872507286886,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286886,-0.9685831611286311,-0.9510565162951535,-0.9297764858882512,-0.9048270524660197,-0.8763066800438637,-0.8443279255020152,-0.8090169943749476,-0.7705132427757893,-0.7289686274214116,-0.684547105928689,-0.6374239897486895,-0.5877852522924732,-0.5358267949789963,-0.48175367410171527,-0.42577929156507216,-0.3681245526846786,-0.30901699437494756,-0.2486898871648553,-0.18738131458572463,-0.1253332335643046,-0.06279051952931321,-1.8369701987210297E-16,0.06279051952931283,0.12533323356430423,0.18738131458572427,0.24868988716485493,0.30901699437494723,0.36812455268467825,0.4257792915650718,0.48175367410171493,0.535826794978996,0.5877852522924729,0.6374239897486893,0.6845471059286886,0.7289686274214112,0.7705132427757894,0.8090169943749473,0.8443279255020153,0.8763066800438636,0.9048270524660197,0.9297764858882511,0.9510565162951535,0.968583161128631,0.9822872507286887,0.9921147013144778,0.9980267284282716,1.0]}],\n",
" {\"xaxis\":{\"title\":\"x axis name\"},\"title\":{\"text\":\"The plot above\"},\"yaxis\":{\"title\":\"y axis name\"}},\n",
" {\"responsive\":true}\n",
" );\n",
"});\n",
"</script>\n",
" <script id=\"kscience.plotly.Plot@11b65246-push\">\n",
" require([\"plotly-server\"], plotlyServer =>{\n",
" startPush('kscience.plotly.Plot@11b65246', 'ws://localhost:8882/ws/kscience.plotly.Plot@11b65246');\n",
" });\n",
" </script>\n",
" </div>\n",
" <hr>\n",
" <h1>A custom separator</h1>\n",
" <hr>\n",
" <div>\n",
" <div id=\"kscience.plotly.Plot@4803d1c0\">\n",
" <script>\n",
"require([\"plotly\"], plotly =>{\n",
" plotly.react(\n",
" 'kscience.plotly.Plot@4803d1c0',\n",
" [{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"sin\",\"y\":[0.0,0.06279051952931337,0.12533323356430426,0.1873813145857246,0.2486898871648548,0.3090169943749474,0.3681245526846779,0.4257792915650727,0.4817536741017153,0.5358267949789967,0.5877852522924731,0.6374239897486896,0.6845471059286886,0.7289686274214116,0.7705132427757893,0.8090169943749475,0.8443279255020151,0.8763066800438637,0.9048270524660196,0.9297764858882513,0.9510565162951535,0.9685831611286311,0.9822872507286886,0.9921147013144779,0.9980267284282716,1.0,0.9980267284282716,0.9921147013144778,0.9822872507286886,0.9685831611286312,0.9510565162951536,0.9297764858882513,0.9048270524660195,0.8763066800438635,0.844327925502015,0.8090169943749475,0.7705132427757893,0.7289686274214114,0.6845471059286888,0.6374239897486899,0.5877852522924732,0.535826794978997,0.4817536741017156,0.4257792915650729,0.36812455268467814,0.3090169943749475,0.24868988716485482,0.18738131458572502,0.12533323356430454,0.06279051952931358,1.2246467991473532E-16,-0.06279051952931335,-0.12533323356430429,-0.18738131458572477,-0.24868988716485502,-0.30901699437494773,-0.3681245526846783,-0.42577929156507227,-0.481753674101715,-0.5358267949789964,-0.587785252292473,-0.6374239897486896,-0.6845471059286887,-0.7289686274214113,-0.7705132427757894,-0.8090169943749473,-0.8443279255020153,-0.8763066800438636,-0.9048270524660198,-0.9297764858882511,-0.9510565162951535,-0.968583161128631,-0.9822872507286887,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286887,-0.9685831611286311,-0.9510565162951536,-0.9297764858882512,-0.9048270524660199,-0.8763066800438638,-0.8443279255020155,-0.8090169943749476,-0.7705132427757896,-0.7289686274214116,-0.684547105928689,-0.6374239897486896,-0.5877852522924734,-0.5358267949789963,-0.4817536741017153,-0.4257792915650722,-0.3681245526846787,-0.3090169943749476,-0.24868988716485535,-0.18738131458572468,-0.12533323356430465,-0.06279051952931326,-2.4492935982947064E-16]},{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"cos\",\"y\":[1.0,0.9980267284282716,0.9921147013144779,0.9822872507286887,0.9685831611286311,0.9510565162951535,0.9297764858882515,0.9048270524660195,0.8763066800438636,0.8443279255020151,0.8090169943749475,0.7705132427757893,0.7289686274214116,0.6845471059286886,0.6374239897486896,0.5877852522924731,0.5358267949789965,0.48175367410171516,0.42577929156507266,0.3681245526846781,0.30901699437494745,0.24868988716485496,0.18738131458572474,0.12533323356430426,0.06279051952931353,6.123233995736766E-17,-0.0627905195293134,-0.12533323356430437,-0.18738131458572482,-0.24868988716485463,-0.30901699437494734,-0.368124552684678,-0.4257792915650727,-0.48175367410171543,-0.5358267949789969,-0.587785252292473,-0.6374239897486897,-0.6845471059286887,-0.7289686274214113,-0.7705132427757891,-0.8090169943749473,-0.8443279255020149,-0.8763066800438634,-0.9048270524660194,-0.9297764858882513,-0.9510565162951535,-0.9685831611286311,-0.9822872507286886,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286886,-0.9685831611286311,-0.9510565162951535,-0.9297764858882512,-0.9048270524660197,-0.8763066800438637,-0.8443279255020152,-0.8090169943749476,-0.7705132427757893,-0.7289686274214116,-0.684547105928689,-0.6374239897486895,-0.5877852522924732,-0.5358267949789963,-0.48175367410171527,-0.42577929156507216,-0.3681245526846786,-0.30901699437494756,-0.2486898871648553,-0.18738131458572463,-0.1253332335643046,-0.06279051952931321,-1.8369701987210297E-16,0.06279051952931283,0.12533323356430423,0.18738131458572427,0.24868988716485493,0.30901699437494723,0.36812455268467825,0.4257792915650718,0.48175367410171493,0.535826794978996,0.5877852522924729,0.6374239897486893,0.6845471059286886,0.7289686274214112,0.7705132427757894,0.8090169943749473,0.8443279255020153,0.8763066800438636,0.9048270524660197,0.9297764858882511,0.9510565162951535,0.968583161128631,0.9822872507286887,0.9921147013144778,0.9980267284282716,1.0]}],\n",
" {\"xaxis\":{\"title\":\"x axis name\"},\"title\":{\"text\":\"The plot below\"},\"yaxis\":{\"title\":\"y axis name\"}},\n",
" {}\n",
" );\n",
"});\n",
"</script>\n",
" <script id=\"kscience.plotly.Plot@4803d1c0-push\">\n",
" require([\"plotly-server\"], plotlyServer =>{\n",
" startPush('kscience.plotly.Plot@4803d1c0', 'ws://localhost:8882/ws/kscience.plotly.Plot@4803d1c0');\n",
" });\n",
" </script>\n",
" </div>\n",
" </div>\n",
"</div>\n"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"val x1 = (0..100).map { it.toDouble() / 100.0 }\n",
"val y1 = x1.map { sin(2.0 * PI * it) }\n",
"val y2 = x1.map { cos(2.0 * PI * it) }\n",
"\n",
"val trace1 = Trace(x1, y1) { name = \"sin\" }\n",
"val trace2 = Trace(x1, y2) { name = \"cos\" }\n",
"\n",
"val fragment = Plotly.fragment { container ->\n",
" plot(container = container, config = PlotlyConfig{responsive = true}) {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot above\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
" }\n",
" hr()\n",
" h1 { +\"A custom separator\" }\n",
" hr()\n",
" div {\n",
" plot(container = container) {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot below\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
" }\n",
" }\n",
"}\n",
"fragment"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"ExecuteTime": {
"end_time": "2020-07-31T11:42+0300",
"start_time": "2020-07-31T11:42+0300"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
" <div id=\"kscience.plotly.Plot@192c70fb\">\n",
" <script>\n",
"require([\"plotly\"], plotly =>{\n",
" plotly.react(\n",
" 'kscience.plotly.Plot@192c70fb',\n",
" [{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"sin\",\"y\":[0.0,0.06279051952931337,0.12533323356430426,0.1873813145857246,0.2486898871648548,0.3090169943749474,0.3681245526846779,0.4257792915650727,0.4817536741017153,0.5358267949789967,0.5877852522924731,0.6374239897486896,0.6845471059286886,0.7289686274214116,0.7705132427757893,0.8090169943749475,0.8443279255020151,0.8763066800438637,0.9048270524660196,0.9297764858882513,0.9510565162951535,0.9685831611286311,0.9822872507286886,0.9921147013144779,0.9980267284282716,1.0,0.9980267284282716,0.9921147013144778,0.9822872507286886,0.9685831611286312,0.9510565162951536,0.9297764858882513,0.9048270524660195,0.8763066800438635,0.844327925502015,0.8090169943749475,0.7705132427757893,0.7289686274214114,0.6845471059286888,0.6374239897486899,0.5877852522924732,0.535826794978997,0.4817536741017156,0.4257792915650729,0.36812455268467814,0.3090169943749475,0.24868988716485482,0.18738131458572502,0.12533323356430454,0.06279051952931358,1.2246467991473532E-16,-0.06279051952931335,-0.12533323356430429,-0.18738131458572477,-0.24868988716485502,-0.30901699437494773,-0.3681245526846783,-0.42577929156507227,-0.481753674101715,-0.5358267949789964,-0.587785252292473,-0.6374239897486896,-0.6845471059286887,-0.7289686274214113,-0.7705132427757894,-0.8090169943749473,-0.8443279255020153,-0.8763066800438636,-0.9048270524660198,-0.9297764858882511,-0.9510565162951535,-0.968583161128631,-0.9822872507286887,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286887,-0.9685831611286311,-0.9510565162951536,-0.9297764858882512,-0.9048270524660199,-0.8763066800438638,-0.8443279255020155,-0.8090169943749476,-0.7705132427757896,-0.7289686274214116,-0.684547105928689,-0.6374239897486896,-0.5877852522924734,-0.5358267949789963,-0.4817536741017153,-0.4257792915650722,-0.3681245526846787,-0.3090169943749476,-0.24868988716485535,-0.18738131458572468,-0.12533323356430465,-0.06279051952931326,-2.4492935982947064E-16]},{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"cos\",\"y\":[1.0,0.9980267284282716,0.9921147013144779,0.9822872507286887,0.9685831611286311,0.9510565162951535,0.9297764858882515,0.9048270524660195,0.8763066800438636,0.8443279255020151,0.8090169943749475,0.7705132427757893,0.7289686274214116,0.6845471059286886,0.6374239897486896,0.5877852522924731,0.5358267949789965,0.48175367410171516,0.42577929156507266,0.3681245526846781,0.30901699437494745,0.24868988716485496,0.18738131458572474,0.12533323356430426,0.06279051952931353,6.123233995736766E-17,-0.0627905195293134,-0.12533323356430437,-0.18738131458572482,-0.24868988716485463,-0.30901699437494734,-0.368124552684678,-0.4257792915650727,-0.48175367410171543,-0.5358267949789969,-0.587785252292473,-0.6374239897486897,-0.6845471059286887,-0.7289686274214113,-0.7705132427757891,-0.8090169943749473,-0.8443279255020149,-0.8763066800438634,-0.9048270524660194,-0.9297764858882513,-0.9510565162951535,-0.9685831611286311,-0.9822872507286886,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286886,-0.9685831611286311,-0.9510565162951535,-0.9297764858882512,-0.9048270524660197,-0.8763066800438637,-0.8443279255020152,-0.8090169943749476,-0.7705132427757893,-0.7289686274214116,-0.684547105928689,-0.6374239897486895,-0.5877852522924732,-0.5358267949789963,-0.48175367410171527,-0.42577929156507216,-0.3681245526846786,-0.30901699437494756,-0.2486898871648553,-0.18738131458572463,-0.1253332335643046,-0.06279051952931321,-1.8369701987210297E-16,0.06279051952931283,0.12533323356430423,0.18738131458572427,0.24868988716485493,0.30901699437494723,0.36812455268467825,0.4257792915650718,0.48175367410171493,0.535826794978996,0.5877852522924729,0.6374239897486893,0.6845471059286886,0.7289686274214112,0.7705132427757894,0.8090169943749473,0.8443279255020153,0.8763066800438636,0.9048270524660197,0.9297764858882511,0.9510565162951535,0.968583161128631,0.9822872507286887,0.9921147013144778,0.9980267284282716,1.0]}],\n",
" {\"xaxis\":{\"title\":\"x axis name\"},\"title\":{\"text\":\"The plot below\"},\"yaxis\":{\"title\":\"y axis name\"}},\n",
" {\"responsive\":true}\n",
" );\n",
"});\n",
"</script>\n",
" <script id=\"kscience.plotly.Plot@192c70fb-push\">\n",
" require([\"plotly-server\"], plotlyServer =>{\n",
" startPush('kscience.plotly.Plot@192c70fb', 'ws://localhost:8882/ws/kscience.plotly.Plot@192c70fb');\n",
" });\n",
" </script>\n",
" </div>\n",
"</div>\n"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Plotly.plot {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot below\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"ExecuteTime": {
"end_time": "2020-07-31T11:42+0300",
"start_time": "2020-07-31T11:42+0300"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
" <div id=\"kscience.plotly.Plot@e8a413\">\n",
" <script>\n",
"require([\"plotly\"], plotly =>{\n",
" plotly.react(\n",
" 'kscience.plotly.Plot@e8a413',\n",
" [{\"x\":[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0],\"name\":\"sin\",\"y\":[0.0,0.06279051952931337,0.12533323356430426,0.1873813145857246,0.2486898871648548,0.3090169943749474,0.3681245526846779,0.4257792915650727,0.4817536741017153,0.5358267949789967,0.5877852522924731,0.6374239897486896,0.6845471059286886,0.7289686274214116,0.7705132427757893,0.8090169943749475,0.8443279255020151,0.8763066800438637,0.9048270524660196,0.9297764858882513,0.9510565162951535,0.9685831611286311,0.9822872507286886,0.9921147013144779,0.9980267284282716,1.0,0.9980267284282716,0.9921147013144778,0.9822872507286886,0.9685831611286312,0.9510565162951536,0.9297764858882513,0.9048270524660195,0.8763066800438635,0.844327925502015,0.8090169943749475,0.7705132427757893,0.7289686274214114,0.6845471059286888,0.6374239897486899,0.5877852522924732,0.535826794978997,0.4817536741017156,0.4257792915650729,0.36812455268467814,0.3090169943749475,0.24868988716485482,0.18738131458572502,0.12533323356430454,0.06279051952931358,1.2246467991473532E-16,-0.06279051952931335,-0.12533323356430429,-0.18738131458572477,-0.24868988716485502,-0.30901699437494773,-0.3681245526846783,-0.42577929156507227,-0.481753674101715,-0.5358267949789964,-0.587785252292473,-0.6374239897486896,-0.6845471059286887,-0.7289686274214113,-0.7705132427757894,-0.8090169943749473,-0.8443279255020153,-0.8763066800438636,-0.9048270524660198,-0.9297764858882511,-0.9510565162951535,-0.968583161128631,-0.9822872507286887,-0.9921147013144778,-0.9980267284282716,-1.0,-0.9980267284282716,-0.9921147013144779,-0.9822872507286887,-0.9685831611286311,-0.9510565162951536,-0.9297764858882512,-0.9048270524660199,-0.8763066800438638,-0.8443279255020155,-0.8090169943749476,-0.7705132427757896,-0.7289686274214116,-0.684547105928689,-0.6374239897486896,-0.5877852522924734,-0.5358267949789963,-0.4817536741017153,-0.4257792915650722,-0.3681245526846787,-0.3090169943749476,-0.24868988716485535,-0.18738131458572468,-0.12533323356430465,-0.06279051952931326,-2.4492935982947064E-16]}],\n",
" {\"xaxis\":{\"title\":\"x axis name\"},\"title\":{\"text\":\"Dynamic plot\"},\"yaxis\":{\"title\":\"y axis name\"}},\n",
" {\"responsive\":true}\n",
" );\n",
"});\n",
"</script>\n",
" <script id=\"kscience.plotly.Plot@e8a413-push\">\n",
" require([\"plotly-server\"], plotlyServer =>{\n",
" startPush('kscience.plotly.Plot@e8a413', 'ws://localhost:8882/ws/kscience.plotly.Plot@e8a413');\n",
" });\n",
" </script>\n",
" </div>\n",
"</div>\n"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"val x = (0..100).map { it.toDouble() / 100.0 }\n",
"val y = x.map { sin(2.0 * PI * it) }\n",
"\n",
"val trace = Trace(x, y) { name = \"sin\" }\n",
"\n",
"\n",
"val dynamicPlot = Plotly.plot {\n",
" traces(trace)\n",
" layout {\n",
" title = \"Dynamic plot\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
"}\n",
"\n",
"dynamicPlot"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"ExecuteTime": {
"end_time": "2020-07-31T11:42+0300",
"start_time": "2020-07-31T11:42+0300"
}
},
"outputs": [],
"source": [
"import kotlinx.coroutines.*\n",
"\n",
"val job = GlobalScope.launch {\n",
" var time: Long = 0\n",
" while (isActive) {\n",
" delay(10)\n",
" time += 10\n",
" val dynamicY = x.map { sin(2.0 * PI * (it + time.toDouble() / 1000.0)) }\n",
" trace.y.set(dynamicY)\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"ExecuteTime": {
"end_time": "2020-07-31T11:42+0300",
"start_time": "2020-07-31T11:42+0300"
}
},
"outputs": [],
"source": [
"job.cancel()"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"ExecuteTime": {
"end_time": "2020-07-31T11:42+0300",
"start_time": "2020-07-31T11:42+0300"
}
},
"outputs": [],
"source": [
"dynamicPlot.layout.xaxis.title = \"крокозябра\""
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"ExecuteTime": {
"end_time": "2020-07-31T11:43+0300",
"start_time": "2020-07-31T11:42+0300"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"11:43:00.894 [DefaultDispatcher-worker-2] DEBUG ktor.application - Closed server socket for kscience.plotly.Plot@1822ae52\n",
"11:43:00.895 [DefaultDispatcher-worker-6] DEBUG ktor.application - Closed server socket for kscience.plotly.Plot@5ec8af0d\n",
"11:43:00.896 [pool-2-thread-1] INFO ktor.application - 101 Switching Protocols: GET - /ws/kscience.plotly.Plot@1822ae52, cancelled\n",
"11:43:00.897 [DefaultDispatcher-worker-14] DEBUG ktor.application - Closed server socket for kscience.plotly.Plot@4eefd342\n",
"11:43:00.897 [pool-2-thread-2] INFO ktor.application - 101 Switching Protocols: GET - /ws/kscience.plotly.Plot@5ec8af0d, cancelled\n",
"11:43:00.898 [pool-2-thread-3] INFO ktor.application - 101 Switching Protocols: GET - /ws/kscience.plotly.Plot@4eefd342, cancelled\n",
"11:43:00.905 [DefaultDispatcher-worker-9] ERROR io.ktor.server.cio.HttpServer - Unhandled exception caught for CoroutineName(http-pipeline-writer)\n",
"kotlinx.coroutines.CoroutinesInternalError: Fatal exception in coroutines machinery for DispatchedContinuation[ExperimentalCoroutineDispatcher@1a6cc06[scheduler = DefaultDispatcher@1aa286ac[Pool Size {core = 14, max = 1536}, Worker States {CPU = 7, blocking = 0, parked = 7, dormant = 0, terminated = 0}, running workers queues = [0c, 0c, 0c, 0c, 1c, 0c, 0c], global CPU queue size = 0, global blocking queue size = 0, Control State {created workers= 14, blocking tasks = 0, CPUs acquired = 7}]], Continuation at io.ktor.server.cio.backend.ServerPipelineKt$startServerConnectionPipeline$1$outputsActor$1.invokeSuspend(ServerPipeline.kt:49)@3401b226]. Please read KDoc to 'handleFatalException' method and report this incident to maintainers\n",
"\tat kotlinx.coroutines.DispatchedTask.handleFatalException$kotlinx_coroutines_core(DispatchedTask.kt:93)\n",
"\tat kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:64)\n",
"\tat kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)\n",
"\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)\n",
"\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)\n",
"\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)\n",
"Caused by: java.lang.ClassCastException: class kotlin.coroutines.jvm.internal.CompletedContinuation cannot be cast to class kotlinx.coroutines.DispatchedContinuation (kotlin.coroutines.jvm.internal.CompletedContinuation is in unnamed module of loader 'app'; kotlinx.coroutines.DispatchedContinuation is in unnamed module of loader java.net.URLClassLoader @7323f4f)\n",
"\tat kotlinx.coroutines.CoroutineDispatcher.releaseInterceptedContinuation(CoroutineDispatcher.kt:103)\n",
"\tat kotlin.coroutines.jvm.internal.ContinuationImpl.releaseIntercepted(ContinuationImpl.kt:118)\n",
"\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:39)\n",
"\tat kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:55)\n",
"\t... 4 common frames omitted\n",
"11:43:00.905 [DefaultDispatcher-worker-4] ERROR io.ktor.server.cio.HttpServer - Unhandled exception caught for CoroutineName(http-pipeline-writer)\n",
"kotlinx.coroutines.CoroutinesInternalError: Fatal exception in coroutines machinery for DispatchedContinuation[ExperimentalCoroutineDispatcher@1a6cc06[scheduler = DefaultDispatcher@1aa286ac[Pool Size {core = 14, max = 1536}, Worker States {CPU = 9, blocking = 0, parked = 5, dormant = 0, terminated = 0}, running workers queues = [0c, 1c, 0c, 0c, 0c, 0c, 1c, 0c, 0c], global CPU queue size = 0, global blocking queue size = 0, Control State {created workers= 14, blocking tasks = 0, CPUs acquired = 7}]], Continuation at io.ktor.server.cio.backend.ServerPipelineKt$startServerConnectionPipeline$1$outputsActor$1.invokeSuspend(ServerPipeline.kt:49)@34cb0946]. Please read KDoc to 'handleFatalException' method and report this incident to maintainers\n",
"\tat kotlinx.coroutines.DispatchedTask.handleFatalException$kotlinx_coroutines_core(DispatchedTask.kt:93)\n",
"\tat kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:64)\n",
"\tat kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)\n",
"\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)\n"
]
},
{
"data": {
"text/html": [
"<div>Update server is stopped</div>\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)\n",
"\tat kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)\n",
"Caused by: java.lang.ClassCastException: class kotlin.coroutines.jvm.internal.CompletedContinuation cannot be cast to class kotlinx.coroutines.DispatchedContinuation (kotlin.coroutines.jvm.internal.CompletedContinuation is in unnamed module of loader 'app'; kotlinx.coroutines.DispatchedContinuation is in unnamed module of loader java.net.URLClassLoader @7323f4f)\n",
"\tat kotlinx.coroutines.CoroutineDispatcher.releaseInterceptedContinuation(CoroutineDispatcher.kt:103)\n",
"\tat kotlin.coroutines.jvm.internal.ContinuationImpl.releaseIntercepted(ContinuationImpl.kt:118)\n",
"\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:39)\n",
"\tat kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:55)\n"
]
}
],
"source": [
"JupyterPlotly.stopUpdates()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"@webio": {
"lastCommId": null,
"lastKernelId": null
},
"hide_input": false,
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"pygments_lexer": "kotlin",
"version": "1.4.20-dev-2342"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": false,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": false,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,226 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-08T21:37+0300",
"start_time": "2020-08-08T21:37+0300"
}
},
"outputs": [],
"source": [
"%use plotly-server\n",
"import kotlin.math.*"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-08T21:37+0300",
"start_time": "2020-08-08T21:37+0300"
}
},
"outputs": [],
"source": [
"val x1 = (0..100).map { it.toDouble() / 100.0 }\n",
"val y1 = x1.map { sin(2.0 * PI * it) }\n",
"val y2 = x1.map { cos(2.0 * PI * it) }\n",
"\n",
"val trace1 = Trace(x1, y1) { name = \"sin\" }\n",
"val trace2 = Trace(x1, y2) { name = \"cos\" }\n",
"\n",
"val fragment = Plotly.fragment { renderer ->\n",
" val plotConfig = PlotlyConfig{\n",
" responsive = true\n",
" } \n",
" \n",
" plot(\"above\", config = plotConfig, renderer = renderer) {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot above\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
" }\n",
" hr()\n",
" h1 { +\"A custom separator\" }\n",
" hr()\n",
" div {\n",
" plot(renderer = renderer) {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot below\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
" }\n",
" }\n",
"}\n",
"fragment"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-08T21:37+0300",
"start_time": "2020-08-08T21:37+0300"
}
},
"outputs": [],
"source": [
"Plotly.plot {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot below\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-08T21:37+0300",
"start_time": "2020-08-08T21:37+0300"
}
},
"outputs": [],
"source": [
"val x = (0..100).map { it.toDouble() / 100.0 }\n",
"val y = x.map { sin(2.0 * PI * it) }\n",
"\n",
"val trace = Trace(x, y) { name = \"sin\" }\n",
"\n",
"\n",
"val dynamicPlot = Plotly.plot {\n",
" traces(trace)\n",
" layout {\n",
" title = \"Dynamic plot\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
"}\n",
"\n",
"dynamicPlot"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-08T21:37+0300",
"start_time": "2020-08-08T21:37+0300"
}
},
"outputs": [],
"source": [
"import kotlinx.coroutines.*\n",
"\n",
"val job = GlobalScope.launch {\n",
" var time: Long = 0\n",
" while (isActive) {\n",
" delay(10)\n",
" time += 10\n",
" val dynamicY = x.map { sin(2.0 * PI * (it + time.toDouble() / 1000.0)) }\n",
" trace.y.set(dynamicY)\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-08T21:37+0300",
"start_time": "2020-08-08T21:37+0300"
}
},
"outputs": [],
"source": [
"job.cancel()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-08T21:37+0300",
"start_time": "2020-08-08T21:37+0300"
}
},
"outputs": [],
"source": [
"dynamicPlot.layout.xaxis.title = \"крокозябра\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-08T21:37+0300",
"start_time": "2020-08-08T21:37+0300"
}
},
"outputs": [],
"source": [
"plotly.port = 8884"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"@webio": {
"lastCommId": null,
"lastKernelId": null
},
"hide_input": false,
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "1.5.30-dev-598"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": false,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": false,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,298 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%use plotly"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# API"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"enum class Severity(val penalty: Double){\n",
" MINOR(1.0),\n",
" MAJOR(2.0),\n",
" CRITICAL(3.0)\n",
"}\n",
"\n",
"enum class State{\n",
" OPEN,\n",
" ASSIGNED,\n",
" RESOLVED\n",
"}\n",
"\n",
"data class Issue(val id: String, val dayCreated: Int, val severity: Severity, val complexity: Int, \n",
" var state: State = State.OPEN, var dayAssigned: Int? = null, var dayResolved: Int? = null){\n",
" fun activate(day: Int){ \n",
" state = State.ASSIGNED\n",
" dayAssigned = day\n",
" }\n",
" \n",
" fun resolve(day: Int){\n",
" state = State.RESOLVED\n",
" dayResolved = day\n",
" }\n",
" \n",
" internal fun tryResolve(day: Int){\n",
" if(state == State.ASSIGNED && day >= (dayAssigned ?: 0) + complexity ){\n",
" resolve(day)\n",
" }\n",
" }\n",
"}\n",
"\n",
"class Worker(val name: String){\n",
" var currentIssue: Issue? = null\n",
" private set\n",
" \n",
" fun isBusy(): Boolean = currentIssue != null\n",
" \n",
" fun update(day: Int){\n",
" currentIssue?.tryResolve(day)\n",
" if(currentIssue?.state == State.RESOLVED){\n",
" currentIssue = null\n",
" }\n",
" }\n",
" \n",
" fun assign(day: Int, issue: Issue){\n",
" if(currentIssue != null) error(\"Can't assign work to a worker which is busy\")\n",
" issue.activate(day)\n",
" currentIssue = issue\n",
" }\n",
"}\n",
"\n",
"interface IssueGenerator{\n",
" fun generate(day: Int): List<Issue>\n",
"}\n",
"\n",
"interface Strategy{\n",
" fun selectIssue(day: Int, issues: List<Issue>): Issue?\n",
"}\n",
"\n",
"class WorkResult(val issues: List<Issue>, val workers: Int, val days: Int)\n",
"\n",
"@OptIn(kotlin.ExperimentalStdlibApi::class)\n",
"fun simulate(generator: IssueGenerator, strategy: Strategy, numWorkers: Int = 10, days: Int = 100): WorkResult{\n",
" val workers = (0 until numWorkers).map{Worker(\"worker $it\")}\n",
" val issues = buildList<Issue>{\n",
" for(day in 0 until days){\n",
" //update all workers\n",
" workers.forEach { it.update(day) }\n",
" //generate new issues\n",
" val newIssues = generator.generate(day)\n",
" addAll(newIssues)\n",
" //Select all free workers\n",
" workers.filter { !it.isBusy() }.forEach { worker->\n",
" val unasigned = filter { it.state == State.OPEN }\n",
" val anIssue = strategy.selectIssue(day, unasigned) //select an issue to assign from all unassigned issues\n",
" if(anIssue != null){\n",
" worker.assign(day, anIssue)\n",
" }\n",
" }\n",
" }\n",
" }\n",
" return WorkResult(issues, numWorkers, days)\n",
"}\n",
"\n",
"fun WorkResult.computeLoss(): Double = issues.sumByDouble { ((it.dayResolved ?: days) - it.dayCreated)*it.severity.penalty } / days / workers / issues.size"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Implementations"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import kotlin.random.Random\n",
"import kotlin.math.pow\n",
"\n",
"/**\n",
"* Generate one random issue per day\n",
"*/\n",
"class RandomIssueGenerator(seed: Long, val issuesPerDay: Int = 4 ) : IssueGenerator{\n",
" private val random = Random(seed)\n",
" override fun generate(day: Int): List<Issue>{\n",
" return List(issuesPerDay){\n",
" val severity = Severity.values()[random.nextInt(3)]\n",
" val complexity = random.nextInt(15)\n",
" Issue(\"${day}_${it}\", day, severity, complexity)\n",
" }\n",
" }\n",
"}\n",
"\n",
"object TakeOldest: Strategy{\n",
" override fun selectIssue(day: Int, issues: List<Issue>): Issue?{\n",
" return issues.minByOrNull { it.dayCreated }\n",
" }\n",
"}\n",
"\n",
"class TakeRandom(seed: Long): Strategy{\n",
" private val random = Random(seed)\n",
" override fun selectIssue(day: Int, issues: List<Issue>): Issue?{\n",
" if(issues.isEmpty()) return null\n",
" return issues.random(random)\n",
" }\n",
"}\n",
"\n",
"object TakeCritical: Strategy{\n",
" override fun selectIssue(day: Int, issues: List<Issue>): Issue?{\n",
" return issues.maxByOrNull { it.severity.penalty*(day - it.dayCreated) }\n",
" }\n",
"}\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Simulate lossseverity"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"val seed = 89L\n",
"val days = 100\n",
"val workers = 10"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Take oldest"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"val result = simulate(RandomIssueGenerator(seed, workers),TakeOldest, days = days)\n",
"//result.issues.forEach { println(it)}\n",
"result.computeLoss()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Take random"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"simulate(RandomIssueGenerator(seed, workers),TakeRandom(seed), days = days).computeLoss()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Take critical"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"simulate(RandomIssueGenerator(seed, workers), TakeCritical, days = days).computeLoss()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"val seeds = List(1000){Random.nextLong()}\n",
"\n",
"Plotly.plot{\n",
" trace{\n",
" x.numbers = seeds.map{ seed -> simulate(RandomIssueGenerator(seed, workers), TakeOldest, days = days).computeLoss()}\n",
" name = \"oldest\"\n",
" type = TraceType.histogram\n",
" }\n",
" trace{\n",
" x.numbers = seeds.map{ seed -> simulate(RandomIssueGenerator(seed, workers), TakeRandom(seed), days = days).computeLoss()}\n",
" name = \"random\"\n",
" type = TraceType.histogram\n",
" }\n",
" trace{\n",
" x.numbers = seeds.map{ seed -> simulate(RandomIssueGenerator(seed, workers), TakeCritical, days = days).computeLoss()}\n",
" name = \"critical\"\n",
" type = TraceType.histogram\n",
" }\n",
" layout{\n",
" title = \"Loss distribtution\"\n",
" xaxis {\n",
" title = \"Loss\"\n",
" }\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "1.5.30-dev-598"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,334 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"21:08:36.601 [DefaultDispatcher-worker-1] INFO ktor.application - No ktor.deployment.watch patterns specified, automatic reload is not active\n",
"21:08:36.645 [DefaultDispatcher-worker-1] INFO ktor.application - Responding at http://0.0.0.0:8882\n"
]
},
{
"data": {
"text/html": [
"<div id=\"plotly-load-scripts\"></div>\n",
"<script type=\"text/javascript\">(function() {\n",
" console.log(\"Starting up plotly script loader\");\n",
" //initialize LaTeX for Jupyter\n",
" window.PlotlyConfig = {MathJaxConfig: 'local'};\n",
"\n",
" window.startupPlotly = function (){\n",
" if (window.MathJax){ \n",
" MathJax.Hub.Config({\n",
" SVG: {\n",
" font: \"STIX-Web\"\n",
" }\n",
" });\n",
" } \n",
" console.info(\"Calling deferred operations in Plotly queue.\")\n",
" window.plotlyCallQueue.forEach(function(theCall) {theCall();});\n",
" window.plotlyCallQueue = []; \n",
" }\n",
"})();</script>\n",
"<script type=\"text/javascript\" src=\"//localhost:8882/js/plotly.min.js\"></script>\n",
"<script type=\"text/javascript\">/**\r\n",
" * Use existing plotly or load it from the CDN if it is not available\r\n",
" * @param action\r\n",
" */\r\n",
"function withPlotly(action) {\r\n",
" if (typeof Plotly !== \"undefined\") {\r\n",
" action(Plotly);\r\n",
" } else if (typeof window.promiseOfPlotly !== \"undefined\") {\r\n",
" window.promiseOfPlotly.then(plotly => action(plotly));\r\n",
" } else {\r\n",
" console.warn(\"Plotly not defined. Loading the script from CDN\")\r\n",
" window.promiseOfPlotly = new Promise((accept, reject) => {\r\n",
" let plotlyLoaderScript = document.createElement(\"script\");\r\n",
" plotlyLoaderScript.src = \"https://cdnjs.cloudflare.com/ajax/libs/plotly.js/1.54.6/plotly.min.js\";\r\n",
" plotlyLoaderScript.type = 'text/javascript';\r\n",
" plotlyLoaderScript.onload = () => {\r\n",
" accept(Plotly);\r\n",
" }\r\n",
" plotlyLoaderScript.onerror = (error) => {\r\n",
" console.error(error);\r\n",
" reject(error)\r\n",
" }\r\n",
" document.head.appendChild(plotlyLoaderScript);\r\n",
" });\r\n",
" }\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Request and parse json from given address\r\n",
" * @param url {URL}\r\n",
" * @param callback\r\n",
" * @return Promise<Json>\r\n",
" */\r\n",
"function getJSON(url, callback) {\r\n",
"\r\n",
" function handleErrors(response) {\r\n",
" if (!response.ok) {\r\n",
" throw Error(response.statusText);\r\n",
" }\r\n",
" return response;\r\n",
" }\r\n",
"\r\n",
" try {\r\n",
" fetch(url, {\r\n",
" method: 'GET',\r\n",
" headers: {\r\n",
" Accept: 'application/json',\r\n",
" }\r\n",
" })\r\n",
" .then(handleErrors)\r\n",
" .then(response => response.json())\r\n",
" .then(json => callback(json))\r\n",
" .catch(error => console.log(error));\r\n",
" } catch (e) {\r\n",
" alert(\"Fetch of plot data failed with error: \" + e)\r\n",
" }\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Safe call for Plotly.newPlot\r\n",
" * @param id\r\n",
" * @param data\r\n",
" * @param layout\r\n",
" * @param config\r\n",
" */\r\n",
"function makePlot(id, data, layout, config) {\r\n",
" withPlotly(plotly => plotly.newPlot(id, data, layout, config))\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Create a plot taking data from given url\r\n",
" * @param id {string} element id for plot\r\n",
" * @param from {URL} json server url\r\n",
" * @param config {object} plotly configuration\r\n",
" * @return {JSON}\r\n",
" */\r\n",
"function createPlotFrom(id, from, config = {}) {\r\n",
" getJSON(from, json => withPlotly(plotly => {\r\n",
" plotly.newPlot(id, json.data, json.layout, config)\r\n",
" }));\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Update a plot taking data from given url\r\n",
" * @param id {string} element id for plot\r\n",
" * @param from {URL} json server url\r\n",
" * @return {JSON}\r\n",
" */\r\n",
"function updatePlotFrom(id, from) {\r\n",
" getJSON(from, json => withPlotly(plotly => plotly.react(id, json.data, json.layout)));\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Start pull updates with regular requests from client side\r\n",
" * @param id {string}\r\n",
" * @param from\r\n",
" * @param millis\r\n",
" */\r\n",
"function startPull(id, from, millis) {\r\n",
" let action = function () {\r\n",
" updatePlotFrom(id, from)\r\n",
" };\r\n",
" window.setInterval(action, millis)\r\n",
"}\r\n",
"\r\n",
"/**\r\n",
" * Start push updates via websocket\r\n",
" * @param id {string} element id for plot\r\n",
" * @param ws {URL} a websocket address\r\n",
" */\r\n",
"function startPush(id, ws) {\r\n",
" let socket = new WebSocket(ws);\r\n",
"\r\n",
" socket.onopen = function () {\r\n",
" console.log(\"[Plotly.kt] A connection for plot with id = \" + id + \" with server established on \" + ws);\r\n",
" };\r\n",
"\r\n",
" socket.onclose = function (event) {\r\n",
" if (event.wasClean) {\r\n",
" console.log(\"The connection with server is closed\");\r\n",
" } else {\r\n",
" console.log(\"The connection with server is broken\"); // Server process is dead\r\n",
" }\r\n",
" console.log('Code: ' + event.code + ' case: ' + event.reason);\r\n",
" };\r\n",
"\r\n",
" socket.onerror = function (error) {\r\n",
" console.error(\"Ploty push update error: \" + error.message);\r\n",
" socket.close()\r\n",
" };\r\n",
"\r\n",
" socket.onmessage = function (event) {\r\n",
" //console.log('got message: ' + event.data);\r\n",
" let json = JSON.parse(event.data);\r\n",
" //TODO check if plotly is initialized in a cell\r\n",
" if (json.plotId === id) {\r\n",
" if (json.contentType === \"layout\") {\r\n",
" withPlotly(plotly => plotly.relayout(id, json.content));\r\n",
" } else if (json.contentType === \"trace\") {\r\n",
" let content = json.content;\r\n",
" //This is done to satisfy plotly requirements of arrays-in-arrays for data\r\n",
" if (content.hasOwnProperty('x')) {\r\n",
" content.x = [content.x];\r\n",
" }\r\n",
" if (content.hasOwnProperty('y')) {\r\n",
" content.y = [content.y];\r\n",
" }\r\n",
" if (content.hasOwnProperty('z')) {\r\n",
" content.z = [content.z];\r\n",
" }\r\n",
" withPlotly(plotly => plotly.restyle(id, content, json['trace']));\r\n",
" }\r\n",
" }\r\n",
" };\r\n",
"\r\n",
" //gracefully close socket just in case\r\n",
" window.onbeforeunload = function () {\r\n",
" console.log(\"Gracefully closing socket\");\r\n",
" socket.onclose = function () {\r\n",
" }; // disable onclose handler first\r\n",
" socket.close();\r\n",
" };\r\n",
"}\r\n",
"\r\n",
"\r\n",
"window.startupPlotly()</script>\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%use plotly"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"ExecuteTime": {
"end_time": "2020-08-07T11:08+0300",
"start_time": "2020-08-07T11:08+0300"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
" <div id=\"scientifik.plotly.Plot@122c8b64\">\n",
" <script>\n",
"let theCall = function(){\n",
" makePlot(\n",
" 'scientifik.plotly.Plot@122c8b64',\n",
" [{\"x\":[2,3,4,5],\"y\":[10,15,13,17],\"type\":\"scatter\"}],\n",
" {\"annotations\":[{\"@index\":\"0\",\"x\":2,\"y\":10,\"text\":\"$\\\\alpha$\",\"font\":{\"size\":18}},{\"@index\":\"1\",\"x\":5,\"y\":17,\"text\":\"$\\\\Omega$\",\"font\":{\"size\":18}}],\"title\":{\"text\":\"$\\\\text{Plot with annotations } \\\\alpha~and~\\\\Omega$\"}},\n",
" {\"responsive\":true}\n",
" ); \n",
"};\n",
"\n",
"if(typeof Plotly === 'undefined'){\n",
" if(!window.plotlyCallQueue) {\n",
" window.plotlyCallQueue = [];\n",
" } \n",
" window.plotlyCallQueue.push(theCall)\n",
" window.plotlyCall(theCall);\n",
"} else {\n",
" theCall();\n",
"}\n",
"</script>\n",
" <script id=\"scientifik.plotly.Plot@122c8b64-push\">\n",
" \n",
" startPush('scientifik.plotly.Plot@122c8b64', 'ws://localhost:8882/ws/scientifik.plotly.Plot@122c8b64');\n",
" \n",
" </script>\n",
" </div>\n",
"</div>\n"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Plotly.plot {\n",
" scatter {\n",
" x(2, 3, 4, 5)\n",
" y(10, 15, 13, 17)\n",
" }\n",
"\n",
" text {\n",
" position(2, 10)\n",
" font {\n",
" size = 18\n",
" }\n",
" text = \"\\$\\\\alpha\\$\"\n",
" }\n",
"\n",
" text {\n",
" position(5, 17)\n",
" font {\n",
" size = 18\n",
" }\n",
" text = \"\\$\\\\Omega\\$\"\n",
" }\n",
"\n",
" layout {\n",
" title {\n",
" text = \"\\$\\\\text{Plot with annotations } \\\\alpha~and~\\\\Omega\\$\"\n",
" }\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"hide_input": false,
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"pygments_lexer": "kotlin",
"version": "1.4.20-dev-2342"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": false,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": false,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,156 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import space.kscience.plotly.PlotlyIntegration\n",
"USE(PlotlyIntegration())\n",
"//@file:CompilerArgs(\"-jvm-target=11\")\n",
"//@file:Repository(\"https://repo.kotlin.link\")\n",
"//@file:DependsOn(\"space.kscience:plotlykt-jupyter-jvm:0.7.1\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"import kotlin.math.*\n",
"\n",
"val x1 = (0..100).map { it.toDouble() / 100.0 }\n",
"val y1 = x1.map { sin(2.0 * PI * it) }\n",
"val y2 = x1.map { cos(2.0 * PI * it) }\n",
"\n",
"val trace1 = Trace(x1, y1) { name = \"sin\" }\n",
"val trace2 = Trace(x1, y2) { name = \"cos\" }\n",
"\n",
"Plotly.page { renderer ->\n",
" val plotConfig = PlotlyConfig{\n",
" responsive = true\n",
" imageFormat = \"svg\"\n",
" } \n",
" h1 { +\"A custom header\" }\n",
" hr()\n",
" plot(\"below\", config = plotConfig, renderer = renderer) {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot below\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
" }\n",
"\n",
"}"
]
},
{
"cell_type": "code",
"outputs": [],
"source": [
"HTML(\n",
" \"\"\"\n",
" <div id=\"debug\">\n",
" debug\n",
" </div>\n",
" \"\"\".trimIndent()\n",
")"
],
"metadata": {
"collapsed": false
},
"execution_count": null
},
{
"cell_type": "code",
"outputs": [],
"source": [
"HTML(\"\"\"\n",
"<script type = \"text/javascript\">\n",
" element = document.getElementById(\"debug\")\n",
" element.append(window.Plotly)\n",
" element.append(window.plotlyConnect)\n",
"</script>\n",
" \"\"\".trimIndent())"
],
"metadata": {
"collapsed": false
},
"execution_count": null
},
{
"cell_type": "code",
"outputs": [],
"source": [],
"metadata": {
"collapsed": false
},
"execution_count": null
},
{
"cell_type": "code",
"outputs": [],
"source": [
"HTML(\"\"\"\n",
"<script src=\"https://cdn.plot.ly/plotly-2.29.1.min.js\" charset=\"utf-8\"></script>\n",
"\"\"\")"
],
"metadata": {
"collapsed": false
},
"execution_count": null
},
{
"cell_type": "code",
"outputs": [],
"source": [],
"metadata": {
"collapsed": false
}
}
],
"metadata": {
"@webio": {
"lastCommId": null,
"lastKernelId": null
},
"hide_input": false,
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "1.5.30-dev-598"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": false,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": false,
"toc_window_display": false
},
"ktnbPluginMetadata": {
"projectDependencies": true
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,213 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [
"import space.kscience.plotly.server.PlotlyServerIntegration\n",
"import space.kscience.plotly.server.jupyter\n",
"\n",
"USE(PlotlyServerIntegration())"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import kotlin.math.*"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"val x1 = (0..100).map { it.toDouble() / 100.0 }\n",
"val y1 = x1.map { sin(2.0 * PI * it) }\n",
"val y2 = x1.map { cos(2.0 * PI * it) }\n",
"\n",
"val trace1 = Trace(x1, y1) { name = \"sin\" }\n",
"val trace2 = Trace(x1, y2) { name = \"cos\" }\n",
"\n",
"val fragment = Plotly.fragment { renderer ->\n",
" val plotConfig = PlotlyConfig {\n",
" responsive = true\n",
" }\n",
"\n",
" plot(\"above\", config = plotConfig, renderer = renderer) {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot above\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
" }\n",
" hr()\n",
" h1 { +\"A custom separator\" }\n",
" hr()\n",
" div {\n",
" plot(\"below\", renderer = renderer) {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot below\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
" }\n",
" }\n",
"}\n",
"fragment"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Plotly.plot {\n",
" traces(trace1, trace2)\n",
" layout {\n",
" title = \"The plot below\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"val x = (0..100).map { it.toDouble() / 100.0 }\n",
"val y = x.map { sin(2.0 * PI * it) }\n",
"\n",
"val trace = Trace(x, y) { name = \"sin\" }\n",
"\n",
"\n",
"val dynamicPlot = Plotly.plot {\n",
" traces(trace)\n",
" layout {\n",
" title = \"Dynamic plot\"\n",
" xaxis.title = \"x axis name\"\n",
" yaxis.title = \"y axis name\"\n",
" }\n",
"}\n",
"\n",
"dynamicPlot"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import kotlinx.coroutines.*\n",
"\n",
"val job = GlobalScope.launch {\n",
" var time: Long = 0\n",
" while (isActive) {\n",
" delay(10)\n",
" time += 10\n",
" val dynamicY = x.map { sin(2.0 * PI * (it + time.toDouble() / 1000.0)) }\n",
" trace.y.set(dynamicY)\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"job.cancel()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"dynamicPlot.layout.xaxis.title = \"крокозябра\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Plotly.jupyter.port = 8884"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Plotly.jupyter.port"
]
},
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [],
"metadata": {
"collapsed": false
}
}
],
"metadata": {
"@webio": {
"lastCommId": null,
"lastKernelId": null
},
"hide_input": false,
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "1.5.30-dev-598"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": false,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": false,
"toc_window_display": false
},
"ktnbPluginMetadata": {
"projectDependencies": true
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,30 @@
package annotation
import space.kscience.plotly.*
import space.kscience.plotly.models.ScatterMode
fun main() {
val plot = Plotly.plot {
scatter {
x(2, 3, 4, 5)
y(10, 15, 13, 17)
mode = ScatterMode.lines
}
text {
position(2, 10)
text = "start"
}
text {
position(5, 17)
text = "finish"
}
layout {
title = "Plot with annotation"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,45 @@
package bar
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.bar
import space.kscience.plotly.makeFile
/**
* - Bar chart with hover text
* - Use rgb color palette
* - Rotate axis ticks
*/
fun main() {
val plot = Plotly.plot {
bar {
x("Liam", "Sophie", "Jacob", "Mia", "William", "Olivia")
y(8.0, 8.0, 12.0, 12.0, 13.0, 20.0)
text("4.17 below the mean", "4.17 below the mean", "0.17 below the mean",
"0.17 below the mean", "0.83 above the mean", "7.83 above the mean")
marker {
color("rgb(142, 124, 195)")
}
showlegend = false
}
layout {
title {
text = "Number of Graphs Made this Week"
font {
family = "Raleway, sans-serif"
}
}
xaxis {
tickangle = -45
}
yaxis {
zeroline = false
gridwidth = 2
}
bargap = 0.05
}
}
plot.makeFile()
}

View File

@ -0,0 +1,72 @@
package bar
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Bar
import space.kscience.plotly.models.BarMode
/**
* - Colored and styled bar chart
* - Change font size and color of axis title & labels
* - Use grouped barmode
*/
fun main() {
val years = listOf(1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012)
val trace1 = Bar {
x.set(years)
y(219, 146, 112, 127, 124, 180, 236, 207, 236, 263, 350, 430, 474, 526, 488, 537, 500, 439)
name = "Rest of world"
marker {
color("rgb(55, 83, 109)")
}
}
val trace2 = Bar {
x.set(years)
y(16, 13, 10, 11, 28, 37, 43, 55, 56, 88, 105, 156, 270, 299, 340, 403, 549, 499)
name = "China"
marker {
color("rgb(26, 118, 255)")
}
}
val plot = Plotly.plot {
traces(trace1, trace2)
layout {
title = "US Export of Plastic Scrap"
xaxis {
tickfont {
size = 14
color("rgb(107, 107, 107)")
}
}
yaxis {
title {
text = "USD (millions)"
font {
size = 16
color("rgb(107, 107, 107)")
}
}
tickfont {
size = 14
color("rgb(107, 107, 107)")
}
}
legend {
x = 0
y = 1.0
bgcolor("rgba(255, 255, 255, 0)")
bordercolor("rgba(255, 255, 255, 0)")
}
barmode = BarMode.group
bargap = 0.15
bargroupgap = 0.1
}
}
plot.makeFile()
}

View File

@ -0,0 +1,43 @@
package bar
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Bar
import space.kscience.plotly.models.BarMode
import space.kscience.plotly.palettes.Xkcd
/**
* - Grouped bar chart
* - Use XKCD color palette
*/
fun main() {
val trace1 = Bar {
x("giraffes", "orangutans", "monkeys")
y(20, 14, 23)
name = "SF Zoo"
marker {
color(Xkcd.GREEN)
}
}
val trace2 = Bar {
x("giraffes", "orangutans", "monkeys")
y(12, 18, 29)
name = "LA Zoo"
marker {
color(Xkcd.BLUE)
}
}
val plot = Plotly.plot {
traces(trace1, trace2)
layout {
title = "Grouped Bar Chart"
barmode = BarMode.group
}
}
plot.makeFile()
}

View File

@ -0,0 +1,62 @@
package bar
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Bar
import space.kscience.plotly.models.TextPosition
/**
* - Grouped bar chart
* - Use rgb(a) color palette
* - Hide hoverinfo & legend
* - Show text on the bars
*/
fun main() {
val xValues = listOf("Product A", "Product B", "Product C")
val yValues = listOf(20, 14, 23)
val yValues2 = listOf(24, 16, 20)
val trace1 = Bar {
x.strings = xValues
y.numbers = yValues
text.strings = yValues.map { it.toString() }
textposition = TextPosition.auto
hoverinfo = "none"
opacity = 0.5
showlegend = false
marker {
color("rgb(158, 202, 225)")
line {
color("rgb(8, 48, 107)")
width = 2
}
}
}
val trace2 = Bar {
x.strings = xValues
y.numbers = yValues2
text.strings = yValues2.map { it.toString() }
textposition = TextPosition.auto
hoverinfo = "none"
showlegend = false
marker {
color("rgba(58, 200, 225, 0.5)")
line {
color("rgb(8, 48, 107)")
width = 2
}
}
}
val plot = Plotly.plot {
traces(trace1, trace2)
layout {
title = "January 2013 Sales Report"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,61 @@
package bar
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Bar
import space.kscience.plotly.models.Orientation
import kotlin.random.Random
/**
* - Horizontal bar chart
* - Use css named color palette
* - Change fontsize of the ticks
* - Add space between axis and ticklabels (set tickcolor to white)
*/
fun main() {
val colors = listOf("DarkOliveGreen", "OliveDrab", "YellowGreen", "GreenYellow", "Yellow", "PeachPuff",
"Pink", "HotPink", "DeepPink", "MediumVioletRed", "Purple", "RebeccaPurple", "MediumBlue", "Blue",
"DodgerBlue", "SteelBlue", "LightSlateGrey", "SlateGrey", "DarkSlateGrey", "Black")
val length = mutableListOf<Double>()
for (i in colors.indices) {
length.add(Random.nextDouble())
}
val bar = Bar {
y.strings = colors
x.numbers = length
orientation = Orientation.h
marker {
colors(colors)
}
}
val plot = Plotly.plot {
traces(bar)
layout {
title = "What an Awesome Plot!"
height = 700
width = 1200
margin {
l = 160
}
xaxis {
tickfont {
size = 14
}
}
yaxis {
tickfont {
size = 16
}
ticklen = 4
tickcolor("white")
}
}
}
plot.makeFile()
}

View File

@ -0,0 +1,41 @@
package bar
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Bar
/**
* - Bar chart with customized base
* -
*/
fun main() {
val trace1 = Bar {
x("2016", "2017", "2018")
y(500, 600, 700)
base = listOf(-500, -600, -700)
marker {
color("red")
}
name = "expenses"
}
val trace2 = Bar {
x("2016", "2017", "2018")
y(300, 400, 700)
marker {
color("blue")
}
name = "revenue"
}
val plot = Plotly.plot {
traces(trace1, trace2)
layout {
title = "Customizing individual bar base"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,32 @@
package bar
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.bar
import space.kscience.plotly.makeFile
/**
* - Colored bar chart
* - Use array of colors
* - Make bar chart without making Bar piece
* - Customizing individual bar colors and width
*/
fun main() {
val plot = Plotly.plot {
bar {
x("Feature A", "Feature B", "Feature C", "Feature D", "Feature E")
y(20, 14, 23, 25, 22)
widthList = listOf<Number>(0.8, 0.8, 0.9, 0.6, 0.8)
marker {
colors(listOf("rgba(204, 204, 204, 1)", "rgba(222, 45, 38, 0.8)", "rgba(204, 204, 204, 1)",
"rgba(204, 204, 204, 1)", "rgba(204, 204, 204, 1)"))
}
}
layout {
title = "Least Used Feature"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,62 @@
package bar
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.bar
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.BarMode
import space.kscience.plotly.models.XAnchor
import space.kscience.plotly.models.YAnchor
/**
* - Stacked bar chart
* - Use css named colors
* - Show legend inside the plot
* - Change margins
*/
fun main() {
val values = listOf<Number>(1, 2, 3.5, 4.1, 4.7, 4, 3.2, 1.95, 1)
val plot = Plotly.plot {
bar {
y.numbers = values
marker { color("red") }
}
bar {
y.numbers = values
marker { color("orange") }
}
bar {
y.numbers = values
marker { color("yellow") }
}
bar {
y.numbers = values
marker { color("greenyellow") }
}
bar {
y.numbers = values
marker { color("limegreen") }
}
layout {
barmode = BarMode.stack
title = "Stacked Bar Chart"
margin { l = 20; r = 20; b = 20; t = 40 }
legend {
xanchor = XAnchor.right
yanchor = YAnchor.top
x = 1
y = 1
borderwidth = 1
}
}
}
plot.makeFile()
}

View File

@ -0,0 +1,46 @@
package box
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Box
import space.kscience.plotly.models.BoxPoints
import kotlin.random.Random
/**
* - Basic Box plot with all points
*/
fun main() {
val size = 50
val y0 = mutableListOf<Double>()
val y1 = mutableListOf<Double>()
for (i in 0 until size) {
y0.add(Random.nextDouble())
y1.add(Random.nextDouble())
}
val trace1 = Box {
y.set(y0)
boxpoints = BoxPoints.all
jitter = 0.3
pointpos = -1.8
}
val trace2 = Box {
y.set(y1)
boxpoints = BoxPoints.all
jitter = 0.3
pointpos = -1.8
}
val plot = Plotly.plot {
traces(trace1, trace2)
layout {
title = "Basic Box Plot"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,88 @@
package box
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Box
import space.kscience.plotly.models.BoxPoints
import space.kscience.plotly.models.Trace
import kotlin.random.Random
fun getRandom(size: Int, mul: Double): List<Double> {
val value = mutableListOf<Double>()
for (i in 0..size) {
value.add(Random.nextDouble() * mul)
}
return value.toList()
}
/**
* - Styled box plot
* - Style zeroline & grid
* - Change background color of the plot
* - Use array of traces
*/
fun main() {
val xData = listOf("Carmelo<br>Anthony", "Dwyane<br>Wade", "Deron<br>Williams",
"Brook<br>Lopez", "Damian<br>Lillard", "David<br>West",
"Blake<br>Griffin", "David<br>Lee", "Demar<br>Derozan")
val yData = listOf(
getRandom(30, 10.0),
getRandom(30, 20.0),
getRandom(30, 25.0),
getRandom(30, 40.0),
getRandom(30, 45.0),
getRandom(30, 30.0),
getRandom(30, 20.0),
getRandom(30, 15.0),
getRandom(30, 43.0),
getRandom(30, 10.0)
)
val data = mutableListOf<Trace>()
for (i in xData.indices) {
val result = Box {
y.set(yData[i])
name = xData[i]
boxpoints = BoxPoints.all
jitter = 0.5
whiskerwidth = 0.2
fillcolor("cls")
marker {
size = 2
}
line {
width = 1
}
showlegend = false
}
data.add(result)
}
val plot = Plotly.plot {
traces(data)
layout {
title = "Points Scored by the Top 9 Scoring NBA Players in 2012"
yaxis {
autorange = true
showgrid = true
zeroline = true
gridcolor("rgb(255, 255, 255)")
gridwidth = 1
zerolinecolor("rgb(255, 255, 255)")
zerolinewidth = 2
}
margin {
l = 40
r = 30
b = 80
t = 100
}
paper_bgcolor("rgb(243, 243, 243)")
plot_bgcolor("rgb(243, 243, 243)")
}
}
plot.makeFile()
}

View File

@ -0,0 +1,67 @@
package box
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Box
import space.kscience.plotly.models.BoxMean
import space.kscience.plotly.models.BoxMode
import space.kscience.plotly.models.Orientation
/**
* - Horizontal box plot
* - Grouped boxes
* - Change box colors
*/
fun main() {
val y0 = listOf("day 1", "day 1", "day 1", "day 1", "day 1", "day 1",
"day 2", "day 2", "day 2", "day 2", "day 2", "day 2")
val trace1 = Box {
x(0.2, 0.2, 0.6, 1.0, 0.5, 0.4, 0.2, 0.7, 0.9, 0.1, 0.5, 0.3)
y.strings = y0
name = "kale"
marker {
color("#3D9970")
}
boxmean = BoxMean.`false`
orientation = Orientation.h
}
val trace2 = Box {
x(0.6, 0.7, 0.3, 0.6, 0.0, 0.5, 0.7, 0.9, 0.5, 0.8, 0.7, 0.2)
y.strings = y0
name = "radishes"
marker {
color("#FF4136")
}
boxmean = BoxMean.`false`
orientation = Orientation.h
}
val trace3 = Box {
x(0.1, 0.3, 0.1, 0.9, 0.6, 0.6, 0.9, 1.0, 0.3, 0.6, 0.8, 0.5)
y.strings = y0
name = "carrots"
marker {
color("#FF851B")
}
boxmean = BoxMean.`false`
orientation = Orientation.h
}
val plot = Plotly.plot {
traces(trace1, trace2, trace3)
layout {
title = "Grouped Horizontal Box Plot"
xaxis {
title = "normalized moisture"
zeroline = false
}
boxmode = BoxMode.group
}
}
plot.makeFile()
}

View File

@ -0,0 +1,40 @@
package box
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Box
import space.kscience.plotly.models.BoxMean
import space.kscience.plotly.palettes.Xkcd
fun main() {
val y1 = listOf(2.37, 2.16, 4.82, 1.73, 1.04, 0.23, 1.32, 2.91, 0.11, 4.51, 0.51,
3.75, 1.35, 2.98, 4.50, 0.18, 4.66, 1.30, 2.06, 1.19)
val trace1 = Box {
y.numbers = y1
name = "Only Mean"
marker {
color(Xkcd.CERULEAN)
}
boxmean = BoxMean.`true`
}
val trace2 = Box {
y.numbers = y1
name = "Mean and Standard Deviation"
marker {
color(Xkcd.BLUE_VIOLET)
}
boxmean = BoxMean.sd
}
val plot = Plotly.plot {
traces(trace1, trace2)
layout {
title = "Box Plot Styling Mean and Standard Deviation"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,66 @@
package box
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Box
import space.kscience.plotly.models.BoxPoints
fun main() {
val y1 = listOf<Number>(0.75, 5.25, 5.5, 6, 6.2, 6.6, 6.80, 7.0, 7.2, 7.5, 7.5, 7.75, 8.15, 8.15,
8.65, 8.93, 9.2, 9.5, 10, 10.25, 11.5, 12, 16, 20.90, 22.3, 23.25)
val trace1 = Box {
y.set(y1)
name = "All Points"
jitter = 0.3
pointpos = -1.8
marker {
color("rgb(7, 40, 89)")
}
boxpoints = BoxPoints.all
}
val trace2 = Box {
y.set(y1)
name = "Only Wiskers"
marker {
color("rgb(9, 56, 125)")
}
boxpoints = BoxPoints.`false`
}
val trace3 = Box {
y.set(y1)
name = "Suspected Outlier"
marker {
color("rgb(8, 81, 156)")
outliercolor("rgba(219, 64, 82, 0.6)")
line {
outliercolor("rgba(219, 64, 82, 1.0)")
outlierwidth = 2
}
}
boxpoints = BoxPoints.suspectedoutliers
}
val trace4 = Box {
y.set(y1)
name = "Wiskers and Outliers"
marker {
color("rgb(107, 174, 214)")
}
boxpoints = BoxPoints.outliers
}
val plot = Plotly.plot {
traces(trace1, trace2, trace3, trace4)
layout {
width = 700
height = 450
title = "Box Plot Styling Outliers"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,215 @@
package candlestick
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.layout
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.AxisType
import space.kscience.plotly.models.CandleStick
import space.kscience.plotly.models.DragMode
internal val candleStickTrace = CandleStick {
x.strings = listOf(
"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.numbers = listOf(
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
)
high.numbers = listOf(
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 {
lineColor("#17BECF")
}
decreasing {
lineColor("#7F7F7F")
}
line { color("rgba(31,119,180,1)") }
low.numbers = listOf(
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.numbers = listOf(
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
)
}
fun main() {
Plotly.plot {
traces(candleStickTrace)
layout {
dragmode = DragMode.zoom
margin {
r = 10
t = 25
b = 40
l = 60
}
showlegend = false
xaxis {
autorange = true
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 = AxisType.date
}
yaxis {
autorange = true
range(114.609999778..137.410004222)
type = AxisType.linear
}
}
}.makeFile()
}

View File

@ -0,0 +1,59 @@
package candlestick
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import space.kscience.plotly.Plotly
import space.kscience.plotly.layout
import space.kscience.plotly.models.AxisType
import space.kscience.plotly.models.DragMode
import space.kscience.plotly.plot
import space.kscience.plotly.server.close
import space.kscience.plotly.server.pushUpdates
import space.kscience.plotly.server.serve
import space.kscience.plotly.server.show
import kotlin.random.Random
fun main() {
val server = Plotly.serve {
pushUpdates(50)
page { plotly ->
plot(renderer = plotly) {
traces(candleStickTrace)
layout {
dragmode = DragMode.zoom
margin {
r = 10
t = 25
b = 40
l = 60
}
showlegend = false
xaxis {
type = AxisType.date
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"
}
yaxis {
range(114.609999778..137.410004222)
}
}
launch {
while (isActive) {
delay(400)
candleStickTrace.open.numbers = candleStickTrace.open.doubles.map { it + Random.nextDouble() - 0.5 }
}
}
}
}
}
server.show()
println("Enter 'exit' to close server")
while (readLine()?.trim() != "exit") {
//wait
}
server.close()
}

View File

@ -0,0 +1,138 @@
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.zip
import kotlinx.coroutines.launch
import kotlinx.html.div
import kotlinx.html.link
import space.kscience.plotly.Plotly
import space.kscience.plotly.layout
import space.kscience.plotly.models.Trace
import space.kscience.plotly.plot
import space.kscience.plotly.server.pushUpdates
import space.kscience.plotly.server.serve
import space.kscience.plotly.server.show
import space.kscience.plotly.trace
import java.time.Instant
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.math.cos
import kotlin.math.sin
/**
* In-place replacement for absent method from stdlib
*/
fun <T> Flow<T>.windowed(size: Int): Flow<Iterable<T>> {
val queue = ConcurrentLinkedQueue<T>()
return flow {
this@windowed.collect {
queue.add(it)
if (queue.size >= size) {
queue.poll()
}
emit(queue)
}
}
}
suspend fun Trace.updateFrom(axisName: String, flow: Flow<Iterable<Double>>) {
flow.collect {
axis(axisName).numbers = it
}
}
suspend fun Trace.updateXYFrom(flow: Flow<Iterable<Pair<Double, Double>>>) {
flow.collect { pairs ->
x.numbers = pairs.map { it.first }
y.numbers = pairs.map { it.second }
}
}
fun main() {
val server = Plotly.serve {
val sinFlow = flow {
while (true) {
delay(40)
val time = Instant.now()
emit(sin(time.toEpochMilli().toDouble() / 2500))
}
}
val cosFlow = flow {
while (true) {
delay(50)
val time = Instant.now()
emit(cos(time.toEpochMilli().toDouble() / 2500))
}
}
val sinCosFlow = sinFlow.zip(cosFlow) { sin, cos ->
sin to cos
}
page { renderer ->
link {
rel = "stylesheet"
href = "https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
attributes["integrity"] = "sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
attributes["crossorigin"] = "anonymous"
}
div("row") {
div("col-6") {
plot(renderer = renderer) {
layout {
title = "sin property"
xaxis.title = "point index"
yaxis.title = "sin"
}
trace {
val flow: Flow<Iterable<Double>> = sinFlow.windowed(100)
launch {
updateFrom(Trace.Y_AXIS, flow)
}
}
}
}
div("col-6") {
plot(renderer = renderer) {
layout {
title = "cos property"
xaxis.title = "point index"
yaxis.title = "cos"
}
trace {
val flow: Flow<Iterable<Double>> = cosFlow.windowed(100)
launch {
updateFrom(Trace.Y_AXIS, flow)
}
}
}
}
}
div("row") {
div("col-12") {
plot(renderer = renderer) {
layout {
title = "cos vs sin"
xaxis.title = "sin"
yaxis.title = "cos"
}
trace {
name = "non-synchronized"
val flow: Flow<Iterable<Pair<Double, Double>>> = sinCosFlow.windowed(30)
launch {
updateXYFrom(flow)
}
}
}
}
}
}
pushUpdates(100) // start sending updates via websocket to the front-end
}
server.show()
println("Press Enter to close server")
readLine()
server.stop(1000, 5000)
}

View File

@ -0,0 +1,60 @@
package contour
import space.kscience.plotly.Plotly
import space.kscience.plotly.layout
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Contour
import space.kscience.plotly.models.MeasureMode
/**
* - basic contour plot
* - change font size of labels ticks
* - setting x and y coordinates
* - change color bar size
*/
fun main() {
val values: List<List<Number>> = listOf(
listOf<Number>(10, 10.625, 12.5, 15.625, 20.0),
listOf<Number>(5.625, 6.25, 8.125, 11.25, 15.625),
listOf<Number>(2.5, 3.125, 5.0, 8.125, 12.5),
listOf<Number>(0.625, 1.25, 3.125, 6.25, 10.625),
listOf<Number>(0.0, 0.625, 2.5, 5.625, 10)
)
val x1 = listOf(-9, -6, -5, -3, -1)
val y1 = listOf(0, 1, 4, 5, 7)
val contour = Contour{
x.numbers = x1
y.numbers = y1
z(values)
colorbar {
thickness = 75.0
thicknessmode = MeasureMode.pixels
len = 0.9
lenmode = MeasureMode.fraction
outlinewidth = 0
}
}
val plot = Plotly.plot {
traces(contour)
layout {
title = "Basic Contour Plot"
xaxis {
tickfont {
size = 16
}
}
yaxis {
tickfont {
size = 16
}
}
}
}
plot.makeFile()
}

View File

@ -0,0 +1,59 @@
package contour
import space.kscience.dataforge.meta.Value
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Contour
import kotlin.math.cos
import kotlin.math.pow
import kotlin.math.sin
/**
* - simple contour plot without level lines
* - transpose axis
* - change size of the plot
* - change color scale
*/
fun main() {
val size = 25
val x1 = (0..size).map { it.toDouble() / 5 }
val y1 = (0..size).map { it.toDouble() / 5 }
val z = mutableListOf<MutableList<Double>>()
for (i in y1.indices) {
z.add(MutableList(size + 1) { 0.0 })
}
for (i in x1.indices) {
for (j in y1.indices) {
z[i][j] = sin(x1[i]).pow(10) + cos(10 + y1[j] * x1[i]) * cos(x1[i])
}
}
val contour = Contour {
x.numbers = x1
y.numbers = y1
z(z)
transpose = true
colorscale = Value.of("Portland")
reversescale = true
contours {
showlines = false
}
}
val plot = Plotly.plot {
traces(contour)
layout {
width = 1000
height = 500
title = "Colored Contour Plot"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,59 @@
package contour
import space.kscience.plotly.*
import space.kscience.plotly.models.Contour
/**
* - contour plots with and without gaps between not-null values
* - change plot size
* - stack two plots
*/
fun main() {
val x1 = (0..7)
val y2 = (0..6)
val z1 = listOf(
listOf<Number?>(null, null, null, 12, 13, 14, 15, 16),
listOf<Number?>(null, 1, null, 11, null, null, null, 17),
listOf<Number?>(null, 2, 6, 7, null, null, null, 18),
listOf<Number?>(null, 3, null, 8, null, null, null, 19),
listOf<Number?>(5, 4, 10, 9, null, null, null, 20),
listOf<Number?>(null, null, null, 27, null, null, null, 21),
listOf<Number?>(null, null, null, 26, 25, 24, 23, 22))
val contour1 = Contour{
x.set(x1)
y.set(y2)
z.set(z1)
showscale = false
}
val contour2 = Contour {
x.set(x1)
y.set(y2)
z.set(z1)
showscale = false
connectgaps = true
}
Plotly.fragment {
plot {
traces(contour1)
layout {
width = 800
height = 450
title = "Gaps Between Nulls"
}
}
plot {
traces(contour2)
layout {
width = 800
height = 450
title = "Connected Gaps"
}
}
}.makeFile()
}

View File

@ -0,0 +1,65 @@
package contour
import space.kscience.dataforge.meta.Value
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.contour
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.ContoursColoring
import kotlin.math.exp
import kotlin.math.pow
/**
* - colored contour plot lines
* - labels on contour lines
* - change size of the plot and contour lines width
*/
fun main() {
val range = -300..300
val rangeSize = range.last - range.first + 1
val x1 = range.map { it.toDouble() / 100 }
val y1 = range.map { it.toDouble() / 100 }
val values = mutableListOf<MutableList<Double>>()
for (i in y1.indices) {
values.add(MutableList(rangeSize) { 0.0 })
}
for (i in x1.indices) {
for (j in y1.indices) {
val z1 = exp(-x1[i].pow(2) - y1[j].pow(2))
val z2 = exp(-(x1[i] - 1).pow(2) - (y1[j] - 1).pow(2))
values[i][j] = (z1 - z2) * 2
}
}
val plot = Plotly.plot {
contour {
x.set(x1)
y.set(y1)
z.set(values)
line {
width = 4
}
colorscale = Value.of("Jet")
contours {
coloring = ContoursColoring.lines
showlabels = true
labelfont {
size = 16
}
}
}
layout {
width = 700
height = 600
title = "Contour Lines with Labels"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,35 @@
package contour
import space.kscience.dataforge.meta.Value
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Contour
fun main() {
val z1 = listOf(
listOf<Number>(10, 10.625, 12.5, 15.625, 20),
listOf<Number>(5.625, 6.25, 8.125, 11.25, 15.625),
listOf<Number>(2.5, 3.125, 5.0, 8.125, 12.5),
listOf<Number>(0.625, 1.25, 3.125, 6.25, 10.625),
listOf<Number>(0, 0.625, 2.5, 5.625, 10))
val contour = Contour {
z.set(z1)
colorscale = Value.of("Jet")
dx = 10
x0 = Value.of(5)
dy = 10
y0 = Value.of(10)
}
val plot = Plotly.plot {
traces(contour)
layout {
title = "Customizing Spacing Between X and Y Axis Ticks"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,93 @@
package contour
import space.kscience.dataforge.meta.Value
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.contour
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.ContoursColoring
import space.kscience.plotly.models.Dash
import kotlin.math.exp
import kotlin.math.pow
/**
* - colored contour plot lines
* - labels on contour lines
* - hide colorbar
* - change size of the plot and contour lines width
* - change style of contour lines
*/
fun main() {
val range = -160..260 step 4
val rangeSize = (range.last - range.first) / 4 + 1
val x1 = range.map { it.toDouble() / 100 }
val y1 = range.map { it.toDouble() / 100 }
val z1 = mutableListOf<MutableList<Double?>>()
val z2 = mutableListOf<MutableList<Double?>>()
for (i in x1.indices) {
z1.add(MutableList(rangeSize) { 0.0 })
z2.add(MutableList(rangeSize) { 0.0 })
}
for (i in x1.indices) {
for (j in y1.indices) {
val elem1 = exp(-x1[i].pow(2) - y1[j].pow(2))
val elem2 = exp(-(x1[i] - 1).pow(2) - (y1[j] - 1).pow(2))
val elem = (elem1 - elem2) * 2
if (elem >= -0.01) {
z1[i][j] = elem
z2[i][j] = null
} else {
z2[i][j] = elem
z1[i][j] = null
}
}
}
val plot = Plotly.plot {
contour {
x.set(x1)
y.set(y1)
z.set(z1)
line {
width = 4
}
connectgaps = true
colorscale = Value.of("Jet")
showscale = false
contours {
coloring = ContoursColoring.lines
showlabels = true
}
}
contour {
x.set(x1)
y.set(y1)
z.set(z2)
line {
width = 4
dash = Dash.dash
}
connectgaps = true
colorscale = Value.of("Jet")
reversescale = true
showscale = false
contours {
coloring = ContoursColoring.lines
showlabels = true
}
}
layout {
width = 900
height = 750
title = "Negative Contours Dashed"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,52 @@
package contour
import space.kscience.dataforge.meta.asValue
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.contour
import space.kscience.plotly.makeFile
import kotlin.math.cos
import kotlin.math.ln
import kotlin.math.sin
/**
* - simple contour plot
* - change colorscale
* - set x and y coordinates of the plot
*/
fun main() {
val size = 100
val x1 = mutableListOf<Double>()
val y1 = mutableListOf<Double>()
val z1 = mutableListOf<MutableList<Double>>()
for (i in 0 until size) {
val elem = -2 * Math.PI + 4 * Math.PI * i / size
x1.add(elem)
y1.add(elem)
z1.add(MutableList(size) { 0.0 })
}
for (i in x1.indices) {
for (j in y1.indices) {
val r2 = x1[i] * x1[i] + y1[j] * y1[j]
z1[i][j] = sin(x1[i]) * cos(y1[j]) * sin(r2) / ln(r2 + 1)
}
}
val plot = Plotly.plot {
contour {
x.set(x1)
y.set(x1)
z.set(z1)
colorscale = "YlGnBu".asValue()
}
layout {
title = "Simple Contour Plot"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,43 @@
import kotlinx.html.div
import kotlinx.html.h1
import kotlinx.html.hr
import space.kscience.plotly.*
import space.kscience.plotly.models.Trace
import space.kscience.plotly.models.invoke
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
fun main() {
val x1 = (0..100).map { it.toDouble() / 100.0 }
val y1 = x1.map { sin(2.0 * PI * it) }
val y2 = x1.map { cos(2.0 * PI * it) }
val trace1 = Trace(x1, y1) { name = "sin" }
val trace2 = Trace(x1, y2) { name = "cos" }
Plotly.page { container ->
plot(renderer = container) {
traces(trace1, trace2)
layout {
title = "The plot above"
xaxis.title = "x axis name"
yaxis.title = "y axis name"
}
}
hr()
h1 { +"A custom separator" }
hr()
div {
plot {
traces(trace1, trace2)
layout {
title = "The plot below"
xaxis.title = "x axis name"
yaxis.title = "y axis name"
}
}
}
}.makeFile()
}

View File

@ -0,0 +1,36 @@
import space.kscience.plotly.*
import space.kscience.plotly.models.ScatterMode
/**
* - Bubble chart with different marker sizes
* - Download plot as SVG using configuration button
*/
fun main() {
val fragment = Plotly.fragment {
val plotConfig = PlotlyConfig{
saveAsSvg()
}
plot(config = plotConfig) {
scatter {
x(1, 2, 3, 4)
y(10, 11, 12, 13)
text("A<br>size: 40", "B<br>size: 60", "C<br>size: 80", "D<br>size: 100")
mode = ScatterMode.markers
marker {
colors(listOf("rgb(93, 164, 214)", "rgb(255, 144, 14)", "rgb(44, 160, 101)", "rgb(255, 65, 54)"))
sizesList = listOf(40, 60, 80, 100)
}
}
layout {
title = "Download Chart as SVG instead of PNG"
showlegend = false
height = 600
width = 600
}
}
}
fragment.makeFile()
}

View File

@ -0,0 +1,84 @@
import kotlinx.coroutines.*
import kotlinx.html.a
import kotlinx.html.h1
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.models.Trace
import space.kscience.plotly.models.invoke
import space.kscience.plotly.plot
import space.kscience.plotly.server.close
import space.kscience.plotly.server.pushUpdates
import space.kscience.plotly.server.serve
import space.kscience.plotly.server.show
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
@OptIn(DelicateCoroutinesApi::class)
fun main() {
val freq = 1.0 / 1000
val oscillationFreq = 1.0 / 10000
val x = (0..100).map { it.toDouble() / 100.0 }
val sinY = x.map { sin(2.0 * PI * it) }
val cosY = x.map { cos(2.0 * PI * it) }
val sinTrace = Trace(x, sinY) { name = "sin" }
val cosTrace = Trace(x, cosY) { name = "cos" }
val server = Plotly.serve(port = 7878) {
embedData = true
//root level plots go to default page
page { plotly ->
h1 { +"This is the plot page" }
a("/other") { +"The other page" }
plot(renderer = plotly) {
traces(sinTrace, cosTrace)
layout {
title = "Other dynamic plot"
xaxis.title = "x axis name"
yaxis.title = "y axis name"
}
}
}
page("other") { plotly ->
h1 { +"This is the other plot page" }
a("/") { +"Back to the main page" }
plot(renderer = plotly) {
traces(sinTrace)
layout {
title = "Dynamic plot"
xaxis.title = "x axis name"
yaxis.title = "y axis name"
}
}
}
pushUpdates(50) // start sending updates via websocket to the front-end
}
server.show()
//Start pushing updates
GlobalScope.launch {
var time: Long = 0
while (isActive) {
delay(10)
time += 10
sinTrace.y.numbers = x.map { sin(2.0 * PI * (it + time.toDouble() * freq)) }
val cosAmp = cos(2.0 * PI * oscillationFreq * time)
cosTrace.y.numbers = x.map { cos(2.0 * PI * (it + time.toDouble() * freq)) * cosAmp }
}
}
println("Press Enter to close server")
while (readLine()?.trim() != "exit"){
//wait
}
server.close()
}

View File

@ -0,0 +1,32 @@
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.ResourceLocation
import space.kscience.plotly.makeFile
import space.kscience.plotly.trace
import kotlin.math.PI
import kotlin.math.sin
fun main() {
val x1 = (0..100).map { it.toDouble() / 100.0 }
val y1 = x1.map { sin(2.0 * PI * it) }
val plot = Plotly.plot {
trace {
x.set(x1)
y.set(y1)
name = "for a single trace in graph its name would be hidden"
}
layout {
title = "Graph name"
xaxis {
title = "x axis"
}
yaxis {
title = "y axis"
}
}
}
plot.makeFile(resourceLocation = ResourceLocation.EMBED)
}

View File

@ -0,0 +1,74 @@
package errorPlots
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.ErrorType
import space.kscience.plotly.models.TraceOrder
import space.kscience.plotly.models.XAnchor
import space.kscience.plotly.models.YAnchor
import space.kscience.plotly.scatter
/**
* - asymmetric error bars
* - use numeric array as error length
* - use only negative or positive errors
* - change legend position
* - change width of the legend border
* - change order of legend items
*/
fun main() {
val x1 = listOf(1, 2, 3, 4)
val y1 = listOf(2, 3, 5, 8)
val err = listOf(0.5, 0.75, 1.0, 1.25)
val plot = Plotly.plot {
scatter {
x.set(x1)
y.set(y1)
name = "both errors"
error_y {
type = ErrorType.data
array = err
visible = true
}
}
scatter {
x.set(x1)
y.set(y1.map { it + 4 }.toList())
name = "positive err"
error_y {
type = ErrorType.data
array = err
symmetric = false
visible = true
}
}
scatter {
x.set(x1)
y.set(y1.map { it + 8 }.toList())
name = "negative err"
error_y {
type = ErrorType.data
arrayminus = err
symmetric = false
visible = true
}
}
layout {
title = "Asymmetric Error Bars"
legend {
x = 0.05
borderwidth = 1
xanchor = XAnchor.left
yanchor = YAnchor.top
traceorder = TraceOrder.reversed
}
}
}
plot.makeFile()
}

View File

@ -0,0 +1,60 @@
package errorPlots
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.bar
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.BarMode
import space.kscience.plotly.models.ErrorType
import space.kscience.plotly.models.XAnchor
/**
* - bar chart with symmetrical error bars
* - use numeric array as error bars length
* - change color and width of legend border
*/
fun main() {
val x1 = listOf("Trial 1", "Trial 2", "Trial 3")
val y1 = listOf(3, 6, 4)
val y2 = listOf(4, 7, 3)
val plot = Plotly.plot {
bar {
x.set(x1)
y.set(y1)
name = "Experimental"
error_y {
type = ErrorType.data
array = listOf(1, 0.5, 1.5)
visible = true
}
}
bar {
x.set(x1)
y.set(y2)
name = "Control"
error_y {
type = ErrorType.data
array = listOf(1, 0.5, 1.5)
visible = true
}
}
layout {
barmode = BarMode.group
title = "Bar Chart with Error Bars"
legend {
x = 1
y = 1
bordercolor("black")
borderwidth = 1
xanchor = XAnchor.auto
}
}
}
plot.makeFile()
}

View File

@ -0,0 +1,37 @@
package errorPlots
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.ErrorType
import space.kscience.plotly.trace
/**
* - basic symmetric error bars
* - use numeric array as error length
* - change color of error bars
*/
fun main() {
val xValues = listOf(0, 1, 2)
val yValues = listOf(6, 10, 2)
val err = listOf(1, 2, 3)
val plot = Plotly.plot {
trace {
x.numbers = xValues
y.numbers = yValues
error_y {
type = ErrorType.data
array = err
visible = true
color("orange")
}
}
layout {
title = "Basic Symmetric Error Bars"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,44 @@
package errorPlots
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.box
import space.kscience.plotly.makeFile
import space.kscience.plotly.palettes.T10
import java.util.*
/**
* - basic box plot
* - change color of the boxes
* - use T10 as color palette
*/
fun main() {
val rnd = Random()
val y1 = List(50) { rnd.nextDouble() }
val y2 = List(50) { rnd.nextDouble() + 1 }
val plot = Plotly.plot {
box {
y.set(y1)
name = "Sample A"
marker {
color(T10.PINK)
}
}
box {
y.set(y2)
name = "Sample B"
marker {
color(T10.OLIVE)
}
}
layout {
title = "Colored Box Plot"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,112 @@
package errorPlots
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.FillType
import space.kscience.plotly.models.Scatter
import space.kscience.plotly.models.ScatterMode
import space.kscience.plotly.models.Ticks
/**
* - Scatter plot with filled error lines
* - Use rgb(a) color palette
* - Change colors of grid, paper background and line fills
*/
fun main() {
val trace1 = Scatter {
x(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
y(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
fill = FillType.tozerox
fillcolor("rgba(0, 100, 80, 0.2)")
line {
color("transparent")
}
name = "Fair"
showlegend = false
}
val trace2 = Scatter {
x(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
y(5.5, 3, 5.5, 8, 6, 3, 8, 5, 6, 5.5, 4.75, 5, 4, 7, 2, 4, 7, 4.4, 2, 4.5)
fill = FillType.tozerox
fillcolor("rgba(0, 176, 246, 0.2)")
line {
color("transparent")
}
name = "Premium"
showlegend = false
}
val trace3 = Scatter {
x(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
y(11, 9, 7, 5, 3, 1, 3, 5, 3, 1, -1, 1, 3, 1, -0.5, 1, 3, 5, 7, 9)
fill = FillType.tozerox
fillcolor("rgba(231, 107, 243, 0.2)")
line {
color("transparent")
}
name = "Fair"
showlegend = false
}
val trace4 = Scatter {
x(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
y(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
line {
color("rgb(0, 100, 80)")
}
mode = ScatterMode.lines
name = "Fair"
}
val trace5 = Scatter {
x(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
y(5, 2.5, 5, 7.5, 5, 2.5, 7.5, 4.5, 5.5, 5)
line {
color("rgb(0, 176, 246)")
}
mode = ScatterMode.lines
name = "Premium"
}
val trace6 = Scatter {
x(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
y(10, 8, 6, 4, 2, 0, 2, 4, 2, 0)
line {
color("rgb(231, 107, 243)")
}
mode = ScatterMode.lines
name = "Ideal"
}
val plot = Plotly.plot {
traces(trace1, trace2, trace3, trace4, trace5, trace6)
layout {
paper_bgcolor("rgb(255, 255, 255)")
plot_bgcolor("rgb(229, 229, 229)")
xaxis {
gridcolor("rgb(255, 255, 255)")
range(1.0..10.0)
showgrid = true
showline = false
showticklabels = true
tickcolor("rgb(127, 127, 127)")
ticks = Ticks.outside
zeroline = false
}
yaxis {
gridcolor("rgb(255, 255, 255)")
showgrid = true
showline = false
showticklabels = true
tickcolor("rgb(127, 127, 127)")
ticks = Ticks.outside
zeroline = false
}
}
}
plot.makeFile()
}

View File

@ -0,0 +1,38 @@
package errorPlots
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.palettes.Xkcd
import space.kscience.plotly.trace
import java.util.*
/**
* - simple scatter with random length of horizontal error bars
* - change error bars color
* - use XKCD as color palette
*/
fun main() {
val rnd = Random()
val xValues = (0..100 step 4).toList().map { it / 20.0 }
val err = List(26) { rnd.nextDouble() / 2 }
val plot = Plotly.plot {
trace {
x.numbers = xValues
marker {
color(Xkcd.PURPLE)
}
error_x {
array = err
color(Xkcd.PALE_PURPLE)
}
}
layout {
title = "Random Data Error"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,35 @@
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.UnstablePlotlyAPI
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.functionXY
import space.kscience.plotly.trace
import kotlin.math.PI
import kotlin.math.sin
@OptIn(UnstablePlotlyAPI::class)
fun main() {
val plot = Plotly.plot {
repeat(50) { phase ->
trace {
functionXY(0.0..2 * PI, step = 0.05) {
sin(it + phase * 2 * PI / 60)
}
name = "Sin with phase offset ${phase * 2 * PI / 60}"
}
}
layout {
title = "Graph name"
xaxis {
title = "x axis"
}
yaxis {
title = "y axis"
}
height = 700
}
}
plot.makeFile()
}

View File

@ -0,0 +1,42 @@
package geo
import io.invoke
import org.jetbrains.kotlinx.dataframe.DataFrame
import org.jetbrains.kotlinx.dataframe.io.readCSV
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.layout
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.geo.GeoScope
import space.kscience.plotly.models.geo.LocationMode
import space.kscience.plotly.models.geo.choropleth
import space.kscience.plotly.models.geo.geo
private val df = DataFrame.readCSV("https://raw.githubusercontent.com/plotly/datasets/master/2014_usa_states.csv")
//https://plotly.com/javascript/choropleth-maps/#choropleth-map-of-2014-us-population-by-state
fun main() {
val plot = Plotly.plot {
choropleth {
locationmode = LocationMode.`USA-states`
text(df["State"])
locations(df["Postal"])
z(df["Population"])
}
layout {
title = "2014 US Popultaion by State"
geo{
scope = GeoScope.usa
countrycolor(255,255,255)
landcolor(217, 217, 217)
showland = true
lakecolor(255, 255, 255)
showlakes = true
subunitcolor(255,255,255)
}
}
}
plot.makeFile()
}

View File

@ -0,0 +1,76 @@
package geo
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.serialization.json.int
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.layout
import space.kscience.plotly.models.geo.LocationMode
import space.kscience.plotly.models.geo.choroplethMapBox
import space.kscience.plotly.models.geo.json.GeoJsonFeatureCollection
import space.kscience.plotly.models.geo.json.combine
import space.kscience.plotly.models.geo.openStreetMap
import space.kscience.plotly.server.close
import space.kscience.plotly.server.plot
import space.kscience.plotly.server.serve
import java.net.URL
import kotlin.random.Random
fun main() {
//downloading GeoJson
val geoJsonString =
URL("https://raw.githubusercontent.com/isellsoap/deutschlandGeoJSON/main/4_kreise/4_niedrig.geo.json").readText()
// Filtering GeoJson features and creating new feature set
val features = GeoJsonFeatureCollection.parse(geoJsonString).filter {
it.getString("NAME_1") == "Sachsen"
}.combine()
val server = Plotly.serve {
plot {
choroplethMapBox {
geoJsonFeatures(features)
//Switch to geojson-id mode
locationmode = LocationMode.`geojson-id`
//Setup the background map
openStreetMap {
center {
lat = 51.05
lon = 13.73
}
zoom = 7.0
} // Set hover text to region names
text.strings = features.map { it.getString("NAME_3")!! }
// Set displayed locations
locations.numbers = features.map { it.id!!.int }
// Set random values to locations
z.numbers = features.map { Random.nextDouble(1.0, 10.0) }
launch {
while (isActive) {
delay(300)
z.numbers = features.map { Random.nextDouble(1.0, 10.0) }
}
}
}
layout {
title = "Geojson demo"
height = 800
}
embedData = true
}
}
println("Press Enter to close server")
while (readLine()?.trim() != "exit") {
//wait
}
server.close()
}

View File

@ -0,0 +1,61 @@
package geo
import kotlinx.serialization.json.int
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.layout
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.geo.LocationMode
import space.kscience.plotly.models.geo.choroplethMapBox
import space.kscience.plotly.models.geo.json.GeoJsonFeatureCollection
import space.kscience.plotly.models.geo.json.combine
import space.kscience.plotly.models.geo.openStreetMap
import java.net.URL
import kotlin.random.Random
fun main() {
//downloading GeoJson
val geoJsonString =
URL("https://raw.githubusercontent.com/isellsoap/deutschlandGeoJSON/main/4_kreise/4_niedrig.geo.json").readText()
// Filtering GeoJson features and creating new feature set
val features = GeoJsonFeatureCollection.parse(geoJsonString).filter {
it.getString("NAME_1") == "Sachsen"
}.combine()
val plot = Plotly.plot {
choroplethMapBox {
// Use this for remote-loaded feature set
// geojsonUrl =
// "https://raw.githubusercontent.com/isellsoap/deutschlandGeoJSON/main/4_kreise/4_niedrig.geo.json"
//load local in-memory feature set and switch to
geoJsonFeatures(features)
//Switch to geojson-id mode
locationmode = LocationMode.`geojson-id`
// Set hover text to region names
text.strings = features.map { it.getString("NAME_3")!! }
// Set displayed locations
locations.numbers = features.map { it.id!!.int }
// Set random values to locations
z.numbers = features.map { Random.nextDouble(1.0, 10.0) }
}
layout {
title = "Geojson demo"
height = 800
}
// Setup the background map
openStreetMap {
center {
lat = 51.05
lon = 13.73
}
zoom = 7.0
}
}
plot.makeFile()
}

View File

@ -0,0 +1,47 @@
package geo
import io.invoke
import org.jetbrains.kotlinx.dataframe.DataFrame
import org.jetbrains.kotlinx.dataframe.io.readCSV
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.layout
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.DragMode
import space.kscience.plotly.models.geo.mapbox
import space.kscience.plotly.models.geo.scattermapbox
import space.kscience.plotly.models.geo.useOpenStreetMap
private val df = DataFrame.readCSV(
"https://raw.githubusercontent.com/plotly/datasets/master/2015_06_30_precipitation.csv"
)
//https://plotly.com/javascript/mapbox-layers/#openstreetmap-tiles-no-token-needed
fun main() {
val plot = Plotly.plot {
scattermapbox {
text(df["Globvalue"])
lon(df["Lon"])
lat(df["Lat"])
marker {
color("fuchsia")
size = 4
}
}
layout {
title = "OpenStreetMap with markers"
dragmode = DragMode.zoom
//margin { r = 0; t= 0; b= 0; l= 0 }
mapbox {
useOpenStreetMap()
center {
lat = 38
lon = -90
}
zoom = 3.0
}
}
}
plot.makeFile()
}

View File

@ -0,0 +1,129 @@
import kotlinx.html.div
import space.kscience.plotly.*
import space.kscience.plotly.models.Trace
import space.kscience.plotly.models.invoke
import space.kscience.plotly.palettes.T10
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
private class PlotGrid {
public data class PlotCell(val id: String, val plot: Plot, val row: Int, val col: Int, val width: Int = 1)
private val cells = HashMap<String, PlotCell>()
/**
* @return Columns in ascending order, grouped by rows in ascending order.
* */
public val grid: List<List<PlotCell>>
get() = cells.values.groupBy { it.row }.toSortedMap().values.map {
it.sortedBy { cell -> cell.col }
}.toList()
public operator fun get(id: String): PlotCell? = cells[id]
private var currentRow = 0
private var currentCol = 0
public fun plot(
plot: Plot,
id: String = plot.toString(),
width: Int = 6,
row: Int? = null,
col: Int? = null,
): Plot {
val actualRow = if (row != null) {
row
} else {
currentCol = 0
currentRow++
}
val actualColumn = col ?: currentCol++
cells[id] = PlotCell(id, plot, actualRow, actualColumn, width)
return plot
}
public fun plot(
row: Int? = null,
col: Int? = null,
id: String? = null,
width: Int = 6,
block: Plot.() -> Unit,
): Plot {
val plot = Plotly.plot(block)
return plot(plot, id ?: plot.toString(), width, row, col)
}
}
private fun Plotly.grid(block: PlotGrid.() -> Unit): PlotlyPage {
val grid = PlotGrid().apply(block)
return page(cdnBootstrap, cdnPlotlyHeader) { container ->
div("col") {
grid.grid.forEach { row ->
div("row") {
row.forEach { cell ->
div("col-${cell.width}") {
plot(cell.plot, cell.id, renderer = container)
}
}
}
}
}
}
}
fun main() {
val x = (0..100).map { it.toDouble() / 100.0 }
val y1 = x.map { sin(2.0 * PI * it) }
val y2 = x.map { cos(2.0 * PI * it) }
val trace1 = Trace(x, y1) {
name = "sin"
marker.color(T10.BLUE)
}
val trace2 = Trace(x, y2) {
name = "cos"
marker.color(T10.ORANGE)
}
val plot = Plotly.grid {
// title = "Page sample"
plot(row = 1, width = 8) {
traces(trace1, trace2)
layout {
title = "First graph, row: 1, size: 8/12"
xaxis.title = "x axis name"
xaxis.title = "y axis name"
}
}
plot(row = 1, width = 4) {
traces(trace1, trace2)
layout {
title = "Second graph, row: 1, size: 4/12"
xaxis.title = "x axis name"
xaxis.title = "y axis name"
}
}
plot(row = 2, width = 12) {
traces(trace1, trace2)
layout {
title = "Third graph, row: 2, size: 12/12"
xaxis.title = "x axis name"
xaxis.title = "y axis name"
}
}
}
plot.makeFile()
}

View File

@ -0,0 +1,75 @@
package heatmap
import space.kscience.dataforge.meta.Value
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.heatmap
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Font
import space.kscience.plotly.models.Text
import kotlin.math.cos
import kotlin.math.pow
import kotlin.math.sin
/**
* - Heatmap with annotations
* - Change font color and size of annotations text
* - Remove annotations arrows
* - Change colorscale and size of plot
*/
fun main() {
val x1 = (5..25).map { it.toDouble() / 5 }
val y1 = (5..25).map { it.toDouble() / 5 }
val z1 = mutableListOf<MutableList<Double>>()
for (i in y1.indices) {
z1.add(MutableList(x1.size) { 0.0 })
}
val annotationsList = mutableListOf<Text>()
for (i in y1.indices) {
for (j in x1.indices) {
z1[i][j] = sin(x1[i]).pow(10) + cos(10 + y1[j] * x1[i]) * cos(x1[i])
val annotation = Text()
annotation.x = Value.of(x1[j])
annotation.y = Value.of(y1[i])
annotation.text = z1[i][j].toString().substring(0..4)
val annotationsFont = Font()
annotationsFont.size = 16
if (z1[i][j] > 0) {
annotationsFont.color("black")
} else {
annotationsFont.color("white")
}
annotation.font = annotationsFont
annotation.showarrow = false
annotationsList.add(annotation)
}
}
val plot = Plotly.plot {
heatmap {
x.set(x1)
y.set(y1)
z.set(z1)
colorscale = Value.of("Viridis")
}
layout {
height = 800
width = 1400
xaxis {
tickcolor("white")
}
yaxis {
tickcolor("white")
}
annotations = annotationsList
title = "Heatmap with Annotations"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,55 @@
package heatmap
import space.kscience.dataforge.meta.Value
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.heatmap
import space.kscience.plotly.makeFile
import space.kscience.plotly.palettes.Xkcd
/**
* - Heatmap with custom colorscale
* - Add axis label
* - Use XKCD color palette
* - Change size of the plot
*/
fun main() {
val months = listOf("January", "February", "March", "April", "May", "June", "July", "August",
"September", "October", "November", "December")
val years = 1949..1961
val flights = listOf(
listOf(112, 115, 145, 171, 196, 204, 242, 284, 315, 340, 360, 417), /* January */
listOf(118, 126, 150, 180, 196, 188, 233, 277, 301, 318, 342, 391), /* February */
listOf(132, 141, 178, 193, 236, 235, 267, 317, 356, 362, 406, 419), /* March */
listOf(129, 135, 163, 181, 235, 227, 269, 313, 348, 348, 396, 461), /* April */
listOf(121, 125, 172, 183, 229, 234, 270, 318, 355, 363, 420, 472), /* May */
listOf(135, 149, 178, 218, 243, 264, 315, 374, 422, 435, 472, 535), /* June */
listOf(148, 170, 199, 230, 264, 302, 364, 413, 465, 491, 548, 622), /* July */
listOf(148, 170, 199, 242, 272, 293, 347, 405, 467, 505, 559, 606), /* August */
listOf(136, 158, 184, 209, 237, 259, 312, 355, 404, 404, 463, 508), /* September */
listOf(119, 133, 162, 191, 211, 229, 274, 306, 347, 359, 407, 461), /* October */
listOf(104, 114, 146, 172, 180, 203, 237, 271, 305, 310, 362, 390), /* November */
listOf(118, 140, 166, 194, 201, 229, 278, 306, 336, 337, 405, 432) /* December */)
val customColorscale = listOf(listOf(0, Xkcd.POWDER_BLUE), listOf(1, Xkcd.PURPLE))
val plot = Plotly.plot {
heatmap {
x.set(years)
y.set(months)
z.set(flights)
colorscale = Value.of(customColorscale)
}
layout {
width = 900
height = 900
xaxis {
title = "Years"
}
title = "Heatmap of Flight Density from 1949 to 1961"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,34 @@
package heatmap
import space.kscience.dataforge.meta.Value
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.heatmap
import space.kscience.plotly.makeFile
/**
* - basic heatmap from 1 to 25
* - change heatmap colorscale
* - use 2D array as z
*/
fun main() {
val x1 = listOf(1, 2, 3, 4, 5)
val y1 = listOf(6, 7, 8, 9, 10)
val z1 = (1..25).chunked(5)
val plot = Plotly.plot {
heatmap {
x.set(x1)
y.set(y1)
z.set(z1)
colorscale = Value.of("Reds")
}
layout {
title = "Red Heatmap"
}
}
plot.makeFile()
}

View File

@ -0,0 +1,49 @@
package heatmap
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.heatmap
import space.kscience.plotly.makeFile
/**
* - Annotated heatmap with categorical labels
* - change size of labels font
* - rotate axis labels
*/
fun main() {
val x1 = listOf("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
val y1 = listOf("Morning", "Afternoon", "Evening")
val z1 = listOf(
listOf<Number?>(1, null, 30, 50, 1),
listOf<Number>(20, 1, 60, 80, 30),
listOf<Number>(30, 60, 1, -10, 20))
val plot = Plotly.plot {
heatmap {
x.set(x1)
y.set(y1)
z.set(z1)
}
layout {
xaxis {
tickfont {
size = 16
}
}
yaxis {
tickangle = -90
tickfont {
size = 16
}
}
title {
text = "Heatmap with Categorical Axis Labels"
font { size = 20 }
}
}
}
plot.makeFile()
}

View File

@ -0,0 +1,59 @@
package heatmap
import space.kscience.plotly.*
import space.kscience.plotly.models.Heatmap
/**
* - heatmaps with and without gaps between not-null values
* - change plot size
* - stack two plots
*/
fun main() {
val x1 = (0..7)
val y2 = (0..6)
val z1 = listOf(
listOf<Number?>(null, null, null, 12, 13, 14, 15, 16),
listOf<Number?>(null, 1, null, 11, null, null, null, 17),
listOf<Number?>(null, 2, 6, 7, null, null, null, 18),
listOf<Number?>(null, 3, null, 8, null, null, null, 19),
listOf<Number?>(5, 4, 10, 9, null, null, null, 20),
listOf<Number?>(null, null, null, 27, null, null, null, 21),
listOf<Number?>(null, null, null, 26, 25, 24, 23, 22))
val heatmap1 = Heatmap {
x.set(x1)
y.set(y2)
z.set(z1)
showscale = false
}
val heatmap2 = Heatmap {
x.set(x1)
y.set(y2)
z.set(z1)
showscale = false
connectgaps = true
}
Plotly.fragment {
plot {
traces(heatmap1)
layout {
width = 800
height = 450
title = "Gaps Between Nulls"
}
}
plot {
traces(heatmap2)
layout {
width = 800
height = 450
title = "Connected Gaps"
}
}
}.makeFile()
}

View File

@ -0,0 +1,71 @@
package heatmap
import space.kscience.dataforge.meta.Value
import space.kscience.dataforge.meta.invoke
import space.kscience.plotly.Plotly
import space.kscience.plotly.heatmap
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.Font
import space.kscience.plotly.models.Text
/**
* - Simple heatmap with annotations
* - Change annotation font color anf size
* - Use custom colorscale
*/
fun main() {
val x1 = listOf("Monday", "Wednesday", "Friday", "Sunday")
val y1 = listOf("June", "July", "August")
val z1 = listOf(
listOf<Number>(.1, .3, .5, .7),
listOf<Number>(1.0, .8, .6, .4),
listOf<Number>(.6, .4, .2, 0.0),
listOf<Number>(.9, .7, .5, .3))
val customColorscale = listOf(listOf(0, "navy"), listOf(1, "plum"))
val annotationsList = mutableListOf<Text>()
val annotationFont = Font()
annotationFont.color("white")
annotationFont.size = 16
for (i in y1.indices) {
for (j in x1.indices) {
val curAnnotation = Text()
curAnnotation.font = annotationFont
curAnnotation.x = Value.of(x1[j])
curAnnotation.y = Value.of(y1[i])
curAnnotation.text = z1[i][j].toString()
curAnnotation.showarrow = false
annotationsList.add(curAnnotation)
}
}
val plot = Plotly.plot {
heatmap {
x.set(x1)
y.set(y1)
z(z1)
colorscale = Value.of(customColorscale)
colorbar {
tickfont { size = 16 }
}
}
layout {
xaxis {
tickfont { size = 16 }
}
yaxis {
tickfont { size = 16 }
tickangle = -45
}
annotations = annotationsList
title {
text = "Heatmap with Custom Colorscale"
font { size = 20 }
}
}
}
plot.makeFile()
}

Some files were not shown because too many files have changed in this diff Show More