1

I have a Plotly.js chart. How can I position a button beneath the legend (or key)?

Here is an example of what I’m working with: https://codepen.io/synaptik/pen/YLmRMM

<div id="myDiv"></div>
<div id="inset" style="margin-left:80px;">
    <button style="background:grey;">Target<br/>Info</button
</div>
synaptik
  • 8,971
  • 16
  • 71
  • 98

1 Answers1

1

A complicated but robust solution is, use javascript and get the position of the legend in the plot ( using the function getBoundingClientRect) and then set that positioning to the button, JQuery library is being used by me to do this, but can be also possible through javascript with some adjustments.

Run function after plot render:

The javascript funtion that positions the button should run only after the plotly graph has completed rendering, so based on this SO Answer, I call the function that positions the buttons after the plot has completely rendered.

References:

  1. getBoundingClientRect

var data_x = ['2018-05-01', '2018-05-02', '2018-05-03', '2018-05-04', '2018-05-05', '2018-05-06', '2018-05-07', '2018-05-08', '2018-05-09'];

// data
var Data = {
  type: 'scatter',
  x: data_x,
  y: [4, 2, -1, 4, -5, -7, 0, 3, 8],
  mode: 'lines+markers',
  name: 'Data',
  showlegend: true,
  hoverinfo: 'all',
  line: {
    color: 'blue',
    width: 2
  },
  marker: {
    color: 'blue',
    size: 8,
    symbol: 'circle'
  }
}

// violations
var Viol = {
  type: 'scatter',
  x: ['2018-05-06', '2018-05-09'],
  y: [-7, 8],
  mode: 'markers',
  name: 'Violation',
  showlegend: true,
  marker: {
    color: 'rgb(255,65,54)',
    line: {
      width: 6
    },
    opacity: 0.5,
    size: 14,
    symbol: 'circle-open'
  }
}
// control limits
var CL = {
  type: 'scatter',
  x: data_x.concat([null]).concat(data_x),
  y: [5, 5, 5, 5, 6, 6, 7, 7, 7, null, -5, -5, -5, -5, -6, -6, -7, -7, -7],
  mode: 'lines',
  name: 'LCL/UCL',
  showlegend: true,
  line: {
    color: 'green',
    width: 2,
    dash: 'dash'
  }
}

// centre
var Centre = {
  type: 'scatter',
  x: data_x,
  y: [3, 1, 2, 2, 2, -2, 2, 2, 2],
  mode: 'lines',
  name: 'EWMA',
  showlegend: true,
  line: {
    color: 'grey',
    width: 2
  }
}

// all traces
var data = [Data, Viol, CL, Centre]

// layout
var layout = {
  title: 'Basic SPC Chart',
  xaxis: {
    zeroline: false
  },
  yaxis: {
    range: [data_x[0], data_x[data_x.length - 1]],
    zeroline: false
  }
}

function positionButton() {
  var offsets = $("g.legend")[0].getBoundingClientRect();
  $("div#inset").css("left", offsets.left);
  var offsetTop = offsets.height + offsets.top;
  $("div#inset").css("top", offsetTop);
}

Plotly.plot('myDiv', data, layout).then(function() {
  window.requestAnimationFrame(function() {
    window.requestAnimationFrame(function() {
      positionButton();
    });
  });
});


$(window).on("resize", function() {
  positionButton();
});
.position-button {
  position: absolute;
}

.style-this {
  background: grey;
}

.wrapper {
  position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<head>
  <!-- Plotly.js -->
  <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>

<body>
  <!-- Plotly chart will be drawn inside this DIV -->
  <div class="wrapper">
    <div id="myDiv"></div>
    <div id="inset" class="position-button">
      <button class="style-this">Target<br/>Info</button
</div>
   </div>
  <script>
  /* JAVASCRIPT CODE GOES HERE */
  </script>
</body>
</html>

A simple way to do it will be, wrap the plot in a div set to relative positioning and make the div wrapping the button absolute positioned and align it to the legend. Please refer the below sample.

var data_x = ['2018-05-01' , '2018-05-02' , '2018-05-03' , '2018-05-04' , '2018-05-05' , '2018-05-06' , '2018-05-07' , '2018-05-08' , '2018-05-09' ];

// data
var Data = {
  type: 'scatter',  
  x: data_x, 
  y: [4,2,-1,4,-5,-7,0,3,8], 
  mode: 'lines+markers', 
  name: 'Data', 
  showlegend: true,
  hoverinfo: 'all',
  line: {
    color: 'blue', 
    width: 2
  }, 
  marker: {
    color: 'blue', 
    size: 8, 
    symbol: 'circle'
  }
}

// violations
var Viol = {
  type: 'scatter', 
  x: ['2018-05-06', '2018-05-09'], 
  y: [-7,8], 
  mode: 'markers', 
  name: 'Violation', 
  showlegend: true, 
  marker: {
    color: 'rgb(255,65,54)', 
    line: {width: 6}, 
    opacity: 0.5, 
    size: 14, 
    symbol: 'circle-open'
  }
}
// control limits
var CL = {
  type: 'scatter', 
  x: data_x.concat([null]).concat(data_x), 
  y: [5,5,5,5,6,6,7,7,7, null, -5,-5,-5,-5,-6,-6,-7,-7,-7], 
  mode: 'lines', 
  name: 'LCL/UCL', 
  showlegend: true, 
  line: {
    color: 'green', 
    width: 2,
    dash: 'dash'
  }
}

// centre
var Centre = {
  type: 'scatter',  
  x: data_x, 
  y: [3,1,2,2,2,-2,2,2,2], 
  mode: 'lines', 
  name: 'EWMA', 
  showlegend: true, 
  line: {
    color: 'grey', 
    width: 2
  }
}

// all traces
var data = [Data,Viol,CL,Centre]

// layout
var layout = {
  title: 'Basic SPC Chart',
  xaxis: {
    zeroline: false
  },
  yaxis: {
    range: [data_x[0], data_x[data_x.length-1]],
    zeroline: false
  }
}

Plotly.plot('myDiv', data,layout);
.position-button {
 position: absolute;
 top: 190px;
 left: 89%;
}
.style-this{
 background:grey;
}
.wrapper{
 position:relative;
}
<head>
 <!-- Plotly.js -->
 <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>

<body>
 <!-- Plotly chart will be drawn inside this DIV -->
 <div class="wrapper">
  <div id="myDiv"></div>
  <div id="inset" class="position-button">
   <button class="style-this">Target<br/>Info</button
</div>
   </div>
  <script>
  /* JAVASCRIPT CODE GOES HERE */
  </script>
</body>
</html>
user697473
  • 2,165
  • 1
  • 20
  • 47
Naren Murali
  • 19,250
  • 3
  • 27
  • 54