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

Size unit implementation for PointGeom and TextGeom #215

Merged
merged 17 commits into from
Oct 27, 2020
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
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
492 changes: 492 additions & 0 deletions docs/examples/jupyter-notebooks-dev/size_unit.ipynb

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ package jetbrains.datalore.plot.base.geom

import jetbrains.datalore.base.geometry.DoubleVector
import jetbrains.datalore.base.values.Color
import jetbrains.datalore.plot.base.*
import jetbrains.datalore.plot.base.Aesthetics
import jetbrains.datalore.plot.base.CoordinateSystem
import jetbrains.datalore.plot.base.DataPointAesthetics
import jetbrains.datalore.plot.base.GeomContext
import jetbrains.datalore.plot.base.PositionAdjustment
import jetbrains.datalore.plot.base.aes.AestheticsUtil
import jetbrains.datalore.plot.base.geom.util.GeomHelper
import jetbrains.datalore.plot.base.geom.util.GeomHelper.Companion.getUnitResBySizeUnit
import jetbrains.datalore.plot.base.geom.util.HintColorUtil.fromColorValue
import jetbrains.datalore.plot.base.interact.GeomTargetCollector.TooltipParams
import jetbrains.datalore.plot.base.interact.GeomTargetCollector.TooltipParams.Companion.params
Expand All @@ -24,6 +29,7 @@ import jetbrains.datalore.vis.svg.slim.SvgSlimElements
open class PointGeom : GeomBase() {

var animation: Any? = null
var sizeUnit: String? = null

override val legendKeyElementFactory: LegendKeyElementFactory
get() = PointLegendKeyElementFactory()
Expand All @@ -40,6 +46,8 @@ open class PointGeom : GeomBase() {

val count = aesthetics.dataPointCount()
val slimGroup = SvgSlimElements.g(count)
val sizeUnitRatio = getSizeUnitRatio(ctx)

for (i in 0 until count) {
val p = aesthetics.dataPointAt(i)
val x = p.x()
Expand All @@ -49,16 +57,30 @@ open class PointGeom : GeomBase() {
val location = helper.toClient(DoubleVector(x!!, y!!), p)

val shape = p.shape()!!
targetCollector.addPoint(i, location, shape.size(p) / 2,

targetCollector.addPoint(
i, location, sizeUnitRatio * shape.size(p) / 2,
tooltipParams(p)
)
val o = PointShapeSvg.create(shape, location, p)
val o = PointShapeSvg.create(shape, location, p, sizeUnitRatio)
o.appendTo(slimGroup)
}
}
root.add(wrap(slimGroup))
}

private fun getSizeUnitRatio(ctx: GeomContext): Double {
sizeUnit?.let { sizeUnitValue ->
alshan marked this conversation as resolved.
Show resolved Hide resolved
val unitRes = getUnitResBySizeUnit(ctx, sizeUnitValue)
// TODO: Need refactoring: It's better to use NamedShape.FILLED_CIRCLE.size(1.0)
// but Shape.size() can't be used because it takes DataPointAesthetics as param
val unitShapeSize = 2.2
alshan marked this conversation as resolved.
Show resolved Hide resolved
return unitRes / unitShapeSize
}

return 1.0
}

companion object {
const val HANDLES_GROUPS = false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,18 @@ import jetbrains.datalore.plot.common.data.SeriesUtil
class TextGeom : GeomBase() {
var formatter: StringFormat? = null
var naValue = DEF_NA_VALUE
var sizeUnit: String? = null

override val legendKeyElementFactory: LegendKeyElementFactory
get() = TextLegendKeyElementFactory()

override fun buildIntern(root: SvgRoot, aesthetics: Aesthetics, pos: PositionAdjustment, coord: CoordinateSystem, ctx: GeomContext) {
override fun buildIntern(
root: SvgRoot,
aesthetics: Aesthetics,
pos: PositionAdjustment,
coord: CoordinateSystem,
ctx: GeomContext
) {
val helper = GeomHelper(pos, coord, ctx)
val targetCollector = getGeomTargetCollector(ctx)
for (p in aesthetics.dataPoints()) {
Expand All @@ -37,7 +44,7 @@ class TextGeom : GeomBase() {
val text = toString(p.label())
if (SeriesUtil.allFinite(x, y) && !Strings.isNullOrEmpty(text)) {
val label = TextLabel(text)
GeomHelper.decorate(label, p)
GeomHelper.decorate(label, p, getSizeUnitRatio(ctx))

val loc = helper.toClient(x, y, p)
label.moveTo(loc)
Expand All @@ -55,6 +62,19 @@ class TextGeom : GeomBase() {
}
}

// This implementation is oversimplified.
// Current implementation works for label_format ='.2f'
// and values between -1.0 and 1.0.
private fun getSizeUnitRatio(ctx: GeomContext): Double {
sizeUnit?.let { sizeUnitValue ->
val textWidth = 6.0
val unitRes = GeomHelper.getUnitResBySizeUnit(ctx, sizeUnitValue)
alshan marked this conversation as resolved.
Show resolved Hide resolved
return unitRes / textWidth
}

return 1.0
}

private fun toString(label: Any?): String {
return when {
label == null -> naValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package jetbrains.datalore.plot.base.geom.util
import jetbrains.datalore.base.gcommon.base.Strings
import jetbrains.datalore.base.geometry.DoubleRectangle
import jetbrains.datalore.base.geometry.DoubleVector
import jetbrains.datalore.plot.base.Aes
import jetbrains.datalore.plot.base.CoordinateSystem
import jetbrains.datalore.plot.base.DataPointAesthetics
import jetbrains.datalore.plot.base.GeomContext
Expand Down Expand Up @@ -162,11 +163,11 @@ open class GeomHelper(private val myPos: PositionAdjustment, coord: CoordinateSy
"mono" to "monospace"
)

fun decorate(label: TextLabel, p: DataPointAesthetics) {
fun decorate(label: TextLabel, p: DataPointAesthetics, scale: Double = 1.0) {

label.textColor().set(p.color())
label.textOpacity().set(p.alpha())
label.setFontSize(AesScaling.textSize(p))
label.setFontSize(AesScaling.textSize(p) * scale)

// family
var family = p.family()
Expand Down Expand Up @@ -255,5 +256,18 @@ open class GeomHelper(private val myPos: PositionAdjustment, coord: CoordinateSy
shape.setStroke(stroke, strokeAlpha)
shape.setStrokeWidth(AesScaling.strokeWidth(p))
}

fun getSizeUnitAes(sizeUnitName: String): Aes<Double> {
return when (sizeUnitName.toLowerCase()) {
"x" -> Aes.X
"y" -> Aes.Y
else -> error("Size unit value must be either 'x' or 'y', but was $sizeUnitName.")
}
}

fun getUnitResBySizeUnit( ctx: GeomContext, sizeUnitName: String ) : Double {
val aes = getSizeUnitAes(sizeUnitName)
return ctx.getUnitResolution(aes)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import jetbrains.datalore.plot.config.Option.Geom.PointRange
import jetbrains.datalore.plot.config.Option.Geom.Segment
import jetbrains.datalore.plot.config.Option.Geom.Step


class GeomProtoClientSide(geomKind: GeomKind) : GeomProto(geomKind) {
private val preferredCoordinateSystem: CoordProvider? = when (geomKind) {
GeomKind.TILE,
Expand Down Expand Up @@ -115,9 +116,12 @@ class GeomProtoClientSide(geomKind: GeomKind) : GeomProto(geomKind) {

GeomKind.POINT -> return GeomProvider.point {
val geom = PointGeom()

if (opts.has(Point.ANIMATION)) {
geom.animation = opts[Point.ANIMATION]
}

geom.sizeUnit = opts.getString(Point.SIZE_UNIT)?.toLowerCase()
geom
}

Expand Down Expand Up @@ -148,6 +152,8 @@ class GeomProtoClientSide(geomKind: GeomKind) : GeomProto(geomKind) {
}
}

geom.sizeUnit = opts.getString(Text.SIZE_UNIT)?.toLowerCase()

geom
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ object Option {

object Point {
const val ANIMATION = "animation"
const val SIZE_UNIT = "size_unit"
}

object Image {
Expand All @@ -148,6 +149,7 @@ object Option {
object Text {
const val LABEL_FORMAT = "label_format"
const val NA_VALUE = "na_value"
const val SIZE_UNIT = "size_unit"
}

object LiveMap {
Expand All @@ -166,6 +168,11 @@ object Option {
const val GEOCODING = "geocoding"
const val DEV_PARAMS = "dev_params"
}

object SizeUnit {
const val X = "x"
const val Y = "y"
}
}

object Scale {
Expand Down