Repository: streamlit/streamlit

Issue:
SVG support
## Is your feature request related to a problem? Please describe the problem.

I want a way to output svg graphics in Python. [I'm not the only one](https://discuss.streamlit.io/t/display-svg/172)!

## Describe the solution you'd like

I would love for `st.write(...)` to support an existing svg python library like
* [`svgwrite`](https://pypi.org/project/svgwrite/)
* [`svglib`](https://pypi.org/project/svglib/)
* [`CairoSVG`](https://cairosvg.org/)
(Never tried these, so not sure which is good, but we should pick the best / most widely used one.)

## Describe alternatives you've considered
We could also look to see if Jupyter supports SVG and which libraries they're using.



Discussion:
Hi!
This would be great!
My personal goal is to be able to display SVG + XML images on Streamlit.
It is possible to embed such an image with `st.write(html_for_svg, unsafe_allow_html=True)` but it require to write HTML code in the `html_for_svg` variable:
 `<figure><embed type="image/svg+xml" src="accessible/path/to/image.svg" /></figure>`
and to have the svg image somewhere directly accessible, which is not the case by default.
This is a workaround to display SVGs in Streamlit apps now: https://discuss.streamlit.io/t/display-svg/172/5?u=adrien_treuille

[Here is an additional forum conversation](https://discuss.streamlit.io/t/include-svg-image-as-part-of-markdown/1314/4) regarding this enhancement.
A few additional notes from offline conversations:

- It would be great if we could autodetect the ``format`` parameter too.
- These should all be viable:

```
st.image(url_to_svg, format="svg")
st.image(svg_string, format="svg")
st.image(stringio_with_svg, format="svg")  # (So it supports files)
```

I think TC's approach is the cleanest route eng-wise, and it makes a lot of sense in terms of API too. So I'll flesh out the spec a little more here. 

We can talk about whether we want `st.write` to support SVG strings later on, as that proposal needs a little more thinking. 

### Proposal 

The `st.image` function signature today looks like this:

```
    def image(
        self,
        element,
        image,
        caption=None,
        width=None,
        use_column_width=False,
        clamp=False,
        channels="RGB",
        format="JPEG",
    ):
```

Here are the proposed changes:
* `image` should accept SVG file-like objects (i.e. BytesIO) as well as SVG strings. (And also arrays of either of those, since `st.image` lets you specify multiple images).
* If `image` is a string, we need to detect whether it's a URL or SVG.
* SVG data should be transferred "as is" to the frontend, without being rasterized into PNG or JPG. The frontend then just renders pure SVG normally.
* `clamp`, `channels` don't make sense for a vector file format. We should add some text to the docstring explaining that. And we should also consider showing warnings to users when they fill out those fields and the input is SVG.
* `format` doesn't make sense for SVG because it's actually used to convert a raw image array into either JPG or PNG. So should add some text to `format`'s docstring, explaining that it doesn't apply in this case. In fact we should rename that option, as described in https://github.com/streamlit/streamlit/issues/1137 , but that's another story! 
Just to make sure, when @tvst refers to the case when the value of `image` is either URL or SVG, does it also cover the case of a local file of type SVG?
@drorata : I believe that for that case you'd have to first open the file with [Python's `open()` function](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files), then pass it into `st.image()`.

I hope you and your loved ones are safe and well! ✌️

Resolving patch:
diff --git a/lib/streamlit/elements/image_proto.py b/lib/streamlit/elements/image_proto.py
--- a/lib/streamlit/elements/image_proto.py
+++ b/lib/streamlit/elements/image_proto.py
@@ -306,7 +306,7 @@ def image_to_url(
             with open(image) as textfile:
                 image = textfile.read()
         # If it's an SVG string, then format and return an SVG data url
-        if image.startswith("<svg"):
+        if image.startswith("<svg") or image.strip().startswith("<svg"):
             return f"data:image/svg+xml,{image}"
 
         # Finally, see if it's a file.


Test patch:
diff --git a/lib/tests/streamlit/image_proto_test.py b/lib/tests/streamlit/image_proto_test.py
--- a/lib/tests/streamlit/image_proto_test.py
+++ b/lib/tests/streamlit/image_proto_test.py
@@ -156,6 +156,7 @@ def test_marshall_images_with_auto_output_format(self, data_in, expected_format)
             (IMAGES["img_32_32_3_rgb"]["np"], "/media/",),
             ("https://streamlit.io/test.png", "https://streamlit.io/test.png",),
             ("<svg fake></svg>", "data:image/svg+xml,<svg fake></svg>",),
+            ("\n<svg fake></svg>", "data:image/svg+xml,\n<svg fake></svg>",),
             ("🦈", "🦈",),
             (":shark:", ":shark:",),
         ]