Search code examples
pythonplotly

Specifying marker size in data unit for plotly


I switched from matplotlib to plotly mainly to plot smooth animations in 2D/3D. I want to plot the motion of robots consisting of multiple circles/spheres.

The different body parts of the robot have different sizes and the circles need to represent that accurately. Is there a way in plotly to specify the size of the markers in data units? For example, I want to draw a 5m x 5m section in which circles with a radius of 0.1m are moving along different trajectories.

In matplotlib I know two alternatives. One is to use patches matplotlib.patches.Circle. The second option is to plot the points and scale their markersize correctly by taking the dpi into account (See the answers to this question for matplotlib).

Is there a way in poorly to specify the size of the markers in data units or scale the sizeref attribute correctly?

# Point with radius 2 (approx.)
from plotly.offline import plot
import plotly.graph_objs as go

trace = go.Scatter(x=[4], y=[4],
                   mode='markers',
                   marker={'size': 260, 'sizeref': 1})  # ???

layout = dict(yaxis=dict(range=[0, 10]),
              xaxis=dict(range=[0, 10]))

fig = dict(data=[trace], layout=layout)
plot(fig, image_height=1000, image_width=1000)

A problem with scaling the markersize is that the image is only correct as long as you don't zoom in or out, because the markersize stays constant. Therefore the cleaner approach would be to specify the size of the circles directly in data units.


Solution

  • Drawing circles is probably your best bet. Updating markersize with each resize would be a bit cumbersome. Here's something you could try for drawing circles

    from plotly.offline import plot
    import plotly.graph_objects as go
    
    xy = [[4, 4], [1, 5], [2, 2]]
    r = 0.1
    
    fig = go.Figure()
    kwargs = {'type': 'circle', 'xref': 'x', 'yref': 'y', 'fillcolor': 'black'}
    points = [go.layout.Shape(x0=x-r, y0=y-r, x1=x+r, y1=y+r, **kwargs) for x, y in xy]
    fig.update_layout(shapes=points)
    
    fig.update_xaxes(range=[0, 10])
    fig.update_yaxes(range=[0, 10])
    fig.update_layout(width=1000, height=1000)
    plot(fig)
    

    Default (1st) and zoomed (2nd) view: