diff --git a/CHANGELOG.md b/CHANGELOG.md index e9a15e23..95e160e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Candlestick support +- Range builders for axis ### Changed - build tools 0.10.0 ### Deprecated +- Direct usage of `range` in axis ### Removed diff --git a/build.gradle.kts b/build.gradle.kts index 19cde0ce..64287aec 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ val dataforgeVersion by extra("0.4.3") allprojects { group = "space.kscience" - version = "0.4.4-dev-2" + version = "0.4.4" } apiValidation { diff --git a/examples/src/main/kotlin/candlestick/basicCandleStick.kt b/examples/src/main/kotlin/candlestick/basicCandleStick.kt index 0fc4d8cc..b17dbd23 100644 --- a/examples/src/main/kotlin/candlestick/basicCandleStick.kt +++ b/examples/src/main/kotlin/candlestick/basicCandleStick.kt @@ -1,21 +1,14 @@ package candlestick +import space.kscience.dataforge.meta.invoke import space.kscience.dataforge.meta.set 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.Trace -import space.kscience.plotly.models.TraceValues +import space.kscience.plotly.models.CandleStick -val Trace.close: TraceValues get() = axis("close") -val Trace.high: TraceValues get() = axis("high") -val Trace.low: TraceValues get() = axis("low") -val Trace.open: TraceValues get() = axis("open") - - -internal val candleStickTrace = Trace { - set("type", "candlestick") +internal val candleStickTrace = CandleStick { x.strings = listOf( "2017-01-04", "2017-01-05", @@ -82,8 +75,6 @@ internal val candleStickTrace = Trace { 135.509995 ) -// decreasing: { line: { color: "#7F7F7F" } }, - high.numbers = listOf( 116.510002, 116.860001, @@ -117,7 +108,13 @@ internal val candleStickTrace = Trace { 136.270004 ) - //increasing: { line: { color: "#17BECF" } }, + increasing { + lineColor("#17BECF") + } + + decreasing { + lineColor("#7F7F7F") + } line { color("rgba(31,119,180,1)") } @@ -186,8 +183,6 @@ internal val candleStickTrace = Trace { 133.470001, 135.520004 ) - set("xaxis", "x") - set("yaxis", "y") } @@ -205,16 +200,14 @@ fun main() { showlegend = false xaxis { autorange = true - set("domain", listOf(0, 1)) - set("range", listOf("2017-01-03 12:00", "2017-02-15 12:00")) + 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 - set("domain", listOf(0, 1)) - range = 114.609999778..137.410004222 + range(114.609999778..137.410004222) type = AxisType.linear } } diff --git a/examples/src/main/kotlin/candlestick/dynamicCandleStick.kt b/examples/src/main/kotlin/candlestick/dynamicCandleStick.kt index d5c46264..673c092d 100644 --- a/examples/src/main/kotlin/candlestick/dynamicCandleStick.kt +++ b/examples/src/main/kotlin/candlestick/dynamicCandleStick.kt @@ -4,12 +4,15 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -import space.kscience.dataforge.meta.set 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.* +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() { @@ -19,7 +22,7 @@ fun main() { plot(renderer = plotly) { traces(candleStickTrace) layout { - set("dragmode", "zoom") + dragmode = DragMode.zoom margin { r = 10 t = 25 @@ -28,18 +31,13 @@ fun main() { } showlegend = false xaxis { - autorange = true - set("domain", listOf(0, 1)) - set("range", listOf("2017-01-03 12:00", "2017-02-15 12:00")) + 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" - type = AxisType.date } yaxis { - autorange = true - set("domain", listOf(0, 1)) - range = 114.609999778..137.410004222 - type = AxisType.linear + range(114.609999778..137.410004222) } } diff --git a/examples/src/main/kotlin/errorPlots/FillLines.kt b/examples/src/main/kotlin/errorPlots/FillLines.kt index 525d68b5..d9978cda 100644 --- a/examples/src/main/kotlin/errorPlots/FillLines.kt +++ b/examples/src/main/kotlin/errorPlots/FillLines.kt @@ -89,7 +89,7 @@ fun main() { plot_bgcolor("rgb(229, 229, 229)") xaxis { gridcolor("rgb(255, 255, 255)") - range = 1.0..10.0 + range(1.0..10.0) showgrid = true showline = false showticklabels = true diff --git a/examples/src/main/kotlin/scatter/DataLabelsOnThePlot.kt b/examples/src/main/kotlin/scatter/DataLabelsOnThePlot.kt index 01aef3df..60379e7b 100644 --- a/examples/src/main/kotlin/scatter/DataLabelsOnThePlot.kt +++ b/examples/src/main/kotlin/scatter/DataLabelsOnThePlot.kt @@ -44,7 +44,7 @@ fun main() { layout { title = "Data Labels Hover" xaxis { - range = 0.75..5.25 + range(0.75..5.25) } legend { y = 0.5 diff --git a/examples/src/main/kotlin/scatter/VerticalAndHorizontalLines.kt b/examples/src/main/kotlin/scatter/VerticalAndHorizontalLines.kt index 6cfc3600..7cf21c0b 100644 --- a/examples/src/main/kotlin/scatter/VerticalAndHorizontalLines.kt +++ b/examples/src/main/kotlin/scatter/VerticalAndHorizontalLines.kt @@ -29,10 +29,10 @@ fun main() { layout { title = "Vertical and Horizontal Lines Positioned Relative to the Axes" xaxis { - range = 0.0..7.0 + range(0.0..7.0) } yaxis { - range = 0.0..2.5 + range(0.0..2.5) } width = 700 diff --git a/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Axis.kt b/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Axis.kt index 185d5bf2..d3354223 100644 --- a/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Axis.kt +++ b/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Axis.kt @@ -132,12 +132,35 @@ public class Axis : Scheme() { * numbers, using the scale where each category is assigned * a serial number from zero in the order it appears. */ + @Deprecated("Use range() instead") public var range: ClosedFloatingPointRange? get() = this["range"]?.value?.doubleArray?.let { it[0]..it[1] } set(value) { this["range"] = value?.let { ListValue(listOf(value.start.asValue(), value.endInclusive.asValue())) } } + /** + * Set the range using arbitrary values + */ + public fun range(from: Value, to: Value) { + this["range"] = ListValue(listOf(from, to)) + } + + /** + * Set range using double kotlin range + */ + public fun range(value: ClosedFloatingPointRange) { + range(value.start.asValue(), value.endInclusive.asValue()) + } + + /** + * Set range using kotlin string range + */ + public fun range(value: ClosedRange) { + range(value.start.asValue(), value.endInclusive.asValue()) + } + + /** * Sets default for all colors associated with this axis all at once: * line, font, tick, and grid colors. Grid color is lightened diff --git a/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/CandleStick.kt b/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/CandleStick.kt new file mode 100644 index 00000000..747424ef --- /dev/null +++ b/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/CandleStick.kt @@ -0,0 +1,86 @@ +package space.kscience.plotly.models + +import space.kscience.dataforge.meta.* +import space.kscience.dataforge.names.toName +import space.kscience.dataforge.values.Value +import space.kscience.dataforge.values.asValue +import space.kscience.plotly.doubleInRange + + +public enum class XPeriodAlignment{ + start, + middle, + end +} + +public class CandleStickLine: Scheme(){ + public val fillcolor: Color by color() + public val lineColor: Color by color("line.color".toName()) + public var lineWidth: Double by double(2.0, key = "line.width".toName()) + public companion object: SchemeSpec(::CandleStickLine) +} + +public class CandleStick : Trace() { + init { + type = TraceType.candlestick + } + + /** + * Assigns id labels to each datum. These ids for object constancy of data points during animation. + * Should be an array of strings, not numbers or any other type. + */ + public var ids: List? by stringList() + + /** + * Only relevant when the axis `type` is "date". Sets the period positioning in milliseconds or "M" on the x axis. + * Special values in the form of "M" could be used to declare the number of months. In this case `n` must be a positive integer. + * Default 0 + */ + public var xperiod: Value by value { 0.asValue() } + + public var xperiod0: Value? by value() + + /** + * Only relevant when the axis `type` is "date". Sets the alignment of data points on the x axis. + */ + public var xperiodalignment: XPeriodAlignment by enum(XPeriodAlignment.middle) + + public val open: TraceValues by axis + public val high: TraceValues by axis + public val close: TraceValues by axis + public val low: TraceValues by axis + public val hovertext: TraceValues by axis + + + public var meta: Value? by value() + + /** + * Sets a reference between this trace's x coordinates and a 2D cartesian x axis. If "x" (the default value), + * the x coordinates refer to `layout.xaxis`. If "x2", the x coordinates refer to `layout.xaxis2`, and so on. + * Default "x" + */ + public var xaxis: String by string("x") + + /** + * Sets a reference between this trace's y coordinates and a 2D cartesian y axis. If "y" (the default value), + * the y coordinates refer to `layout.yaxis`. If "y2", the y coordinates refer to `layout.yaxis2`, and so on. + */ + public var yaxis: String by string("y") + + + public var lineWidth: Double by double(2.0, "line.width".toName()) + + public var increasing: CandleStickLine by spec(CandleStickLine) + public var decreasing: CandleStickLine by spec(CandleStickLine) + + /** + * Number between 0 and 1. + * + * Selects the width of the whiskers relative to the box´s width. + * For example, with 1, the whiskers are as wide as the box(es). + * Default 0 + */ + public var whiskerwidth: Double by doubleInRange(0.0..1.0) + + public companion object: SchemeSpec(::CandleStick) +} \ No newline at end of file diff --git a/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Layout.kt b/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Layout.kt index f4a4f379..30bed413 100644 --- a/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Layout.kt +++ b/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Layout.kt @@ -83,6 +83,10 @@ public enum class ViolinMode { overlay } +public enum class DragMode { + zoom, pan, select, lasso, drawclosedpath, drawopenpath, drawline, drawrect, drawcircle, orbit, turntable, `false` +} + public class Layout : Scheme() { /** * Sets the plot's width (in px). @@ -257,6 +261,12 @@ public class Layout : Scheme() { */ public var calendar: Calendar by enum(Calendar.gregorian) + /** + * Determines the mode of drag interactions. "select" and "lasso" apply only to scatter traces with markers or text. + * "orbit" and "turntable" apply only to 3D scenes. + */ + public var dragmode: DragMode by enum(DragMode.zoom) + public fun legend(block: Legend.() -> Unit) { legend.apply(block) } diff --git a/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Trace.kt b/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Trace.kt index 0268e023..d89f4af2 100644 --- a/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Trace.kt +++ b/plotlykt-core/src/commonMain/kotlin/space/kscience/plotly/models/Trace.kt @@ -9,6 +9,7 @@ import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.asValue import space.kscience.plotly.* import kotlin.js.JsName +import kotlin.properties.ReadOnlyProperty public enum class TraceType { @@ -32,9 +33,10 @@ public enum class TraceType { histogram, histogram2d, histogram2dcontour, -// // Finance + + // // Finance // ohlc, -// candlestick, + candlestick, // waterfall, // // 3D // scatter3d, @@ -696,6 +698,10 @@ public class Hoverlabel : Scheme() { public open class Trace : Scheme() { public fun axis(axisName: String): TraceValues = TraceValues(this, axisName.toName()) + public val axis: ReadOnlyProperty = ReadOnlyProperty { thisRef, property -> + TraceValues(thisRef, property.name.asName()) + } + /** * Sets the x coordinates. */