Open StasSpawn opened 1 year ago
@StasSpawn I am not sure if you can update the layout when using the default export button but you can download the graph directly using plotly functionality.
https://plotly.com/javascript/plotlyjs-function-reference/#plotlydownloadimage
You can override the original graph with whatever layout / configurations you want. Here is an example snippet.
import Plotly from 'plotly.js/lib/core';
Plotly.downloadImage(
{
data: plotlyPlot.data,
layout: {
...plotlyPlot.layout,
...{ Override Options Here }
},
config: plotlyPlot.config,
}, {
format: 'png',
filename: 'filename',
width: 1000,
height: 500,
}
);
@JohnCos247 Thank you for the answer.
I'm using React. This is supposed to be in config then?
I'm using React. This is supposed to be in config then?
@StasSpawn pretty much. You want to pass a reference to that plots element. Here is a quick example of how it could be done. I have done something similar to this before.
import React, { useState } from 'react';
import Plotly from 'plotly.js/lib/core';
import createPlotlyComponent from 'react-plotly.js/factory';
import Heatmap from 'plotly.js/lib/heatmap';
Plotly.register([Heatmap]);
const Plot = createPlotlyComponent(Plotly);
const triggerDownload = (plotlyPlot) => {
// Ensure that the plot is instantiated
if (plotlyPlot) {
// Turn off the colorscale
const scaleOffData = plotlyPlot.data.map((trace) => {
...trace,
trace.showScale: false
});
// Fire the download.
Plotly.downloadImage(
{
data: scaleOffData,
layout: {
...plotlyPlot.layout,
...{ Override Options Here }
},
config: plotlyPlot.config,
}, {
format: 'png',
filename: 'your_filename',
width: 1000,
height: 500,
}
);
}
};
const yourRenderFunction = () => {
...Some variables and stuff
// this will be the plots ref.
const [plotRef, setPlotRef] = useState(null);
// This will be the dom element
const plotDomElement = plotRef?.el;
return (
<>
<div onClick={() => triggerDownload(plotDomElement)}></div>
<Plot
ref={setPlotRef}
data={json.data}
layout={json.layout}
frames={json.config}
revision={revision}
onUpdate={onPlotUpdate}
onButtonClicked={plotlyButtonClicked}
onSliderEnd={onSliderEnd}
onRelayout={onPlotRelayout}
/>
</>
);
};
You can also use the plotlyPlot
to set the width and height to be the same as you see it on screen with a bit more code.
Hi @JohnCos247,
Your solution for enabling image downloads from Plotly charts was incredibly helpful! I implemented it successfully in a React project, but I'm encountering a "self is not defined" error in a Next.js project.
I understand this might be related to Next.js dynamic imports. I've tried using the dynamic
function as follows:
` 'use client'
import React from "react"; import dynamic from 'next/dynamic'; const Plotly = dynamic(() => import('plotly.js/lib/core'), { ssr: false });
const createPlotlyComponent = dynamic(() => import('react-plotly.js/factory'), { ssr: false });
const Scatter = dynamic(() => import('plotly.js/lib/scatter'), { ssr: false });
import { Typography, Divider, Card, Button, } from "@mui/material"; import { useState } from "react";
Plotly.register([Scatter]); const Plot = createPlotlyComponent(Plotly);
const triggerDownload = (plotlyPlot) => {
if (plotlyPlot) {
Plotly.downloadImage(
{
data: plotlyPlot.data,
layout: {
...plotlyPlot.layout,
},
config: plotlyPlot.config,
}, {
format: 'png',
filename: 'your_filename',
width: 1000,
height: 500,
}
);
}
};
const Graph = () => {
const [plotRef, setPlotRef] = useState(null)
return (
<Card
sx={{
boxShadow: "1px 1px 8px #80808085",
height: "598px",
borderRadius: '9px',
}}
>
<Typography sx={{ padding: 2, color: '#0A5F59' }}>Graph</Typography>
<Divider />
<Button onClick={() => triggerDownload(plotRef.el)}>
Download Image
</Button>
<Plot
ref={setPlotRef}
style={{ Width: "100%" }}
data={[
{
x: [1, 2, 3, 4, 5, 6, 7, 8],
y: [1, 5, 6, 54, 12, 14, 45, 90],
marker: { color: "red" },
name: "Seasonality",
type: "scatter",
},
{
x: [1, 2, 3, 4, 5, 6, 7, 8],
y: [1, 2, 36, 45, 5, 64, 7, 45],
marker: { color: "blue" },
name: "Demand",
type: "scatter",
},
{
x: [1, 2, 3, 4, 5, 6, 7, 8],
y: [1, 29, 36, 43, 5, 46, 67, 18],
marker: { color: "Purple" },
name: "Residual",
type: "scatter",
},
{
x: [1, 2, 3, 4, 5, 6, 7, 8],
y: [1, 25, 37, 44, 65, 46, 37, 81],
marker: { color: "green" },
name: "Trend",
type: "scatter",
},
]}
config={{ responsive: true }}
/>
</Card>
);
};
export default Graph;`
i got this error
Hello everyone,
I encountered an issue in my React project involving a component called TimeSeriousPlot
that uses Plotly charts. Specifically, I wanted to implement a feature to download images of these charts when a certain condition is met.
After some investigation and debugging, I managed to find a solution to the problem, and I wanted to share it with the community in case others face a similar issue.
Here's the updated code for the TimeSeriousPlot
component with the solution:
import { forwardRef, useEffect, useState, useCallback } from 'react';
import Plotly from "plotly.js/lib/core";
import createPlotlyComponent from 'react-plotly.js/factory';
import Scatter from 'plotly.js/lib/scatter';
Plotly.register([Scatter]);
const Plot = createPlotlyComponent(Plotly);
const TimeSeriousPlot = forwardRef((props, ref) => {
const { customRef, screenShot, setScreenShot } = props;
const [plotRef, setPlotRef] = useState(null);
const triggerDownload = useCallback(() => {
if (screenShot) {
Plotly.downloadImage(
{
data: plotRef?.el?.data,
layout: {
...plotRef?.el?.layout,
},
config: plotRef?.el?.config,
}, {
format: 'png',
filename: 'your_filename',
width: 1000,
height: 500,
);
}
setScreenShot(false);
}, [screenShot]);
triggerDownload();
useEffect(() => {
if (plotRef !== null) {
if (!!customRef) customRef(plotRef);
}
}, [plotRef]);
return (
<Plot ref={setPlotRef} {...props} />
);
});
export default TimeSeriousPlot;
than i just dynamically import in the main page
So, how to make an image ONLY with plot graph. Here is demonstation:
This is default saving![newplot](https://user-images.githubusercontent.com/56681850/194433741-0b0606ae-db23-41ca-b4b6-d6e1c37ba5e2.png)
This is nedeed result![2022-10-07_015848](https://user-images.githubusercontent.com/56681850/194433600-539303fa-ba29-4b96-a3e6-6256e64305df.png)