diff --git a/docs/f-23b/geom_lollipop.ipynb b/docs/f-23b/geom_lollipop.ipynb index f7cb76558a2..bf94f32d346 100644 --- a/docs/f-23b/geom_lollipop.ipynb +++ b/docs/f-23b/geom_lollipop.ipynb @@ -58,7 +58,7 @@ " \n", " \n", @@ -252,7 +252,7 @@ { "data": { "text/html": [ - "
\n", + "
\n", " " ], "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -318,7 +318,7 @@ { "data": { "text/html": [ - "
\n", + "
\n", " " ], "text/plain": [ - "" + "" ] }, "execution_count": 6, @@ -453,7 +453,7 @@ { "data": { "text/html": [ - "
\n", + "
\n", " " ], "text/plain": [ - "" + "" ] }, "execution_count": 7, @@ -499,7 +502,8 @@ ], "source": [ "ggplot(df, aes(y=\"class\")) + \\\n", - " geom_lollipop(stat='count', orientation='y')" + " geom_lollipop(stat='count', orientation='y') + \\\n", + " theme_minimal()" ] }, { @@ -521,7 +525,7 @@ { "data": { "text/html": [ - "
\n", + "
\n", " " ], "text/plain": [ - "" + "" ] }, "execution_count": 8, @@ -587,7 +592,8 @@ "ggplot(df, aes(\"hwy\", \"cty\")) + \\\n", " geom_bin2d(binwidth=[1, 1]) + \\\n", " ggmarginal(\"r\", size=.2, \\\n", - " layer=geom_lollipop(aes(color='..count..'), stat='count', orientation='y'))" + " layer=geom_lollipop(aes(color='..count..'), \\\n", + " stat='count', orientation='y', size=1))" ] }, { @@ -609,7 +615,7 @@ { "data": { "text/html": [ - "
\n", + "
\n", " " ], "text/plain": [ - "" + "" ] }, "execution_count": 9, @@ -716,7 +722,7 @@ { "data": { "text/html": [ - "
\n", + "
\n", " " ], "text/plain": [ - "" + "" ] }, "execution_count": 10, @@ -813,7 +819,7 @@ { "data": { "text/html": [ - "
\n", + "
\n", " " ], "text/plain": [ - "" + "" ] }, "execution_count": 11, diff --git a/future_changes.md b/future_changes.md index c4ecea9a6e2..2aa3b293bbd 100644 --- a/future_changes.md +++ b/future_changes.md @@ -4,7 +4,7 @@ - New geometry `geom_lollipop()`. - See: [example notebook](https://nbviewer.org/github/JetBrains/lets-plot/blob/master/docs/f-23b/lollipop_plot.ipynb). + See: [example notebook](https://nbviewer.org/github/JetBrains/lets-plot/blob/master/docs/f-23b/geom_lollipop.ipynb). - `stroke` aesthetic for `geom_point()`, `geom_jitter()`, `geom_qq()`, `geom_qq2()`, `geom_pointrange()`, `geom_dotplot()`, `geom_ydotplot()` and `outlier_stroke` parameter for `geom_boxplot()`. @@ -14,7 +14,7 @@ - New aesthetic `linewidth`. Used only for `geom_lollipop()` at the moment. - See: [example notebook](https://nbviewer.org/github/JetBrains/lets-plot/blob/master/docs/f-23b/lollipop_plot.ipynb). + See: [example notebook](https://nbviewer.org/github/JetBrains/lets-plot/blob/master/docs/f-23b/geom_lollipop.ipynb). - the 'newline' character (`\n`) now works as `line break` in legend text ([[#726](https://github.com/JetBrains/lets-plot/issues/726)]) diff --git a/plot-builder-portable/src/commonMain/kotlin/jetbrains/datalore/plot/builder/assemble/GeomLayerBuilder.kt b/plot-builder-portable/src/commonMain/kotlin/jetbrains/datalore/plot/builder/assemble/GeomLayerBuilder.kt index b203b97fead..fdc213800df 100644 --- a/plot-builder-portable/src/commonMain/kotlin/jetbrains/datalore/plot/builder/assemble/GeomLayerBuilder.kt +++ b/plot-builder-portable/src/commonMain/kotlin/jetbrains/datalore/plot/builder/assemble/GeomLayerBuilder.kt @@ -16,6 +16,7 @@ import jetbrains.datalore.plot.base.data.TransformVar import jetbrains.datalore.plot.base.geom.GeomBase import jetbrains.datalore.plot.base.geom.LiveMapGeom import jetbrains.datalore.plot.base.geom.LiveMapProvider +import jetbrains.datalore.plot.base.geom.LollipopGeom import jetbrains.datalore.plot.base.interact.ContextualMapping import jetbrains.datalore.plot.base.interact.GeomTargetLocator.LookupSpec import jetbrains.datalore.plot.base.interact.MappedDataAccess @@ -320,7 +321,12 @@ class GeomLayerBuilder( override fun rangeIncludesZero(aes: Aes<*>): Boolean { @Suppress("NAME_SHADOWING") val aes = aes.afterOrientation(isYOrientation) - return aestheticsDefaults.rangeIncludesZero(aes) + return if (geom is LollipopGeom && aes == Aes.Y) { + // Pin the lollipops to an axis when baseline coincides with this axis and sticks are perpendicular to it + geom.slope == 0.0 && geom.intercept == 0.0 && geom.direction != LollipopGeom.Direction.ALONG_AXIS + } else { + aestheticsDefaults.rangeIncludesZero(aes) + } } override fun setLiveMapProvider(liveMapProvider: LiveMapProvider) { diff --git a/plot-config-portable/src/commonMain/kotlin/jetbrains/datalore/plot/config/GeomProtoClientSide.kt b/plot-config-portable/src/commonMain/kotlin/jetbrains/datalore/plot/config/GeomProtoClientSide.kt index ef0e8a3ec02..57eb3427c33 100644 --- a/plot-config-portable/src/commonMain/kotlin/jetbrains/datalore/plot/config/GeomProtoClientSide.kt +++ b/plot-config-portable/src/commonMain/kotlin/jetbrains/datalore/plot/config/GeomProtoClientSide.kt @@ -293,31 +293,11 @@ class GeomProtoClientSide(geomKind: GeomKind) : GeomProto(geomKind) { } GeomKind.LOLLIPOP -> return GeomProvider.lollipop { - // As in LayerConfig - val isYOrientation: Boolean = when (opts.hasOwn(Option.Layer.ORIENTATION)) { - true -> opts.getString(Option.Layer.ORIENTATION)?.lowercase()?.let { - when (it) { - "y" -> true - "x" -> false - else -> throw IllegalArgumentException("${Option.Layer.ORIENTATION} expected x|y but was $it") - } - } ?: false - - false -> false - } val directionValue = opts.getString(Lollipop.DIRECTION)?.lowercase() val direction = directionValue?.let { when (it) { - "v" -> if (isYOrientation) { - Direction.ALONG_AXIS - } else { - Direction.ORTHOGONAL_TO_AXIS - } - "h" -> if (isYOrientation) { - Direction.ORTHOGONAL_TO_AXIS - } else { - Direction.ALONG_AXIS - } + "v" -> Direction.ORTHOGONAL_TO_AXIS + "h" -> Direction.ALONG_AXIS "s" -> Direction.SLOPE else -> throw IllegalArgumentException( "Unsupported value for ${Lollipop.DIRECTION} parameter: '$it'. " + @@ -334,7 +314,6 @@ class GeomProtoClientSide(geomKind: GeomKind) : GeomProto(geomKind) { throw IllegalArgumentException( "Incompatible lollipop parameters: " + "${Lollipop.SLOPE}=$slope, " + - "${Option.Layer.ORIENTATION}='${if (isYOrientation) "y" else "x"}', " + "${Lollipop.DIRECTION}='${directionValue}'" ) } diff --git a/python-package/lets_plot/plot/geom.py b/python-package/lets_plot/plot/geom.py index 6b6db0589b7..9a899380772 100644 --- a/python-package/lets_plot/plot/geom.py +++ b/python-package/lets_plot/plot/geom.py @@ -6350,11 +6350,9 @@ def geom_lollipop(mapping=None, *, data=None, stat=None, position=None, show_leg orientation : {'x', 'y'}, default='x' Specify the axis that the baseline should run along. Possible values: 'x', 'y'. - dir : {'v', 'h', 's'} + dir : {'v', 'h', 's'}, default='v' Direction of the lollipop stick. 'v' for vertical, 'h' for horizontal, 's' for orthogonal to the baseline. - If `orientation='x'`, default `dir` is 'v'. - If `orientation='y'`, default `dir` is 'h'. fatten : float, default=2.5 A multiplicative factor applied to size of the point. slope : float