Skip to content

Commit

Permalink
Multiline facet titles (#1064)
Browse files Browse the repository at this point in the history
* Add multiline facet titles: split by '\n' as a text separator.

* Add margins and text justifications.

* Use the max height facet header for headers in the same row.

* Fix after merging with master.

* Refactoring.

* Minor cleanup.

* Fix applying margins to text bounds.

* Add word wrapping for facet titles - `labwidth` parameters.

* Add notebook.

* `labwidth in facet_wrap()` can be specified via list of numbers.

* Refactoring.

* Update notebook.

* Update notebook (renaming).

* Update future_changes.md.

* Fix after merge with master.

* Refactoring:
  • Loading branch information
OLarionova-HORIS committed Mar 27, 2024
1 parent ab547e9 commit 5236da5
Show file tree
Hide file tree
Showing 20 changed files with 1,067 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
package org.jetbrains.letsPlot.commons.formatting.string

fun wrap(text: String, lengthLimit: Int, countLimit: Int = -1): String {
if (text.length <= lengthLimit || text.contains("\n")) {
if (lengthLimit < 0 || text.length <= lengthLimit || text.contains("\n")) {
return text
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class FacetGridDemo {
both(),
bothFlipped(),
both_YOrderingDesc(),
withLabWidth(),
numericFacetVariable(),
)
}
Expand All @@ -26,7 +27,7 @@ class FacetGridDemo {
val plotSpec = commonSpecs()
plotSpec["facet"] = mapOf(
"name" to "grid",
"x" to demo.plot.common.data.AutoMpg.cylinders.name,
"x" to AutoMpg.cylinders.name,
"x_format" to "{d} cyl"
)

Expand All @@ -45,7 +46,7 @@ class FacetGridDemo {
val plotSpec = commonSpecs()
plotSpec["facet"] = mapOf(
"name" to "grid",
"y" to demo.plot.common.data.AutoMpg.origin.name
"y" to AutoMpg.origin.name
)
return plotSpec
}
Expand All @@ -54,8 +55,8 @@ class FacetGridDemo {
val plotSpec = commonSpecs()
plotSpec["facet"] = mapOf(
"name" to "grid",
"x" to demo.plot.common.data.AutoMpg.cylinders.name,
"y" to demo.plot.common.data.AutoMpg.origin.name,
"x" to AutoMpg.cylinders.name,
"y" to AutoMpg.origin.name,
"x_format" to "{d} cyl"
)
return plotSpec
Expand All @@ -65,8 +66,8 @@ class FacetGridDemo {
val plotSpec = commonSpecs()
plotSpec["facet"] = mapOf(
"name" to "grid",
"x" to demo.plot.common.data.AutoMpg.origin.name,
"y" to demo.plot.common.data.AutoMpg.cylinders.name,
"x" to AutoMpg.origin.name,
"y" to AutoMpg.cylinders.name,
"y_format" to "{d} cyl"
)
return plotSpec
Expand All @@ -77,22 +78,35 @@ class FacetGridDemo {
val plotSpec = commonSpecs()
plotSpec["facet"] = mapOf(
"name" to "grid",
"x" to demo.plot.common.data.AutoMpg.cylinders.name,
"y" to demo.plot.common.data.AutoMpg.origin.name,
"x" to AutoMpg.cylinders.name,
"y" to AutoMpg.origin.name,
"y_order" to -1,
"x_format" to "{d} cyl"
)
return plotSpec
}

private fun withLabWidth(): MutableMap<String, Any> {
val plotSpec = commonSpecs()
plotSpec["facet"] = mapOf(
"name" to "grid",
"x" to AutoMpg.cylinders.name,
"y" to AutoMpg.origin.name,
"x_format" to "{d} cyl",
"x_labwidth" to 3,
"y_labwidth" to 1
)
return plotSpec
}

private fun commonSpecs(): MutableMap<String, Any> {
val spec = """
{
'kind': 'plot',
'mapping': {
'x': "${demo.plot.common.data.AutoMpg.horsepower.name}",
'y': "${demo.plot.common.data.AutoMpg.mpg.name}",
'color': "${demo.plot.common.data.AutoMpg.origin.name}"
'x': "${AutoMpg.horsepower.name}",
'y': "${AutoMpg.mpg.name}",
'color': "${AutoMpg.origin.name}"
},
'layers': [
{
Expand All @@ -104,7 +118,7 @@ class FacetGridDemo {
""".trimIndent()

val plotSpec = HashMap(parsePlotSpec(spec))
plotSpec["data"] = demo.plot.common.data.AutoMpg.df
plotSpec["data"] = AutoMpg.df
return plotSpec
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ class FacetWrapDemo {
oneFacet4rows(),
twoFacets(),
twoFacets_CylindersOrderDesc(),
twoFacets_LabWidth(),
)
}

private fun oneFacetDef(): MutableMap<String, Any> {
val plotSpec = commonSpecs()
plotSpec["facet"] = mapOf(
"name" to "wrap",
"facets" to demo.plot.common.data.AutoMpg.cylinders.name,
"facets" to AutoMpg.cylinders.name,
"format" to "{d} cyl"
)
return plotSpec
Expand All @@ -33,7 +34,7 @@ class FacetWrapDemo {
val plotSpec = commonSpecs()
plotSpec["facet"] = mapOf(
"name" to "wrap",
"facets" to listOf(demo.plot.common.data.AutoMpg.cylinders.name), // one facet variant
"facets" to listOf(AutoMpg.cylinders.name), // one facet variant
"ncol" to 3,
"format" to "{d} cyl"
)
Expand All @@ -44,7 +45,7 @@ class FacetWrapDemo {
val plotSpec = commonSpecs()
plotSpec["facet"] = mapOf(
"name" to "wrap",
"facets" to demo.plot.common.data.AutoMpg.cylinders.name,
"facets" to AutoMpg.cylinders.name,
"nrow" to 4,
"format" to "{d} cyl",
"dir" to "v"
Expand All @@ -57,8 +58,8 @@ class FacetWrapDemo {
plotSpec["facet"] = mapOf(
"name" to "wrap",
"facets" to listOf(
demo.plot.common.data.AutoMpg.origin.name,
demo.plot.common.data.AutoMpg.cylinders.name,
AutoMpg.origin.name,
AutoMpg.cylinders.name,
),
"ncol" to 5,
"format" to listOf(null, "{d} cyl")
Expand All @@ -72,8 +73,8 @@ class FacetWrapDemo {
plotSpec["facet"] = mapOf(
"name" to "wrap",
"facets" to listOf(
demo.plot.common.data.AutoMpg.origin.name,
demo.plot.common.data.AutoMpg.cylinders.name,
AutoMpg.origin.name,
AutoMpg.cylinders.name,
),
"ncol" to 5,
"order" to listOf(null, -1),
Expand All @@ -82,15 +83,32 @@ class FacetWrapDemo {
return plotSpec
}

@Suppress("FunctionName")
private fun twoFacets_LabWidth(): MutableMap<String, Any> {
val plotSpec = commonSpecs()
plotSpec["facet"] = mapOf(
"name" to "wrap",
"facets" to listOf(
AutoMpg.origin.name,
AutoMpg.cylinders.name,
),
"ncol" to 5,
"order" to listOf(null, -1),
"format" to listOf(null, "{d} cyl"),
"labwidth" to listOf(null, 3)
)
return plotSpec
}

@Suppress("DuplicatedCode")
private fun commonSpecs(): MutableMap<String, Any> {
val spec = """
{
'kind': 'plot',
'mapping': {
'x': "${demo.plot.common.data.AutoMpg.horsepower.name}",
'y': "${demo.plot.common.data.AutoMpg.mpg.name}",
'color': "${demo.plot.common.data.AutoMpg.origin.name}"
'x': "${AutoMpg.horsepower.name}",
'y': "${AutoMpg.mpg.name}",
'color': "${AutoMpg.origin.name}"
},
'layers': [
{
Expand All @@ -102,7 +120,7 @@ class FacetWrapDemo {
""".trimIndent()

val plotSpec = HashMap(parsePlotSpec(spec))
plotSpec["data"] = demo.plot.common.data.AutoMpg.df
plotSpec["data"] = AutoMpg.df
return plotSpec
}
}
794 changes: 794 additions & 0 deletions docs/f-24b/facet_multiline_titles.ipynb

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions future_changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

### Added

- Parameter `labwidth` in `facet_wrap()` and `x_labwidth/y_labwidth` in `facet_grid()`.

See: [example notebook](https://nbviewer.org/github/JetBrains/lets-plot/blob/master/docs/f-24b/facet_multiline_titles.ipynb).


### Changed
### Fixed
Expand All @@ -15,4 +20,5 @@
- Livemap: `vjust` implemented incorrectly [[#1051](https://github.com/JetBrains/lets-plot/issues/1051)].
- Add tooltips for `geom_curve()` [[#1053](https://github.com/JetBrains/lets-plot/issues/1053)].
- `geom_density2d`: the doc missing some 'computed' variables [[#1062](https://github.com/JetBrains/lets-plot/issues/1062)].
- Any way to line-wrap facet labels? [[LPK-237](https://github.com/JetBrains/lets-plot-kotlin/issues/237)].
- Missing marginal gridlines.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
package org.jetbrains.letsPlot.core.plot.base.theme

import org.jetbrains.letsPlot.commons.values.Color
import org.jetbrains.letsPlot.core.plot.base.layout.TextJustification
import org.jetbrains.letsPlot.core.plot.base.layout.Thickness

interface FacetsTheme {
fun showStrip(): Boolean
Expand All @@ -15,4 +17,6 @@ interface FacetsTheme {
fun stripColor(): Color
fun stripStrokeWidth(): Double
fun stripTextStyle(): ThemeTextStyle
fun stripMargins(): Thickness
fun stripTextJustification(): TextJustification
}
Loading

0 comments on commit 5236da5

Please sign in to comment.