ASKSAGE: Sage Q&A Forum - Individual question feedhttps://ask.sagemath.org/questions/Q&A Forum for SageenCopyright Sage, 2010. Some rights reserved under creative commons license.Mon, 03 Aug 2020 20:31:34 -0500Outputting SVG source of a plothttps://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/Given a plot, how do I return the source code of its SVG representation? (Not save the SVG to disk.)
E.g. this saves to disk:
`plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).save('foo.svg')`
I want something like:
`plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).svg_source()`
which returns a string containing the source of the SVG.
Sun, 02 Aug 2020 10:36:30 -0500https://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/Comment by nbruin for <p>Given a plot, how do I return the source code of its SVG representation? (Not save the SVG to disk.)</p>
<p>E.g. this saves to disk:</p>
<p><code>plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).save('foo.svg')</code></p>
<p>I want something like:</p>
<p><code>plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).svg_source()</code></p>
<p>which returns a string containing the source of the SVG.</p>
https://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/?comment=52844#post-id-52844It would be totally doable to implement that. Sage plotting (at least the 2d stuff) is all wrapping matplotlib, so whatever is available there can be exposed fairly straightforwardly in sage as well. It just needs someone willing and able to do the job.Mon, 03 Aug 2020 20:31:34 -0500https://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/?comment=52844#post-id-52844Comment by StevenClontz for <p>Given a plot, how do I return the source code of its SVG representation? (Not save the SVG to disk.)</p>
<p>E.g. this saves to disk:</p>
<p><code>plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).save('foo.svg')</code></p>
<p>I want something like:</p>
<p><code>plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).svg_source()</code></p>
<p>which returns a string containing the source of the SVG.</p>
https://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/?comment=52841#post-id-52841It's a shame that there's no (optional) keyword argument in Sage ala `.save('foo.xml',file_format='svg')` that lets you explicitly ask for a desired file format.Mon, 03 Aug 2020 17:50:19 -0500https://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/?comment=52841#post-id-52841Comment by nbruin for <p>Given a plot, how do I return the source code of its SVG representation? (Not save the SVG to disk.)</p>
<p>E.g. this saves to disk:</p>
<p><code>plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).save('foo.svg')</code></p>
<p>I want something like:</p>
<p><code>plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).svg_source()</code></p>
<p>which returns a string containing the source of the SVG.</p>
https://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/?comment=52824#post-id-52824The real engine behind this is matplotlib's "savefig" function. It explicitly also allows a "file-like" object (in which case the "file" format must be specified explicitly, because there's no file name extension to infer it from). With that, you'd be able to write to a StringIO object. Probably using a temporary file is easier, though, and it might be the case that the wrapping that sage has done loses the ability to use a file-like object rather than a file name.Mon, 03 Aug 2020 03:08:55 -0500https://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/?comment=52824#post-id-52824Answer by StevenClontz for <p>Given a plot, how do I return the source code of its SVG representation? (Not save the SVG to disk.)</p>
<p>E.g. this saves to disk:</p>
<p><code>plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).save('foo.svg')</code></p>
<p>I want something like:</p>
<p><code>plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).svg_source()</code></p>
<p>which returns a string containing the source of the SVG.</p>
https://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/?answer=52818#post-id-52818As an illustration of @slelievre's answer, I wrote a couple functions to read in the SVG (or other graphics) source to convert the result into Base64.
def base64(obj, file_format="svg"):
"""
Generates Base64 encoding of the graphic in the requested file_format.
"""
if not isinstance(obj,Graphics):
raise TypeError("Only graphics may be encoded as base64")
if file_format not in ["svg", "png"]:
raise ValueError("Invalid file format")
filename = tmp_filename(ext=f'.{file_format}')
obj.save(filename)
with open(filename, 'rb') as f:
from base64 import b64encode
b64 = b64encode(f.read()).decode('utf-8')
return b64
def data_url(obj, file_format="svg"):
"""
Generates Data URL representing the graphic in the requested file_format.
"""
b64 = base64(obj, file_format=file_format)
if file_format=="svg":
file_format = "svg+xml"
return f"data:image/{file_format};base64,{b64}"
f = lambda x, y: sin(x + y) + cos(x + y)
p = plot_slope_field(f, (-3, 3), (-3, 3))
du = data_url(p,file_format="png")
from IPython.core.display import display, HTML
display(HTML(f"<img src='{du}'>"))
print(f"<img src='{du}'>")Sun, 02 Aug 2020 19:31:55 -0500https://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/?answer=52818#post-id-52818Answer by slelievre for <p>Given a plot, how do I return the source code of its SVG representation? (Not save the SVG to disk.)</p>
<p>E.g. this saves to disk:</p>
<p><code>plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).save('foo.svg')</code></p>
<p>I want something like:</p>
<p><code>plot_slope_field(sin(x+y) + cos(x+y), (x,-3,3), (y,-3,3)).svg_source()</code></p>
<p>which returns a string containing the source of the SVG.</p>
https://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/?answer=52816#post-id-52816Certain classes of Sage objects may provide methods
to return svg or tikz representations as strings.
For plots such as the one in the question though, plotting
and saving are delegated to matplotlib, who produces the
svg string. No direct method provides the svg string.
The obvious workaround is to save to a file, and then read the file into a string.
To illustrate, define a function and plot the corresponding slope field:
sage: f = lambda x, y: sin(x + y) + cos(x + y)
sage: p = plot_slope_field(f, (-3, 3), (-3, 3))
Save the plot into a file (see note at the end of this answer):
sage: filename = 'slope_field.svg'
sage: p.save(filename)
Read the saved file:
sage: with open(filename, 'r') as f:
....: s = f.read()
Check the result by printing an initial and a final fragment:
sage: print(s[:155], "...", s[-30:], sep='\n')
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
...
</clipPath>
</defs>
</svg>
Note: to create the file as a temporary file that will get cleaned up automatically when Sage exits:
sage: filename = tmp_filename(ext='.svg')
It is of course also possible to delete the file oneself, without waiting for Sage to exit:
sage: os.remove(filename)Sun, 02 Aug 2020 15:20:01 -0500https://ask.sagemath.org/question/52810/outputting-svg-source-of-a-plot/?answer=52816#post-id-52816