I can create a Polygon by:
#!/usr/bin/env python
from shapely.geometry import Polygon
area = Polygon(((52, 13), (57, 14), (58, 12)))
with open('test.svg', 'w') as f:
f.write(area.svg())
which returns
<path fill-rule="evenodd" fill="#66cc99" stroke="#555555" stroke-width="2.0" opacity="0.6" d="M 52.0,13.0 L 57.0,14.0 L 58.0,12.0 L 52.0,13.0 z" />
This is not a valid SVG file. How can I get a valid SVG?
I tried
#!/usr/bin/env python
from shapely.geometry import Polygon
area = Polygon(((52, 13), (57, 14), (58, 12)))
with open('test.svg', 'w') as f:
f.write('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">')
f.write(area.svg())
f.write('</svg>')
When I view this, the viewport is way to big for the polygon. Manually editing it with Inkscape and resizing it gives:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="test.svg"
width="7.9687681"
height="4.4396091">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1364"
id="namedview6"
showgrid="false"
inkscape:zoom="2.36"
inkscape:cx="-1.8038839"
inkscape:cy="-34.869627"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg2"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<path
d="m 0.19611614,2.3092357 4.99999996,1 1,-2 -5.99999996,1 z"
id="path4"
inkscape:connector-curvature="0"
style="opacity:0.6;fill:#66cc99;fill-rule:evenodd;stroke:#555555;stroke-width:2" />
</svg>
Is there a way to get this automatically?
try:
with open('test.svg', 'w') as f:
f.write(area._repr_svg_())
the BaseGeometry._repr_svg_ function is used for IPython/Jupyter integration, in order to render Shapely objects inline in Jupyter notebooks. Hence the "internal" naming, which is defined here:
http://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html
Effectively, it results in a valid SVG output.
You would need to specify the size and viewBox of the resulting image. For example:
#!/usr/bin/env python
from shapely.geometry import Polygon
import textwrap
area = Polygon(((52, 13), (57, 14), (58, 12)))
with open('test.svg', 'w') as f:
#specify margin in coordinate units
margin = 5
bbox = list(area.bounds)
bbox[0] -= margin
bbox[1] -= margin
bbox[2] += margin
bbox[3] += margin
width = bbox[2] - bbox[0]
height = bbox[3] - bbox[1]
#transform each coordinate unit into "scale" pixels
scale = 10
props = {
'version': '1.1',
'baseProfile': 'full',
'width': '{width:.0f}px'.format(width = width*scale),
'height': '{height:.0f}px'.format(height = height*scale),
'viewBox': '%.1f,%.1f,%.1f,%.1f' % (bbox[0], bbox[1], width, height),
'xmlns': 'http://www.w3.org/2000/svg',
'xmlns:ev': 'http://www.w3.org/2001/xml-events',
'xmlns:xlink': 'http://www.w3.org/1999/xlink'
}
f.write(textwrap.dedent(r'''
<?xml version="1.0" encoding="utf-8" ?>
<svg {attrs:s}>
{data:s}
</svg>
''').format(
attrs = ' '.join(['{key:s}="{val:s}"'.format(key = key, val = props[key]) for key in props]),
data = area.svg()
).strip())
Related
How can I add radial gradient in SwiftUI using provided SVG file?
All I have got is below SVG file which has gradient inforamtion:
<defs>
<clipPath id>
<path d="M1890, 0 L1890, 888 L0, 888 L0, 0L1890, 0 Z" />
</clipPath>
<radialGradient id: "grad1" cx = "0px" cy = "0px" r = "1000px" gradientTransform = "scale(1.0.0.56)" gradientUnits="userSpaceOnUse">
<stop stop-color = "rgba(0,0,0,0.6)" offset="0%" />
<stop stop-color = "rgba(0,0,0,0)" offset="100%" />
</radialGradient>
<clipPath id>
<path d="0, 0 1890, 0 1890, 888 0, 888 0, 0" />
</clipPath>
</defs>
My SwiftUI code has image which needs above gradient:
Image(room.thumbnailImage)
.resizable()
.frame(maxWidth: 400, maxHeight: 140.0)
I was wondering why this D3 code just does not work:
...
console.log(data["SAT"]);
/************* Generic line definition ************/
var line = d3.line()
.x(d => xScale(d.x))
.y(d => yScale1(d.y));
/******************* SAT line *****************/
var SATPath = svg.append("g")
.attr("class", "SAT-curve")
.selectAll("path")
.data(data["SAT"])
.enter().append('path')
.attr("fill", "none")
.attr("stroke-width", 1.5)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("d", d => line(d))
.attr("stroke", colors.purple);
The console.log() line just shows data in apparently correct way:
[0 … 99]
0: {x: 0.0011, y: 178.75}
1: {x: 0.0011, y: 180.75}
...
94: {x: 0.0014, y: 366.75}
95: {x: 0.0014, y: 368.75}
96: {x: 0.0014, y: 370.75}
97: {x: 0.0014, y: 372.75}
98: {x: 0.0014, y: 374.75}
99: {x: 0.0015, y: 376.75}
[100 … 199]
[200 … 299]
[300 … 307]
length: 308
[[Prototype]]: Array(0)
... And all margin.*, xScale and yScale1 axes are correctly defined (or I think so) because they are correctly rendered.
The problem is that it generates all 308 paths with all attributes, EXCEPT the d one, and then the path results in 0x0 size:
<g class="SAT-curve">
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
....
<path fill="none" stroke-width="1.5" transform="translate(50,30)" stroke="#8e69b3"></path>
</g>
No JS console errors.
Any ideas?
Thanks in advance.
The data() method binds one array element to one DOM element. That said, you don't want 308 paths, you want just one path with 308 data points. Therefore, wrap everything in an outer array, witch has just one element:
.data([data["SAT"]])
I am using vips PHP library. I want to add svg path on my image. I implemented below code for that but it's not giving me expected output. The problem is how can I set svg path according to the actual image height & width. I tried using resize and thumbnail but it doesn't give me expected output. Also I want to fill the grey color on my actual image blocks like in expected output image.
The expected output image generated using imagick
$background = Vips\Image::newFromFile($arg[1], ['access' => 'sequential']);
$svg = Vips\Image::svgload_buffer('<svg>
<path
d="M0 200 v-200 h200
a100,100 90 0,1 0,200
a100,100 90 0,1 -200,0
z" stroke="#fff" fill="transparent"/>
</svg>');
// $svg = $svg->resize(2.5);
$svg = $svg->thumbnail_image(700, ['height' => 700, 'size' => 'both']);
$image = $background->composite($svg, 'dest-in');
$image->writeToFile([$arg2], ['background' => [128, 128, 128], 'Q' => 100]);
Below is the image on which I added my svg path
My vips output image
Expected output image
Try:
#!/usr/bin/php
<?php
require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;
$background = Vips\Image::newFromFile($argv[1], ['access' => 'sequential']);
$width = $background->width;
$height = $background->height;
$svg = Vips\Image::svgload_buffer(<<<EOF
<svg
viewBox="0 0 300 300"
width="$width"
height="$height">
<path
d="M0 200 v-200 h200
a100,100 90 0,1 0,200
a100,100 90 0,1 -200,0
z" stroke="#fff" fill="white"/>
</svg>
EOF);
$image = $background->colourspace('b-w')->composite($svg, 'dest-in');
$image->writeToFile($argv[2], ['background' => [128, 128, 128], 'Q' => 100]);
Associated github issue: https://github.com/libvips/php-vips/issues/109
I am attempting to produce an SVG image from the package RDKit. A minimum reproducable example:
from rdkit import Chem
from rdkit.Chem import Draw
img = Draw.MolsToGridImage([Chem.MolFromSmiles(x) for x in ['C', 'CO', 'CN']], useSVG = True)
print(img)
The output is below, but doesn't render any image in any browser or image viewer I have tried. Is this a valid SVG file, or is the package producing an invalid format? Or is there some other error I cannot see?
<?xml version='1.0' encoding='iso-8859-1'?>
<svg version='1.1' baseProfile='full'
xmlns='http://www.w3.org/2000/svg'
xmlns:rdkit='http://www.rdkit.org/xml'
xmlns:xlink='http://www.w3.org/1999/xlink'
xml:space='preserve'
width='600px' height='200px' >
<!-- END OF HEADER -->
<rect style='opacity:1.0;fill:#FFFFFF;stroke:none' width='600' height='200' x='0' y='0'> </rect>
<text x='0' y='200' style='font-size:0px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#000000' ><tspan>CH</tspan><tspan style='baseline-shift:sub;font-size:0px;'>4</tspan><tspan></tspan></text>
<path class='bond-0' d='M 200,200 200,200' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<path class='bond-0' d='M 200,200 200,200' style='fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<text x='200' y='200' style='font-size:0px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#FF0000' ><tspan>OH</tspan></text>
<path d='M 200,200 200,200 200,200 200,200 200,200' style='fill:none;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<path class='bond-0' d='M 400,200 400,200' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<path class='bond-0' d='M 400,200 400,200' style='fill:none;fill-rule:evenodd;stroke:#0000FF;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
<text x='400' y='200' style='font-size:0px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#0000FF' ><tspan>NH</tspan><tspan style='baseline-shift:sub;font-size:0px;'>2</tspan><tspan></tspan></text>
<path d='M 400,200 400,200 400,200 400,200 400,200' style='fill:none;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
</svg>
RDKit is for an unknown reason producing SVG code which doesn't show anything. However, changing the list of molecules does result in SVG code which produces a visible image.
This works:
from rdkit import Chem
from rdkit.Chem import Draw
img = Draw.MolsToGridImage([Chem.MolFromSmiles(x) for x in ['C', 'CO', 'CN', 'CCC']], useSVG = True)
print(img)
A bug has been opened here: https://github.com/rdkit/rdkit/issues/2641
I've got SVG image (code below):
<svg height="500" width="500">
<!-- Inner line -->
<path d="M100,50 L 100,100 A 45,45 0 1,0 150,150 L 200 150" style="stroke:#000; stroke-width:6; fill:none;" />
<!-- Outer line -->
<path d="M 90,50 L 90,92.5 A 54.5,54.5 0 0,0 90,197.5 L 90, 240.5" style="stroke:#000; stroke-width:1; fill:none;" />
<circle cx="105" cy="145" r="35" stroke="black" stroke-width="1" fill="green" />
I cannot see any pattern while drawing curved lines that are separated by the same margin (I've made the image above just by "guessing"). The number of lines is dynamic so I need a formula to count every M L A parameter. E.g. I can take inner line as static (showing just the d attribute),
d="M100,50 L 100,100 A 45,45 0 1,0 150,150 L 200 150"
but then first outer should be calculated somehow, to get d:
d="M 90,50 L 90,92.5 A 54.5,54.5 0 0,0 90,197.5 L 90, 240.5"
SVG arcs are drawn with A rx ry rotation large-arc-flag sweep-flag x y
The key parameters here are rx and ry: the radii of the arc and x and y which are the final point in the arc.
For example, if you have a circle centred on (cx, cy) with radius r, you can create and arc around it, d units from the edge of the circle with:
<path d="M cx cy+r+d A r+d r+d 0 0 0 cx+r+d cy" />
This arc will be in the lower, right quadrant because of where it starts (cx, cy+r+d) and ends (cx+r+d, cy).
So call the radius of the inner arc r and the radius of the outer arc r + d. Now we need to know where to start and stop the arc. The x-coordinate of the start and stop points is d units to the left of the cx. We can find the y-coordinate by using Pythagoras's theorem to calculate the height of the triangle with a hypotenuse of r+d and a base of d:
h = sqrt((r + d)^2 - d^2).
The code for the arc will therefore be:
d="M cx-d, 50 L cx-d, cy-h A r+d r+d 0 0 0 cx-d, cy+h L cx-d, 240"
For example, with (cx, cy) = (100, 150), r = 50, and d = 10
<path d="M100,50 L 100,100 A 50,50 0 1,0 150,150 L 200 150" style="stroke:#000; stroke-width:6; fill:none;" />
<path d="M 90,50 L 90,90.8 A 60,60 0 0,0 90,209.1 L 90, 240.5" style="stroke:#000; stroke-width:1; fill:none;" />
<circle cx="100" cy="150" r="40" stroke="black" stroke-width="1" fill="green" />
Does that make sense?