JetBrains / lets-plot-kotlin

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

X axis labels are not sorted alphanumerically #48

Closed krzema12 closed 3 years ago

krzema12 commented 3 years ago

I'm trying to visualize a number of commits made per module in my single-repo project, per month. On X axis I want to have labels like 2020-04, and Y axis should show the number of commits. My code is as follows:

    ...
    val plotData = mapOf (
        "yearMonth" to yearMonths,
        "module" to modules,
    )

    var plot = lets_plot(plotData) +
            geom_bar { x = "yearMonth"; fill = "module" } +
            ggsize(1920, 1080) +
            ggtitle("Number of commits per module")

Everything works fine, except that I'm getting such order of labels which looks totally random:

image

As you can see, the order is not even alphanumeric, and I'd expect it to be so (analogy to ggplot, see e.g. https://sebastiansauer.github.io/ordering-bars/: "And the rule is: ... if character, an alphabetical order ist used"). My data provided in yearMonths is ordered the way I want (alphanumerically).

How can I control the order of the labels? I'm also curious what's the contract with lets-plot for this matter. How about sorting it alphanumerically by default, and providing a way to customize it?

I didn't manage to reproduce it on a smaller set of data.

alshan commented 3 years ago

The 'official' way to control the order of the values on discrete scale is by using the 'limits' parameter of the scale_xxx function. See scale_x_discrete for the instance.

limits [..] - A character vector that defines possible values of the scale and their order

So, the workaround for you in this casa would be to pass a sorted list of strings (dates) to scale_x_discrete(limits=..)

I don't see the a mention of the default alphabetical order in ggplot2 docs but it might make sense. Its not very clear though, what should we order - the values or the labels.

"Sorting bars by some numeric variable" is also an interesting proposition, thanks!

Alternatively, you could have one of Kotlin/Java date-time objects in your "yearMonth" series (see this comment here https://github.com/JetBrains/lets-plot-kotlin/issues/37#issuecomment-687680945).

In this case there will be correct ordering but the provided date-time formatting might be not what you wanted. We are going to add the formatting option in one of the nearest releases.

krzema12 commented 3 years ago

Thanks @alshan!

I went forward with the scale_x_discrete approach because as you wrote, it gives me more control over how things are displayed.

image

I'm unblocked, but leaving the issue open so that you can decide whether to perform the sorting by default. I also +1 the feature of custom formatting of the labels.

Thanks, Piotr

alshan commented 3 years ago

Hi @krzema12!

We've added a formatting option for the axis labels in v2.0.0.

Please check out this formatting demo

Does this help in your case?

See also: Formatting.

alshan commented 3 years ago

@krzema12 sorry, I forgot you are using Kotlin API. The facet_wrap is not there yet.

alshan commented 3 years ago

Hi @krzema12 ! All the above is finally in Lets-Plot-Kotlin v1.3.0 :)

The formatting demo is here: https://nbviewer.jupyter.org/github/JetBrains/lets-plot-kotlin/blob/master/docs/examples/jupyter-notebooks/formatting_axes_etc.ipynb

krzema12 commented 3 years ago

Thank you @alshan for this feature!