3

As I am working on an interactive interface with dash, I am using plotly for my figures. However, I have limited experience with the package - I commonly use matplotlib to make figures.

Anyhow, I want to create a figure using 3D data, where the third dimension is expressed by means of colour. With matplotlib, I would use pcolormesh (or pcolor). Unfortunately, I cannot find an equivalent function within plotly. I cannot use Contour or alike, as the z-data should follow specific (x,y)-coordinates.

Let me clarify with an example. For convenience, we can use the following dummy data:

import numpy as np

x, y = np.meshgrid(np.linspace(0, 10), np.linspace(0, 10))
y += 2 * np.sin(x * 2 * np.pi / 10)
z = np.exp(-x / 10)

What I want - and am able to produce using matplotlib - results from the following code (with the result after it):

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.pcolormesh(x, y, z)

enter image description here

However, with plotly, I do not get any further than using a colour-coded scatter-plot:

fig = go.Figure()
fig.add_trace(
    go.Scatter(x=x, y=y, marker=dict(color=z))
)

This would look something like the following: enter image description here

This is, however, not what I am aiming for. Enlarging the size of the markers to 'trick' the viewer would not suffice, as the actual data is slightly more complex with varying gaps between the (x,y)-coordinates.

Hopefully, anyone can help me out. Thanks a lot for your effort!

PS. I have seen this post with a similar question. However, its solution does not apply to me.

user15519982
  • 123
  • 5

1 Answers1

0

You can increase number of x-axis coordinates

import numpy as np
import plotly.graph_objects as go

x, y = np.meshgrid(np.linspace(0, 10, 200), np.linspace(0, 10))
y += 2 * np.sin(x * 2 * np.pi / 10)
z = np.exp(-x / 10)

go.Figure(go.Scatter(x=x.flatten(), y=y.flatten(), mode="markers", marker_color=z.flatten()))

enter image description here

experimental

not fully working, inspired from Matplotlib: save plot to numpy array

import numpy as np
import plotly.express as px
import io
import matplotlib.pyplot as plt


x, y = np.meshgrid(np.linspace(0, 10), np.linspace(0, 10))
y += 2 * np.sin(x * 2 * np.pi / 10)
z = np.exp(-x / 10)

# plt.axes("off")
fig, ax = plt.subplots()
# ax.axes.visible = False
ax = ax.pcolormesh(x, y, z)
with io.BytesIO() as buff:
    fig.savefig(buff, format='raw', pad_inches=0, bbox_inches=0)
    buff.seek(0)
    data = np.frombuffer(buff.getvalue(), dtype=np.uint8)
w, h = fig.canvas.get_width_height()
im = data.reshape((int(h), int(w), -1))

px.imshow(im)
Rob Raymond
  • 29,118
  • 3
  • 14
  • 30
  • Hi Rob, thanks for the suggestions. The first method I have implemented right now, but I am not happy about it (makes the plotting very slow) and was mentioned as "not suitable". The latter is not fully working you say, which part is causing troubles? – user15519982 Jan 19 '22 at 09:52
  • it's the matplotlib axes being included in the image. only invested some time in trying to get rid of them – Rob Raymond Jan 19 '22 at 11:03