-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
add Y-axis autoscaling with X-axis range change #6995
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I've also spent a lot of time looking into whether and how it's possible in Plotly to automatically update the y-axis after zooming in on only the x-axis. I'm actually really enthusiastic about Plotly, so I was very surprised to see how such a feature, which is present in virtually every serious plotting program, could be missing. After extensive research, I found out that there's simply no direct way to do this. Communication with the developers was generally always something like this:
All joking aside, I would like to express my greatest respect to the developers who make such a modern tool freely available. To the solution: We are definitely not the first users and we won't be the last to have dealt with this. The approach is based on the idea of supplementing the y-autoscale feature directly in JavaScript. There were some suggestions from
as well as useful links to documentation mentioned therein
Enclosed is a code suggestion that should at least make the idea clear: Code suggestionPrepare data for Plotlyimport numpy as np
from scipy.spatial.transform import Rotation
import scipy as sp
from scipy.signal import savgol_filter
import time
import crocoddyl
import pinocchio
import matplotlib.pyplot as plt
import meshcat.geometry as g
import meshcat.transformations as tf
import webbrowser
import os
from meshcat.animation import Animation
from pinocchio.visualize import MeshcatVisualizer
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.offline as py
from typing import overload
from bs4 import BeautifulSoup
def calc_7dof_data(us, xs, t, TCP_frame_id, robot_model, param_trajectory, frep_per_Ta_step):
robot_data = robot_model.createData()
N = len(xs)
n = robot_model.nq
p_e = np.zeros((N, 3))
p_e_p = np.zeros((N, 3))
p_e_pp = np.zeros((N, 3))
quat_e = np.zeros((N, 4))
omega_e = np.zeros((N, 3))
omega_e_p = np.zeros((N, 3))
p_d = param_trajectory['p_d']
p_d_p = param_trajectory['p_d_p']
p_d_pp = param_trajectory['p_d_pp']
quat_d = param_trajectory['q_d']
omega_d = param_trajectory['omega_d']
omega_d_p = param_trajectory['omega_d_p']
w = np.zeros(N) # manipulability
q = np.zeros((N, n))
q_p = np.zeros((N, n))
q_pp = np.zeros((N, n))
p_err = np.zeros((N, 3))
p_err_p = np.zeros((N, 3))
p_err_pp = np.zeros((N, 3))
e_x = np.zeros(N)
e_x_p = np.zeros(N)
e_x_pp = np.zeros(N)
e_y = np.zeros(N)
e_y_p = np.zeros(N)
e_y_pp = np.zeros(N)
e_z = np.zeros(N)
e_z_p = np.zeros(N)
e_z_pp = np.zeros(N)
quat_err = np.zeros((N, 4))
omega_err = np.zeros((N, 3))
omega_err_p = np.zeros((N, 3))
tau = np.zeros((N, n))
window_length = 301
poly_order = 2
frep_per_Ta_step_mean = smooth_signal_savgol(frep_per_Ta_step, window_length, poly_order)
for i in range(N):
q[i] = xs[i, 0:n]
q_p[i] = xs[i, n:2 * n]
tau[i] = us[i]
q_pp[i] = pinocchio.aba(robot_model, robot_data, q[i], q_p[i], tau[i])
pinocchio.forwardKinematics(robot_model, robot_data, q[i], q_p[i], q_pp[i])
pinocchio.updateFramePlacements(robot_model, robot_data)
pinocchio.computeJointJacobians(robot_model, robot_data, q[i])
J = pinocchio.getFrameJacobian(robot_model, robot_data, TCP_frame_id, pinocchio.ReferenceFrame.LOCAL_WORLD_ALIGNED)
pinocchio.computeJointJacobiansTimeVariation(robot_model, robot_data, q[i], q_p[i])
J_p = pinocchio.getFrameJacobianTimeVariation(robot_model, robot_data, TCP_frame_id, pinocchio.ReferenceFrame.LOCAL_WORLD_ALIGNED)
p_e[i] = robot_data.oMf[TCP_frame_id].translation.T.copy()
p_e_p[i] = J[0:3, :] @ q_p[i]
# p_e_pp[i] = J[0:3, :] @ q_pp[i] + J_p[0:3, :] @ q_p[i]
p_e_pp[i] = pinocchio.getFrameClassicalAcceleration(robot_model, robot_data, TCP_frame_id, pinocchio.ReferenceFrame.LOCAL_WORLD_ALIGNED).linear
quat_e_7val = pinocchio.SE3ToXYZQUAT(robot_data.oMf[TCP_frame_id])
quat_e_xyzw = pinocchio.Quaternion(quat_e_7val[3::])
quat_e[i] = np.hstack([quat_e_7val[6], quat_e_7val[3:6]]) #wxyz
omega_e[i] = pinocchio.getFrameVelocity(robot_model, robot_data, TCP_frame_id, pinocchio.ReferenceFrame.LOCAL_WORLD_ALIGNED).angular
omega_e_p[i] = pinocchio.getFrameAcceleration(robot_model, robot_data, TCP_frame_id, pinocchio.ReferenceFrame.LOCAL_WORLD_ALIGNED).angular
w[i] = np.sqrt(sp.linalg.det(J @ J.T))
p_err[i] = p_e[i] - p_d[:, i]
p_err_p[i] = p_e_p[i] - p_d_p[:, i]
p_err_pp[i] = p_e_pp[i] - p_d_pp[:, i]
e_x[i] = p_err[i][0]
e_y[i] = p_err[i][1]
e_z[i] = p_err[i][2]
e_x_p[i] = p_err_p[i][0]
e_y_p[i] = p_err_p[i][1]
e_z_p[i] = p_err_p[i][2]
e_x_pp[i] = p_err_pp[i][0]
e_y_pp[i] = p_err_pp[i][1]
e_z_pp[i] = p_err_pp[i][2]
quat_d_xyzw = pinocchio.Quaternion( np.hstack([quat_d[1:, i], quat_d[0, i]]) )
q_d_xyzw_inv = pinocchio.Quaternion.inverse(quat_d_xyzw)
quat_err_temp = quat_e_xyzw * q_d_xyzw_inv
quat_err[i] = np.array([quat_err_temp.w, quat_err_temp.x, quat_err_temp.y, quat_err_temp.z])
omega_err[i] = omega_e[i] - param_trajectory['omega_d'][:, i]
omega_err_p[i] = omega_e_p[i] - param_trajectory['omega_d_p'][:, i]
# make data shorter, use only each N_dec sample
N_dec = 100
t = t[::N_dec]
p_e = p_e[::N_dec]
p_e_p = p_e_p[::N_dec]
p_e_pp = p_e_pp[::N_dec]
quat_e = quat_e[::N_dec]
omega_e = omega_e[::N_dec]
omega_e_p = omega_e_p[::N_dec]
p_d = p_d[:, ::N_dec]
p_d_p = p_d_p[:, ::N_dec]
p_d_pp = p_d_pp[:, ::N_dec]
quat_d = quat_d[:, ::N_dec]
omega_d = omega_d[:, ::N_dec]
omega_d_p = omega_d_p[:, ::N_dec]
p_err = p_err[::N_dec]
p_err_p = p_err_p[::N_dec]
p_err_pp = p_err_pp[::N_dec]
e_x = e_x[::N_dec]
e_y = e_y[::N_dec]
e_z = e_z[::N_dec]
e_x_p = e_x_p[::N_dec]
e_y_p = e_y_p[::N_dec]
e_z_p = e_z_p[::N_dec]
e_x_pp = e_x_pp[::N_dec]
e_y_pp = e_y_pp[::N_dec]
e_z_pp = e_z_pp[::N_dec]
quat_err = quat_err[::N_dec]
omega_err = omega_err[::N_dec]
omega_err_p = omega_err_p[::N_dec]
w = w[::N_dec]
q = q[::N_dec]
q_p = q_p[::N_dec]
q_pp = q_pp[::N_dec]
tau = tau[::N_dec]
# create subplot data array
subplot1 = {'title': 'p_e (m) (Y: x, B: y, P: z)',
'sig_labels': ['p_e_x (m)', 'p_e_y (m)', 'p_e_z (m)', 'p_d_x (m)', 'p_d_y (m)', 'p_d_z (m)'],
'sig_xdata': t,
'sig_ydata': [p_e[:, 0], p_e[:, 1], p_e[:, 2], p_d[0], p_d[1], p_d[2]],
'sig_linestyles': ['-', '-', '-', '--', '--', '--'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,153,200)', 'rgb(0,0,255)', 'rgb(255,0,0)', 'rgb(0,127,0)']}
subplot2 = {'title': 'ṗ_e (m/s) (Y: x, B: y, P: z)',
'sig_labels': ['ṗ_e_x (m/s)', 'ṗ_e_y (m/s)', 'ṗ_e_z (m/s)', 'ṗ_d_x (m/s)', 'ṗ_d_y (m/s)', 'ṗ_d_z (m/s)'],
'sig_xdata': t,
'sig_ydata': [p_e_p[:, 0], p_e_p[:, 1], p_e_p[:, 2], p_d_p[0], p_d_p[1], p_d_p[2],
],
'sig_linestyles': ['-', '-', '-', '--', '--', '--'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,153,200)', 'rgb(0,0,255)', 'rgb(255,0,0)', 'rgb(0,127,0)']}
subplot3 = {'title': 'p̈_e (m/s²) (Y: x, B: y, P: z)',
'sig_labels': ['p̈_e_x (m/s²)', 'p̈_e_y (m/s²)', 'p̈_e_z (m/s²)', 'p̈_d_x (m/s²)', 'p̈_d_y (m/s²)', 'p̈_d_z (m/s²)'],
'sig_xdata': t,
'sig_ydata': [p_e_pp[:, 0], p_e_pp[:, 1], p_e_pp[:, 2], p_d_pp[0], p_d_pp[1], p_d_pp[2]],
'sig_linestyles': ['-', '-', '-', '--', '--', '--'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,153,200)', 'rgb(0,0,255)', 'rgb(255,0,0)', 'rgb(0,127,0)']}
# manipulate subplot data array
subplot4 = {'title': 'Manip. w = √( det( JJ⸆ ) )',
'sig_labels': ['Manip. w = √( det( JJ⸆ ) )'],
'sig_xdata': t,
'sig_ydata': [w],
'sig_linestyles': ['-'],
'sig_colors': ['rgb(255,255,17)']}
subplot5 = {'title': 'e_x (m)',
'sig_labels': ['e_x (m)'],
'sig_xdata': t,
'sig_ydata': [e_x],
'sig_linestyles': ['-'],
'sig_colors': ['rgb(255,255,17)']}
subplot6 = {'title': 'ė_x (m/s)',
'sig_labels': ['ė_x (m/s)'],
'sig_xdata': t,
'sig_ydata': [e_x_p],
'sig_linestyles': ['-'],
'sig_colors': ['rgb(255,255,17)']}
subplot7 = {'title': 'ё_x (m/s²)',
'sig_labels': ['ё_x (m/s²)'],
'sig_xdata': t,
'sig_ydata': [e_x_pp],
'sig_linestyles': ['-'],
'sig_colors': ['rgb(255,255,17)']}
subplot8 = {'title': 'q (rad)',
'sig_labels': ['q1', 'q2', 'q3', 'q4', 'q5', 'q6'],
'sig_xdata': t,
'sig_ydata': [q[:, 0], q[:, 1], q[:, 2], q[:, 3], q[:, 4], q[:, 5]],
'sig_linestyles': ['-', '-', '-', '-', '-', '-'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,105,41)', 'rgb(100,212,19)', 'rgb(183,70,255)', 'rgb(15,255,255)']}
subplot9 = {'title': 'e_y (m)',
'sig_labels': ['e_y (m)'],
'sig_xdata': t,
'sig_ydata': [e_y],
'sig_linestyles': ['-'],
'sig_colors': ['rgb(19,159,255)']}
subplot10 = {'title': 'ė_y (m/s)',
'sig_labels': ['ė_y (m/s)'],
'sig_xdata': t,
'sig_ydata': [e_y_p],
'sig_linestyles': ['-'],
'sig_colors': ['rgb(19,159,255)']}
subplot11 = {'title': 'ё_y (m/s²)',
'sig_labels': ['ё_y (m/s²)'],
'sig_xdata': t,
'sig_ydata': [e_y_pp],
'sig_linestyles': ['-'],
'sig_colors': ['rgb(19,159,255)']}
subplot12 = {'title': 'q̇ (rad/s)',
'sig_labels': ['q̇_1', 'q̇_2', 'q̇_3', 'q̇_4', 'q̇_5', 'q̇_6'],
'sig_xdata': t,
'sig_ydata': [q_p[:, 0], q_p[:, 1], q_p[:, 2], q_p[:, 3], q_p[:, 4], q_p[:, 5]],
'sig_linestyles': ['-', '-', '-', '-', '-', '-'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,105,41)', 'rgb(100,212,19)', 'rgb(183,70,255)', 'rgb(15,255,255)']}
subplot13 = {'title': 'e_z (m)',
'sig_labels': ['e_z (m)'],
'sig_xdata': t,
'sig_ydata': [e_z],
'sig_linestyles': ['-'],
'sig_colors': ['rgb(255,153,200)']}
subplot14 = {'title': 'ė_z (m/s)',
'sig_labels': ['ė_z (m/s)'],
'sig_xdata': t,
'sig_ydata': [e_z_p],
'sig_linestyles': ['-'],
'sig_colors': ['rgb(255,153,200)']}
subplot15 = {'title': 'ё_z (m/s²)',
'sig_labels': ['ё_z (m/s²)'],
'sig_xdata': t,
'sig_ydata': [e_z_pp],
'sig_linestyles': ['-'],
'sig_colors': ['rgb(255,153,200)']}
subplot16 = {'title': 'q̈ (rad/s²)',
'sig_labels': ['q̈_1', 'q̈_2', 'q̈_3', 'q̈_4', 'q̈_5', 'q̈_6'],
'sig_xdata': t,
'sig_ydata': [q_pp[:, 0], q_pp[:, 1], q_pp[:, 2], q_pp[:, 3], q_pp[:, 4], q_pp[:, 5]],
'sig_linestyles': ['-', '-', '-', '-', '-', '-'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,105,41)', 'rgb(100,212,19)', 'rgb(183,70,255)', 'rgb(15,255,255)']}
subplot17 = {'title': 'quat_e(2:4)',
'sig_labels': ['quat_e_2', 'quat_e_3', 'quat_e_4', 'quat_d_2', 'quat_d_3', 'quat_d_4'],
'sig_xdata': t,
'sig_ydata': [quat_e[:, 1], quat_e[:, 2], quat_e[:, 3], quat_d[1], quat_d[2], quat_d[3]],
'sig_linestyles': ['-', '-', '-', '--', '--', '--'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,105,41)', 'rgb(0,0,255)', 'rgb(255,0,0)', 'rgb(0,127,0)']}
subplot18 = {'title': 'ω_e (rad/s)',
'sig_labels': ['ω_e_x (rad/s)', 'ω_e_y (rad/s)', 'ω_e_z (rad/s)', 'ω_d_x (rad/s)', 'ω_d_y (rad/s)', 'ω_d_z (rad/s)'],
'sig_xdata': t,
'sig_ydata': [omega_e[:, 0], omega_e[:, 1], omega_e[:, 2], omega_d[0], omega_d[1], omega_d[2]],
'sig_linestyles': ['-', '-', '-', '--', '--', '--'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,105,41)', 'rgb(0,0,255)', 'rgb(255,0,0)', 'rgb(0,127,0)']}
subplot19 = {'title': 'ὠ_e (rad/s²)',
'sig_labels': ['ὠ_e_x (rad/s²)', 'ὠ_e_y (rad/s²)', 'ὠ_e_z (rad/s²)', 'ὠ_d_x (rad/s²)', 'ὠ_d_y (rad/s²)', 'ὠ_d_z (rad/s²)'],
'sig_xdata': t,
'sig_ydata': [omega_e_p[:, 0], omega_e_p[:, 1], omega_e_p[:, 2], omega_d_p[0], omega_d_p[1], omega_d_p[2]],
'sig_linestyles': ['-', '-', '-', '--', '--', '--'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,105,41)', 'rgb(0,0,255)', 'rgb(255,0,0)', 'rgb(0,127,0)']}
subplot20 = {'title': 'freq per Ta step (Hz)',
'sig_labels': ['frep_per_Ta_step', 'frep_per_Ta_step_mean'],
'sig_xdata': t,
'sig_ydata': [frep_per_Ta_step, frep_per_Ta_step_mean],
'sig_linestyles': ['-', '-'],
'sig_colors': ['rgb(255,255,17)', 'rgb(255,0,0)']}
subplot21 = {'title': 'quat_err',
'sig_labels': ['quat_err_2', 'quat_err_3', 'quat_err_4'],
'sig_xdata': t,
'sig_ydata': [quat_err[:, 1], quat_err[:, 2], quat_err[:, 3]],
'sig_linestyles': ['-', '-', '-', '-'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,105,41)', 'rgb(100,212,19)']}
subplot22 = {'title': 'e_ω (rad/s)',
'sig_labels': ['e_ω_x (rad/s)', 'e_ω_y (rad/s)', 'e_ω_z (rad/s)'],
'sig_xdata': t,
'sig_ydata': [omega_err[:, 0], omega_err[:, 1], omega_err[:, 2]],
'sig_linestyles': ['-', '-', '-'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,105,41)']}
subplot23 = {'title': 'ė_ω (rad/s)',
'sig_labels': ['ė_ω_x (rad/s)', 'ė_ω_y (rad/s)', 'ė_ω_z (rad/s)'],
'sig_xdata': t,
'sig_ydata': [omega_err_p[:, 0], omega_err_p[:, 1], omega_err_p[:, 2]],
'sig_linestyles': ['-', '-', '-'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,105,41)']}
subplot24 = {'title': 'tau (Nm)',
'sig_labels': ['tau_1', 'tau_2', 'tau_3', 'tau_4', 'tau_5', 'tau_6'],
'sig_xdata': t,
'sig_ydata': [tau[:, 0], tau[:, 1], tau[:, 2], tau[:, 3], tau[:, 4], tau[:, 5]],
'sig_linestyles': ['-', '-', '-', '-', '-', '-'],
'sig_colors': ['rgb(255,255,17)', 'rgb(19,159,255)', 'rgb(255,105,41)', 'rgb(100,212,19)', 'rgb(183,70,255)', 'rgb(15,255,255)']}
subplot_data = [subplot1, subplot2, subplot3, subplot4, subplot5, subplot6, subplot7, subplot8, subplot9, subplot10, subplot11, subplot12, subplot13, subplot14, subplot15, subplot16, subplot17, subplot18, subplot19, subplot20, subplot21, subplot22, subplot23, subplot24]
return subplot_data Plotly: create html file with zoom eventdef plot_solution_7dof(subplot_data, save_plot=False, file_name='plot_saved', plot_fig=True, matlab_import=True):
subplot_number = len(subplot_data)
sig_labels = np.empty(24, dtype=object)
if matlab_import:
for i in range(0, subplot_number):
sig_label = subplot_data[i][0][0][0][0]
if len(subplot_data[i][0]) > 1:
sig_labels[i] = sig_label[:-2]
else:
sig_labels[i] = sig_label
#row=1+np.mod(i,4), col=1+int(np.floor(i/4)
else:
for i in range(0, subplot_number):
sig_labels[i] = subplot_data[i]['title']
sig_labels_orig = sig_labels
sig_labels = sig_labels.reshape(6,4).T.flatten().tolist()
# Create a Plotly subplot
fig = make_subplots(rows=4, cols=int(subplot_number/4), shared_xaxes=False, vertical_spacing=0.05, horizontal_spacing=0.035, subplot_titles=sig_labels)
# Plot tdata
for i in range(0, subplot_number):
sig_title = sig_labels_orig[i]
signal_number = len(subplot_data[i]['sig_ydata'])
for j in range(0, signal_number):
if matlab_import:
sig_label = subplot_data[i][0][j][0][0]
sig_xdata = subplot_data[i][0][j][1][0]
sig_ydata = subplot_data[i][0][j][2][0]
sig_linestyle = subplot_data[i][0][j][3][0]
sig_color = 255*subplot_data[i][0][j][4][0]
sig_color = f"rgb({','.join(map(str, sig_color))})"
else:
sig_label = subplot_data[i]['sig_labels'][j]
sig_xdata = subplot_data[i]['sig_xdata']
sig_ydata = subplot_data[i]['sig_ydata'][j]
sig_linestyle = subplot_data[i]['sig_linestyles'][j]
sig_color = subplot_data[i]['sig_colors'][j]
if sig_linestyle == '-':
line_style = dict(width=1, color=sig_color, dash='solid')
elif sig_linestyle == '--':
line_style = dict(width=1, color=sig_color, dash='dash')
act_row = 1+np.mod(i,4)
act_col = 1+int(np.floor(i/4))
fig.add_trace(go.Scatter(x=sig_xdata, y=sig_ydata, name=sig_label, line = line_style, hoverinfo = 'x+y+text', hovertext=sig_label, text=sig_title), row=act_row, col=act_col)
if act_row == 4:
fig.update_xaxes(title_text='t (s)', row=act_row, col=act_col)
# fig.update_layout(plot_bgcolor='#1e1e1e', paper_bgcolor='#1e1e1e', font=dict(color='#ffffff'), legend=dict(orientation='h'))
fig.update_layout(
plot_bgcolor='#101010', # Set plot background color
paper_bgcolor='#1e1e1e', # Set paper background color
font=dict(color='#ffffff'), # Set font color
legend=dict(orientation='h', yanchor='middle', y=10, yref='container'), # Set legend orientation
hovermode = 'closest',
margin=dict(l=10, r=10, t=50, b=70),
height=1080,
# legend_indentation = 0,
# margin_pad=0,
# Gridline customization for all subplots
**{f'xaxis{i}': dict(gridwidth=1, gridcolor='#757575', linecolor='#757575', zerolinecolor='#757575', zerolinewidth=1) for i in range(1, subplot_number+1)},
**{f'yaxis{i}': dict(gridwidth=1, gridcolor='#757575', linecolor='#757575', zerolinecolor='#757575', zerolinewidth=1) for i in range(1, subplot_number+1)}
)
fig.update_layout(
**{f'xaxis{i}': dict(showticklabels=False) for i in range(1, subplot_number+1-6)}
)
fig.update_xaxes(matches='x', autorange=True)
if(plot_fig):
fig.show()
if(save_plot):
autoscale_code='''
rec_time = 100; //ms
function autoscale_function(){
//console.log('run');
graphDiv = document.querySelector('.plotly-graph-div');
//console.log(graphDiv);
if(graphDiv == null || graphDiv.on == undefined)
{
setTimeout(autoscale_function, rec_time);
}
else
{
var on_event=true;
function test(eventdata){
//console.log(eventdata);
graphDiv = document.querySelector('.plotly-graph-div');
if(on_event==true)
{
on_event=false;
labels = graphDiv.layout.annotations;
// Get changed axes
yaxis_change = Object.keys(eventdata).some(key => key.includes('yaxis'));
xaxis_change = Object.keys(eventdata).some(key => key.includes('xaxis'));
changed_yaxis = Object.keys(eventdata).filter(key => key.includes('yaxis'));
yaxis_names = changed_yaxis.map(name => name.split('.')[0]); // get only axis name
yaxis_names = [...new Set(yaxis_names)]; // get unique names
trace_numbers = yaxis_names.map(name => name.split('yaxis')[1]); // get trace numbers from names
trace_numbers = trace_numbers.map(name => name === '' ? 0 : Number(name)-1); // trace number '' should be 0
//create a array with length of the number of traces and false for each yaxis that was not in trace_numbers
// and true for each yaxis that is in trace numbers
yaxis_in_trace = Array.from({length: labels.length}, (_, i) => trace_numbers.includes(i));
update={};
labels.forEach(function(act_label, i){
trace = graphDiv.data.filter(trace => trace.text.includes(labels[i].text));
xrange = graphDiv.layout.xaxis.range;
yaxisName = i === 0 ? 'yaxis' : `yaxis${i + 1}`;
yrange = graphDiv.layout[yaxisName].range;
filteredIndices = trace[0].x.map((x, index) => x >= xrange[0] && x <= xrange[1] ? index : -1).filter(index => index !== -1);
//filteredX = filteredIndices.map(index => trace[0].x[index]);
g_ymax=-Infinity;
g_ymin=Infinity;
trace.forEach(function(el,id){
filteredY = filteredIndices.map(index => el.y[index]);
if( (yaxis_change && !xaxis_change) || (yaxis_in_trace[i] && xaxis_change) )
{
y_rangefilteredIndices = filteredY.map((y, index) => y >= yrange[0] && y <= yrange[1] ? index : -1).filter(index => index !== -1);
filteredY = y_rangefilteredIndices.map(index => filteredY[index]);
}
act_min = Math.min.apply(null, filteredY);
act_max = Math.max.apply(null, filteredY);
g_ymax = Math.max(g_ymax, act_max);
g_ymin = Math.min(g_ymin, act_min);
});
offset = 1/9*(g_ymax - g_ymin)/2;
if(offset == 0)
{
offset=0.001;
}
if(i == 0)
{
ylabel='yaxis.range';
}
else
{
ylabel='yaxis'+(1+i)+'.range';
}
update[ylabel] = [g_ymin-offset,g_ymax+offset];
});
Plotly.relayout(graphDiv, update);
}
else
{
on_event=true;
}
}
graphDiv.on('plotly_relayout', test);
}
}
setTimeout(autoscale_function, rec_time);
'''
py.plot(fig, filename=file_name, include_mathjax='cdn', auto_open=False, include_plotlyjs='cdn') # remove include_plotlyjs='cdn' for offline only use
with open(file_name, 'r', encoding='utf-8') as file:
html_content = file.read()
soup = BeautifulSoup(html_content, 'html.parser')
first_script_tag = soup.find('script')
if first_script_tag:
new_script = soup.new_tag('script')
new_script.string = "document.body.style.background='#1e1e1e';"+autoscale_code
first_script_tag.insert_after(new_script)
with open(file_name, 'w', encoding='utf-8') as file:
file.write(str(soup))
webbrowser.open('file://' + file_name) It's certainly not the fastest or most stable way to implement something like this (e.g., there's a bug when zooming in too close so that no sample is visible), but it works satisfactorily for me as long as there's no official solution. Attached is also an html file in which this approach has been implemented: 240910_traj2_crocddyl_mpc_thorizon_25ms.html.zip I hope this feature will be implemented very soon. Best regards |
This should be a top priority. They have auto scaling for other fields, but not for title. |
Unfortunately we have a lot of other top priorities :-( If someone from the community would like to put together a PR, I can get eyes on it for review, but otherwise it's going to be a while before anyone can tackle this in-house. Thanks - @gvwilson |
Do you have any tips on where to start looking to fix this bug. I would like to give this a try. Thank you for the quick response. |
This is a common request.
I would expect when I zoom on the x-axis, in a linked plot configuration, the y-axis would scale to the selected/zoomed range.
Here are reports of users requesting this feature
The text was updated successfully, but these errors were encountered: