plotly / plotly.py

The interactive graphing library for Python :sparkles: This project now includes Plotly Express!
https://plotly.com/python/
MIT License
15.62k stars 2.51k forks source link

imshow does not respect plot height, width in combination with binary_string = True #4631

Open secretaliasname opened 2 weeks ago

secretaliasname commented 2 weeks ago

I discovered what seems like a bug in imshow or at least very unexpected behavior. I cannot make height and width arguments work in combination with binary_string=True. Happy to try and help fix this if someone can point me on the right trail. Replication code below along with demonstration of expected behavior when binary_string=False.

Here the plot gets crushed. binary_string=True in combination with x and y arguments

image

import numpy as np
import plotly.express as px

x_extents = (0,5000)
y_extents = (10,50)
grid_shape = (400,200)

grid_data = np.random.random(grid_shape)
xs = np.linspace(x_extents[0], x_extents[1], grid_shape[0])
ys = np.linspace(y_extents[0], y_extents[1], grid_shape[1])

plt = px.imshow(
    grid_data.T,
    binary_string = True,
    origin = 'lower',
    x = xs,
    y = ys,
    aspect = 'auto',
    height = 500,
    width = 500,
)

plt.show()

binary_string=True in combination without x and y arguments. Image gets mis-scaled in a different incorrect way

image

import numpy as np
import plotly.express as px

x_extents = (0,5000)
y_extents = (10,50)
grid_shape = (400,200)

grid_data = np.random.random(grid_shape)
xs = np.linspace(x_extents[0], x_extents[1], grid_shape[0])
ys = np.linspace(y_extents[0], y_extents[1], grid_shape[1])

plt = px.imshow(
    grid_data.T,
    binary_string = True,
    origin = 'lower',
    # x = xs,
    # y = ys,
    aspect = 'auto',
    height = 500,
    width = 500,
)

plt.show()

This behaves as expected. Height and Width are respected. Binary_string=False, x and y present

image

import numpy as np
import plotly.express as px

x_extents = (0,5000)
y_extents = (10,50)
grid_shape = (400,200)

grid_data = np.random.random(grid_shape)
xs = np.linspace(x_extents[0], x_extents[1], grid_shape[0])
ys = np.linspace(y_extents[0], x_extents[1], grid_shape[1])

plt = px.imshow(
    grid_data.T,
    binary_string = False,
    origin = 'lower',
    x = xs,
    y = ys,
    aspect = 'auto',
    height = 500,
    width = 500,
)

plt.show()

This also behaves as expected. Height and Width are respected. Binary_string=False, x and y not provided

image

import numpy as np
import plotly.express as px

x_extents = (0,5000)
y_extents = (10,50)
grid_shape = (400,200)

grid_data = np.random.random(grid_shape)
xs = np.linspace(x_extents[0], x_extents[1], grid_shape[0])
ys = np.linspace(y_extents[0], y_extents[1], grid_shape[1])

plt = px.imshow(
    grid_data.T,
    binary_string = False,
    origin = 'lower',
    #x = xs,
    #y = ys,
    aspect = 'auto',
    height = 500,
    width = 500,
)

plt.show()
Coding-with-Adam commented 3 days ago

Hi @archmoj Here's the codepen in case it's helpful.

empet commented 3 days ago

help(px.imshow) reveals that:

 binary_string: bool, default None
        if True, the image data are first rescaled and encoded as uint8 and
        then passed to plotly.js as a b64 PNG string. 
        If False, data are passed
        unchanged as a numerical array. Setting to True may lead to performance
        gains, at the cost of a loss of precision depending on the original data
        type. If None, use_binary_string is set to True for multichannel (eg) RGB
        arrays, and to False for single-channel (2D) arrays. 2D arrays are
        represented as grayscale and with no colorbar if use_binary_string is
        True.

and


    x, y: list-like, optional
        x and y are used to label the axes of single-channel heatmap visualizations and
        their lengths must match the lengths of the second and first dimensions of the
        img argument. They are auto-populated if the input is an xarray.

Taking into account this information we are rewriting the initial code in a simpler way:

import numpy as np
import plotly.express as px
grid_shape = (200, 400)

grid_data = np.random.random(grid_shape)
xs = np.linspace(0, 400, 400)
ys = np.linspace(0, 200, 200)

plt = px.imshow(
    grid_data,
    binary_string = True,
    origin = 'lower',
    x = xs,
    y = ys,
    aspect = 'auto',
    height = 500,
    width = 500,
)

we get the rescaled image as stated in help test