plotly / plotly.js

Open-source JavaScript charting library behind Plotly and Dash
https://plotly.com/javascript/
MIT License
16.85k stars 1.85k forks source link

Exposing more events #145

Closed aderidder closed 3 months ago

aderidder commented 8 years ago

Hi,

From a recent community post, I learned that the January release will probably support a brushing feature, which is great. I think it would be really useful if you'd expose more events, such as double-click, as this would allow us to better control the desired functionality.

Thanks, Sander

etpinard commented 8 years ago

@aderidder thanks again for the suggestion.

Adding more events is definitely on our roadmap. The only things blocking us at the moment, is the fact that each plotly.js plot type (cartesian, geo, gl, ...) has its own event emitting internals.

Some work should be dedicated to generalizing our internals before exposing more events.

etpinard commented 8 years ago

@ifll please comment here if you any suggestions about other potential plotly.js events. Thank you.

ifll commented 8 years ago

What about having the "plotly_zommin", "plotly_zoomout", "plotly_pan", etc... events?

This would help a lot to control the user interaction with the plot

Thank you!

mmek123 commented 8 years ago

when graph is in edit mode would like to get events like title Edited, X/Y axis edited , annotations edited

also would highly benefit from having a event when you hover over the extrapolated graph points.. currently its only on data points..

thanks..

On Wed, Feb 17, 2016 at 3:25 AM, ifll notifications@github.com wrote:

What about having the "plotly_zommin", "plotly_zoomout", "plotly_pan", etc... events?

This would help a lot to control the user interaction with the plot

Thank you!

— Reply to this email directly or view it on GitHub https://github.com/plotly/plotly.js/issues/145#issuecomment-184753863.

czellweg commented 8 years ago

I second @mmek123 comments: we currently want to reload data based on zoom-events but not when relayouting. At the moment, we can't distinguish whether the relayout was caused by an actual zoom-in or simply the user changing the size of the browser window (which will cause a relayout as the plot is responsive).

We'd love to see the following:

It would be great if all the available data of the current view port to the plot is made available such as start-x, end-x, start-y, end-y etc.

Can you make a statement about a possible roadmap for this?

etpinard commented 8 years ago

From @mdfederici in https://github.com/plotly/plotly.js/issues/722 with PoC in https://github.com/plotly/plotly.js/pull/721

It is desirable for my container to receive notifications when a user has edited an annotation in an editable graph by moving, rotating or changing length [using a new plotly_editannotation event]

Response in https://github.com/plotly/plotly.js/issues/722#issuecomment-230880313

etpinard commented 8 years ago

From @paneyi in https://github.com/plotly/plotly.js/issues/788

It would be great to expose the original event along with the data in Plotly events. One practical example would be to know if the user was pressing any special keys when clicking and act accordingly, like add to a selection.

var acummulate = originalEvent.altKey || originalEvent.ctrlKey || originalEvent.shiftKey || originalEvent.metaKey

paneyi commented 8 years ago

Also it would be useful to be able to click on the background of the chart and get the coordinates, in order to create more points in an interactive way.

etpinard commented 8 years ago

@paneyi

it would be useful to be able to click on the background of the chart and get the coordinates

You might want to check out http://codepen.io/etpinard/pen/EyydEj

paneyi commented 8 years ago

Thank you @etpinard, I already saw that but it wasn't enough. Whenever you zoom, it stops working.

etpinard commented 7 years ago

Maybe relayout event data should list the current visible point on the graph as described in http://community.plot.ly/t/get-datapoints-in-currently-zoomed-view/259/

etpinard commented 7 years ago

From @CalvinFernandez in #935

It would be super useful to have the computed tooltip positioning information provided to the hover callback. It would help a lot with rendering our own custom tooltips.

etpinard commented 7 years ago

From @smalesys in https://github.com/plotly/plotly.js/issues/1138 :

Sounds logical to me to have two distinct events here. I think maybe the names can be confusing, since "doubleclick" sounds general and "deselect" is specific, while they are actually both on the same level (im not sure if i am clear here haha).

But i admit that i have no idea for renaming the event. Maybe unzoom or resetplot but i don't think that this will englobe all the use cases of the event. I guess just mentionning it in the doc should be enough for the users.

etpinard commented 7 years ago

From @destradafilm in https://github.com/plotly/plotly.js/issues/1471

I'm working on a SCATTERPLOT and adding some user interactions.

'plotly_click' is only called when a user clicks a point

plotly_selected' is also called when a user clicks either a blank area of the plot OR when a user clicks a point (but returns an empty data obj)

I feel like it makes more sense to call 'plotly_click' no matter where you click on the chart, return data if a point is clicked, but return empty data if no points are clicked.

I'm asking for this feature for some interactions on my scatterplot.

For example: If a user clicks a point, color the point 'red'

easy, since I can use the data.points[0] to find which marker to color If a user clicks an empty part of the chart, reset the 'selected' points and color it back to original color.

I can use 'if data == undefined' then color all points back to original color', but problem is data == undefined if I click a point, or click an empty place in chart...'plotly_click' is never called here

etpinard commented 7 years ago

From @destradafilm's https://github.com/plotly/plotly.js/issues/1548

To expose more reliable p2c functionality, I wrote:

What I think we should do: is add another plotly_ event (e.g. plotly_mouse) that would get fired on anytime you mouse over a graph with or without triggering plotly_hover.

BruceSherwood commented 6 years ago

I gather that there’s currently no way to detect overall mouse down and mouse up events, which are important for being able to pause incremental graphing and a synchronous animation during the time that the mouse button is down. Is that a future possibility?

jensb commented 6 years ago

Please also expose some "before" edit events, especially when editing text (annotations, legends, titles etc). I would like to be able to let users edit placeholder text or select from a list of template strings to be inserted instead of just editing text. In this case I need to change the text being edited before edit mode is activated (and replace it again when edit mode is closed). Thanks!

etu29414 commented 6 years ago

Hello everyone, i would like add an event when i click on a trace. for exemple when i click on a trace, i show an alert “you click on trace X”.

for example: i would like that if i click on red trace there an alert but not on black point image

thanks !

Pierre-Bartet commented 4 years ago

Any progress on this ? It's a deal breaker.

ccssmnn commented 4 years ago

I want to plot a server generated histogram in a bar plot that is getting more refined when the user zooms in by updating the data object. Unfortunately I run into an endless loop, because using the update event as a trigger for loading a new refinement (based on new x-min and x-max) does fire everytime the plot is drawn with new data.

I don't see any way right now to avoid the endless loop without a dedicated zoom event. Is there anything happening? Is there something I could provide?

alexcjohnson commented 4 years ago

@ccssmnn can you hold onto the range from the previous call, and abort the request for new data if the range hasn't actually changed? Something like this is what's typically done.

jensb commented 4 years ago

This should be doable using uirevision: https://plotly.com/javascript/uirevision/

ccssmnn commented 4 years ago

Thank you for the fast replies @alexcjohnson & @jensb

I have prepared a Sandbox showing what I've got so far. Here is the Sandbox In case the link is not working properly I will show the code at the bottom if this comment.

The problem with this solution seems to be that the update event is fired several times after a zoom event with different xmin/xmax values. I would expect one call for the zoom and another one that is triggered because the data changes if we zoom enough. But because there are more calls the user does not nessecarily end up at the expected range after zoom.

import React, { useState, useEffect, useCallback } from "react";
import "./styles.css";
import Plot from "react-plotly.js";

function binning(nBins, data, xMin, xMax) {
  const lower = xMin === undefined ? Math.min(...data) : xMin;
  const upper = xMax === undefined ? Math.max(...data) : xMax;

  const count = new Array(nBins).fill(0);
  data.forEach((value) => {
    if (value >= lower && value <= upper) {
      const bin = Math.floor(
        (Math.abs(value - lower) * nBins) / Math.abs(upper - lower)
      );
      count[bin] = count[bin] + 1;
    }
  });
  const binMean = new Array(nBins).fill(0);
  binMean.forEach((_, i) => {
    binMean[i] = lower + (i * (upper - lower)) / nBins;
  });
  const binWidth = Math.abs(upper - lower) / nBins;
  return [count, binMean, binWidth];
}

function randomNormal() {
  const [u, v] = [1 - Math.random(), 1 - Math.random()];
  return Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
}

export default function App() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);
  const requestData = useCallback(async () => {
    setLoading(true);
    const arr = [];
    for (let i = 0; i < 200; i++) {
      arr.push(randomNormal());
    }
    console.log(arr);
    setDataArr(arr);
    setLoading(false);
  }, []);
  const [layout, setLayout] = useState({ autosize: true });
  const [dataArr, setDataArr] = useState([]);
  const [xMin, setXMin] = useState(undefined);
  const [xMax, setXMax] = useState(undefined);
  useEffect(() => {
    const [count, mean, width] = binning(50, dataArr, xMin, xMax);
    setData([
      {
        x: mean,
        y: count,
        width: new Array(count.length).fill(width),
        type: "bar"
      }
    ]);
    setLayout({
      autosize: true,
      xaxis: {
        range: [xMin, xMax]
      }
    });
  }, [dataArr, xMin, xMax]);
  return (
    <div className="App">
      <h1>Plot Updating on Zoom</h1>
      <button onClick={requestData}>
        {loading ? "Loading..." : "Request Data"}
      </button>
      <Plot
        data={data}
        layout={layout}
        useResizeHandler
        style={{ width: "100%", height: "100%" }}
        onDoubleClick={() => {
          setXMin(undefined);
          setXMax(undefined);
        }}
        onUpdate={(figure) => {
          console.log(
            `onUpdate:
              - old Xmin ${xMin}
              - old Xmax ${xMax}
              - new Xmin ${figure.layout.xaxis?.range?.[0]}
              - new Xmax ${figure.layout.xaxis?.range?.[1]}
            `
          );
          const newXMax = figure.layout.xaxis?.range?.[1];
          const newXMin = figure.layout.xaxis?.range?.[0];
          if (newXMax === undefined || newXMin === undefined) return;
          if (xMax === undefined || xMin === undefined) {
            setXMax(newXMax);
            setXMin(newXMin);
            return;
          }
          const overlap = Math.max(
            0,
            Math.abs(Math.min(newXMax, xMax) - Math.max(newXMin, xMin))
          );
          const currentRange = Math.abs(xMax - xMin);
          const newRange = Math.abs(newXMax - newXMin);
          if (overlap / currentRange < 0.7 || overlap / newRange < 0.7) {
            setXMax(newXMax);
            setXMin(newXMin);
          }
        }}
      />
    </div>
  );
}
jackparmer commented 3 years ago

This issue has been tagged with NEEDS SPON$OR

A community PR for this feature would certainly be welcome, but our experience is deeper features like this are difficult to complete without the Plotly maintainers leading the effort.

Sponsorship range: $15k-$20k

What Sponsorship includes:

Please include the link to this issue when contacting us to discuss.

gvwilson commented 3 months ago

Hi - this issue has been sitting for a while, so as part of our effort to tidy up our public repositories I'm going to close it. If it's still a concern, we'd be grateful if you could open a new issue (with a short reproducible example if appropriate) so that we can add it to our stack. Cheers - @gvwilson