ronisbr / PrettyTables.jl

Print data in formatted tables.
MIT License
405 stars 38 forks source link

Multicolumn headers? #12

Open dpo opened 5 years ago

dpo commented 5 years ago

I wonder if there is any support or plan to support multicolumn headers. The idea would be to produce something in the vein of

┌───────────────────┬───────────────────┐
│   Header 1        │   Header 2        │ 
├──────────┬────────┼────────┬──────────┤
│   Col. 1 │ Col. 2 │ Col. 3 │   Col. 4 │
├──────────┼────────┼────────┼──────────┤
│    1.000 │  false │    1.0 │    1.000 │
│    2.000 │   true │    2.0 │    2.000 │
│    3.000 │  false │    3.0 │    3.000 │
│    4.000 │   true │    4.0 │    4.000 │
│    5.000 │  false │    5.0 │    5.000 │
│    6.000 │   true │    6.0 │    6.000 │
└──────────┴────────┴────────┴──────────┘

Thanks!

ronisbr commented 5 years ago

Hi @dpo ,

Thanks for the suggestion. This is the kind of thing that should be relatively easy to implement, but very hard to think about how to make the interface. I mean, do you have any suggestions on how the user should pass this information to the function?

dpo commented 5 years ago

Hi @ronisbr. Thanks for the fast response. I admit I haven't thought about the interface. Perhaps some like

pretty_table(data, [["Col. 1", "Col. 2"], ["Col. 3", "Col. 4"]], ["Header 1", "Header 2"])
ronisbr commented 5 years ago

Hi @dpo ,

I don't think I like your idea. Notice that it is very different from the API today. In your proposal, we will have two entries for headers instead of one. We must think of something that will not change the current basic API and that adds this functionality. I still could not think in a good way to do this.

c42f commented 5 years ago

Your current API treats the headings as a simple matrix with the same width as the data. This seems like a nice simple model.

I suggest you just keep that and use Julia's existing block matrix concatenation syntax with a custom HeadingBox type (or some such) to allow simple creation of custom heading layouts. In some ways this is analogous to the layout system in Plots.jl.

A sketch of one way to do the user interface part:

using PrettyTables

mutable struct HeadingBox <: AbstractMatrix{Any}
    content
    size
end

struct HeadingCell
    box
    index
end

Base.show(io::IO, hc::HeadingCell) = show(io, "$(hc.box.content) $(hc.index)")

Base.getindex(hb::HeadingBox, i::Vararg{Int}) = HeadingCell(hb, i)
Base.size(hb::HeadingBox) = hb.size

then making the heading in code can be justified to look reasonably nice:

julia> headings = [HeadingBox("Span1",(1,2))  HeadingBox("Span2",(1,2));
                   "Col 1"   "Col 2"          "Col 3"   "Col 4"]

julia> headings
2×4 Array{Any,2}:
 "Span1 (1, 1)"  "Span1 (1, 2)"  "Span2 (1, 1)"  "Span2 (1, 2)"
 "Col 1"         "Col 2"         "Col 3"         "Col 4"       

By itself this doesn't look like much, but inside PrettyTables you can then detect which HeadingCells share a common HeadingBox, and merge those cells together as required.

Another option would be to inspect the layouting systems from Plots.jl or Makie.jl and take inspiration from there.

ronisbr commented 5 years ago

Thanks for the advice @c42f ! I will see if I can implement it :)

c42f commented 5 years ago

I hope it works out! Thanks very much for this package by the way. I've been wanting a table pretty printing package for a couple of years or so.

ronisbr commented 5 years ago

Just an update! I am trying to create a scheme based on @c42f suggestion to allow multicolumn cells in the entire table. I am facing some problems due to the internals of the package. For example, if a cell spans along more than 1 columns and there is a horizontal line, I get this:

┌────────┬────────┬────────┬────────┐
│ Col. 1 │ Col. 2 │ Col. 3 │ Col. 4 │
├────────┼────────┼────────┼────────┤
│ 1      │  false │  1.0   │ 1      │
│ 2      │   true │  2.0   │      2 │
│ 3      │  false │  3.0   │   3    │
├────────┼────────┼────────┼────────┤
│ 4               │  4.0   │   4    │
├────────┼────────┼────────┼────────┤
│ 5      │  false │  5.0   │ 5      │
│ 6      │   true │  6.0   │      6 │
└────────┴────────┴────────┴────────┘

So the algorithm will be more complicated than I thought. There are many cases to treat (two multicolumn cells one above the other, etc.). I also have to think what to do if we have a multicolumn cell that is hidden by the column filter mechanism.

Conclusion: it will take more time to be implemented, but I am working on it :)

jonniedie commented 3 years ago

Is this still being considered? I found myself looking for something like this today.

ronisbr commented 3 years ago

Hi @jonniedie !

Yes, this is still being considered, but extremely hard to implement for the general case :)

I need to finish first the other two backends (HTML and LaTeX) so that we can use PrettyTables in DataFrames in those cases also. After that, I will try to implement this feature.

jonniedie commented 3 years ago

Thanks for the response (and the package!). That’s great to hear.

jo-fleck commented 8 months ago

Many thanks for your work on this great package @ronisbr and congrats on its current state!

Just to make sure I haven't overlooked something in the documentation: Are multicolumn headers already included?