I have a case where I have several 3D scatterplots side-by-side. All of them show the same data with different colorings and overlays. I would like to synchronize the cameras in the subplots so that they always show the same view. In other words, zooming/panning/rotating in one subplot will affect all of the 3D subplots. It appears that itās possible to do something similar for 2D plots via the āmatchesā axis attribute, but I am unsure about a 3D equivalent. Is this possible to do with the Python api?
Hi @zotgabe,
is this what you are aiming to do? ->:
- with ipywidgets :
import plotly.graph_objs as go
import pandas as pd
import ipywidgets as widgets
# Read data from a csv
z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')
data1 = [
go.Surface(
z=z_data.values
)
]
data2 = [
go.Surface(
z=z_data.values, colorscale='viridis'
)
]
layout1 = go.Layout(title=dict(text='Mt Bruno Elevation'))
layout2 = go.Layout(title=dict(text='Mt Bruno Elevation 2'))
fig1 = go.FigureWidget(data=data1, layout=layout1)
fig2 = go.FigureWidget(data=data2, layout=layout2)
def cam_change(layout, camera):
fig2.layout.scene.camera = camera
fig1.layout.scene.on_change(cam_change, 'camera')
display(widgets.HBox([fig1,fig2]))
- or with subplots:
import plotly.graph_objs as go
import pandas as pd
from plotly import tools
# Read data from a csv
z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')
trace1 = dict(type='surface', scene='scene1', z=z_data.values)
trace2 = dict(type='surface', scene='scene2', z=z_data.values, colorscale='viridis')
f= tools.make_subplots(rows=1, cols=2, specs=[[{'is_3d': True}, {'is_3d': True}]])
f.append_trace(trace1, 1, 1)
f.append_trace(trace2, 1, 2)
fig = go.FigureWidget(f)
def cam_change(layout, camera):
fig.layout.scene2.camera = camera
fig.layout.scene1.on_change(cam_change, 'camera')
fig
Thank you for the help! Your example does exactly what I was looking for. Iāve been using iplot exclusively and wasnāt familiar with the FigureWidget interface (still new to Plotly), it does seem very useful.
Unfortunately, my plot also uses animation frames, which seem to be not supported with FigureWidgets. From other forum posts, it sounds like thatās a planned feature, so I guess Iāll just have to wait for that to be implemented.
Edit: Actually it seems that I could probably accomplish what Iām looking for via FigureWidget updates, so I guess this is completely solved.
Hi there,
I just wrote a solution to get around this by using a bit of javascript
. This time it works by using only āgo.Figureā object and making the callback function via javascript and not the python backend.
import numpy as np
from IPython.core.display import display, HTML
from plotly.offline import plot
from plotly import tools
import plotly.graph_objs as go
# Read data from a csv
z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')
trace1 = go.Surface(scene='scene1', z=z_data.values, colorscale='Blues')
trace2 = go.Surface(scene='scene2', z=z_data.values, colorscale='Greens')
f= tools.make_subplots(rows=1, cols=2, specs=[[{'is_3d': True}, {'is_3d': True}]])
f.append_trace(trace1, 1, 1)
f.append_trace(trace2, 1, 2)
fig = go.Figure(f)
# get the a div
div = plot(fig, include_plotlyjs=False, output_type='div')
# retrieve the div id (you probably want to do something smarter here with beautifulsoup)
div_id = div.split('=')[1].split()[0].replace("'", "").replace('"', '')
# your custom JS code
js = '''
<script>
var gd = document.getElementById('{div_id}');
var isUnderRelayout = false
gd.on('plotly_relayout', () => {{
console.log('relayout', isUnderRelayout)
if (!isUnderRelayout) {{
Plotly.relayout(gd, 'scene2.camera', gd.layout.scene.camera)
.then(() => {{ isUnderRelayout = false }} )
}}
isUnderRelayout = true;
}})
</script>'''.format(div_id=div_id)
# merge everything
div = '<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>' + div + js
# show the plot
display(HTML(div))
You are awesome! That worked beautifully with my plot, animations and all. Thanks so much for the help!
Definitely glad I decided to try out Plotly, itās been perfect for my needs so far and this community seems great.
Can this be done with dash? I am trying to do it with no luck.
Hey Alexboiboi,
Nice work. Best solution I found so farā¦
BUT
Is there a possibility to even synchronize them both?
In this example only the second one is adapting.
And in the IPython widget, the second plot is jumping in an other position from time to timeā¦
Thanks in advance
Ben
Is it also possible to keep acquire this synchronization when the figure is saved as .html?
Awesome, that snippet still worked in the latest plotly
@pcicales from the futureā¦ did you end up having any luck synchronizing 3D subplots? Iām trying to find a solution using callbacks.
Thanks!
Matt
I have just put together a multiple page multiple tab multiple window synchronizing demo. Bit more complex than you might expect, but it works for me. The only think I have to do is refresh the window where I want to pick up the updated graph and click data. peteasa / pyquickly Ā· GitLab
Is it possible to rotate them all together, online, meaning as a user viewing the chart, using the rotation widgets present in the html chart?