Search code examples
pythonpandasdataframeplotlybubble-chart

How to place bubble charts in an image using Plotly?


enter image description here

Hello, I want to place these bubble charts on the item shown in the image. The first question is that how can I place them on the items? The second is how can I show all bubbles in the same place by time. Because when the time changes the bubbles have different values and I want to show them at the same point. The size of bubbles is enough to show values. Can anyone help me through this? Thanks in advance.

data= {'device': {0: 'Laptop', 1: 'Laptop', 2: 'Laptop', 3: 'Laptop', 4: 'Laptop'},
 'power': {0: 20, 1: 23, 2: 20, 3: 22, 4: 19},
 'time': {0: '16/11/2012 11:29',
  1: '16/11/2012 11:30',
  2: '16/11/2012 11:31',
  3: '16/11/2012 11:32',
  4: '16/11/2012 11:33'}}

img=enter image description here

# Create figure
fig = go.Figure()

fig = px.scatter(dt_lap, x="power", y="time",
             size="power", color="device",animation_frame="time",animation_group="device",
                   height=600,
    width=800, hover_name="time", log_x=True)

                

# Add images
fig.add_layout_image(
        dict(
            source=img,
            xref="paper",
            yref="paper",
            x=0,
            y=1,
            sizex=1,
            sizey=1,
          
            sizing="contain",
            opacity=1,
            layer="below")
)

# update layout properties
fig.update_layout(
    autosize=False,
    height=600,
    width=800,
    )

# Set templates
fig.update_layout(template="plotly_white")

fig.show()

Solution

  • As far as I can tell, your current x and y-axes aren't needed. The size of the bubble indicates the amount of power, and the animation frames show how the power changes over time.

    Instead you can effectively make the x and y-axes paper coordinates by setting their ranges to [0,1], then create new columns "x" and "y" to hold the coordinate values of the different objects in the background image, and use these column names when creating your scatter: px.scatter(dt_lap, x="x", y="y", ...) so that the bubbles appear on the desired objects.

    Here is an example:

    import numpy as np
    import pandas as pd
    
    from PIL import Image
    
    import plotly.express as px
    import plotly.graph_objects as go
    
    ## create some sample data
    np.random.seed(42)
    dt_lap = pd.DataFrame({
        "time": list(pd.date_range(start='16/11/2012 11:20', periods=30, freq="1min"))*3,
        "power": np.random.randint(low=0, high=50, size=90),
        "device": ["Laptop"]*30+["Fridge"]*30+["Kettle"]*30
    })
    dt_lap["time_string"] = dt_lap["time"].astype(str)
    
    ## coordinate mapping:
    device_coordinate_map = {
        'Laptop': [0.18, 0.8],
        'Fridge': [0.67, 0.5],
        'Kettle': [0.88, 0.40]
    }
    
    dt_lap['x'], dt_lap['y'] = zip(*list(dt_lap['device'].map(device_coordinate_map).values))
    
    ## load image
    img = Image.open('room_img.png')
    
    # Create figure
    fig = px.scatter(dt_lap, x="x", y="y",
                 size="power", color="device",animation_frame="time_string",animation_group="device",
                       height=600,
        width=800, hover_name="time")         
    
    # Add images
    fig.add_layout_image(
        dict(
            source=img,
            xref="paper",
            yref="paper",
            x=0,
            y=1,
            sizex=1,
            sizey=1,
            sizing="contain",
            layer="below"
        )
    )
    
    # Set templates
    fig.update_layout(
        template="plotly_white", 
        xaxis=dict(range=[0,1], showgrid=False),
        yaxis=dict(range=[0,1], showgrid=False)
    )
    
    fig.show()
    

    enter image description here