Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Hook-based API#275

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
JamesRamm wants to merge5 commits intoplotly:master
base:master
Choose a base branch
Loading
fromJamesRamm:patch-1
Open
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletionsREADME.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -113,6 +113,34 @@ In short, this means that simply adding data points to a trace in `data` or chan

## API Reference

### usePlotly Hook

As an alternative to the `Plot` component, you may use the `usePlotly` react _hook_. This provides a more powerful API with full control over the plot element, compatibility with functional components, intuitive responsive behaviour and ability to use `extendTraces`.
Here is a simple example of creating a chart with `usePlotly`:

```jsx
function MyChart(props) {
const { ref, updates, appendData } = usePlotly();

// Here is a function that will change the data. You must pass a partial Figure object (plotly DSL object) which will be
// merged with all previous calls to `updates`
const changeData = () => updates({ data: [ { y: [Math.random() * 10], type: 'scatter' } ] })

// Here we start extending traces using the `appendData` stream
const extendData = setInterval(() => {
appendData({ data: { y: [[Math.random() * 10]]}, tracePos: [0] });
}, 500);

return (
<div>
<div ref={ref} style={{ width: '500px', height: '300px' }}/>
<button onClick={changeData}>React!</button>
<button onClick={extendData}>Extend!</button>
</div>);
}
```


### Basic Props

**Warning**: for the time being, this component may _mutate_ its `layout` and `data` props in response to user input, going against React rules. This behaviour will change in the near future once https://github.com/plotly/plotly.js/issues/2389 is completed.
Expand Down
4 changes: 3 additions & 1 deletionpackage.json
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -70,7 +70,9 @@
},
"peerDependencies": {
"plotly.js": ">1.34.0",
"react": ">0.13.0"
"react": ">0.13.0",
"flyd": ">=0.2.8",
"ramda": ">=0.28.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

flyd andramda seem like they'd be better asdependencies rather thanpeerDependencies - and then let's change from>= to^

Copy link

@floriancargoetfloriancargoetOct 13, 2022
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Are 2 news deps really required?
ramda seems to be used just to write this code in the functional style.
The author himself said in the related issue that it could be replaced with:

function getSizeForLayout(entries) {    const { width, height } = entries[0].contentRect;    return { layout: { width, height } };}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Good question@floriancargoet -ramda has a couple of other uses in this PR (and we do use it a good deal elsewhere at Plotly), but to my mind yourgetSizeForLayout rewrite is more readable than the full functional version.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

While yesgetSizeForLayout can be written easily withoutramda (happy to do this), the main reason it was included was formergeDeepRight which is a relatively complex function to implement.
We could go for an independent implementation but my argument would be thatramda is relatively small and compatible with tree shaking

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Right, deep merge is annoying to reimplement. I have no problem adding this (andflyd) but I do think they belong independencies.

},
"browserify-global-shim": {
"react": "React"
Expand Down
50 changes: 50 additions & 0 deletionssrc/usePlotly.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
import { useLayoutEffect, useState, useMemo } from 'react';
import { head, prop, compose, pick, objOf, mergeDeepRight } from 'ramda';
import { stream, scan } from 'flyd';

/**
* A simple debouncing function
*/
const debounce = (fn, delay) => {
let timeout;

return function (...args) {
const functionCall = () => fn.apply(this, args);

timeout && clearTimeout(timeout);
timeout = setTimeout(functionCall, delay);
};
};

const getSizeForLayout = compose(objOf('layout'), pick(['width', 'height']), prop('contentRect'), head);

export default function usePlotly() {
const updates = useMemo(stream, []);
const appendData = useMemo(stream, []);
const plotlyState = useMemo(
() => scan(mergeDeepRight, { data: [], config: {}, layout: {} }, updates),
[]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Shouldn'tupdates be added to the dependencies list here since it's used inside the hook?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

sinceupdates is memoized with an empty array, it will only be computed once on mount, so adding it to the dependencies array or not forplotlyState will have no effect....

);

const observer = new ResizeObserver(debounce(compose(updates, getSizeForLayout), 100));
const [internalRef, setRef] = useState(null);
useLayoutEffect(() => {
if (internalRef) {
observer.observe(internalRef);
const endS = plotlyState.map(state => {
Plotly.react(internalRef, state);
});

const endAppend = appendData.map(({ data, tracePos }) => Plotly.extendTraces(internalRef, data, tracePos));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Since you've implementedextendTraces here, let's finish it by includingmaxPoints (the optional 4th argument toextendTraces)

JamesRamm reacted with thumbs up emoji

return () => {
Plotly.purge(internalRef);
observer.unobserve(internalRef);
endAppend.end(true);
endS.end(true);
};
}
}, [internalRef, plotlyState, updates, appendData]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Shouldn'tobserver be added as a dependency here since it's used inside the hook?

nlappas reacted with thumbs up emoji

return { ref: setRef, updates, appendData };
}

[8]ページ先頭

©2009-2025 Movatter.jp