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

Output to LaTeX added (useful for IJulia notebook export to PDF) #845

Merged
merged 11 commits into from
Oct 3, 2016
54 changes: 54 additions & 0 deletions src/abstractdataframe/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,60 @@ end
write(io, "</table>")
end

##############################################################################
#
# LaTeX output
#
##############################################################################

function latex_char_escape(char::SubString)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's my understanding that SubString will eventually be merged into String. Also, why not use Char?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, should either be Char or AbstractString.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think this should be Char or AbstractString. Either is fine, though the function and argument name suggest to me that Char would make the most sense.

if char == "\\"
return "\\textbackslash{}"
elseif char == "~"
return "\\textasciitilde{}"
else
return string("\\", char)
end
end

function latex_escape(cell::AbstractString)
cell = replace(cell, ['\\','~','#','$','%','&','_','^','{','}'], latex_char_escape)
return cell
end

function Base.show(io::IO, ::MIME"text/latex", df::AbstractDataFrame)
nrows = size(df, 1)
ncols = size(df, 2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be written more succinctly as nrows, ncols = size(df). Doesn't matter too much, just thought I'd point it out.

cnames = _names(df)
alignment = repeat("c", ncols)
write(io, "\\begin{tabular}{r|")
write(io, alignment)
write(io, "}\n")
write(io, "\t& ")
header = join(map(c -> latex_escape(string(c)), cnames), " & ")
write(io, header)
write(io, "\\\\ \n")
write(io, "\t\\hline \n")
for row in 1:nrows
write(io, "\t")
write(io, @sprintf("%d", row))
for col in 1:ncols
write(io, " & ")
cell = df[row,col]
if !isnull(cell)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I hadn't noticed this. This should print #NULL instead of nothing for null values, just like at the REPL and in HTML. Could you apply the strategy I described at #1084 in a new PR?

content = get(cell)
if mimewritable(MIME("text/latex"), content)
show(io, MIME("text/latex"), content)
else
print(io, latex_escape(string(content)))
end
end
end
write(io, " \\\\ \n")
end
write(io, "\\end{tabular}\n")
end

##############################################################################
#
# MIME
Expand Down
1 change: 1 addition & 0 deletions test/REQUIRE
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ Compat 0.9.0
DataStructures
RDatasets # can be removed when deprecated.jl doesn't test read_rda anymore
RData
LaTeXStrings
10 changes: 10 additions & 0 deletions test/io.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module TestIO
using Base.Test
using DataFrames, Compat
using LaTeXStrings
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this introduces a test dependency on an external package, the package will have to be included in test/REQUIRE.


#test_group("We can read various file types.")

Expand Down Expand Up @@ -490,4 +491,13 @@ module TestIO
# Need to wrap macro call inside eval to prevent the error from being
# thrown prematurely
@test_throws ArgumentError eval(:(csv"foo,bar"a))

# Test LaTeX export
df = DataFrame(A = 1:4,
B = ["\$10.0", "M&F", "A~B", "\\alpha"],
C = [L"\alpha", L"\beta", L"\gamma", L"\sum_{i=1}^n \delta_i"],
D = [1.0, 2.0, Nullable(), 3.0]
)
@test isequal(reprmime(MIME("text/latex"), df), "\\begin{tabular}{r|cccc}\n\t& A & B & C & D\\\\ \n\t\\hline \n\t1 & 1 & \\\$10.0 & \$\\alpha\$ & 1.0 \\\\ \n\t2 & 2 & M\\&F & \$\\beta\$ & 2.0 \\\\ \n\t3 & 3 & A\\textasciitilde{}B & \$\\gamma\$ & \\\\ \n\t4 & 4 & \\textbackslash{}alpha & \$\\sum_{i=1}^n \\delta_i\$ & 3.0 \\\\ \n\\end{tabular}\n")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using a multiline string block (""") you should be able to replace the \n by actual line breaks to make it more readable.


end