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:
teh_coderer
2023-04-03 11:25:08 -05:00
committed by GitHub
parent 13a91af400
commit 43dbc12e17
9 changed files with 274 additions and 131 deletions

View File

@@ -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 = []

View File

@@ -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">

View File

@@ -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

View File

@@ -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",

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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]:

View File

@@ -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)