Coder Social home page Coder Social logo

cduck / drawsvg Goto Github PK

View Code? Open in Web Editor NEW
553.0 9.0 61.0 3.56 MB

Programmatically generate SVG (vector) images, animations, and interactive Jupyter widgets

License: MIT License

Python 100.00%
drawsvg vector-drawings jupyter-notebook animation draw drawing jupyter-lab svg svg-animation visualization

drawsvg's Introduction

Hi, I'm an engineer, architect, and artist. I currently build quantum computers at QuEra Computing and in my free time, I create computer-generated art and integrate interactive programming into everything I make.

I open source my projects and tools for other to use in their artwork, education, and other projects. Check them out below!

Featured Python and Julia packages

Art

  • drawsvg — Programmatically generate vector SVG drawings, animations, and interactive Jupyter widgets
  • hyperbolic — Construct, draw, and manipulate hyperbolic geometry
  • latextools — Conveniently build, render, and convert Latex documents and figures
  • alime — Fancy animated anti-bot email obfuscation for your website
  • InteractiveAudio.jl — Generate and play audio while dynamically changing the underlying code in real time

Quantum Computing

Education

and many more...

See also: my website, robotics projects

drawsvg's People

Contributors

apapsch avatar bocchio avatar cduck avatar chrisjefferson avatar joachimheintz avatar kogswell avatar madanh avatar marekyggdrasil avatar matthewturk avatar nmay231 avatar sl-prog avatar themightycomp avatar wholden avatar zeerdonker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

drawsvg's Issues

how to move the drawSvg.elements integrally

Discussed in #72

Originally posted by lythhh April 9, 2022
I make a simple drawSvg.elements(a triangle), what i want to do is to move the triangle a certain distance, and finally form a series of ordered triangles. So i want to konw is there any function can help me? Thank you very much
the code is as follows:
import drawSvg as draw
def mm2pt(x):
return 2.835x
dw=mm2pt(3)
dh=mm2pt(3)
d = draw.Drawing(dw, dh, origin=(0, 0), displayInline=False)
r = draw.Lines(dw/4,dh/4,dw/4
3,dh/4,dw/2,dh/4*3,close=True,fill='none',stroke='black',stroke_width=mm2pt(0.1))
r.appendTitle("角砾")
d.append(r)
d.setPixelScale(5)
d
#def move(drawSvg,w,h): #i want to construct a function with a drawSvg object and certain distance on x and y, to realize the movement of drawSvg objects.
1

Save svg animation from frames?

Hey! Thanks for making this amazing package. I'm trying to save an SVG animation from animation frames, but am not sure how to go about it. This is what I have so far:

import webcolors
import drawSvg as draw

def make_gradient(rectangles=3, width=500, height=200):
    d = draw.Drawing(width, height, displayInline=False)
    rectanglewidths = width / rectangles
    rgb_max_value = 255
    gradient_color_values = find_n_equidistant(rectangles,range(rgb_max_value))
    rectangles = range(1, rectangles+1)

    rectangle_position = 0

    for rectangle, color in zip(rectangles, gradient_color_values):

        rectangle = draw.Rectangle(rectangle_position,0,rectanglewidths,height, fill=webcolors.rgb_to_hex((color, color, color)))
        d.append(rectangle)
        rectangle_position+=rectanglewidths
    d.rasterize()
    return d

def draw_frame(t):
    d = make_gradient(t)
    return d

with draw.animate_jupyter(draw_frame, delay=0.1) as anim:

    for i in range(1,30):
        anim.draw_frame(i)

#anim.saveSvg('animated.svg')  # Save to file

This works in my jupyter notebook as an svg animation but when I try that last line, I get the error AttributeError: 'Animation' object has no attribute 'saveSvg'

Would love any help whatsoever!

Stupid question

Hi,
I have tried various permutations to get the layout correct using the library.
My problem is very simple. I have a rectangular canvas which I know the width and height of.
On this canvas I want to draw a series of rectangles and have already calculated the x, y and width and height.
All my numbers are based on the canvas being having (0,0) in a corner and x and y are positive
No matter what I do I cannot get a any sensible coordinates
What am I doing wrong.

e.g. width of paper is 1980 height is 900. and I have some rectangles. What should I do to the values for them to draw as expected (5 long rectangles, stacked on top of one another with a break of gap of 25 between then with a small box in one of them)

Sorry for the stupid question, but I cannot see how to get this to plot as expected.

Cheers,

{'height': 150.0, 'width': 1972.0, 'x': 0.0, 'y': 150.0},
{'height': 36.0, 'width': 36.0, 'x': 68.0, 'y': 207.0}
{'height': 150.0, 'width': 1972.0, 'x': 0.0, 'y': 325.0},
{'height': 150.0, 'width': 1972.0, 'x': 0.0, 'y': 500.0},
{'height': 150.0, 'width': 1972.0, 'x': 0.0, 'y': 675.0},
{'height': 150.0, 'width': 1972.0, 'x': 0.0, 'y': 850.0}]

Can't include characters like Σ in SVG text element

When I try to save a SVG with the character Σ (sigma) in a text element, I get the error:

Traceback (most recent call last):
  File "C:\Users\Mitch\Code\mc log analysis\diagrammer.py", line 401, in <module>
    drawing.saveSvg("output.svg")
  File "C:\Users\Extreme PC\AppData\Local\Programs\Python\Python39\lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u03a3' in position 7970: character maps to <undefined>

When I try to use the XML entity &#931; to replace it, it gets escaped and is output literally. My current solution is to use the entity and then unescape the resulting output, like:

with open("output.svg", "w+") as output_file:
  output_file.write(xml.sax.saxutils.unescape(drawing.asSvg()))

which is a little inelegant. I think that the user should either be able to specify whether a string that they enter for the text of a text element should be XML escaped or not or be able to explicitly specify the encoding that they want to use for the file they are outputting. (I'm using Python 3.9.1 on Windows 10; on this platform, UTF-8 encoding is (apparently) not the default.)

Problems working on an M1 Mac

Hi, I've been having problems getting this to work on an M1 Mac. The problem actually lays with CairoSVG which drawSVG uses. A discussion about this issue and possible solutions can be found here CairoSVG issue 354

Just thought I'd drop a link here for anyone else experiencing the same issue

How to zoom?

Thanks for great work. I am trying to do something like crop part of svg and zoom to the full picture , I think this is one of natural svg operations.

As far as I understand I can implement crop with help of clip_path with rectangle as clip figure, but how to zoom the picture that I get to the original drawing size?

Here is my play code that generates random points and trying to crop and zoom with no luck:

import drawSvg as draw
import random
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import math

GRID_SIZE = 32
PTS_TO_GEN = 33

coloursIdsToColNames = {0:'black', 1:'white', 2:'blue', 3:'red', 4:'green', 5:'gray', 6:'olive', 7:'purple', 8:'tan', 9:'tomato'}

def gen_img(imW, imH, cropSize):
    curDrawing1 = draw.Drawing(imW, imH)
    curDrawing2 = draw.Drawing(imW, imH)
    cclip = draw.ClipPath()
    cclip.append(draw.Rectangle(cropSize[0], cropSize[1], cropSize[2], cropSize[3]))

    for i in range(PTS_TO_GEN):
        curCol = random.randint(0, 9)
        curColName = coloursIdsToColNames[curCol]
        cx = random.randint(0, imW)
        cy = random.randint(0, imH)

        curDrawing1.append(draw.Rectangle(cx, cy, 1, 1, fill=curColName))
        curDrawing2.append(draw.Rectangle(cx, cy, 1, 1, fill=curColName, clip_path = cclip))
    return curDrawing1, curDrawing2

def gen_couple():
    random.seed(0)
    imW = 32
    imH =  32

    cropX = 0
    cropY = 0
    cropW = 16
    cropH = 16

    curDrawing1, curDrawing2  = gen_img(imW, imH, [cropX, cropY, cropW, cropH])

    # curDrawing2.setRenderSize(16)  - Not working
    curDrawing2.savePng('scaled.png')
    curDrawing2.saveSvg('scaled.svg')

gen_couple()

inverted Y?

Seems like all the Y coordinates are inverted?

In this example, you'd expect the text to be lowered by 20px but it's raised instead.

import drawSvg as draw
d = draw.Drawing(80, 80, origin='center', style='background-color:#abc;border:2px solid black')
d.append(draw.Text(text='line1\nline2', fontSize=12, x=0, y=20, text_anchor='middle'))

print(d.asSvg())
y is -20

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
     width="80" height="80" viewBox="-40.0 -40.0 80 80" style="background-color:#abc;border:2px solid black">
<defs>
</defs>
<text x="0" y="-20" font-size="12" text-anchor="middle"><tspan x="0" dy="0em">line1</tspan><tspan x="0" dy="1em">line2</tspan></text>
</svg>

But I love how it handles the multiline text with tspans!

Specifying z-coordinates of shapes

Are more recently drawn shapes always placed on top of older ones? or is it possible to specify a z-coordinate of a new shape, so that it is drawn underneath already existing shapes?

No arrow heads in the png output

I ran the sample script in https://github.com/cduck/drawSvg/blob/afd0de670850e316d1327de6d92a5b0051b895bd/README.md#basic-drawing-elements directly on Python, and have got the following png output which misses the arrow heads:

example

The svg output does have the arrow heads.

I have [email protected] installed via Homebrew and the following in pip freeze:

cairocffi==1.2.0
CairoSVG==2.5.1
cffi==1.14.5
cssselect2==0.4.1
defusedxml==0.6.0
drawSvg==1.8.1
hyperbolic==1.3.1
imageio==2.9.0
numpy==1.20.1
Pillow==8.1.1
pycparser==2.20
tinycss2==1.1.0
webencodings==0.5.1

Add presentation attributes to svg elements to allow setting after creation and autocomplete

Hi @cduck , really enjoying the package you put together. From the title of my post, there were two things I thought would be natural to be able to do with this library: (1) set attributes (e.g. width, stroke) after creation of an object and (2) have available attributes exposed in a way that they can easily be seen with autocomplete, for example in a Jupyter notebook or ipython. I didn't immediately see these capabilites in the library, but if they are there and I missed it, please let me know.

At any rate, I took a swing at the problem. (1) was relatively straightforward, but (2) turned out to be a challenging (albeit fun) problem to solve.

I made a demo showing the functionality for the Circle svg element. (https://github.com/wholden/drawSvg/tree/with-presentation-attritbutes) I added an attribute "presentation" which contains the "most notable" editable svg attributes

Basically, I created the ability to dynamically add property attributes to the class, then populated it based on the list of "most notable" presentation attributes from the svg specification (https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle#Attributes).

Let me know what you think of this idea.

Here is a demo of the result:

drawsvg_presentation_attributes_demo

the unit

hello!
Class Drawing in module drawSvg.drawing is 'Drawing(width, height, origin=(0, 0), idPrefix='d', displayInline=True, **svgArgs)'
i want to konw the unit of width or height in Drawing() . Is it the pt?how can i use the unit of 'mm'?Thank you very much!

Text alignment

Is there any way to align text to the right, so that the coordinates given to drawSvg.Text correspond to the right margin of the text rather than the left? What about center? Thanks!

Support for pattern def

Are you intending to add support for patterns, to be included in the definition?

An example

<pattern id="pattern-chevron" x="0" y="0" width="15" height="15" patternUnits="userSpaceOnUse">
  <path d="M8 2.156l-1.406 1.438-6.594 6.563v5.688l.125-.125 7.875-7.906 8 8v-5.625l-6.594-6.594-1.406-1.438z" />
</pattern>

Transparent gifs

First of all thank you for this nice package!
I was trying to export an animation as a gif with a transparent background. Unfortunately, this was not possible using imageio (at least based on my googeling). There is a solution using PIL (see below).

However, this requires implementing a custom save function. Would you be interested in adding alternative support for PIL to save gifs to allow this solution natively? I would be willing to implement this properly. If not, I hope this issue serves as potential information for others who ran into the same issue I did.

import drawSvg as draw
from PIL import Image
from drawSvg import Drawing, render_svg_frames


def convert_to_transparent_frame(im):
    """Modified from https://stackoverflow.com/questions/46850318/transparent-background-in-gif-using-python-imageio"""
    alpha = im.getchannel("A")

    # Convert the image into P mode but only use 255 colors in the palette out of 256
    im = im.convert("RGB").convert("P", palette=Image.ADAPTIVE, colors=255)

    # Mark all pixels with alpha=0 as transparent
    mask = Image.eval(alpha, lambda a: 255 if a == 0 else 0)

    # Paste the color of index 255 and use alpha as a mask
    im.paste(255, mask)

    # The transparency index is 255
    im.info["transparency"] = 255

    return im


def save_video(frames, file, **kwargs):
    """
    Save a series of drawings as a GIF or video.

    Arguments:
        frames: A list of `Drawing`s or a list of `numpy.array`s.
        file: File name or file like object to write the video to.  The
            extension determines the output format.
        align_bottom: If frames are different sizes, align the bottoms of each
            frame in the video.
        align_right: If frames are different sizes, align the right edge of each
            frame in the video.
        bg: If frames are different sizes, fill the background with this color.
            (default is white: (255, 255, 255, 255))
        duration: If writing a GIF, sets the duration of each frame.
        fps: If writing a video, sets the frame rate in FPS.
        **kwargs: Other arguments to imageio.mimsave().

    """
    if isinstance(frames[0], Drawing):
        frames = render_svg_frames(frames, **kwargs)
    kwargs.pop("align_bottom", None)
    kwargs.pop("align_right", None)
    kwargs.pop("bg", None)
    frames = [
        convert_to_transparent_frame(Image.fromarray(frame, "RGBA")) for frame in frames
    ]
    frames[0].save(
        file,
        save_all=True,
        append_images=frames[1:],
        disposal=2,  # This "cleans" the canvas after every draw
        optimize=False,  # This is critical for transparent background
        **kwargs,
    )


# Draw a frame of the animation
def draw_frame(t):
    d = draw.Drawing(2, 6.05, origin=(-1, -1.05))
    d.setRenderSize(h=300)
    # d.append(draw.Rectangle(-2, -2, 4, 8, fill="white")) # Commented out, as we want to have transparent background
    d.append(draw.Rectangle(-1, -1.05, 2, 0.05, fill="brown"))
    t = (t + 1) % 2 - 1
    y = 4 - t ** 2 * 4
    d.append(draw.Circle(0, y, 1, fill="lime"))
    return d


with draw.animate_video(None, draw_frame) as anim:
    # Add each frame to the animation
    for i in range(20):
        anim.draw_frame(i / 10)
    for i in range(20):
        anim.draw_frame(i / 10)
    for i in range(20):
        anim.draw_frame(i / 10)

    save_video(anim.frames, "test.gif", duration=0.05)

style tag

Hi! Building on #24 I added a way to add <STYLE> tags to the drawing. Would this be a good pull request, or is it sufficiently niche+straightforward that it doesn't belong in the core?

"in" property for FilterItems

How do you specify the "in" property in a FilterItem?

cloudFilter.append(drawSVG.FilterItem("feBlend", mode="screen", in="blue", in2="wispyCloud"))

This snippet won't work because "in" is a reserved keyword.

It would be nice to be able to prepend any property with 'svg' like svgIn="blue" which could be removed while processing.

OS Error when importing

I just installed this package. When importing as in your example I get the following error:

OSError                                   Traceback (most recent call last)
<ipython-input-1-18b5d834a3c4> in <module>()
----> 1 import drawSvg as draw

~/anaconda3/lib/python3.6/site-packages/drawSvg/__init__.py in <module>()
     46 
     47 from .defs import *
---> 48 from .raster import Raster
     49 from .drawing import Drawing
     50 from .elements import *

~/anaconda3/lib/python3.6/site-packages/drawSvg/raster.py in <module>()
      3 
      4 try:
----> 5     import cairosvg
      6 except ImportError:
      7     import warnings

~/anaconda3/lib/python3.6/site-packages/cairosvg/__init__.py in <module>()
     39 
     40 # VERSION is used in the "url" module imported by "surface"
---> 41 from . import surface  # noqa
     42 
     43 

~/anaconda3/lib/python3.6/site-packages/cairosvg/surface.py in <module>()
     22 import io
     23 
---> 24 import cairocffi as cairo
     25 
     26 from .colors import color

~/anaconda3/lib/python3.6/site-packages/cairocffi/__init__.py in <module>()
     39 
     40 
---> 41 cairo = dlopen(ffi, 'cairo', 'cairo-2', 'cairo-gobject-2')
     42 
     43 

~/anaconda3/lib/python3.6/site-packages/cairocffi/__init__.py in dlopen(ffi, *names)
     36             except OSError:
     37                 pass
---> 38     raise OSError("dlopen() failed to load a library: %s" % ' / '.join(names))
     39 
     40 

OSError: dlopen() failed to load a library: cairo / cairo-2 / cairo-gobject-2

I've also attempted to fix by explicitly pip installing cairosvg with no change in the error.

Change viewport (new setViewPort method)

New to git, so I'm sure there's an easier way to do this, but here's the code (from drawing.py, 51):

 def setRenderSize(self, w=None, h=None):

      self.renderWidth = w

      self.renderHeight = h

      if origin == 'center':

        self.viewBox = (-width/2, -height/2, width, height)

      return

Haven't tested the code, and it already works well on most borwsers/etc, but I'm trying to develop on Kivy, and they barely support SVG files.

Feedback is welcome

EDIT: looks like you may need to make the 'origin' global, or create a setViewPort func

saveSvg: ascii codec can't encode character

Hello, I'm trying to draw some SVG's and some of them have texts with umlauts. Jupyter can show the generated svg, but not save it to disk.
Here's a MWE:

import drawSvg as draw
d = draw.Drawing(50, 50)
d.append(draw.Text("König", 8, 25,25,center=True))
d.saveSvg("test.svg")

The error is UnicodeEncodeError: 'ascii' codec can't encode character '\xf6' in position 1: ordinal not in range(128)

Any ideas?

Rotate group

Is it possible to rotate a group with <g transform="rotate(45 50 50)">...</g>?

text following circular path

Hello!
I was wondering if it is possible to recreate effect like on following example? Of text following a curved path.

<svg xmlns="http://www.w3.org/2000/svg"
     width="300" height="100" viewBox="0 0 300 100">

  <path id="MyPath" stroke="lightblue" fill="none"
	d="M 50,50 C 100,0 200,100 250,50"/>

  <text style="font: 24px sans-serif;">
    <textPath href="#MyPath">Text on a path.</textPath>
  </text>

</svg>

Screenshot 2020-09-21 at 10 49 52 PM

reference: https://www.w3.org/TR/SVG/text.html

more examples:
http://thenewcode.com/482/Placing-Text-on-a-Circle-with-SVG
https://css-tricks.com/snippets/svg/curved-text-along-path/
https://codepen.io/rdfriedl/pen/rOegaP

Thanks a lot for hints!

Any subDrawing instances ?

Hello,

I like your library, although I can't find any complete doc about it.

I don't manage to create multiple drawing elements and then combine them. Would there be a way to do that properly ?
For example :

# A map element
d = draw.subDrawing(2, 2, origin='center', id='map')
d.append(draw.Circle(position_relative_to_map[0],position_relative_to_map[1], 0.03,
                fill=pick_fill_col, stroke_width=0.008, stroke=pick_strok_col))

# An information element
panel = draw.subDrawing(2, 2, origin='center', id='data_panel')
panel.append(draw.Text(data_text, position_in_data[0], position_in_data[1], fill=target_text_color, text_anchor='start'))

# Final combination of booth
final = draw.Drawing(4,2, origin='center')
final.append(d, (3, 1)) #Inserting subDrawing at determinated position
final.append(panel, (1, 1))

A hacky way would be to append everything directly to the final drawing with a offset that depends on the 'subDrawing'. It is unpleasant tho.

Thank you in advance for your help
Best,
T.

examples of changing font?

Hi,
I am having a great time using your library to make graphics that I would like to print. but I am hitting a roadblock

It is unclear to me how I would change fonts using this library. is there even a way to add or import fonts? not sure if this is just a noob question but some examples or reference to some documentation would be nice.

Trigger timed event in DrawWidget

Is there a way to trigger an event every t seconds in widget? I find there's a feature called widget.timed. Could you please give an example to show how to use that?

Filters with children like feMerge

I'm using a variety of effects that require merging filter nodes in an feMerge. FilterItem currently prevents this because it has hasContent set to false. Setting this to true seems to allow filter nodes to be nested, and doesn't seem to have any other detrimental effects. Is there a reason this was set to false to begin with?

Class attribute unsupported?

Hi, I want to generate SVG for injection and am trying to attach classes to svg tags for later dynamic styling with CSS.

Using class keyword doesn't work, since it's a python keyword. Tried using class_=, but this leads to "class-=: in generated SVGs.

Is there an official API solution for this?

resize page to drawing feature?

Is it possible to add a feature that shrinks the canvas so that it's just big enough to hold the objects in it?

I was thinking of a workflow of something like this:

d = draw.Drawing(200, 100, origin='center', displayInline=False)
d.append(some stuff)
d.append(some more stuff)
d.shrink_to_fit()
svg_data = d.to_svg()

The ability to initialize the drawing's width and height to None and have the canvas size be autocalculated on output would be cool:
d = draw.Drawing(None, None, origin='center', displayInline=False)

RuntimeWarning: Failed to import CairoSVG

I've followed the instructions and installed Cairo with brew install cairo. I've also tried other ways, through pip install etc. to try and get rid of this error, but can't. This is the error I get when simply running a file with import drawSvg:

RuntimeWarning: Failed to import CairoSVG. drawSvg will be unable to output PNG or other raster image formats. See https://github.com/cduck/drawSvg#prerequisites for more details.
Original OSError: no library called "cairo-2" was found
no library called "cairo" was found
no library called "libcairo-2" was found
cannot load library 'libcairo.so.2': dlopen(libcairo.so.2, 0x0002): tried: 'libcairo.so.2' (no such file), '/usr/local/lib/libcairo.so.2' (no such file), '/usr/lib/libcairo.so.2' (no such file), '/Users/andrew/Code/ai/ai4/libcairo.so.2' (no such file), '/usr/local/lib/libcairo.so.2' (no such file), '/usr/lib/libcairo.so.2' (no such file)
cannot load library 'libcairo.2.dylib': dlopen(libcairo.2.dylib, 0x0002): tried: 'libcairo.2.dylib' (no such file), '/usr/local/lib/libcairo.2.dylib' (no such file), '/usr/lib/libcairo.2.dylib' (no such file), '/Users/andrew/Code/ai/ai4/libcairo.2.dylib' (no such file), '/usr/local/lib/libcairo.2.dylib' (no such file), '/usr/lib/libcairo.2.dylib' (no such file)
cannot load library 'libcairo-2.dll': dlopen(libcairo-2.dll, 0x0002): tried: 'libcairo-2.dll' (no such file), '/usr/local/lib/libcairo-2.dll' (no such file), '/usr/lib/libcairo-2.dll' (no such file), '/Users/andrew/Code/ai/ai4/libcairo-2.dll' (no such file), '/usr/local/lib/libcairo-2.dll' (no such file), '/usr/lib/libcairo-2.dll' (no such file)
  warnings.warn(msg, RuntimeWarning)

Editing position of drawing elements

Hi, is it possible to modify the member variables for the position of a DrawingBasicElement (such as Rectangle) to move the element instead of having to re-create the element?

For example:
d = draw.Drawing(640, 480)
d.append(draw.Rectangle(0, 0, 50, 100, fill='#fff'))

and then move the origin of the Rectangle to (50, 75), equivalent to deleting the element and re-drawing
d.append(draw.Rectangle(50, 75, 50, 100, fill='#fff'))

How to embed a base64 encoded image?

I'm trying to insert a background image (from an existing svg file).

The element itself is something like this (saved as the variable content)
<g id="surface1"> <use xlink:href="#image5" transform="matrix(0.24,0,0,0.24,0,0)"/> </g>

The definition is something like this (saved as the variable blob)

<image id="image5" width="5334" height="4267" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAFNYAABCrC .... </>

I attempted to create the element like this

rawElement = draw.Raw(content=content, defs=('image5', blob))

But I'm getting a

TypeError: No tag with id="image5" found.

Any tips on how to make it work?

make it possible to print the svg

It is possible to do saveSvg(). It would be great, if one could do printSvg() as well, so one has the option to append the svg to some already existing svg file.

reversed Y coordinate interacts badly with translate

drawSvg, as mentioned in #11, reverses the direction of the Y coordinate so that increasing values are upwards (like Cartesian coordinates), rather than downwards (like screen position.)

Unfortunately, this means that translate() operations have to explicitly take this into account. Here's an example:

import drawSvg as draw

d = draw.Drawing( 200, 200, (0,0) )
d.append( draw.Circle( 100, 100, 50, fill="none", stroke="black" ) )
g = draw.Group( transform="translate(100,100)" )
g.append( draw.Circle( 0, 0, 40, fill="none", stroke="black" ) )
d.append( g )
d.saveSvg( "example-transform.svg" )

If everything was using the same coordinate system, this should result in two concentric circles, but instead the output is:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
     width="200" height="200" viewBox="0 -200 200 200">
<defs>
</defs>
<circle cx="100" cy="-100" r="50" fill="none" stroke="black" />
<g transform="translate(100,100)">
<circle cx="0" cy="0" r="40" fill="none" stroke="black" />
</g>
</svg>

example-transform

Is there a preferred way of specifying translations and other transforms? I didn't find one in the code or examples.

Could the library parse transform attributes and rewrite them to the preferred coordinate system?

Failing that, the documentation should be more clear about the flipped coordinate system and what will and won't work.

On the style tag

As far as I understand, there is no style tag implemented (as mentioned in some other issue). However, is there a way to print a line that is dashed? This is usually done in the style tag, but maybe there is some way to implement some sort of custom view.

Ellipse and elliptical arc

How can I draw ellipse or elliptical arc?
Is it possible to fill complex figure (composed by multiple elements like Lines and ArcLines)?
I want for example to fill a figure composed by 4 elleptical arcs.

SVG's initial coordinate system

Hello,
Is it possible to setup SVG viewport to SVG's initial coordinate system? Where 0;0 is the top-left corner. Now I can see, that by default 0;0 is the bottom-left corner.
Thank you

Writing text vertically

Hi, I am trying to write text vertically.

Using rotate=90 as a parameter in the Text(as per the example below), turns every letter 90 degrees, but not the whole text.

d.append(draw.Text(text,textSize,label[0],label[1],rotate=90, fill='red'))

Including more than a single raw svg doesn't work

Hi all,

I discovered a following problem which can be reproduced as follows.

import drawSvg as draw
d = draw.Drawing(100, 100, origin='center')
# load external SVGs
raw_latex_1 = ''
raw_latex_2 = ''
with open('latex_1.svg', 'r') as file:
    raw_svg = file.read()
    raw_latex_1 = raw_svg.replace('<?xml version=\'1.0\'?>', '')
with open('latex_2.svg', 'r') as file:
    raw_svg = file.read()
    raw_latex_2 = raw_svg.replace('<?xml version=\'1.0\'?>', '')
# display one on top of another
raw_rendered_svg_1 = draw.Raw(raw_latex_1)
raw_rendered_svg_2 = draw.Raw(raw_latex_2)
d.append(raw_rendered_svg_1)
d.append(raw_rendered_svg_2)
# create a file that can be included in this issue
d.setPixelScale(4)
d.savePng('case1.png')

it is rather hard to say but output seems ok

case1

now let us translate second SVG so that they are not on top of each other

import drawSvg as draw
d = draw.Drawing(100, 100, origin='center')
# load external SVGs
raw_latex_1 = ''
raw_latex_2 = ''
with open('latex_1.svg', 'r') as file:
    raw_svg = file.read()
    raw_latex_1 = raw_svg.replace('<?xml version=\'1.0\'?>', '')
with open('latex_2.svg', 'r') as file:
    raw_svg = file.read()
    raw_latex_2 = raw_svg.replace('<?xml version=\'1.0\'?>', '')
# display one on top of another
raw_rendered_svg_1 = draw.Raw(raw_latex_1)
raw_rendered_svg_2 = draw.Raw(raw_latex_2, transform="translate(10,20)")
d.append(raw_rendered_svg_1)
d.append(raw_rendered_svg_2)
# create a file that can be included in this issue
d.setPixelScale(4)
d.savePng('case2.png')

the second SVG gets messed up!

case2

let's see what happens when we still perform the translation but lets do not include first SVG

import drawSvg as draw
d = draw.Drawing(100, 100, origin='center')
# load external SVGs
raw_latex_1 = ''
raw_latex_2 = ''
with open('latex_1.svg', 'r') as file:
    raw_svg = file.read()
    raw_latex_1 = raw_svg.replace('<?xml version=\'1.0\'?>', '')
with open('latex_2.svg', 'r') as file:
    raw_svg = file.read()
    raw_latex_2 = raw_svg.replace('<?xml version=\'1.0\'?>', '')
# display one on top of another
raw_rendered_svg_1 = draw.Raw(raw_latex_1)
raw_rendered_svg_2 = draw.Raw(raw_latex_2, transform="translate(10,20)")
# d.append(raw_rendered_svg_1)
d.append(raw_rendered_svg_2)
# create a file that can be included in this issue
d.setPixelScale(4)
d.savePng('case3.png')

now the second SVG is perfectly fine even after performing the translation

case3

I noticed the larger the translation the more messed up figure gets but it only occurs if multiple raw SVGs are added and the first one appended to the Drawing is always perfectly fine.

Here are the included SVGs (I purposely changed the extension from to .txt because otherwise GitHub won't let me include them, .svg is not a supported attachment extension).

latex_1.txt
latex_2.txt

Those svg files are generated using https://github.com/tuxu/latex2svg

Visualize/Draw google's quickdraw data

I wanted to try and use Google Quick Draw's stroke data to draw and visualize the drawing like the do on their preview page but could not get to use their stroke data since I think DrawSVG and QD uses slightly different format.

QuickDraw - https://github.com/googlecreativelab/quickdraw-dataset
Preview - https://quickdraw.withgoogle.com/data

Quick Draw provides strokes data for their drawing like this

Example strokes for a drawing
[[[251,255,242,232,237,249],[0,153,153,166,170,160]],[[253,253,248,236,232],[154,164,172,174,167]],[[2,9,32,45,59,69,66],[2,32,88,102,107,103,94]],[[0,6,11,31,58,79,86,86,69],[3,19,73,111,128,128,122,106,91]]]

From their page:

The format of the drawing array is as following:

[ 
  [  // First stroke 
    [x0, x1, x2, x3, ...],
    [y0, y1, y2, y3, ...],
    [t0, t1, t2, t3, ...]
  ],
  [  // Second stroke
    [x0, x1, x2, x3, ...],
    [y0, y1, y2, y3, ...],
    [t0, t1, t2, t3, ...]
  ],
  ... // Additional strokes
]
Where x and y are the pixel coordinates, and t is the time in milliseconds since the first point. x and y are real-valued while t is an integer. The raw drawings can have vastly different bounding boxes and number of points due to the different devices used for display and input.

Would appreciate if you could help or point me in right direction to make use of DrawSVG to for QD

Interactive widgets not compatible with JupyterLab

This error appears when attempting to execute the "Interactive Widget" example found in the repository-level README.md. I ran the code within a code cell in the latest version of JupyterLab and the output was:

Error displaying widget

The following image shows what is outputted to the JavaScript console after executing the example:
console

Width and Height from Group

Thank you for drawSVG, I use it a lot!

Is there a way to get the dimensions from a draw.Group?

I like to place different groups on the canvas in a specific orientation. After creating each group in its one zero-point, I want to transform/translate them to a specific position on the canvas. Without the width and height, this is difficult.

DrawingDef usage

# Subclass DrawingDef if it must go between <def></def> tags in an SVG

Hi, can you please provide an example of using this? I'd like to define a few elements so that the final result looks like this:

  <defs>
    <!-- everything starts with a single bond -->
    <line id="bond" x1="0" y1="0" x2="60" y2="0" />
  </defs>

I can see that DrawingDef inherits from DrawingParentElement, and then... I'm lost.

Interactive widgets not working anymore in recent Jupyter notebook

As commented already in #78, I observe an issue similar to #17, but here in a standard Jupyter notebook. The javascript error message also looks different.

While it was working perfectly a few months ago, I am now unable to use the drawingWidget in Jupyter. I guess that this is related to the update of python and/or Jupyter.
I now get the following error message:

Failed to create view for 'DrawingView' from module 'drawingview' with model 'DOMWidgetModel' from module '@jupyter-widgets/base'
TypeError: Class constructor O cannot be invoked without 'new'

I just confirmed the problem in a clean virtualenv following the recipe below and running the interactive widget demo.

virtualenv -p python3 debug-venv
source debug-venv/bin/activate
pip install drawSvg hyperbolic jupyter
pip freeze >packages.txt
jupyter notebook

I am running Python 3.10.8 on Fedora Linux 36. The issue appears both with the chrome-based Vivaldi browser 5.5.2805.44
and in Firefox 106.0.4 . The packages list is there: packages.txt

Thanks for your help!

textwidth

i want to be able to calculate the end coordinate of a given text element.

for example:

e = draw.Text('Hyperlink',0.2, 0,0, center=0.6, fill='black')
x1,y1,x2,y2 = e.bbox() # x1,y1 = upper left corner x2,y2 = lower right corner

or something.

usecase:
put two text elements after eachother

gradient stop animation

am i missing something or is these as it stands no way to add an animation to a gradient stop?

Parse and show a certain SVG file with correct color fillings

tiger
Is that possible that I can parse this tiger SVG file and draw exactly the same as the input?
I found I couldn't fill the closed paths with color correctly, as DrawSVG seems to treat them as segments and does not detect the closed curves automatically. In the end, I will get an output like this.
image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.