JetBrains / lets-plot-kotlin

Grammar of Graphics for Kotlin
https://lets-plot.org/kotlin/
MIT License
430 stars 36 forks source link

Add legend to plot with multiple lines #74

Closed jgreenyer closed 2 years ago

jgreenyer commented 3 years ago

Hi all, how can I add a legend to a plot with multiple lines? In the quickstart example with the density there seems to be some magic to have a legend showing "A", "B".

How can I do something like that for geomLines?

Here is my example

image

Naively, I would like to give each geomLine a title and have that printed in a legend.

In Python matplotlib, I would do it like this: image

to get something like this image

Any hints on how to do that with Lets-plot in Kotlin?

alshan commented 3 years ago

Hi, Lets-plot is best suited for series of observations rather than lists of values. In your case one observation would consist of the following valued: 't (step)', 'mean reward', 'epsilon'.

What you need is to combine your data into one 'dataframe' to form the series of observations.

Then you add just one geomPoint where you'll map x,y and color aesthetics to 't (step)', 'mean reward' and 'epsilon' respectively:

letsPlot(data) + geomPoint(size = 1.0) {
  x = "t (step)"
  y = "mean reward"
  color = "epsilon"
}

Better if "epsilon" column contained strings (not numbers), because in this case a "discrete" color scale will be automatically selectd.

alshan commented 3 years ago

You might want to take a look at this resource ggplot2: Elegant Graphics for Data Analysis.

Specifically:

jgreenyer commented 3 years ago

Dear Igor, thanks for the hints. It works!

Just for others who come here with a similar question, this is what I ended up doing: (learnEpsilonGreedy returns a list of "mean reward" values)

val numberOfPlays = 1000
val stepsList = (1..numberOfPlays).toList()
val data = mapOf<String, Any>(
    "t (step)" to stepsList + stepsList,
    "mean reward" to learnEpsilonGreedy(epsilon = 0.05, numberOfPlays) + learnEpsilonGreedy(epsilon = 0.1, numberOfPlays),
    "epsilon" to  List(numberOfPlays) { "0.05" } + List(numberOfPlays) { "0.1" }
)

val p = letsPlot(data) +
        geomLine(size=1.0) {
            x = "t (step)"
            y = "mean reward"
            color = "epsilon"
        }

p.show()