Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coord_polar: axis, ticks, labels, xlim/ylim #979

Merged
merged 18 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
c574810
Make expand additive
IKupriyanov-HORIS Dec 20, 2023
2467a22
coord_polar: reduce number of ticks for v axis
IKupriyanov-HORIS Dec 20, 2023
4fc32be
coord_polar: replace absolute expand with relative
IKupriyanov-HORIS Dec 20, 2023
4be95a0
coord_polar: v axis ticks alignment
IKupriyanov-HORIS Dec 20, 2023
e3d7535
coord_polar: hardcoded anchor for ticks
IKupriyanov-HORIS Dec 20, 2023
a9705f1
coord_polar: more ticks for circle axis
IKupriyanov-HORIS Dec 21, 2023
52151a7
coord_polar: fix horizontal axis ticks order, fix axis circle positio…
IKupriyanov-HORIS Dec 21, 2023
7af0732
coord_polar: fix horizontal axis first and last ticks overlapping
IKupriyanov-HORIS Dec 21, 2023
f6fd891
coord_polar: update notebook
IKupriyanov-HORIS Dec 22, 2023
0900649
coord_polar: replace thetaFromX with flipped
IKupriyanov-HORIS Dec 25, 2023
f54d197
coord_polar: temp fix for axis, need proper fix for the domain flip
IKupriyanov-HORIS Dec 26, 2023
62f8d02
coord_polar: properly handle theta=y in PolarCoordinateSystem
IKupriyanov-HORIS Dec 27, 2023
dc71ebc
coord_polar: handle theta=y mostly in PolarCoordinateSystem. Investig…
IKupriyanov-HORIS Dec 27, 2023
9c94803
coord_polar: fixed breaks and ticks. The only not working case is a Y…
IKupriyanov-HORIS Dec 28, 2023
a550e39
coord_polar: fixed breaks and ticks with start parameter
IKupriyanov-HORIS Dec 28, 2023
b99f9ea
coord_polar: minor code cleanup
IKupriyanov-HORIS Dec 29, 2023
09921c8
coord_polar: fix domain for discrete angle scale
IKupriyanov-HORIS Jan 1, 2024
0e4782f
coord_polar: add xlim/ylim for radar plot / lollipop
IKupriyanov-HORIS Jan 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
coord_polar: replace thetaFromX with flipped
  • Loading branch information
IKupriyanov-HORIS committed Jan 5, 2024
commit 0900649d9fd315ee05d6f6b2212c35fc34c6bf56
2,959 changes: 73 additions & 2,886 deletions docs/dev/notebooks/coord_polar.ipynb

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class PlotAssembler constructor(
val flipAxis = coordProvider.flipped

val (hAxisPosition, vAxisPosition) = if (coordProvider is PolarCoordProvider) {
AxisPosition.TOP to AxisPosition.LEFT
AxisPosition.BOTTOM to AxisPosition.LEFT
} else {
when (flipAxis) {
true -> yAxisPosition.flip() to xAxisPosition.flip()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ object CoordProviders {
)
}

fun polar(thetaFromX: Boolean, start: Double, clockwise: Boolean): CoordProvider {
return PolarCoordProvider(thetaFromX, start, clockwise)
fun polar(flipped: Boolean, start: Double, clockwise: Boolean): CoordProvider {
return PolarCoordProvider(flipped, start, clockwise)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,35 @@ import kotlin.math.min
import kotlin.math.sin

internal class PolarCoordProvider(
private val thetaFromX: Boolean,
private val start: Double,
private val clockwise: Boolean
) : CoordProviderBase(xLim = null, yLim = null, false) {
flipped: Boolean,
val start: Double,
val clockwise: Boolean
) : CoordProviderBase(xLim = null, yLim = null, flipped) {

override val isLinear: Boolean
get() = false

// TODO: polar coord actually does not support flipped and xLim/yLim
override fun with(xLim: DoubleSpan?, yLim: DoubleSpan?, flipped: Boolean): CoordProvider {
return PolarCoordProvider(thetaFromX, start, clockwise)
return PolarCoordProvider(!flipped, start, clockwise)
}

override fun adjustDomain(domain: DoubleRectangle): DoubleRectangle {
// Domain of a data withouth any adjustments (i.e. no expand).
// Keep lower end as is to avoid hole in the center and to keep correct start angle.
// Extend upper end of the radius domain by 0.75 to make room for labels and axis line.

val (rDomain, thetaDomain) = when (thetaFromX) {
true -> domain.yRange() to domain.xRange()
false -> domain.xRange() to domain.yRange()
val (rDomain, thetaDomain) = when (flipped) {
false -> domain.yRange() to domain.xRange()
true -> domain.xRange() to domain.yRange()
}.let { (rDomain, thetaDomain) ->
val rDomainAdjusted = DoubleSpan(rDomain.lowerEnd, rDomain.upperEnd + rDomain.length * 0.15)
rDomainAdjusted to thetaDomain
}

return when (thetaFromX) {
true -> DoubleRectangle(thetaDomain, rDomain)
false -> DoubleRectangle(rDomain, thetaDomain)
return when (flipped) {
false -> DoubleRectangle(thetaDomain, rDomain)
true -> DoubleRectangle(rDomain, thetaDomain)
}
}

Expand All @@ -57,9 +57,9 @@ internal class PolarCoordProvider(
}

override fun createCoordinateMapper(adjustedDomain: DoubleRectangle, clientSize: DoubleVector): CoordinatesMapper {
val (rDomain, thetaDomain) = when (thetaFromX) {
true -> adjustedDomain.yRange() to adjustedDomain.xRange()
false -> adjustedDomain.xRange() to adjustedDomain.yRange()
val (rDomain, thetaDomain) = when (flipped) {
false -> adjustedDomain.yRange() to adjustedDomain.xRange()
true -> adjustedDomain.xRange() to adjustedDomain.yRange()
}

val rNorm = 0.0 - rDomain.lowerEnd
Expand All @@ -72,17 +72,17 @@ internal class PolarCoordProvider(
val thetaScaleMapper = Mappers.mul(thetaRangeNorm, 2.0 * PI)
val center = clientSize.mul(0.5)

val norm = when (thetaFromX) {
true -> DoubleVector(thetaNorm, rNorm)
false -> DoubleVector(rNorm, thetaNorm)
val norm = when (flipped) {
false -> DoubleVector(thetaNorm, rNorm)
true -> DoubleVector(rNorm, thetaNorm)
}

fun scalerThetaX(v: DoubleVector) = rScaleMapper(v.y) to thetaScaleMapper(v.x)
fun scalerThetaY(v: DoubleVector) = rScaleMapper(v.x) to thetaScaleMapper(v.y)

val scaler = when (thetaFromX) {
true -> ::scalerThetaX
false -> ::scalerThetaY
val scaler = when (flipped) {
false -> ::scalerThetaX
true -> ::scalerThetaY
}

val sign = if (clockwise) -1.0 else 1.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.jetbrains.letsPlot.core.plot.builder.FrameOfReferenceProvider
import org.jetbrains.letsPlot.core.plot.builder.MarginSide
import org.jetbrains.letsPlot.core.plot.builder.coord.CoordProvider
import org.jetbrains.letsPlot.core.plot.builder.coord.MarginalLayerCoordProvider
import org.jetbrains.letsPlot.core.plot.builder.coord.PolarCoordProvider
import org.jetbrains.letsPlot.core.plot.builder.guide.Orientation
import org.jetbrains.letsPlot.core.plot.builder.layout.*
import org.jetbrains.letsPlot.core.plot.builder.layout.axis.AxisBreaksProviderFactory
Expand Down Expand Up @@ -115,20 +116,39 @@ internal class SquareFrameOfReferenceProvider(

val coord = coordProvider.createCoordinateSystem(adjustedDomain, client)

val hScale = hScaleProto.with()
.breaks(hAxisLayoutInfo.axisBreaks.domainValues)
.labels(hAxisLayoutInfo.axisBreaks.labels)
.build()
val hScale: Scale
val vScale: Scale
val domain: DoubleRectangle
if (coordProvider is PolarCoordProvider && coordProvider.flipped) {
domain = adjustedDomain.flip()
vScale = hScaleProto.with()
.breaks(hAxisLayoutInfo.axisBreaks.domainValues)
.labels(hAxisLayoutInfo.axisBreaks.labels)
.build()

hScale = vScaleProto.with()
.breaks(vAxisLayoutInfo.axisBreaks.domainValues)
.labels(vAxisLayoutInfo.axisBreaks.labels)
.build()

} else {
domain = adjustedDomain
hScale = hScaleProto.with()
.breaks(hAxisLayoutInfo.axisBreaks.domainValues)
.labels(hAxisLayoutInfo.axisBreaks.labels)
.build()

vScale = vScaleProto.with()
.breaks(vAxisLayoutInfo.axisBreaks.domainValues)
.labels(vAxisLayoutInfo.axisBreaks.labels)
.build()
}

val vScale = vScaleProto.with()
.breaks(vAxisLayoutInfo.axisBreaks.domainValues)
.labels(vAxisLayoutInfo.axisBreaks.labels)
.build()

val tileFrameOfReference = SquareFrameOfReference(
hScaleBreaks = hScale.getScaleBreaks(),
vScaleBreaks = vScale.getScaleBreaks(),
adjustedDomain,
domain,
coord,
layoutInfo,
marginsLayout,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import kotlin.test.assertEquals
class BreaksDataTest {
@Test
fun simple() {
val polarCoordProvider = PolarCoordProvider(thetaFromX = true, start = 0.0, clockwise = true)
val polarCoordProvider = PolarCoordProvider(flipped = false, start = 0.0, clockwise = true)
val adjustedDomain = DoubleRectangle.XYWH(-5.0, 10.0, 5.0, 8.625)
val clientSize = DoubleVector(504.0, 504.0)
val coordinateSystem = polarCoordProvider.createCoordinateSystem(adjustedDomain, clientSize)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class PolarCoordTest {
private val clientSize = DoubleVector(200.0, 200.0)

private fun applyPolarTransform(start: Double, clockwise: Boolean): List<Vector> {
val polarCoordProvider = PolarCoordProvider(thetaFromX = true, start, clockwise)
val polarCoordProvider = PolarCoordProvider(flipped = true, start, clockwise)

val polarMapper = polarCoordProvider.createCoordinateMapper(
adjustedDomain = adjustedDomain,
Expand All @@ -33,7 +33,7 @@ class PolarCoordTest {
}

private fun applyPolarScreenTransform(start: Double, clockwise: Boolean): List<Vector> {
val polarCoordProvider = PolarCoordProvider(thetaFromX = true, start, clockwise)
val polarCoordProvider = PolarCoordProvider(flipped = true, start, clockwise)
val coordinateSystem = polarCoordProvider.createCoordinateSystem(adjustedDomain, clientSize)

return x.zip(y)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ internal object CoordProto {
}

POLAR -> CoordProviders.polar(
thetaFromX = when (val theta = options.getString(Coord.THETA)) {
Coord.Theta.X -> true
Coord.Theta.Y -> false
null -> true
flipped = when (val theta = options.getString(Coord.THETA)) {
Coord.Theta.X -> false
Coord.Theta.Y -> true
null -> false
else -> error("Unsupported theta: expected `x` or `y`, but was `$theta`")
},
start = options.getDouble(Coord.START) ?: 0.0,
Expand Down