Loading .svg into Plot for further processing

I am working on an image that combines a chart, white space, and text. I am using Plot for this. I start by producing the chart and then save it as a .png image. Then I load the image and add various designs like white space borders and text. Finally, I save the image produced as .svg.

Unfortunately, I have hit an obstacle. While I can save the produced image as .svg, the application that I need to read the image (non-julia related) complains that the vector image cannot contain an imbedded image like .png.

So, I thought, why not save the produced chart as .svg? Well, that is no problem, but it seems that I cannot load a .svg image into plot for further processing, like I can with the .png version.

How might I solve this problem? Is there no way to load the .svg into plot?

Or am I going about htis the wrong way? Do I really need to save the chart as an image only to load it for further processing?

I think a minimum example of what you’re looking to do might help people recommend possible workflows.

There’s a difference between “placing” an SVG and “reading in” an SVG (interpreting the SVG code). Rsvg.jl can do the latter (for Cairo).

Below is my minimum example (please see code for comments):

using Plots

# ----------------------------------------------------------------------------------------------------
# The following works no problem at all:
# -----------------------------------------------------------------------------------------------------
# Generate chart and save as PNG
# -----------------------------------------------------------------------------------------------------
x = rand(100)
y = x .+ rand(100)
plot(x,y, seriestype = :scatter, size = [750,750])
savefig(my_path*"saved_image.png")
# -----------------------------------------------------------------------------------------------------
# Load image for further processing
# -----------------------------------------------------------------------------------------------------
img_path = my_path*"saved_image.png"
image = load(img_path)
# -----------------------------------------------------------------------------------------------------
# Place whitespace top and bottom of image
# -----------------------------------------------------------------------------------------------------
top = Gray.(ones(100,750))
bottom = left
processed_image = [top;image;bottom]
# -----------------------------------------------------------------------------------------------------
savefig(my_path*"savedPNG.png")
# -----------------------------------------------------------------------------------------------------
# EOF



# ----------------------------------------------------------------------------------------------------
# The following causes problems:
# -----------------------------------------------------------------------------------------------------
# Generate chart and save as SVG
# -----------------------------------------------------------------------------------------------------
x = rand(100)
y = x .+ rand(100)
plot(x,y, seriestype = :scatter, size = [750,750])
savefig(my_path*"saved_image.svg")
# -----------------------------------------------------------------------------------------------------
# (Here comes the problem) Load image for further processing
# -----------------------------------------------------------------------------------------------------
img_path = my_path*"saved_image.svg"
image = load(img_path) # ERROR: No applicable_loaders found for SVG
# -----------------------------------------------------------------------------------------------------
# Place whitespace top and bottom of image
# -----------------------------------------------------------------------------------------------------
top = Gray.(ones(100,750))
bottom = left
processed_image = [top;image;bottom]
# -----------------------------------------------------------------------------------------------------
savefig(my_path*"savedSVG.svg")
# -----------------------------------------------------------------------------------------------------
# EOF

So, the first, PNG, workflow works but the output is not a vector format suitable for your target application, and the second, SVG, workflow would generate vector output if only Plots.jl could place SVG files into plots.

So really you want to combine two SVG files into a third SVG file using a package other than Plots…?

Well, ideally I would like to use Plots. But if there is no other way…

Here is the reason why .SVG become an issue in the first place. The annotation in PNG although shown correctly in the REPL, saves as black. That is no issue when saved as .svg (but then I get the combined svg/png issue)

using Plots

# ----------------------------------------------------------------------------------------------------
# The following script works no problem at all, until an annotation in non-black custom color saves as black
# -----------------------------------------------------------------------------------------------------
# Generate chart and save as PNG
# -----------------------------------------------------------------------------------------------------
x = rand(100)
y = x .+ rand(100)
plot(x,y, seriestype = :scatter, size = [750,750])
savefig(my_path*"saved_image.png")
# -----------------------------------------------------------------------------------------------------
# Load image for further processing
# -----------------------------------------------------------------------------------------------------
img_path = my_path*"saved_image.png"
image = load(img_path)
# -----------------------------------------------------------------------------------------------------
# Place whitespace left and right of image
# -----------------------------------------------------------------------------------------------------
top = Gray.(ones(100,750))
bottom = left
processed_image = [top;image;bottom]
# -----------------------------------------------------------------------------------------------------
# Place annotation in custom color, but when saved, the annotation is black
# -----------------------------------------------------------------------------------------------------
plot(processed_image)
Plots.annotate!(375, 50, Plots.text("Text in Custom Color - Not Black", RGB(50/255,200/255,218/255), :centre, 12, "Helvetica Bold"))
savefig(my_path*"savedPNG.png")
# -----------------------------------------------------------------------------------------------------
# Loading the image shows a black title ...
# -----------------------------------------------------------------------------------------------------
# EOF

savedPNG

A weird bug indeed. Looks like you can’t have both colored text and Helvetica Bold at the same time.

using Plots, FileIO

y = rand(10)
p = plot(y, annotations=(3, y[3], 
    Plots.text("orange text", RGB(1, 0.5, 0.0), :centre, "Helvetica Bold", 12)))
savefig("/tmp/savedPNG.png")
p

I tried changing the order of the arguments, lost the font but kept the color.

using Plots, FileIO

y = rand(10)
p = plot(y, annotations=(3, y[3], 
    Plots.text("orange text", RGB(1, 0.5, 0.0), "Helvetica Bold", :centre, 12)))
savefig("/tmp/savedPNG.png")
p

Strange that the order of arguments brings the color back. By the way, I just posted the problem as a seperate issue since it is only somewhat related to the .svg problem.

Changing the order doesn’t have the same effect on my system (Visual Studio Code). However, when I removed the Helvetica specifyer, the problem went away.

A note about vector and raster graphics: SVG files can embed a raster image, but that doesn’t magically turn the raster image into a vector image. It is almost certainly better to export to a vector format to begin with, and keep to vector as long as possible.