plotly.js icon indicating copy to clipboard operation
plotly.js copied to clipboard

Shape drawing: Draw closed path by clicking

Open HTenkanen opened this issue 5 years ago • 7 comments

Relates to #4775 and #4374

Hi guys!

I have a following situation where I basically would like to draw bounding boxes around objects in images such as following: image

Currently, this can be done by using the 'drawclosedpath', but as you can see this seems to be working only with "freehand" style that does not produce very good results (at least on my shaky hands 🙂 ). What I would like to do is to have a possibility to draw closed polyline by clicking the image (corners) and finishing the shape for example by double clicking. Is this somehow possible currently? Other good option would be, if it would be possible to rotate the rectangle after it has been drawn. Now the direction of the shape is only allowed to two directions which is very limiting in many cases.

Any help or ideas how I could manage to do these things would be very welcomed! 🙂

@emmanuelle @archmoj

HTenkanen avatar Jun 18 '20 15:06 HTenkanen

Wondering if we may consider a feature request to remove undesirable vertices on double click instead.

archmoj avatar Jun 18 '20 16:06 archmoj

@HTenkanen polyline annotations were not added to the shape-drawing features because they do not correspond to a dragmode (instead it's a series of mouseDown event). Is your web app in Javascript only or are you using Dash?

emmanuelle avatar Jun 18 '20 16:06 emmanuelle

@archmoj Well yes that is another useful feature as well, but I think ideal situation e.g. in my case would be that I would be able to draw a shape only by adding four nodes/vertices. This is very commonly used approach in many softwares that support drawing shapes on top of images (e.g. several GIS softwares have this functionality). Take a look for example of this live example that allows you to draw an area by clicking points on the corners (done with MapboxGL): https://hel-pop.firebaseapp.com/

The problem with removing vertices after you have created a shape using free-hand style drawing, is that currently you might end up having tens (or even hundreds) of vertices, and I would want to have as few of them as possible. Hence, removing them one by one would cause a lot of extra work.

HTenkanen avatar Jun 18 '20 16:06 HTenkanen

@emmanuelle I am currently exploring my possibilities, and I have been starting to build the annotation tool with Dash. Would like to continue with Plotly/Dash (as I have some experience doing apps with it) but this might unfortunately be a deal breaker as I need to regularly do rectangles/bounding boxes that are not straight (i.e. I would need to be able to rotate them).

I would like to keep my tech-stack rather simple (for research purposes) which is why I'd rather stick with Python / Dash.

HTenkanen avatar Jun 18 '20 16:06 HTenkanen

If going to the React world (which I would like to avoid) then this tool has available something that I'd need, i.e. drawing Polygons of any shape that adds vertices by clicking: https://github.com/waoai/react-image-annotate

HTenkanen avatar Jun 18 '20 16:06 HTenkanen

@emmanuelle I understand that you don't want to start messing around with the "dragmode", but do you know if there would be any alternative approaches to draw polygons on top of images by adding vertices based on clicks?

HTenkanen avatar Jun 18 '20 16:06 HTenkanen

Hi, I would also be interested in such a functionality, although much time has passed, has any solution or workaround been found in the meantime? @HTenkanen @emmanuelle .I believe UDT ( Universal Data tool) has a similar polygon functionality , where the line is actually dragged. My reasoning is the same as @HTenkanen was, trying to stay with dash/python. Thanks and Best Regards

ronin2304 avatar Aug 07 '22 16:08 ronin2304

@HTenkanen @ronin2304 Here is a workaround this issue, that I find useful so far. First install :

pip3 install svgpath2mpl
pip3 install shapely
pip3 install beautifulsoup4

Then try this on a dash app, it will simplify all drawn polygons immediately in real-time using shapely simplify function : https://shapely.readthedocs.io/en/stable/manual.html#object.simplify

from svgpath2mpl import parse_path
from shapely.geometry import Polygon
from bs4 import BeautifulSoup

@app.callback(
    Output('some_graph_id', 'figure'),
    Input('some_graph_id', 'figure'),
)
def main_callback(figure_config):

    if 'shapes' in figure_config['layout']  : 
        for shape in figure_config['layout']['shapes']:
	    if shape['type'] == 'path' :
		shape['path'] = BeautifulSoup(Polygon(parse_path(shape['path']).to_polygons()[0]).simplify(30.0, preserve_topology=False).svg().replace('path','input'), 'html.parser').input['d'].replace(" ", "").upper()

    return figure_config

BOUKARY avatar Dec 24 '22 17:12 BOUKARY

you can play with the tolerance argument in the simplify function, 30.0 works fine for me

BOUKARY avatar Dec 24 '22 17:12 BOUKARY