mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-11-04 08:22:26 +00:00
Feature/Interactive Plot CSV Bar (#4664)
* init * cleanup * Update popups.js * Update popups.js * Update plotly.html * add hoverlabel to `ba/redditsent` #4618
This commit is contained in:
@@ -3,6 +3,7 @@ __docformat__ = "numpy"
|
||||
|
||||
import logging
|
||||
import os
|
||||
import textwrap
|
||||
from datetime import datetime
|
||||
from typing import Dict, Optional, Union
|
||||
|
||||
@@ -24,9 +25,6 @@ from openbb_terminal.rich_config import console
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# TODO: Test OpenBBFigure conversion
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
@check_api_key(reddit_requirements)
|
||||
def print_and_record_reddit_post(
|
||||
@@ -313,11 +311,19 @@ def display_redditsent(
|
||||
console.print(f"Sentiment Analysis for {symbol} is {avg_polarity}\n")
|
||||
|
||||
if graphic:
|
||||
df["Title"] = df["Title"].apply(
|
||||
lambda x: "<br>".join(textwrap.wrap(str(x), 50))
|
||||
)
|
||||
fig = OpenBBFigure(
|
||||
title=f"Sentiment Score of {symbol}",
|
||||
xaxis_title="Sentiment Score",
|
||||
)
|
||||
fig.add_bar(x=polarity_scores)
|
||||
fig.add_bar(
|
||||
x=polarity_scores,
|
||||
customdata=df["Title"],
|
||||
hovertemplate="%{customdata}<extra></extra>",
|
||||
)
|
||||
fig.update_layout(hovermode="y")
|
||||
|
||||
# remove y ticks of graph object because number based index doesn't make sense here
|
||||
fig.layout.yaxis.tickvals = []
|
||||
|
||||
33
openbb_terminal/core/plots/plotly.html
vendored
33
openbb_terminal/core/plots/plotly.html
vendored
@@ -56,7 +56,7 @@
|
||||
<div
|
||||
id="openbb_footer"
|
||||
class="_footer flex items-center justify-between gap-4 py-2 px-4 text-center"
|
||||
style="z-index: 99999999999; width: 100%; bottom: 0; max-height: 60px;"
|
||||
style="z-index: 99999999999; width: 100%; bottom: 0; max-height: 60px; font-size: 0px;"
|
||||
>......................</div>
|
||||
|
||||
<div id="loading" class="saving">
|
||||
@@ -71,37 +71,42 @@
|
||||
<div id="popup_csv" class="popup_content">
|
||||
<div>
|
||||
<label for="csv_file">CSV file</label>
|
||||
<input type="file" id="csv_file" accept=".csv, .txt" />
|
||||
<input type="file" id="csv_file" accept=".csv" />
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px">
|
||||
<label for="csv_trace_type">Display data type</label>
|
||||
<div style="margin-top: 15px">
|
||||
<label for="csv_trace_type"><b>Display data type:</b></label>
|
||||
<select id="csv_trace_type" value="scatter">
|
||||
<option value="scatter">Scatter</option>
|
||||
<option value="bar">Bar</option>
|
||||
<option value="candlestick">Candlestick</option>
|
||||
<option value="scatter">Scatter (Line)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px">
|
||||
<label for="csv_name">Name of the trace</label>
|
||||
<div style="margin-top: 12px">
|
||||
<label for="csv_name"><b>Trace Name:</b></label>
|
||||
<textarea
|
||||
id="csv_name" style="width: 100%; max-width: 100%;
|
||||
id="csv_name" style="padding: 5px 2px 2px 5px !important; width: 100%; max-width: 100%;
|
||||
max-height: 200px; margin-top: 8px;" rows="2" cols="20"
|
||||
value="" placeholder="Enter a name for the trace"></textarea>
|
||||
value="" placeholder="Enter a name to give this trace"></textarea>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px" id="csv_columns"><!-- Empty --></div>
|
||||
<div style="margin-top: 10px" id="csv_colors"><!-- Empty --></div>
|
||||
<div style="margin-top: 15px" id="csv_columns"><!-- Empty --></div>
|
||||
<div style="margin-top: 15px" id="csv_colors"><!-- Empty --></div>
|
||||
|
||||
<div style="margin-top: 10px; display: none;" id="csv_scatter_options">
|
||||
<div style="margin-top: 10px; display: none;" id="csv_plot_yaxis_options">
|
||||
|
||||
<div id="csv_percent_change_div" style="display: none;">
|
||||
<input type="checkbox" id="csv_percent_change" name="csv_scatter_check" onclick="onlyOne(this)" />
|
||||
<input type="checkbox" id="csv_percent_change" name="csv_plot_yaxis_check" onclick="onlyOne(this)" />
|
||||
<label for="csv_percent_change">Plot as percent change from first value</label>
|
||||
</div><br />
|
||||
|
||||
<input type="checkbox" id="csv_same_yaxis" name="csv_scatter_check" onclick="onlyOne(this)" />
|
||||
<input type="checkbox" id="csv_same_yaxis" name="csv_plot_yaxis_check" onclick="onlyOne(this)" />
|
||||
<label for="csv_same_yaxis">Share Y-axis</label>
|
||||
</div>
|
||||
<div style="margin-top: 2px; display: none;" id="csv_bar_orientation">
|
||||
<input type="checkbox" id="csv_bar_horizontal" />
|
||||
<label for="csv_bar_horizontal">Plot horizontally</label>
|
||||
</div><br />
|
||||
|
||||
<div style="float: right; margin-top: 20px">
|
||||
|
||||
@@ -1530,7 +1530,7 @@ class OpenBBFigure(go.Figure):
|
||||
return
|
||||
|
||||
margin_add = (
|
||||
dict(l=80, r=60, b=85, t=40, pad=0)
|
||||
dict(l=80, r=60, b=90, t=40, pad=0)
|
||||
if not self._has_secondary_y
|
||||
else dict(l=60, r=50, b=85, t=40, pad=0)
|
||||
)
|
||||
@@ -1599,7 +1599,11 @@ class OpenBBFigure(go.Figure):
|
||||
self.layout.margin["l"] += 20
|
||||
|
||||
if (yaxis2 and yaxis2.side == "left") or yaxis.side == "left":
|
||||
title = yaxis.title.text if not yaxis2 else yaxis2.title.text
|
||||
title = (
|
||||
yaxis.title.text
|
||||
if not yaxis2 or yaxis2.side != "left"
|
||||
else yaxis2.title.text
|
||||
)
|
||||
xshift = -110 if not title else -135
|
||||
self.layout.margin["l"] += 60
|
||||
|
||||
|
||||
4
openbb_terminal/core/plots/web/bar_menus.js
vendored
4
openbb_terminal/core/plots/web/bar_menus.js
vendored
@@ -244,8 +244,8 @@ function downloadImage(filename, extension) {
|
||||
imageDownload = domtoimage.toPng;
|
||||
} else if (extension == "jpeg") {
|
||||
imageDownload = domtoimage.toJpeg;
|
||||
// } else if (extension == "svg") {
|
||||
// imageDownload = domtoimage.toSvg;
|
||||
// } else if (extension == "svg") {
|
||||
// imageDownload = domtoimage.toSvg;
|
||||
} else if (["svg", "pdf"].includes(extension)) {
|
||||
Plotly.downloadImage(globals.CHART_DIV, {
|
||||
format: "svg",
|
||||
|
||||
38
openbb_terminal/core/plots/web/helpers.js
vendored
38
openbb_terminal/core/plots/web/helpers.js
vendored
@@ -27,10 +27,10 @@ const ICONS = {
|
||||
};
|
||||
|
||||
function onlyOne(checkbox) {
|
||||
var checkboxes = document.getElementsByName('csv_scatter_check')
|
||||
var checkboxes = document.getElementsByName("csv_plot_yaxis_check");
|
||||
checkboxes.forEach((item) => {
|
||||
if (item !== checkbox) item.checked = false
|
||||
})
|
||||
if (item !== checkbox) item.checked = false;
|
||||
});
|
||||
}
|
||||
|
||||
function add_annotation(data, yshift, popup_data, current_text = null) {
|
||||
@@ -97,10 +97,13 @@ function checkFile(popup, type = false) {
|
||||
let csv_type = popup.querySelector("#csv_trace_type");
|
||||
let csv_columns = popup.querySelector("#csv_columns");
|
||||
let csv_colors = popup.querySelector("#csv_colors");
|
||||
let csv_scatter_options = popup.querySelector("#csv_scatter_options");
|
||||
csv_scatter_options.style.display = "none";
|
||||
csv_scatter_options.querySelector("#csv_percent_change_div").style.display = "inline-block";
|
||||
|
||||
let csv_plot_yaxis_options = popup.querySelector("#csv_plot_yaxis_options");
|
||||
let csv_bar_orientation = popup.querySelector("#csv_bar_orientation");
|
||||
csv_plot_yaxis_options.style.display = "none";
|
||||
csv_bar_orientation.style.display = "none";
|
||||
csv_plot_yaxis_options.querySelector(
|
||||
"#csv_percent_change_div"
|
||||
).style.display = "inline-block";
|
||||
|
||||
if (csv_file.files.length > 0) {
|
||||
console.log("file selected");
|
||||
@@ -158,7 +161,7 @@ function checkFile(popup, type = false) {
|
||||
`;
|
||||
|
||||
csv_colors.innerHTML = `
|
||||
<b>Candlestick colors:</b><br><br>
|
||||
<b>Candlestick colors:</b><br>
|
||||
|
||||
<label for="csv_increasing">Increasing</label>
|
||||
<input type="color" id="csv_increasing" value="#00ACFF"></input>
|
||||
@@ -175,11 +178,13 @@ function checkFile(popup, type = false) {
|
||||
headers[headers_lower.indexOf("date")];
|
||||
}
|
||||
}
|
||||
globals.CSV_DIV.querySelector("#csv_percent_change_div").style.display = "none";
|
||||
globals.CSV_DIV.querySelector("#csv_percent_change_div").style.display =
|
||||
"none";
|
||||
} else {
|
||||
let color_text = csv_type.value == "bar" ? "Bar color" : "Line color";
|
||||
csv_columns.innerHTML = `
|
||||
<b>Columns:</b><br>
|
||||
<div style="margin-top: 5px; margin-bottom: 5px;">
|
||||
<div style="margin-top: 5px; margin-bottom: 10px;">
|
||||
<label for="csv_x">X axis</label>
|
||||
<select id="csv_x">
|
||||
${options}
|
||||
@@ -189,11 +194,12 @@ function checkFile(popup, type = false) {
|
||||
<label for="csv_y">Y axis</label>
|
||||
<select id="csv_y">
|
||||
${options}
|
||||
</select><br><br>
|
||||
</select>
|
||||
</div>
|
||||
`;
|
||||
csv_colors.innerHTML = `
|
||||
<label for="csv_color"><b>Line color:</b></label>
|
||||
<label style="margin-top: 10px; margin-bottom: 10px;"
|
||||
for="csv_color"><b>${color_text}:</b></label>
|
||||
<input type="color" id="csv_color" value="#FFDD00"></input>
|
||||
`;
|
||||
|
||||
@@ -213,7 +219,13 @@ function checkFile(popup, type = false) {
|
||||
headers[headers_lower.indexOf("close")];
|
||||
}
|
||||
}
|
||||
csv_scatter_options.style.display = "inline-block";
|
||||
if (csv_type.value == "bar") {
|
||||
csv_bar_orientation.style.display = "inline-block";
|
||||
globals.CSV_DIV.querySelector("#csv_percent_change_div").style.display =
|
||||
"none";
|
||||
}
|
||||
|
||||
csv_plot_yaxis_options.style.display = "inline-block";
|
||||
|
||||
// we try to guess the date and time to remove from the name of the file
|
||||
// if "_" in the name of the file,
|
||||
|
||||
304
openbb_terminal/core/plots/web/popups.js
vendored
304
openbb_terminal/core/plots/web/popups.js
vendored
@@ -1,39 +1,26 @@
|
||||
function get_popup(data = null, popup_id = null) {
|
||||
let popup = null;
|
||||
popup_id = popup_id.replace("popup_", "");
|
||||
const style =
|
||||
"padding: 5px 2px 2px 5px !important; margin: 2px 0 !important;";
|
||||
|
||||
if (popup_id == "title") {
|
||||
data = globals.CHART_DIV.layout;
|
||||
let use_xaxis = data.xaxis ? "xaxis" : "xaxis2";
|
||||
let use_yaxis = data.yaxis ? "yaxis" : "yaxis2";
|
||||
|
||||
let title = globals.title;
|
||||
let xaxis =
|
||||
"title" in data[use_xaxis] && "text" in data[use_xaxis].title
|
||||
? data[use_xaxis].title.text
|
||||
: "";
|
||||
let yaxis =
|
||||
"title" in data[use_yaxis] && "text" in data[use_yaxis].title
|
||||
? data[use_yaxis].title.text
|
||||
: "";
|
||||
data = globals.CHART_DIV.layout;
|
||||
let yaxes = Object.keys(data).filter((k) => k.startsWith("yaxis"));
|
||||
let xaxes = Object.keys(data).filter((k) => k.startsWith("xaxis"));
|
||||
|
||||
globals.TITLE_DIV.innerHTML = `
|
||||
<div style="display:flex; flex-direction: column; gap: 6px;">
|
||||
<div>
|
||||
<label for="title_text">Title:</label>
|
||||
<textarea
|
||||
id="title_text" style="width: 100%; max-width: 100%;
|
||||
id="title_text" style="${style} width: 100%; max-width: 100%;
|
||||
max-height: 200px; margin-top: 8px;" rows="2" cols="20"
|
||||
value="${title}"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label for="title_xaxis">X axis:</label>
|
||||
<input id="title_xaxis" type="text" value="${xaxis}"></input>
|
||||
</div>
|
||||
<div>
|
||||
<label for="title_yaxis">Y axis:</label>
|
||||
<input id="title_yaxis" type="text" value="${yaxis}"></input>
|
||||
value="${title}">${title}</textarea>
|
||||
</div>
|
||||
<div id="xaxis_div"></div>
|
||||
<div id="yaxis_div"></div>
|
||||
</div>
|
||||
|
||||
<div style="float: right; margin-top: 20px;">
|
||||
@@ -42,12 +29,49 @@ function get_popup(data = null, popup_id = null) {
|
||||
</div>
|
||||
`;
|
||||
|
||||
// if there are multiple titles we create an input for each
|
||||
let yaxis_div = "";
|
||||
for (let i = 0; i < yaxes.length; i++) {
|
||||
if (data[yaxes[i]]?.title?.text != undefined) {
|
||||
let title = data[yaxes[i]].title.text;
|
||||
yaxis_div += `
|
||||
<div style="margin-top: 10px;">
|
||||
<label for="title_${yaxes[i]}">Y axis ${i + 1}:</label>
|
||||
<input id="title_${
|
||||
yaxes[i]
|
||||
}" style="${style}" type="text" value="${title}"></input>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
if (yaxis_div != "") {
|
||||
globals.TITLE_DIV.querySelector("#yaxis_div").innerHTML = yaxis_div;
|
||||
}
|
||||
|
||||
let xaxis_div = "";
|
||||
for (let i = 0; i < xaxes.length; i++) {
|
||||
if (data[xaxes[i]]?.title?.text != undefined) {
|
||||
let title = data[xaxes[i]].title.text;
|
||||
xaxis_div += `
|
||||
<div style="margin-top: 10px;">
|
||||
<label for="title_${xaxes[i]}">X axis ${i + 1}:</label>
|
||||
<input id="title_${
|
||||
xaxes[i]
|
||||
}" style="${style}" type="text" value="${title}"></input>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
if (xaxis_div != "") {
|
||||
globals.TITLE_DIV.querySelector("#xaxis_div").innerHTML = xaxis_div;
|
||||
}
|
||||
|
||||
// when opening the popup, we make sure to focus on the title input
|
||||
globals.TITLE_DIV.style.display = "inline-block";
|
||||
globals.TITLE_DIV.querySelector("#title_text").focus();
|
||||
popup = globals.TITLE_DIV;
|
||||
} else if (popup_id == "text") {
|
||||
let has_annotation = false;
|
||||
let has_annotation = data == undefined ? false : true;
|
||||
if (data == undefined) {
|
||||
data = {
|
||||
text: "",
|
||||
@@ -57,8 +81,6 @@ function get_popup(data = null, popup_id = null) {
|
||||
},
|
||||
bordercolor: "#822661",
|
||||
};
|
||||
} else {
|
||||
has_annotation = true;
|
||||
}
|
||||
|
||||
// we replace <br> with \n so that the textarea can display the text properly
|
||||
@@ -75,9 +97,9 @@ function get_popup(data = null, popup_id = null) {
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label for="popup_textarea"><b>Text:</b>
|
||||
<div id="popup_textarea_warning" class="popup_warning">Text is required</div></label><br>
|
||||
<textarea id="addtext_textarea" style="width: 100%; max-width: 100%; max-height: 200px; margin-top: 8px;" rows="4" cols="50" value="${
|
||||
data.text
|
||||
}"
|
||||
<textarea id="addtext_textarea" style="${style}
|
||||
width: 100%; max-width: 100%; max-height: 200px;
|
||||
margin-top: 8px;" rows="4" cols="50" value="${data.text}"
|
||||
placeholder="Enter text here">${data.text}</textarea><br>
|
||||
</div>
|
||||
<div style="display:flex;justify-content: space-between;">
|
||||
@@ -98,9 +120,9 @@ function get_popup(data = null, popup_id = null) {
|
||||
<div style="display:flex;justify-content: space-between;">
|
||||
<div>
|
||||
<label for="addtext_size"><b>Font size:</b></label>
|
||||
<input style="width: 45px;" type="number" id="addtext_size" value="${
|
||||
data.font.size
|
||||
}"></input>
|
||||
<input style="${style} width: 45px;" type="number" id="addtext_size" value="${
|
||||
data.font.size
|
||||
}"></input>
|
||||
</div>
|
||||
<div>
|
||||
<label for="addtext_above"><b>Position (Above):</b></label>
|
||||
@@ -154,7 +176,8 @@ function get_popup(data = null, popup_id = null) {
|
||||
class="_btn"
|
||||
href="https://twitter.com/intent/tweet?text=Check this chart from @openbb_finance - ${data.url}"
|
||||
>Share</a>
|
||||
<button onclick="navigator.clipboard.writeText('${data.url}')" style="margin-top: 10px;" class="_btn">Copy to clipboard</button>
|
||||
<button onclick="navigator.clipboard.writeText('${data.url}')" style="margin-top: 10px;"
|
||||
class="_btn">Copy to clipboard</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -178,11 +201,34 @@ function get_popup_data(popup_id = null) {
|
||||
let data = null;
|
||||
|
||||
if (popup_id == "title") {
|
||||
data = {
|
||||
title: globals.TITLE_DIV.querySelector("#title_text").value,
|
||||
xaxis: globals.TITLE_DIV.querySelector("#title_xaxis").value,
|
||||
yaxis: globals.TITLE_DIV.querySelector("#title_yaxis").value,
|
||||
};
|
||||
data = { title: globals.TITLE_DIV.querySelector("#title_text").value };
|
||||
|
||||
let xaxis_div = globals.TITLE_DIV.querySelector("#xaxis_div");
|
||||
let yaxis_div = globals.TITLE_DIV.querySelector("#yaxis_div");
|
||||
console.log("xaxis_div: ", xaxis_div, "yaxis_div: ", yaxis_div);
|
||||
|
||||
if (xaxis_div != null) {
|
||||
// We query all inputs that start with 'title_xaxis'
|
||||
let xaxis_inputs = xaxis_div.querySelectorAll(
|
||||
"input[id^=title_xaxis], select[id^=title_xaxis]"
|
||||
);
|
||||
xaxis_inputs.forEach(function (input) {
|
||||
let xaxis_id = input.id.replace("title_", "");
|
||||
data[xaxis_id] = input.value;
|
||||
});
|
||||
}
|
||||
|
||||
if (yaxis_div != null) {
|
||||
// We query all inputs that start with 'title_yaxis'
|
||||
let yaxis_inputs = yaxis_div.querySelectorAll(
|
||||
"input[id^=title_yaxis], select[id^=title_yaxis]"
|
||||
);
|
||||
yaxis_inputs.forEach(function (input) {
|
||||
let yaxis_id = input.id.replace("title_", "");
|
||||
data[yaxis_id] = input.value;
|
||||
});
|
||||
}
|
||||
console.log("Title data:", data);
|
||||
} else if (popup_id == "text") {
|
||||
data = {
|
||||
text: globals.TEXT_DIV.querySelector("#addtext_textarea").value,
|
||||
@@ -201,7 +247,7 @@ function get_popup_data(popup_id = null) {
|
||||
|
||||
// we replace \n with <br> so that line breaks are displayed properly on the graph
|
||||
data.text = data.text.replace(/\n/g, "<br>");
|
||||
console.log(data);
|
||||
console.log("Text data:", data);
|
||||
} else if (popup_id == "csv") {
|
||||
let trace_type = globals.CSV_DIV.querySelector("#csv_trace_type").value;
|
||||
if (trace_type == "candlestick") {
|
||||
@@ -217,7 +263,7 @@ function get_popup_data(popup_id = null) {
|
||||
? true
|
||||
: false,
|
||||
};
|
||||
} else {
|
||||
} else if (trace_type == "scatter") {
|
||||
data = {
|
||||
x: globals.CSV_DIV.querySelector("#csv_x").value,
|
||||
y: globals.CSV_DIV.querySelector("#csv_y").value,
|
||||
@@ -230,15 +276,44 @@ function get_popup_data(popup_id = null) {
|
||||
? true
|
||||
: false,
|
||||
};
|
||||
console.log(data);
|
||||
} else if (trace_type == "bar") {
|
||||
let orientation = globals.CSV_DIV.querySelector("#csv_bar_horizontal")
|
||||
.checked
|
||||
? "h"
|
||||
: "v";
|
||||
data = {
|
||||
x: globals.CSV_DIV.querySelector("#csv_x").value,
|
||||
y: globals.CSV_DIV.querySelector("#csv_y").value,
|
||||
color: globals.CSV_DIV.querySelector("#csv_color").value,
|
||||
same_yaxis: globals.CSV_DIV.querySelector("#csv_same_yaxis").checked
|
||||
? true
|
||||
: false,
|
||||
orientation: orientation,
|
||||
};
|
||||
}
|
||||
data.name = globals.CSV_DIV.querySelector("#csv_name").value;
|
||||
data.file = globals.CSV_DIV.querySelector("#csv_file");
|
||||
data.trace_type = trace_type;
|
||||
data.name = globals.CSV_DIV.querySelector("#csv_name").value;
|
||||
console.log("CSV data:", data);
|
||||
data.file = globals.CSV_DIV.querySelector("#csv_file");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
const trace_defaults = {
|
||||
overlaying: "y",
|
||||
side: "left",
|
||||
tickfont: { size: 12 },
|
||||
tickpadding: 5,
|
||||
showgrid: false,
|
||||
showline: false,
|
||||
showticklabels: true,
|
||||
showlegend: true,
|
||||
zeroline: false,
|
||||
anchor: "x",
|
||||
type: "linear",
|
||||
autorange: true,
|
||||
};
|
||||
|
||||
function on_submit(popup_id, on_annotation = null) {
|
||||
// popup_id is either 'title', 'text', or 'csv' (for now)
|
||||
// and is used to determine which popup to get data from
|
||||
@@ -260,6 +335,7 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
}
|
||||
|
||||
gd.on("plotly_clickannotation", function (eventData) {
|
||||
console.log("plotly_clickannotation", eventData);
|
||||
let annotation = eventData.annotation;
|
||||
openPopup("popup_text");
|
||||
get_popup(annotation, (popup_id = "text"));
|
||||
@@ -276,6 +352,7 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
});
|
||||
|
||||
let clickHandler = function (eventData) {
|
||||
console.log("plotly_click", eventData);
|
||||
let x = eventData.points[0].x;
|
||||
let yaxis = eventData.points[0].fullData.yaxis;
|
||||
let y = 0;
|
||||
@@ -312,13 +389,20 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
return;
|
||||
}
|
||||
} else if (popup_id == "title") {
|
||||
let yaxis = gd.layout.yaxis ? "yaxis" : "yaxis2";
|
||||
let xaxis = gd.layout.xaxis ? "xaxis" : "xaxis2";
|
||||
document.getElementById("title").innerHTML = popup_data.title;
|
||||
let to_update = { title: popup_data.title };
|
||||
to_update[xaxis + ".title"] = popup_data.xaxis;
|
||||
to_update[yaxis + ".title"] = popup_data.yaxis;
|
||||
to_update[yaxis + ".type"] = "linear";
|
||||
|
||||
let to_update = {};
|
||||
|
||||
Object.keys(popup_data).forEach(function (key) {
|
||||
if (key != "title") {
|
||||
to_update[key + ".title"] = popup_data[key];
|
||||
}
|
||||
if (key.includes("yaxis")) {
|
||||
to_update[key + ".type"] = "linear";
|
||||
}
|
||||
});
|
||||
|
||||
console.log(to_update);
|
||||
|
||||
Plotly.update(gd, {}, to_update);
|
||||
} else if (popup_id == "csv") {
|
||||
@@ -355,7 +439,25 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
}
|
||||
});
|
||||
|
||||
// We check how many yaxis have ticklabels on the left
|
||||
let left_yaxis_ticks = Object.keys(gd.layout)
|
||||
.filter((k) => k.startsWith("yaxis"))
|
||||
.map((k) => gd.layout[k])
|
||||
.filter(
|
||||
(yaxis) =>
|
||||
yaxis.side == "left" &&
|
||||
(yaxis.overlaying == "y" ||
|
||||
(yaxis.fixedrange != undefined && yaxis.fixedrange == true))
|
||||
).length;
|
||||
|
||||
// Multiply by 5 to get the xshift for cmd source text
|
||||
let add_xshift = Math.min(left_yaxis_ticks * 5, 30);
|
||||
|
||||
// We set showlegend's to true
|
||||
main_trace.showlegend = true;
|
||||
gd.layout.showlegend = true;
|
||||
|
||||
// Just in case xaxis/yaxis is not defined
|
||||
if (main_trace.xaxis == undefined) {
|
||||
main_trace.xaxis = "x";
|
||||
}
|
||||
@@ -363,8 +465,12 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
main_trace.yaxis = "y";
|
||||
}
|
||||
|
||||
// Set the yaxis id
|
||||
let yaxis_id = main_trace.yaxis;
|
||||
let yaxis;
|
||||
|
||||
// If we want to plot on a secondary yaxis
|
||||
// we get the number of yaxis and add 1 to it
|
||||
if (popup_data.same_yaxis == false) {
|
||||
let yaxes = Object.keys(gd.layout)
|
||||
.filter((k) => k.startsWith("yaxis"))
|
||||
@@ -373,6 +479,9 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
yaxis = `y${yaxes.length + 1}`;
|
||||
yaxis_id = `yaxis${yaxes.length + 1}`;
|
||||
console.log(`yaxis: ${yaxis} ${yaxis_id}`);
|
||||
|
||||
// If percent change is true we set the yaxis id
|
||||
// in the globals so we can use it later
|
||||
if (
|
||||
globals.csv_yaxis_id == null &&
|
||||
popup_data.percent_change == true
|
||||
@@ -381,11 +490,35 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
globals.csv_yaxis = yaxis;
|
||||
}
|
||||
} else {
|
||||
// Plot on the same yaxis
|
||||
yaxis = main_trace.yaxis.replace("yaxis", "y");
|
||||
yaxis_id = main_trace.yaxis;
|
||||
}
|
||||
gd.layout.showlegend = true;
|
||||
|
||||
// We get the yaxis ticksuffix
|
||||
let ticksuffix = left_yaxis_ticks > 0 ? " " : "";
|
||||
if (globals.percent_yaxis_added || globals.added_traces.length > 0) {
|
||||
ticksuffix = " ".repeat(left_yaxis_ticks);
|
||||
}
|
||||
|
||||
// Bar trace
|
||||
if (popup_data.trace_type == "bar") {
|
||||
trace = {
|
||||
x: data.map(function (row) {
|
||||
return row[popup_data.x];
|
||||
}),
|
||||
y: data.map(function (row) {
|
||||
return row[popup_data.y];
|
||||
}),
|
||||
type: popup_data.trace_type,
|
||||
name: popup_data.name,
|
||||
marker: { color: popup_data.color, opacity: 0.7 },
|
||||
orientation: popup_data.orientation,
|
||||
showlegend: true,
|
||||
yaxis: yaxis,
|
||||
};
|
||||
}
|
||||
|
||||
// Candlestick trace
|
||||
if (popup_data.trace_type == "candlestick") {
|
||||
trace = {
|
||||
x: data.map(function (row) {
|
||||
@@ -410,8 +543,11 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
showlegend: true,
|
||||
yaxis: yaxis,
|
||||
};
|
||||
} else {
|
||||
}
|
||||
|
||||
// Scatter trace
|
||||
if (popup_data.trace_type == "scatter") {
|
||||
// We get the first non null value
|
||||
orginal_data = data;
|
||||
let non_null = data.findIndex(
|
||||
(x) => x[popup_data.y] != null && x[popup_data.y] != 0
|
||||
@@ -446,18 +582,15 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
yaxis: popup_data.percent_change ? globals.csv_yaxis : yaxis,
|
||||
};
|
||||
|
||||
// For the percent change we add a new yaxis
|
||||
// if it doesn't exist
|
||||
if (
|
||||
!globals.percent_yaxis_added &&
|
||||
popup_data.percent_change == true &&
|
||||
popup_data.same_yaxis == false
|
||||
) {
|
||||
let ticksuffix =
|
||||
gd.data.length > 1
|
||||
? " ".repeat(globals.added_traces.length + 1)
|
||||
: "";
|
||||
gd.layout[yaxis_id] = {
|
||||
overlaying: "y",
|
||||
side: "left",
|
||||
...trace_defaults,
|
||||
title: {
|
||||
text: "% Change",
|
||||
font: {
|
||||
@@ -465,38 +598,27 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
},
|
||||
standoff: 0,
|
||||
},
|
||||
tickfont: { size: 14 },
|
||||
ticksuffix: ticksuffix,
|
||||
tickformat: ".0%",
|
||||
tickpadding: 5,
|
||||
showgrid: false,
|
||||
showlegend: true,
|
||||
showline: false,
|
||||
showticklabels: true,
|
||||
zeroline: false,
|
||||
anchor: "x",
|
||||
type: "linear",
|
||||
autorange: true,
|
||||
};
|
||||
globals.percent_yaxis_added = true;
|
||||
if (globals.cmd_src_idx != null) {
|
||||
gd.layout.annotations[globals.cmd_src_idx].xshift -=
|
||||
gd.data.length > 1 ? 40 : 35;
|
||||
gd.layout.margin.l += gd.data.length > 1 ? 50 : 45;
|
||||
let xshift = gd.layout.annotations[globals.cmd_src_idx].xshift;
|
||||
xshift -= left_yaxis_ticks > 0 ? 50 + add_xshift : 35;
|
||||
|
||||
// just in case we have a lot of yaxis
|
||||
xshift += xshift < -320 ? 10 + 2 * left_yaxis_ticks : 0;
|
||||
|
||||
gd.layout.annotations[globals.cmd_src_idx].xshift = xshift;
|
||||
gd.layout.margin.l += left_yaxis_ticks > 0 ? 50 + add_xshift : 45;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New yaxis and not percent change
|
||||
if (!popup_data.percent_change && popup_data.same_yaxis == false) {
|
||||
let ticksuffix = gd.data.length > 1 ? " " : "";
|
||||
if (globals.percent_yaxis_added || globals.added_traces.length > 0) {
|
||||
ticksuffix = " ".repeat(globals.added_traces.length + 1);
|
||||
}
|
||||
|
||||
console.log(`data.length: ${gd.data.length}`);
|
||||
gd.layout[yaxis_id] = {
|
||||
overlaying: "y",
|
||||
side: "left",
|
||||
...trace_defaults,
|
||||
title: {
|
||||
text: popup_data.name,
|
||||
font: {
|
||||
@@ -504,25 +626,21 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
},
|
||||
standoff: 0,
|
||||
},
|
||||
tickfont: { size: 14 },
|
||||
ticksuffix: ticksuffix,
|
||||
tickpadding: 5,
|
||||
showgrid: false,
|
||||
showline: false,
|
||||
showticklabels: true,
|
||||
showlegend: true,
|
||||
zeroline: false,
|
||||
anchor: "x",
|
||||
type: "linear",
|
||||
autorange: true,
|
||||
layer: "below traces",
|
||||
};
|
||||
if (globals.cmd_src_idx != null) {
|
||||
gd.layout.annotations[globals.cmd_src_idx].xshift -=
|
||||
globals.added_traces.length > 1 ? 45 : 35;
|
||||
gd.layout.margin.l += globals.added_traces.length > 1 ? 50 : 45;
|
||||
let xshift = gd.layout.annotations[globals.cmd_src_idx].xshift;
|
||||
xshift -= left_yaxis_ticks > 0 ? 40 + add_xshift : 40;
|
||||
|
||||
// just in case we have a lot of yaxis
|
||||
xshift += xshift < -320 ? 10 + 2 * left_yaxis_ticks : 0;
|
||||
|
||||
gd.layout.annotations[globals.cmd_src_idx].xshift = xshift;
|
||||
gd.layout.margin.l += left_yaxis_ticks > 0 ? 50 : 45;
|
||||
}
|
||||
}
|
||||
console.log(trace);
|
||||
console.log("trace: ", trace);
|
||||
|
||||
globals.added_traces.push(trace.name);
|
||||
|
||||
@@ -536,7 +654,7 @@ function on_submit(popup_id, on_annotation = null) {
|
||||
// We empty the fields and innerHTML after the plot is made
|
||||
globals.CSV_DIV.querySelector("#csv_colors").innerHTML = "";
|
||||
globals.CSV_DIV.querySelector("#csv_columns").innerHTML = "";
|
||||
globals.CSV_DIV.querySelector("#csv_scatter_options").style.display =
|
||||
globals.CSV_DIV.querySelector("#csv_plot_yaxis_options").style.display =
|
||||
"none";
|
||||
|
||||
globals.CSV_DIV.querySelectorAll("input").forEach(function (input) {
|
||||
|
||||
@@ -271,7 +271,6 @@ def display_candle(
|
||||
if add_trend:
|
||||
fig.add_trend(data, secondary_y=has_volume)
|
||||
|
||||
fig.add_logscale_menus("yaxis2" if has_volume else "yaxis")
|
||||
fig.update_yaxes(type=yscale, row=1, col=1, nticks=20, secondary_y=has_volume)
|
||||
|
||||
return fig.show(external=external_axes)
|
||||
|
||||
@@ -373,7 +373,7 @@ class BehaviouralAnalysisController(StockBaseController):
|
||||
"--display",
|
||||
action="store_true",
|
||||
dest="display",
|
||||
default=True,
|
||||
default=False,
|
||||
help="Print table of sentiment values",
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
|
||||
@@ -663,7 +663,6 @@ def display_candle(
|
||||
fig.add_trend(data, secondary_y=True)
|
||||
|
||||
fig.update_layout(yaxis2=dict(title="Stock Price ($)", type=yscale))
|
||||
fig.add_logscale_menus("yaxis2")
|
||||
|
||||
return fig.show(external=external_axes)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user