From 1a0fd3baf380cad67ff0707139417b1819500000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Thu, 27 Aug 2020 16:32:02 +0200 Subject: [PATCH 1/6] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2162fed4fa..62b58061ac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ Thanks for taking the plunge! or related issues for context, before opening a new issue * Including minimal examples is greatly appreciated * If it's a bug, or unexpected behaviour, reproducing on the latest development version - (`Pkg.checkout("DataFrames")`) is a good gut check and can streamline the process, + (`Pkg.develop("DataFrames")`) is a good gut check and can streamline the process, along with including the first two lines of output from `versioninfo()` ## Contributing From c1e38d4e8e33e26007bd22a2628542962d533377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Thu, 27 Aug 2020 16:39:29 +0200 Subject: [PATCH 2/6] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 62b58061ac..031e9d1e11 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ Thanks for taking the plunge! or related issues for context, before opening a new issue * Including minimal examples is greatly appreciated * If it's a bug, or unexpected behaviour, reproducing on the latest development version - (`Pkg.develop("DataFrames")`) is a good gut check and can streamline the process, + (`Pkg.add(name="DataFrames", rev="master")`) is a good gut check and can streamline the process, along with including the first two lines of output from `versioninfo()` ## Contributing From ee9884d1a9b7e7e4f2b2569600ceca794c5111fe Mon Sep 17 00:00:00 2001 From: "Nicholas W. M. Ritchie" Date: Fri, 28 Aug 2020 09:45:42 -0400 Subject: [PATCH 3/6] Adding support for rich display of Markdown cells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixing Markdown as "text/csv" and "text/plain" Fix test error in Markdown to HTML in 32-bit systems Fixing show and adding multi-codepoint tests 32 it is... Use chomp to remove trailing '\n Co-authored-by: Bogumił Kamiński Fixing conflicts Pulling df[i,j] out and optimizing ourshow. Formatting improvements Additional formatting improvements Fixing triple-quoted strings in 1.0.X Strip space in test case Co-authored-by: Milan Bouchet-Valat Using @nalimilan suggestion Improving LaTeX output appearance, NEWS.md entry Moved NEWS.md item to "Other relevant changes" section. Correct NEWS.md item on rich display support --- NEWS.md | 2 + Project.toml | 1 + src/DataFrames.jl | 2 + src/abstractdataframe/io.jl | 22 ++++-- src/abstractdataframe/show.jl | 5 ++ test/io.jl | 138 +++++++++++++++++++++++++++++++--- 6 files changed, 155 insertions(+), 15 deletions(-) diff --git a/NEWS.md b/NEWS.md index 135e857113..f96081a08f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -55,3 +55,5 @@ * Documentation is now available also in *Dark* mode ([#2315](https://github.com/JuliaData/DataFrames.jl/pull/2315)) +* add rich display support for Markdown cell entries in HTML and LaTeX + ([#2346](https://github.com/JuliaData/DataFrames.jl/pull/2346)) diff --git a/Project.toml b/Project.toml index 4d8bc8321c..80cb062e3c 100644 --- a/Project.toml +++ b/Project.toml @@ -10,6 +10,7 @@ Future = "9fa8497b-333b-5362-9e8d-4d0656e87820" InvertedIndices = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" IteratorInterfaceExtensions = "82899510-4779-5014-852e-03e436cf321d" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" Missings = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" PooledArrays = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" diff --git a/src/DataFrames.jl b/src/DataFrames.jl index a8e5bf9b60..13c918d5b9 100644 --- a/src/DataFrames.jl +++ b/src/DataFrames.jl @@ -6,6 +6,8 @@ using Reexport, SortingAlgorithms, Compat, Unicode, PooledArrays using Base.Sort, Base.Order, Base.Iterators using TableTraits, IteratorInterfaceExtensions import LinearAlgebra: norm +using Markdown +import LinearAlgebra: norm import DataAPI, DataAPI.All, diff --git a/src/abstractdataframe/io.jl b/src/abstractdataframe/io.jl index 8c999fd8d7..eda9a60200 100644 --- a/src/abstractdataframe/io.jl +++ b/src/abstractdataframe/io.jl @@ -142,6 +142,10 @@ function _show(io::IO, ::MIME"text/html", df::AbstractDataFrame; cell_val = df[row, column_name] if ismissing(cell_val) write(io, "missing") + elseif cell_val isa Markdown.MD + write(io, "") + show(io, "text/html", cell_val) + write(io, "") elseif cell_val isa SHOW_TABULAR_TYPES write(io, "") cell = sprint(ourshow, cell_val) @@ -302,6 +306,8 @@ function _show(io::IO, ::MIME"text/latex", df::AbstractDataFrame; cell = df[row,col] if ismissing(cell) print(io, "\\emph{missing}") + elseif cell isa Markdown.MD + print(io, strip(repr(MIME("text/latex"), cell))) elseif cell isa SHOW_TABULAR_TYPES print(io, "\\emph{") print(io, latex_escape(sprint(ourshow, cell, context=io))) @@ -410,17 +416,23 @@ function printtable(io::IO, quotestr = string(quotemark) for i in 1:n for j in 1:p - if ismissing(df[i, j]) + cell = df[i, j] + if ismissing(cell) print(io, missingstring) - elseif isnothing(df[i, j]) + elseif isnothing(cell) print(io, nothingstring) else - if ! (etypes[j] <: Real) + if cell isa Markdown.MD print(io, quotemark) - escapedprint(io, df[i, j], quotestr) + r = repr(cell) + escapedprint(io, chomp(r), quotestr) + print(io, quotemark) + elseif ! (etypes[j] <: Real) + print(io, quotemark) + escapedprint(io, cell, quotestr) print(io, quotemark) else - print(io, df[i, j]) + print(io, cell) end end if j < p diff --git a/src/abstractdataframe/show.jl b/src/abstractdataframe/show.jl index 85ba621c30..4bbc203943 100644 --- a/src/abstractdataframe/show.jl +++ b/src/abstractdataframe/show.jl @@ -54,6 +54,11 @@ ourshow(io::IO, x::Symbol) = ourshow(io, string(x)) ourshow(io::IO, x::Nothing; styled::Bool=false) = ourshow(io, "", styled=styled) ourshow(io::IO, x::SHOW_TABULAR_TYPES; styled::Bool=false) = ourshow(io, summary(x), styled=styled) +function ourshow(io::IO, x::Markdown.MD) + r = repr(x) + len = min(length(r, 1, something(findfirst(==('\n'), r), lastindex(r)+1)-1), 32) + return print(io, len < length(r) - 1 ? first(r, len)*'…' : first(r, len)) +end # AbstractChar: https://github.com/JuliaLang/julia/pull/34730 (1.5.0-DEV.261) # Irrational: https://github.com/JuliaLang/julia/pull/34741 (1.5.0-DEV.266) diff --git a/test/io.jl b/test/io.jl index 0e9ea5bb64..83065b6a90 100644 --- a/test/io.jl +++ b/test/io.jl @@ -1,28 +1,30 @@ module TestIO -using Test, DataFrames, CategoricalArrays, Dates +using Test, DataFrames, CategoricalArrays, Dates, Markdown # Test LaTeX export @testset "LaTeX export" begin - df = DataFrame(A = 1:4, + df = DataFrame(A = Int64.( 1:4 ), B = ["\$10.0", "M&F", "A~B", "\\alpha"], C = ["A", "B", "C", "S"], D = [1.0, 2.0, missing, 3.0], E = CategoricalArray(["a", missing, "c", "d"]), - F = Vector{String}(undef, 4) + F = Vector{String}(undef, 4), + G = [ md"[DataFrames.jl](http://juliadata.github.io/DataFrames.jl)", md"###A", md"``\frac{A}{B}``", md"*A*b**A**"] ) str = """ - \\begin{tabular}{r|cccccc} - \t& A & B & C & D & E & F\\\\ + \\begin{tabular}{r|ccccccc} + \t& A & B & C & D & E & F & G\\\\ \t\\hline - \t& $(Int) & String & String & Float64? & Cat…? & String\\\\ + \t& Int64 & String & String & Float64? & Cat…? & String & MD…\\\\ \t\\hline - \t1 & 1 & \\\$10.0 & A & 1.0 & a & \\emph{\\#undef} \\\\ - \t2 & 2 & M\\&F & B & 2.0 & \\emph{missing} & \\emph{\\#undef} \\\\ - \t3 & 3 & A\\textasciitilde{}B & C & \\emph{missing} & c & \\emph{\\#undef} \\\\ - \t4 & 4 & \\textbackslash{}\\textbackslash{}alpha & S & 3.0 & d & \\emph{\\#undef} \\\\ + \t1 & 1 & \\\$10.0 & A & 1.0 & a & \\emph{\\#undef} & \\href{http://juliadata.github.io/DataFrames.jl}{DataFrames.jl} \\\\ + \t2 & 2 & M\\&F & B & 2.0 & \\emph{missing} & \\emph{\\#undef} & \\#\\#\\#A \\\\ + \t3 & 3 & A\\textasciitilde{}B & C & \\emph{missing} & c & \\emph{\\#undef} & \$\\frac{A}{B}\$ \\\\ + \t4 & 4 & \\textbackslash{}\\textbackslash{}alpha & S & 3.0 & d & \\emph{\\#undef} & \\emph{A}b\\textbf{A} \\\\ \\end{tabular} """ + @test repr(MIME("text/latex"), df) == str @test repr(MIME("text/latex"), eachcol(df)) == str @test repr(MIME("text/latex"), eachrow(df)) == str @@ -130,6 +132,27 @@ end @test_throws ArgumentError DataFrames._show(stdout, MIME("text/html"), DataFrame(ones(2,2)), rowid=10) + + df = DataFrame( + A=Int64[1,4,9,16], + B = [ + md"[DataFrames.jl](http://juliadata.github.io/DataFrames.jl)", + md"###A", + md"``\frac{A}{B}``", + md"*A*b**A**" ] + ) + + @test repr(MIME("text/html"), df) == + "" * + "

4 rows × 2 columns

" * + "" * + "
AB
Int64MD…
11
" * + "

DataFrames.jl" * + "

\n
24
" * + "

###A

\n
39
" * + "

$\\frac{A}{B}$

\n
416

AbA

"* + "\n
" + end # test limit attribute of IOContext is used @@ -180,6 +203,101 @@ end end end +@testset "Markdown as text/plain and as text/csv" begin + df = DataFrame( + A=Int64[1,4,9,16,25,36,49,64], + B = [ + md"[DataFrames.jl](http://juliadata.github.io/DataFrames.jl)", + md"``\frac{x^2}{x^2+y^2}``", + md"# Header", + md"This is *very*, **very**, very, very, very, very, very, very, very long line" , + md"", + Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫αγ∞1∫αγ∞2∫αγ∞3"), + Markdown.parse("∫αγ∞1∫αγ∞\n"* + " * 2∫αγ∞3∫αγ∞4\n"* + " * ∫αγ∞5∫αγ\n"* + " * ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫α\n"* + " * γ∞1∫α\n"* + " * γ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + ] + ) + @test sprint(show, "text/plain", df) == """ + 8×2 DataFrame + │ Row │ A │ B │ + │ │ Int64 │ Markdown.MD │ + ├─────┼───────┼───────────────────────────────────┤ + │ 1 │ 1 │ [DataFrames.jl](http://juliadata… │ + │ 2 │ 4 │ \$\\frac{x^2}{x^2+y^2}\$ │ + │ 3 │ 9 │ # Header │ + │ 4 │ 16 │ This is *very*, **very**, very, … │ + │ 5 │ 25 │ │ + │ 6 │ 36 │ ∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫α… │ + │ 7 │ 49 │ ∫αγ∞1∫αγ∞… │ + │ 8 │ 64 │ ∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫α… │""" + + @test sprint(show, "text/csv", df) == + """ + \"A\",\"B\" + 1,\"[DataFrames.jl](http://juliadata.github.io/DataFrames.jl)\" + 4,\"\$\\\\frac{x^2}{x^2+y^2}\$\" + 9,\"# Header\" + 16,\"This is *very*, **very**, very, very, very, very, very, very, very long line\" + 25,\"\" + 36,\"∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫αγ∞1∫αγ∞2∫αγ∞3\" + 49,\"∫αγ∞1∫αγ∞\\n\\n * 2∫αγ∞3∫αγ∞4\\n * ∫αγ∞5∫αγ\\n * ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0\" + 64,\"∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫α\\n\\n * γ∞1∫α\\n * γ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0\" + """ +end + +@testset "Markdown as HTML" begin + df = DataFrame( + A=Int64[1,4,9,16,25,36,49,64], + B = [ + md"[DataFrames.jl](http://juliadata.github.io/DataFrames.jl)", + md"``\frac{x^2}{x^2+y^2}``", + md"# Header", + md"This is *very*, **very**, very, very, very, very, very, very, very long line" , + md"", + Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0" * + "∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ\n"* + " * ∞7∫αγ\n"* + " * ∞8∫αγ\n"* + " * ∞9∫αγ∞0∫α\nγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫α\n"* + " * γ∞1∫α\n"* + " * γ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + ] + ) + @test sprint(show,"text/html",df) == + "" * + "" * + "" * + "" * + "" * "

8 rows × 2 columns

" * + "" * + "" * + "" * + "" * + "" * + "" * + "" * + "
AB
Int64MD…
11
" * + "

DataFrames.jl

\n
24

$\\frac{x^2}{x^2+y^2}$

\n
39

Header

\n
416
" * + "

This is very, very, very, very, very, very, very, very, very long line

\n" * + "
525
636
" * + "

∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0

\n" * + "
749
" * + "

∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ

\n
    \n
  • ∞7∫αγ

    \n
  • \n
  • ∞8∫αγ

    \n
  • \n
  • ∞9∫αγ∞0∫α

    \n
  • \n
\n

γ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0

\n" * + "
864
" * + "

∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫α

" * + "\n
    \n" * + "
  • γ∞1∫α

    \n
  • \n" * + "
  • γ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0

    \n
  • \n" * + "
\n" * "
" +end + @testset "empty data frame and DataFrameRow" begin df = DataFrame(a = [1,2], b = [1.0, 2.0]) From 8943c8e4d5001c019f194c1c8388dcbb334aa6f9 Mon Sep 17 00:00:00 2001 From: "Nicholas W. M. Ritchie" Date: Fri, 28 Aug 2020 10:02:33 -0400 Subject: [PATCH 4/6] Removing duplicate import --- src/DataFrames.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/DataFrames.jl b/src/DataFrames.jl index 13c918d5b9..f278e702f8 100644 --- a/src/DataFrames.jl +++ b/src/DataFrames.jl @@ -7,7 +7,6 @@ using Base.Sort, Base.Order, Base.Iterators using TableTraits, IteratorInterfaceExtensions import LinearAlgebra: norm using Markdown -import LinearAlgebra: norm import DataAPI, DataAPI.All, From 792cf783ce65368735a623bf37ecab3ccdd7ca96 Mon Sep 17 00:00:00 2001 From: "Nicholas W. M. Ritchie" Date: Fri, 28 Aug 2020 13:45:06 -0400 Subject: [PATCH 5/6] Adding support for rich display of Markdown cells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixing Markdown as "text/csv" and "text/plain" Fix test error in Markdown to HTML in 32-bit systems Fixing show and adding multi-codepoint tests 32 it is... Use chomp to remove trailing '\n Co-authored-by: Bogumił Kamiński Fixing conflicts Pulling df[i,j] out and optimizing ourshow. Formatting improvements Additional formatting improvements Fixing triple-quoted strings in 1.0.X Strip space in test case Co-authored-by: Milan Bouchet-Valat Using @nalimilan suggestion Improving LaTeX output appearance, NEWS.md entry Moved NEWS.md item to "Other relevant changes" section. Correct NEWS.md item on rich display support Removing duplicate import --- NEWS.md | 2 + Project.toml | 1 + src/DataFrames.jl | 1 + src/abstractdataframe/io.jl | 22 ++++-- src/abstractdataframe/show.jl | 5 ++ test/io.jl | 138 +++++++++++++++++++++++++++++++--- 6 files changed, 154 insertions(+), 15 deletions(-) diff --git a/NEWS.md b/NEWS.md index 135e857113..f96081a08f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -55,3 +55,5 @@ * Documentation is now available also in *Dark* mode ([#2315](https://github.com/JuliaData/DataFrames.jl/pull/2315)) +* add rich display support for Markdown cell entries in HTML and LaTeX + ([#2346](https://github.com/JuliaData/DataFrames.jl/pull/2346)) diff --git a/Project.toml b/Project.toml index 4d8bc8321c..80cb062e3c 100644 --- a/Project.toml +++ b/Project.toml @@ -10,6 +10,7 @@ Future = "9fa8497b-333b-5362-9e8d-4d0656e87820" InvertedIndices = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" IteratorInterfaceExtensions = "82899510-4779-5014-852e-03e436cf321d" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" Missings = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" PooledArrays = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" diff --git a/src/DataFrames.jl b/src/DataFrames.jl index a8e5bf9b60..f278e702f8 100644 --- a/src/DataFrames.jl +++ b/src/DataFrames.jl @@ -6,6 +6,7 @@ using Reexport, SortingAlgorithms, Compat, Unicode, PooledArrays using Base.Sort, Base.Order, Base.Iterators using TableTraits, IteratorInterfaceExtensions import LinearAlgebra: norm +using Markdown import DataAPI, DataAPI.All, diff --git a/src/abstractdataframe/io.jl b/src/abstractdataframe/io.jl index 8c999fd8d7..eda9a60200 100644 --- a/src/abstractdataframe/io.jl +++ b/src/abstractdataframe/io.jl @@ -142,6 +142,10 @@ function _show(io::IO, ::MIME"text/html", df::AbstractDataFrame; cell_val = df[row, column_name] if ismissing(cell_val) write(io, "missing") + elseif cell_val isa Markdown.MD + write(io, "") + show(io, "text/html", cell_val) + write(io, "") elseif cell_val isa SHOW_TABULAR_TYPES write(io, "") cell = sprint(ourshow, cell_val) @@ -302,6 +306,8 @@ function _show(io::IO, ::MIME"text/latex", df::AbstractDataFrame; cell = df[row,col] if ismissing(cell) print(io, "\\emph{missing}") + elseif cell isa Markdown.MD + print(io, strip(repr(MIME("text/latex"), cell))) elseif cell isa SHOW_TABULAR_TYPES print(io, "\\emph{") print(io, latex_escape(sprint(ourshow, cell, context=io))) @@ -410,17 +416,23 @@ function printtable(io::IO, quotestr = string(quotemark) for i in 1:n for j in 1:p - if ismissing(df[i, j]) + cell = df[i, j] + if ismissing(cell) print(io, missingstring) - elseif isnothing(df[i, j]) + elseif isnothing(cell) print(io, nothingstring) else - if ! (etypes[j] <: Real) + if cell isa Markdown.MD print(io, quotemark) - escapedprint(io, df[i, j], quotestr) + r = repr(cell) + escapedprint(io, chomp(r), quotestr) + print(io, quotemark) + elseif ! (etypes[j] <: Real) + print(io, quotemark) + escapedprint(io, cell, quotestr) print(io, quotemark) else - print(io, df[i, j]) + print(io, cell) end end if j < p diff --git a/src/abstractdataframe/show.jl b/src/abstractdataframe/show.jl index 85ba621c30..4bbc203943 100644 --- a/src/abstractdataframe/show.jl +++ b/src/abstractdataframe/show.jl @@ -54,6 +54,11 @@ ourshow(io::IO, x::Symbol) = ourshow(io, string(x)) ourshow(io::IO, x::Nothing; styled::Bool=false) = ourshow(io, "", styled=styled) ourshow(io::IO, x::SHOW_TABULAR_TYPES; styled::Bool=false) = ourshow(io, summary(x), styled=styled) +function ourshow(io::IO, x::Markdown.MD) + r = repr(x) + len = min(length(r, 1, something(findfirst(==('\n'), r), lastindex(r)+1)-1), 32) + return print(io, len < length(r) - 1 ? first(r, len)*'…' : first(r, len)) +end # AbstractChar: https://github.com/JuliaLang/julia/pull/34730 (1.5.0-DEV.261) # Irrational: https://github.com/JuliaLang/julia/pull/34741 (1.5.0-DEV.266) diff --git a/test/io.jl b/test/io.jl index 0e9ea5bb64..83065b6a90 100644 --- a/test/io.jl +++ b/test/io.jl @@ -1,28 +1,30 @@ module TestIO -using Test, DataFrames, CategoricalArrays, Dates +using Test, DataFrames, CategoricalArrays, Dates, Markdown # Test LaTeX export @testset "LaTeX export" begin - df = DataFrame(A = 1:4, + df = DataFrame(A = Int64.( 1:4 ), B = ["\$10.0", "M&F", "A~B", "\\alpha"], C = ["A", "B", "C", "S"], D = [1.0, 2.0, missing, 3.0], E = CategoricalArray(["a", missing, "c", "d"]), - F = Vector{String}(undef, 4) + F = Vector{String}(undef, 4), + G = [ md"[DataFrames.jl](http://juliadata.github.io/DataFrames.jl)", md"###A", md"``\frac{A}{B}``", md"*A*b**A**"] ) str = """ - \\begin{tabular}{r|cccccc} - \t& A & B & C & D & E & F\\\\ + \\begin{tabular}{r|ccccccc} + \t& A & B & C & D & E & F & G\\\\ \t\\hline - \t& $(Int) & String & String & Float64? & Cat…? & String\\\\ + \t& Int64 & String & String & Float64? & Cat…? & String & MD…\\\\ \t\\hline - \t1 & 1 & \\\$10.0 & A & 1.0 & a & \\emph{\\#undef} \\\\ - \t2 & 2 & M\\&F & B & 2.0 & \\emph{missing} & \\emph{\\#undef} \\\\ - \t3 & 3 & A\\textasciitilde{}B & C & \\emph{missing} & c & \\emph{\\#undef} \\\\ - \t4 & 4 & \\textbackslash{}\\textbackslash{}alpha & S & 3.0 & d & \\emph{\\#undef} \\\\ + \t1 & 1 & \\\$10.0 & A & 1.0 & a & \\emph{\\#undef} & \\href{http://juliadata.github.io/DataFrames.jl}{DataFrames.jl} \\\\ + \t2 & 2 & M\\&F & B & 2.0 & \\emph{missing} & \\emph{\\#undef} & \\#\\#\\#A \\\\ + \t3 & 3 & A\\textasciitilde{}B & C & \\emph{missing} & c & \\emph{\\#undef} & \$\\frac{A}{B}\$ \\\\ + \t4 & 4 & \\textbackslash{}\\textbackslash{}alpha & S & 3.0 & d & \\emph{\\#undef} & \\emph{A}b\\textbf{A} \\\\ \\end{tabular} """ + @test repr(MIME("text/latex"), df) == str @test repr(MIME("text/latex"), eachcol(df)) == str @test repr(MIME("text/latex"), eachrow(df)) == str @@ -130,6 +132,27 @@ end @test_throws ArgumentError DataFrames._show(stdout, MIME("text/html"), DataFrame(ones(2,2)), rowid=10) + + df = DataFrame( + A=Int64[1,4,9,16], + B = [ + md"[DataFrames.jl](http://juliadata.github.io/DataFrames.jl)", + md"###A", + md"``\frac{A}{B}``", + md"*A*b**A**" ] + ) + + @test repr(MIME("text/html"), df) == + "" * + "

4 rows × 2 columns

" * + "" * + "
AB
Int64MD…
11
" * + "

DataFrames.jl" * + "

\n
24
" * + "

###A

\n
39
" * + "

$\\frac{A}{B}$

\n
416

AbA

"* + "\n
" + end # test limit attribute of IOContext is used @@ -180,6 +203,101 @@ end end end +@testset "Markdown as text/plain and as text/csv" begin + df = DataFrame( + A=Int64[1,4,9,16,25,36,49,64], + B = [ + md"[DataFrames.jl](http://juliadata.github.io/DataFrames.jl)", + md"``\frac{x^2}{x^2+y^2}``", + md"# Header", + md"This is *very*, **very**, very, very, very, very, very, very, very long line" , + md"", + Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫αγ∞1∫αγ∞2∫αγ∞3"), + Markdown.parse("∫αγ∞1∫αγ∞\n"* + " * 2∫αγ∞3∫αγ∞4\n"* + " * ∫αγ∞5∫αγ\n"* + " * ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫α\n"* + " * γ∞1∫α\n"* + " * γ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + ] + ) + @test sprint(show, "text/plain", df) == """ + 8×2 DataFrame + │ Row │ A │ B │ + │ │ Int64 │ Markdown.MD │ + ├─────┼───────┼───────────────────────────────────┤ + │ 1 │ 1 │ [DataFrames.jl](http://juliadata… │ + │ 2 │ 4 │ \$\\frac{x^2}{x^2+y^2}\$ │ + │ 3 │ 9 │ # Header │ + │ 4 │ 16 │ This is *very*, **very**, very, … │ + │ 5 │ 25 │ │ + │ 6 │ 36 │ ∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫α… │ + │ 7 │ 49 │ ∫αγ∞1∫αγ∞… │ + │ 8 │ 64 │ ∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫α… │""" + + @test sprint(show, "text/csv", df) == + """ + \"A\",\"B\" + 1,\"[DataFrames.jl](http://juliadata.github.io/DataFrames.jl)\" + 4,\"\$\\\\frac{x^2}{x^2+y^2}\$\" + 9,\"# Header\" + 16,\"This is *very*, **very**, very, very, very, very, very, very, very long line\" + 25,\"\" + 36,\"∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫αγ∞1∫αγ∞2∫αγ∞3\" + 49,\"∫αγ∞1∫αγ∞\\n\\n * 2∫αγ∞3∫αγ∞4\\n * ∫αγ∞5∫αγ\\n * ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0\" + 64,\"∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫α\\n\\n * γ∞1∫α\\n * γ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0\" + """ +end + +@testset "Markdown as HTML" begin + df = DataFrame( + A=Int64[1,4,9,16,25,36,49,64], + B = [ + md"[DataFrames.jl](http://juliadata.github.io/DataFrames.jl)", + md"``\frac{x^2}{x^2+y^2}``", + md"# Header", + md"This is *very*, **very**, very, very, very, very, very, very, very long line" , + md"", + Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0" * + "∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ\n"* + " * ∞7∫αγ\n"* + " * ∞8∫αγ\n"* + " * ∞9∫αγ∞0∫α\nγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫α\n"* + " * γ∞1∫α\n"* + " * γ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + ] + ) + @test sprint(show,"text/html",df) == + "" * + "" * + "" * + "" * + "" * "

8 rows × 2 columns

" * + "" * + "" * + "" * + "" * + "" * + "" * + "" * + "
AB
Int64MD…
11
" * + "

DataFrames.jl

\n
24

$\\frac{x^2}{x^2+y^2}$

\n
39

Header

\n
416
" * + "

This is very, very, very, very, very, very, very, very, very long line

\n" * + "
525
636
" * + "

∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0

\n" * + "
749
" * + "

∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ

\n
    \n
  • ∞7∫αγ

    \n
  • \n
  • ∞8∫αγ

    \n
  • \n
  • ∞9∫αγ∞0∫α

    \n
  • \n
\n

γ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0

\n" * + "
864
" * + "

∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫α

" * + "\n
    \n" * + "
  • γ∞1∫α

    \n
  • \n" * + "
  • γ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0

    \n
  • \n" * + "
\n" * "
" +end + @testset "empty data frame and DataFrameRow" begin df = DataFrame(a = [1,2], b = [1.0, 2.0]) From 856ce8892a110dad99f7fd4e2e91f04396cd0ec0 Mon Sep 17 00:00:00 2001 From: Nicholas Ritchie Date: Mon, 31 Aug 2020 08:24:48 -0400 Subject: [PATCH 6/6] Removing space in test case Co-authored-by: Milan Bouchet-Valat --- test/io.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/io.jl b/test/io.jl index 83065b6a90..6df042e064 100644 --- a/test/io.jl +++ b/test/io.jl @@ -260,14 +260,14 @@ end md"This is *very*, **very**, very, very, very, very, very, very, very long line" , md"", Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0" * - "∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + "∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ\n"* - " * ∞7∫αγ\n"* - " * ∞8∫αγ\n"* - " * ∞9∫αγ∞0∫α\nγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + " * ∞7∫αγ\n"* + " * ∞8∫αγ\n"* + " * ∞9∫αγ∞0∫α\nγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), Markdown.parse("∫αγ∞1∫αγ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0∫α\n"* - " * γ∞1∫α\n"* - " * γ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), + " * γ∞1∫α\n"* + " * γ∞2∫αγ∞3∫αγ∞4∫αγ∞5∫αγ∞6∫αγ∞7∫αγ∞8∫αγ∞9∫αγ∞0"), ] ) @test sprint(show,"text/html",df) ==