Files
OpenBB/frontend-components/plotly/src/utils/addAnnotation.tsx
teh_coderer 979930b9e8 feature / Refactor Interactive Charts to React (#4941)
* init

* fix tables

* add shortcuts

* handle svgs

* test

* test2

* test3

* Update loggers.py

* Update sdk_helpers.py

* Update loggers.py

* Update loggers.py

* updates

* updates

* update

* handle add text high/low for candlestick traces when updating

* adding save overlay to tables

* maybe fix

* prints

* asdf

* working

* working

* removing prints

* update

* fix no figure title text

* add trace labels space

* download finished popup for MacOS

* bump pywry

* update

* update table

* Update plotly_helper.py

* only format numbers over 10_000 on tables

* Delete generate_index.py

* turn off logs in generations

* update tables

* bump pywry, fix tables, added ichimoku ta indicator

* Update backend.py

* mypy

* update tables

* updates

* juan more

* tables

* test

* bump pywry

* bump pywry

* Update loggers.py

* test

* fixing some formatting

* add update button to indicators dashboard

* fix oecd dates to be full dates

* prepare charts/tables for pywry update

* Update poetry.lock

* Update finviz_view.py

* tests

* tests

* tests

* tests

* testss?

* tests

* Create test_call_func[call_sec-nasdaq_view.sec_filings-other_args37-called_with37].yaml

* testtss please

* Update loggers.py

* testss

* `with open(newline="\n")`

* tests

* tests -__-

* why

* Revert "`with open(newline="\n")`"

This reverts commit 554e0f53f4.

* Revert "why"

This reverts commit 89f1d9b823.

* Revert "tests -__-"

This reverts commit a9c694ae96.

* Revert "tests"

This reverts commit 5463249498.

* whelp

* .

* rename `streamlit.py` -> `streamlit_run.py`,  bump pywry/finviz/streamlit

* Update backend.py

* update

* Revert "update file"

---------

Co-authored-by: andrewkenreich <andrew.kenreich@gmail.com>
Co-authored-by: James Maslek <jmaslek11@gmail.com>
2023-05-11 17:38:12 +00:00

294 lines
8.4 KiB
TypeScript
Vendored

//@ts-nocheck
import {
Annotations,
PlotMouseEvent,
PlotlyHTMLElement,
} from "plotly.js-dist-min";
import { Figure } from "react-plotly.js";
type PopupData = {
x: number;
y: number;
yref: string;
text: string;
yshift: number;
yanchor: string;
bordercolor: string;
color: string;
size: number;
annotation?: any;
};
export function add_annotation({
plotData,
popup_data,
current_text,
}: {
plotData: Figure;
popup_data: PopupData;
current_text?: string;
}) {
let x = popup_data.x;
let y = popup_data.y;
let yref = popup_data.yref;
let annotations = plotData?.layout?.annotations || [];
let index = -1;
for (let i = 0; i < annotations.length; i++) {
if (
annotations[i].x == x &&
annotations[i].y == y &&
annotations[i].text == current_text
) {
index = i;
break;
}
}
if (popup_data.high != undefined) {
y = popup_data.yanchor == "above" ? popup_data.high : popup_data.low;
}
if (index == -1) {
let annotation: Annotations = {
x: x,
y: y,
xref: "x",
yref: yref,
xanchor: "center",
text: popup_data.text,
showarrow: true,
arrowhead: 2,
arrowsize: 1,
arrowwidth: 2,
ax: x,
ay: y + popup_data.yshift,
ayref: yref,
axref: "x",
bordercolor: popup_data.bordercolor,
bgcolor: "#000000",
borderwidth: 2,
borderpad: 4,
opacity: 0.8,
font: {
color: popup_data.color,
size: popup_data.size,
},
clicktoshow: "onoff",
captureevents: true,
high: popup_data.high || undefined,
low: popup_data.low || undefined,
};
annotations.push(annotation);
} else {
annotations[index].y = y;
annotations[index].text = popup_data.text;
annotations[index].font.color = popup_data.color;
annotations[index].font.size = popup_data.size;
annotations[index].ay = y + popup_data.yshift;
annotations[index].bordercolor = popup_data.bordercolor;
annotations[index].high = popup_data.high || undefined;
annotations[index].low = popup_data.low || undefined;
}
return { annotations: annotations, annotation: annotations[index] };
}
export function plot_text({
plotData,
popup_data,
current_text,
}: {
plotData: Figure;
popup_data: PopupData;
current_text?: string;
}) {
// Plots text on the chart based on the popup_data
// If current_text is not null, it will be replaced with the new text
// If current_text is null, a new annotation will be added
// popup_data is the data from the popup
// data is the data from the chart
console.log("plot_text: current_text", current_text);
let output = undefined;
let yaxis = popup_data.yref.replace("y", "yaxis");
let yrange = plotData.layout[yaxis].range;
let yshift = (yrange[1] - yrange[0]) * 0.2;
if (popup_data.yanchor == "below") {
yshift = -yshift;
}
popup_data.yshift = yshift;
output = add_annotation({ plotData, popup_data, current_text });
let to_update = { annotations: output.annotations, dragmode: "pan" };
to_update[yaxis + ".type"] = "linear";
return { update: to_update, annotation: output.annotation };
}
export function init_annotation({
plotData,
popupData,
setPlotData,
setModal,
setOnAnnotationClick,
setAnnotations,
onAnnotationClick,
ohlcAnnotation,
setOhlcAnnotation,
annotations,
plotDiv,
}: {
plotData: Figure;
popupData: Partial<PopupData>;
setPlotData: (plotData: Partial<Figure>) => void;
setModal: (modal: { name: string; data?: any }) => void;
onAnnotationClick: any;
setOnAnnotationClick: (onAnnotationClick: any) => void;
setAnnotations: (annotations: Partial<Annotations>[]) => void;
ohlcAnnotation: any;
setOhlcAnnotation: (ohlcAnnotation: any) => void;
annotations: Annotations[];
plotDiv: PlotlyHTMLElement;
}) {
if (popupData.text != undefined && popupData.text != "") {
popupData.text = popupData.text.replace(/\n/g, "<br>");
let popup_data: Partial<PopupData>;
let inOhlc = false;
if (popupData.annotation) {
console.log("data", popupData);
popup_data = {
x: popupData.annotation.x,
y: popupData.annotation.y,
yref: popupData.annotation.yref,
yanchor:
popupData.annotation.y < popupData.annotation.ay ? "above" : "below",
...popupData,
};
if (popupData.annotation.high != undefined) {
inOhlc = true;
}
console.log("popup_data", popup_data);
let to_update = plot_text({
plotData,
popup_data: popup_data as PopupData,
current_text: popupData.annotation.text,
});
if (inOhlc) {
// we update the ohlcAnnotation
let ohlcAnnotationIndex = ohlcAnnotation.findIndex(
(a) =>
a.x == popupData.annotation.x &&
a.y == popupData.annotation.y &&
a.yref == popupData.annotation.yref
);
console.log("ohlcAnnotationIndex", ohlcAnnotationIndex);
if (ohlcAnnotationIndex == -1) {
// we add the annotation to the ohlcAnnotation array
setOhlcAnnotation([...ohlcAnnotation, to_update.annotation]);
} else {
// we replace the annotation in the ohlcAnnotation array
ohlcAnnotation[ohlcAnnotationIndex] = to_update.annotation;
setOhlcAnnotation(ohlcAnnotation);
}
}
setAnnotations(
[...annotations, to_update.annotation].filter((a) => a != undefined)
);
plotData.layout.dragmode = "pan";
setPlotData({ ...plotData, ...to_update.update });
setOnAnnotationClick({});
return;
}
plotDiv.on("plotly_clickannotation", (eventData) => {
console.log("plotly_clickannotation", eventData);
let annotation = eventData.annotation;
if (annotation.text == undefined) {
console.log("annotation.text is undefined");
return;
}
console.log("annotation.text", annotation.text);
// we replace <br> with \n so that the textarea can display the text properly
annotation.text = annotation.text.replace(/<br>/g, "\n");
let popup_data = {
x: annotation.x,
y: annotation.y,
high: annotation?.high ?? undefined,
low: annotation?.low ?? undefined,
yanchor: annotation.y < annotation.ay ? "above" : "below",
text: annotation.text,
color: annotation.font.color,
size: annotation.font.size,
bordercolor: annotation.bordercolor,
annotation: annotation,
};
console.log("popup_data_clickannotation", popup_data);
setOnAnnotationClick(popup_data);
setModal({ name: "textDialog", data: popup_data });
setOnAnnotationClick({});
});
function clickHandler(eventData: PlotMouseEvent) {
console.log("plotly_click", eventData);
let x = eventData.points[0].x;
let yaxis = eventData.points[0].fullData.yaxis;
let y = 0;
let high, low;
// We need to check if the trace is a candlestick or not
// this is because the y value is stored in the high or low
if (eventData.points[0].y != undefined) {
y = eventData.points[0].y;
} else if (eventData.points[0].low != undefined) {
high = eventData.points[0].high;
low = eventData.points[0].low;
if (popup_data?.yanchor == "below") {
y = eventData.points[0].low;
} else {
y = eventData.points[0].high;
}
}
popup_data = {
x: onAnnotationClick?.annotation?.x ?? x,
y: onAnnotationClick?.annotation?.y ?? y,
yref: onAnnotationClick?.annotation?.yref ?? yaxis,
high: onAnnotationClick?.annotation?.high ?? high,
low: onAnnotationClick?.annotation?.low ?? low,
...popupData,
};
if (high != undefined) {
// save the annotation to use later
ohlcAnnotation.push(popup_data);
setOhlcAnnotation(ohlcAnnotation);
console.log("ohlcAnnotation", ohlcAnnotation);
}
let to_update = plot_text({
plotData,
popup_data: popup_data as PopupData,
current_text: onAnnotationClick?.annotation?.text,
});
setAnnotations(
[...annotations, to_update.annotation].filter((a) => a != undefined)
);
plotData.layout.dragmode = "pan";
setPlotData({ ...plotData, ...to_update.update });
plotDiv.removeAllListeners("plotly_click");
}
plotData.layout.dragmode = "select";
setPlotData({ ...plotData });
plotDiv.on("plotly_click", clickHandler);
}
}