diff --git a/src/Plots.jl b/src/Plots.jl index fb93c45f..d387275e 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -180,6 +180,8 @@ include("arg_desc.jl") include("plotattr.jl") include("backends.jl") include("output.jl") +include("ijulia.jl") +include("fileio.jl") include("init.jl") include("backends/plotly.jl") diff --git a/src/fileio.jl b/src/fileio.jl new file mode 100644 index 00000000..dbb0469e --- /dev/null +++ b/src/fileio.jl @@ -0,0 +1,24 @@ +# --------------------------------------------------------- +# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert + +_fileio_load(@nospecialize(filename::AbstractString)) = FileIO.load(filename::AbstractString) +_fileio_save(@nospecialize(filename::AbstractString), @nospecialize(x)) = FileIO.save(filename::AbstractString, x) + +function _show_pdfbackends(io::IO, ::MIME"image/png", plt::Plot) + fn = tempname() + + # first save a pdf file + pdf(plt, fn) + + # load that pdf into a FileIO Stream + s = _fileio_load(fn * ".pdf") + + # save a png + pngfn = fn * ".png" + _fileio_save(pngfn, s) + + # now write from the file + write(io, read(open(pngfn), String)) +end + +const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend} diff --git a/src/ijulia.jl b/src/ijulia.jl new file mode 100644 index 00000000..a54c0ca9 --- /dev/null +++ b/src/ijulia.jl @@ -0,0 +1,59 @@ +const use_local_dependencies = Ref(false) +const use_local_plotlyjs = Ref(false) + + +function _init_ijulia_plotting() + # IJulia is more stable with local file + use_local_plotlyjs[] = isfile(plotly_local_file_path) + + ENV["MPLBACKEND"] = "Agg" +end + + +""" +Add extra jupyter mimetypes to display_dict based on the plot backed. + +The default is nothing, except for plotly based backends, where it +adds data for `application/vnd.plotly.v1+json` that is used in +frontends like jupyterlab and nteract. +""" +_ijulia__extra_mime_info!(plt::Plot, out::Dict) = out + +function _ijulia__extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict) + out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o) + out +end + +function _ijulia__extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict) + out["application/vnd.plotly.v1+json"] = Dict( + :data => plotly_series(plt), + :layout => plotly_layout(plt) + ) + out +end + + +function _ijulia_display_dict(plt::Plot) + output_type = Symbol(plt.attr[:html_output_format]) + if output_type == :auto + output_type = get(_best_html_output_type, backend_name(plt.backend), :svg) + end + out = Dict() + if output_type == :txt + mime = "text/plain" + out[mime] = sprint(show, MIME(mime), plt) + elseif output_type == :png + mime = "image/png" + out[mime] = base64encode(show, MIME(mime), plt) + elseif output_type == :svg + mime = "image/svg+xml" + out[mime] = sprint(show, MIME(mime), plt) + elseif output_type == :html + mime = "text/html" + out[mime] = sprint(show, MIME(mime), plt) + else + error("Unsupported output type $output_type") + end + _ijulia__extra_mime_info!(plt, out) + out +end diff --git a/src/init.jl b/src/init.jl index 257ba4b8..1cd1fcd2 100644 --- a/src/init.jl +++ b/src/init.jl @@ -1,16 +1,22 @@ using REPL -const use_local_dependencies = Ref(false) + +function _plots_defaults() + if isdefined(Main, :PLOTS_DEFAULTS) + Main.PLOTS_DEFAULTS::Dict{Symbol,Any} + else + Dict{Symbol,Any}() + end +end + function __init__() - - if isdefined(Main, :PLOTS_DEFAULTS) - if haskey(Main.PLOTS_DEFAULTS, :theme) - theme(Main.PLOTS_DEFAULTS[:theme]) - end - for (k,v) in Main.PLOTS_DEFAULTS - k == :theme || default(k, v) - end + user_defaults = _plots_defaults() + if haskey(user_defaults, :theme) + theme(user_defaults[:theme]) + end + for (k,v) in user_defaults + k == :theme || default(k, v) end insert!(Base.Multimedia.displays, findlast(x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay()) @@ -29,95 +35,26 @@ function __init__() @require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" include(joinpath(@__DIR__, "backends", "pyplot.jl")) @require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" include(joinpath(@__DIR__, "backends", "unicodeplots.jl")) - # --------------------------------------------------------- - # IJulia - # --------------------------------------------------------- - use_local = false @require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin if IJulia.inited - # IJulia is more stable with local file - use_local = isfile(plotly_local_file_path) - """ - Add extra jupyter mimetypes to display_dict based on the plot backed. + _init_ijulia_plotting() - The default is nothing, except for plotly based backends, where it - adds data for `application/vnd.plotly.v1+json` that is used in - frontends like jupyterlab and nteract. - """ - _extra_mime_info!(plt::Plot, out::Dict) = out - function _extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict) - out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o) - out - end - - function _extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict) - out["application/vnd.plotly.v1+json"] = Dict( - :data => plotly_series(plt), - :layout => plotly_layout(plt) - ) - out - end - - function IJulia.display_dict(plt::Plot) - output_type = Symbol(plt.attr[:html_output_format]) - if output_type == :auto - output_type = get(_best_html_output_type, backend_name(plt.backend), :svg) - end - out = Dict() - if output_type == :txt - mime = "text/plain" - out[mime] = sprint(show, MIME(mime), plt) - elseif output_type == :png - mime = "image/png" - out[mime] = base64encode(show, MIME(mime), plt) - elseif output_type == :svg - mime = "image/svg+xml" - out[mime] = sprint(show, MIME(mime), plt) - elseif output_type == :html - mime = "text/html" - out[mime] = sprint(show, MIME(mime), plt) - else - error("Unsupported output type $output_type") - end - _extra_mime_info!(plt, out) - out - end - - ENV["MPLBACKEND"] = "Agg" + IJulia.display_dict(plt::Plot) = _ijulia_display_dict(plt) end end if haskey(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL") - use_local = ENV["PLOTS_HOST_DEPENDENCY_LOCAL"] == "true" - use_local_dependencies[] = isfile(plotly_local_file_path) && use_local - if use_local && !isfile(plotly_local_file_path) + use_local_plotlyjs[] = ENV["PLOTS_HOST_DEPENDENCY_LOCAL"] == "true" + use_local_dependencies[] = isfile(plotly_local_file_path) && use_local_plotlyjs[] + if use_local_plotlyjs[] && !isfile(plotly_local_file_path) @warn("PLOTS_HOST_DEPENDENCY_LOCAL is set to true, but no local plotly file found. run Pkg.build(\"Plots\") and make sure PLOTS_HOST_DEPENDENCY_LOCAL is set to true") end else - use_local_dependencies[] = use_local + use_local_dependencies[] = use_local_plotlyjs[] end - - # --------------------------------------------------------- - # A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert @require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin - PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend} - function _show(io::IO, ::MIME"image/png", plt::Plot{<:PDFBackends}) - fn = tempname() - - # first save a pdf file - pdf(plt, fn) - - # load that pdf into a FileIO Stream - s = FileIO.load(fn * ".pdf") - - # save a png - pngfn = fn * ".png" - FileIO.save(pngfn, s) - - # now write from the file - write(io, read(open(pngfn), String)) - end + _show(io::IO, mime::MIME"image/png", plt::Plot{<:PDFBackends}) = _show_pdfbackends(io, mime, plt) end end