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

Provide entry point for color customization #2831

Open
Arkoniak opened this issue Aug 5, 2021 · 10 comments
Open

Provide entry point for color customization #2831

Arkoniak opened this issue Aug 5, 2021 · 10 comments
Labels
Milestone

Comments

@Arkoniak
Copy link

Arkoniak commented Aug 5, 2021

DataFrames.jl uses hardcoded colors for generating output and unfortunately color choice is not always suitable for all users for various reasons.

I propose to use the following approach instead of colors hardcoding:

# define somewhere at the beginning

const COLOR = Ref((; foo = :red, bar = :green))

# and later in the code, when color is needed
printstyled("what you need to print", COLOR[].foo)

This simple change does not provide full-fledged color theme switching by itself (this probably should be implemented JuliaLang/julia#41435), but it provides an entry point for all future color theme related stuff. I.e. all user level convenience functions would just modify this variable one way or another. And anyway this proposal allows color customization right here and now (maybe slightly cumbersome) unlike the current situation.

Implementing this feature looks like a good beginner PR, doesn't require large modifications of the code base and it solves color issues.

@bkamins bkamins added the display label Aug 5, 2021
@bkamins
Copy link
Member

bkamins commented Aug 5, 2021

@ronisbr should confirm for 100%, but what you ask for is already possible. Just pass appropriate arguments to

show(df, your_printing_options_for_colors)

what is hardcoded is the behavior of:

show(df)

and the related const

const _PRETTY_TABLES_HIGHLIGHTER = Highlighter(_pretty_tables_highlighter_func,

and recently we have been discussing if we can allow this default configuration to be changed.

But let us wait for @ronisbr to comment as he knows best this part of source code.

@ronisbr
Copy link
Member

ronisbr commented Aug 5, 2021

Hi @Arkoniak !

@bkamins is 100% correct. You can pretty much change any color by passing options to show. You can even change that "hard-coded" highlight inside DataFrames.jl but it is a little bit more complicated:

Captura de Tela 2021-08-05 às 09 39 12

For more information, see the docs of the function pretty_table. All those keyword can be passed to show(df, ...).

@Arkoniak
Copy link
Author

Arkoniak commented Aug 5, 2021

But show is a function, which is being called internally, when DataFrame object is displayed, right?

So, currently the only way to make changes permanent is to pirate display function like

Base.display(df::AbstractDataFrame) = show(df, border_crayon = crayon"yellow bold", header_crayon = crayon"green bold", text_crayon = crayon"red")

Piracy is not very welcome around here, as far as I know...

But if it is official way, then it is fine by me :-)

@bkamins
Copy link
Member

bkamins commented Aug 5, 2021

So, currently the only way to make changes permanent

So you want to change the default settings? I am asking, because in your original question you passed arguments with color to a function, so I thought you wanted a one-time change.

Piracy is not very welcome around here, as far as I know...

Indeed type piracy is not something that is recommended. However, for display you most likely can safely assume that there is no big risk of such change that you ask for (of course it needs to be done correctly). I assume you do not have any code that relies on the actual colors displayed.

@Arkoniak
Copy link
Author

Arkoniak commented Aug 5, 2021

Yes, I meant default settings. Function in the snippet is an example of the internal library function which is doing actual printing at some time. It can be printstyled or any custom function that you use to print colored output. What I was trying to say is that people usually do printstyled("something to print", color = :red) and after that it is impossible to use any other color for that element, since it is hardcoded.

In case of DataFrames, you have

const _PRETTY_TABLES_HIGHLIGHTER = Highlighter(_pretty_tables_highlighter_func,
                                               Crayon(foreground = :dark_gray))

which can be changed to

const COLOR = Ref((; foreground = :dark_gray))

and in

highlighters = (_PRETTY_TABLES_HIGHLIGHTER,),

                 highlighters                = (Highlighter(_pretty_tables_highlighter_func,
                                               Crayon(foreground = Color[].foreground)),),

with something along these lines, you can provide customizable colors without the need for pirating display function.

Or maybe something similar should be done deeper in PrettyTables.jl, I do not know.

@bkamins
Copy link
Member

bkamins commented Aug 5, 2021

with something along these lines, you can provide customizable colors without the need for pirating display function.

Yes - we are considering this, but what @ronisbr reports is that making this flexible hugely impacts time-to-first-plot.

@ronisbr
Copy link
Member

ronisbr commented Aug 5, 2021

@bkamins is right. In the very first attempt to integrate PrettyTables.jl with DataFrames.jl, I used a global state variable to handle those options. PrettyTables.jl has a system like this, but the time to print the first table was much higher. I heard that this was greatly enhanced in Julia 1.6. Maybe I need to revisit this.

@bkamins are you ok if I managed to create a global printing state inside of DataFrames.jl that can be changed by the user?

@ronisbr
Copy link
Member

ronisbr commented Aug 5, 2021

Using Julia 1.7, there is also a "huge" slowdown:

julia> using PrettyTables

julia> @time pretty_table(rand(2, 2))
┌──────────┬──────────┐
│   Col. 1 │   Col. 2 │
├──────────┼──────────┤
│ 0.9569280.269498 │
│ 0.5852060.524423 │
└──────────┴──────────┘
  0.775265 seconds (1.04 M allocations: 55.040 MiB, 1.08% gc time, 99.87% compilation time)
julia> using PrettyTables

julia> conf = set_pt_conf(border_crayon = crayon"yellow bold");

julia> @time pretty_table_with_conf(conf, rand(2, 2))
┌──────────┬──────────┐
│   Col. 1 │   Col. 2 │
├──────────┼──────────┤
│ 0.6947640.215185 │
│ 0.2292850.626746 │
└──────────┴──────────┘
  0.908953 seconds (1.17 M allocations: 63.057 MiB, 8.43% gc time, 99.89% compilation time)

@bkamins
Copy link
Member

bkamins commented Aug 5, 2021

are you ok if I managed to create a global printing state inside of DataFrames.jl that can be changed by the user?

Let us wait a bit for @nalimilan. In general we avoid as much as possible mutable global state of DataFrames.jl, but maybe in this case we could go for it.

@nalimilan
Copy link
Member

I'd say it would be OK to allow changing the default colors, that does seem a case where a mutable global state cannot cause severe issues. But would that increase the time needed to print the first table for all users, or only those who change the default colors?

@bkamins bkamins added this to the 1.5 milestone Sep 13, 2022
@bkamins bkamins modified the milestones: 1.5, 1.6 Feb 5, 2023
@bkamins bkamins modified the milestones: 1.6, 1.7 Jul 10, 2023
@bkamins bkamins modified the milestones: 1.7, 1.x Sep 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants