How to plot a 2d Graph on the background (side wall) of a 3d Plot

Hi,

I have a sample 3d plot (shown in the following) and as you see the side walls (Backgrounds) are colored.

import plotly.graph_objects as go
import numpy as np

t = np.linspace(-1, 1.2, 500)
x = (t**3) + (0.3 * np.random.randn(500))
y = (t**6) + (0.3 * np.random.randn(500))
z=(t**2) + (0.3 * np.random.randn(500))

fig = go.Figure()

fig.add_scatter3d( x = x, y = y, z = z,
        mode = 'markers',
        marker = dict( color = 'rgba(0,0,0,0.3)', size = 3)
    )

fig.update_layout(
    autosize = False,
    xaxis = dict(
        zeroline = False,
        showgrid = False,
        showline=True, linecolor='black',
    ),
    yaxis = dict(
        zeroline = False,
        showgrid = False ),)

# xaxis.backgroundcolor is used to set background color
fig.update_layout(scene = dict(
                    xaxis = dict(
                         backgroundcolor="rgb(200, 200, 230)",
                         gridcolor="white",
                         showbackground=True,
                         zerolinecolor="white",),
                    yaxis = dict(
                        backgroundcolor="rgb(230, 200,230)",
                        gridcolor="white",
                        showbackground=True,
                        zerolinecolor="white"),
                    zaxis = dict(
                        backgroundcolor="rgb(230, 230,200)",
                        gridcolor="white",
                        showbackground=True,
                        zerolinecolor="white",),),
                    margin=dict(
                    r=10, l=10,
                    b=10, t=10),
                    height = 1000,
                    width = 1000,
                    showlegend = False
                                )

fig.show()

Let me know how can I plot a 2d plot (For example using scatter or bar or …) on one of the walls (For example on xz side wall?

Thanks in advance.

Hi @Bijan,

The term β€œwall” is quite relative, because the colored surface (i.e backgroundcolor) is basically the corresponding axis. So the axis range matters in this case. What you have to do is fix the β€œwall” i.e axis range and create a scatter3d at this coordinate.

an example:

x_position = 0
x=[x_position, x_position, x_position]
y=[1, 2, 3]
z=[1, 2, 3]

scatter = go.Scatter3d(
    x=x,
    y=y,
    z=z,
    name='2D but 3D'
)

fig.add_trace(scatter)
fig.update_layout({'scene': {'xaxis_range': [0, 3]}})
# ^^ set the axis range

Keep in mind, that the β€œwall” or backgroundcolor switches sides when rotating your 3D graph so you might add a surface trace instead of using backgroundcolor.

1 Like

Thanks @AIMPED for above quote.

Let me know how can I make my own plot (Scatter, Bar, Histogram or …) on axis background? To be clearer, in the following code from 3d surface plots in Python (plotly.com) as you see There is a plot on the axis, but it is a projection of surface on z-axis background.

import plotly.graph_objects as go

import pandas as pd

# Read data from a csv
z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')

fig = go.Figure(data=[go.Surface(z=z_data.values)])
fig.update_traces(contours_z=dict(show=True, usecolormap=True,
                                  highlightcolor="limegreen", project_z=True))
fig.update_layout(title='Mt Bruno Elevation', autosize=False,
                  scene_camera_eye=dict(x=1.87, y=0.88, z=-0.64),
                  width=500, height=500,
                  margin=dict(l=65, r=50, b=65, t=90)
)

fig.show()

Hi @Bijan

In this case they are using the contours parameter of go.Surface()

https://plotly.github.io/plotly.py-docs/generated/plotly.graph_objects.Surface.html

I assume, the contours to be calculated in the browser, that would explain the interactivity (plot changes depending on rotation of 3D).

I don’t think you can do something similar with other traces such as bar. Now that I think of it, β€œmy” approach from above works for scatter3D, right now I don’t know if it’s possible to plot a β€œ3D” bar chart

1 Like

Hi @Bijan,
To add a plot on the scene walls compute after x, y, z definition their min and max values:

t = np.linspace(-1, 1.2, 500)
x = (t**3) + (0.3 * np.random.randn(500))
y = (t**6) + (0.3 * np.random.randn(500))
z=(t**2) + (0.3 * np.random.randn(500))

xm, xM= x.min(), x.max()
ym, yM= y.min(), y.max()
zm, zM= z.min(), z.max()

Then if you want to plot the graph of the function z=sin(2*x) on the wall of equation y=ym
define:

xg=np.linspace(-np.pi/4, 2*np.pi/3, 50) #xm <=-pi/4 <2pi/3<=xM
zg=np.sin(2*xg)
yg=(ym+0.05)*np.ones(x.shape)# I added 0.05 to ym to make the graph visible. Plotting it exctly
                             # on the plane y=ym can make it a fuzzy graph

fig.add_traces(go.Scatter3d(x=xg, y=yg, z=zg, mode="lines", line_color="red", line_width=3))

plot-on-wall

Now if you want to plot a bar chart on the wall x=xm+0.05 you cannot instantiate go.Bar, because it works only in 2d, not in 3d.
To get the bars you should triangulate them and plot as a mesh3d, as it is explaine here:
https://community.plotly.com/t/adding-a-shape-to-a-3d-plot/1441

1 Like

Dear @empet thanks for your contribution on this post.

On above discussion on this post in (How to plot a 2d Graph on the background (side wall) of a 3d Plot - #3 by Bijan), I wanted to know is there any way to plot on the axis background like wat can we do with surfaces that using project_z we can draw on axis backgrounds. In this way by rotating the plot, the axis plot will be transfer with background exactly like surface plots!.

Thanks in advance.

No, only surfaces allow projections onto the walls. For any other plot you should work as I explained above.

1 Like

Dear @adamschroeder Hi

In this post I have requested some feature that according to two Plotly professions (AIMPED and empet ) explanations, seems the requested feature is not available on Plotly. I think this feature will be helpful to show some data analysis more efficient. Let me know if it is proper issue, I add it as a new issue on Plotly GitHub.

Thanks

@Bijan I was a bit confused, wondering why I answered an un-asked question, but now I re-read your post, and saw that you specified β€œLet me know how can I plot a 2d plot (For example using scatter or bar or …) on one of the walls (For example on xz side wall?” :slight_smile:

1 Like

@empet, you like always suggested great solution for my problems, and what you said was a great was also a great solution like what suggested on second response by AIMPED on the current page BUT my problem arose when I rotate the figure and background color moved but what I plotted on the wall remained with white background (case that is show in the following image) and it was not compatible with what I needed to present.

empet quote: wondering why I answered an un-asked question!

I think because of my weak English language I explained my request in bad form and sorry for that. :see_no_evil: :sweat_smile:

Again thanks for your always great helps :muscle: :rose:

@Bijan No problem, however when there was an intense activity here, 2-3 years ago, I happened to read a lot of questions, and then start answering, but not to the question asked, but to another one in another thread.

@Bijan The same is holding for surface projections, as @AIMPED pointed out from the beginning:

projections

1 Like

Hi @Bijan,

I mixed up your (modified) initial code, @empet’s curve and my surface :rofl:

import plotly.graph_objects as go
import numpy as np

# Bijan's base code
t = np.linspace(-1, 1.2, 500)
x = (t ** 3) + (0.3 * np.random.randn(500))
y = (t ** 6) + (0.3 * np.random.randn(500))
z = (t ** 2) + (0.3 * np.random.randn(500))

fig = go.Figure()
fig.add_scatter3d(
    x=x,
    y=y,
    z=z,
    mode='markers',
    marker=dict(color='rgba(0,0,0,0.3)', size=3)
)

fig.update_layout(
    autosize=False,
    xaxis=dict(
        zeroline=False,
        showgrid=False,
        showline=True,
        linecolor='black',
    ),
    yaxis=dict(
        zeroline=False,
        showgrid=False
    )
)

# xaxis.backgroundcolor is used to set background color
fig.update_layout(
    scene=dict(
        xaxis=dict(
            backgroundcolor="rgb(200, 200, 230)",
            gridcolor="white",
            showbackground=True,
            zerolinecolor="white"
        ),
        yaxis=dict(
            backgroundcolor="rgb(230, 200,230)",
            gridcolor="white",
            showbackground=False,
            # ^^ do not plot the background
            zerolinecolor="white"
        ),
        zaxis=dict(
            backgroundcolor="rgb(230, 230,200)",
            gridcolor="white",
            showbackground=True,
            zerolinecolor="white"
        )
    ),
    margin=dict(
        r=10, l=10,
        b=10, t=10
    ),
    height=400,
    width=400,
    showlegend=False
)

# empet's curve
xm, xM = x.min(), x.max()
ym, yM = y.min(), y.max()
zm, zM = z.min(), z.max()

xg=np.linspace(-np.pi/4, 2*np.pi/3, 50) #xm <=-pi/4 <2pi/3<=xM
zg=np.sin(2*xg)
yg=(ym+0.05)*np.ones(x.shape)# I added 0.05 to ym to make the graph visible. Plotting it exctly
                             # on the plane y=ym can make it a fuzzy graph

fig.add_traces(
    go.Scatter3d(
        x=xg,
        y=yg,
        z=zg,
        mode="lines",
        line_color="red",
        line_width=3
    )
)


# AIMPED's surface
y1 = np.ones(2) * (ym + 0.05)
x1 = np.linspace(xm, xM, 2)
z1 = np.linspace(zm, zM, 2)

fig.add_traces(
    go.Surface(
        x=x1,
        y=y1,
        z=np.array([z1] * y1.shape[0]).T,
        colorscale=[
            [0, 'rgb(230, 200,230)'], 
            [1, 'rgb(230, 200,230)']
        ],
        opacity=0.7,
        showscale=False
    )
)

creates:
newplot(47)

:laughing: :laughing: Well done @AIMPED :laughing: :laughing: