Why is my bar plots disappear when scatter plots appear? - javascript

I want to display some scatter dots at the right-end edge of the bars and successfully did it, as shown in the Image 1 below.
But when there is only one length of data for the bar chart to draw, the bar disappears or become super thin, so only scatter dot are visible, as shown in Image 2 below.
Then, I disabled the scatter trace and the bars are visible as shown in Image 3 below.
Below are the scripts to produce these plots.
let initial = new Date("2020-11-08T00:00:00.000Z");
let final = new Date("2020-12-08T00:00:00.000Z");
let half = new Date((initial.getTime() + final.getTime())/2);
Plotly.newPlot(
testplot, {
data: [
{ y: [1000], x: [half], type: 'bar', offsetgroup: 0},
{ y: [1000], x: [half], type: 'bar', offsetgroup: 1},
{ y: [250], x: [final]},
], layout: { title: 'single bar', bargap: 0}, config: { responsive: true },
}
);
let t0 = initial, t1 = half, t2 = final;
let h0 = new Date((t0.getTime() + t1.getTime())/2);
let h1 = new Date((t1.getTime() + t2.getTime())/2);
Plotly.newPlot(
testplot2, {
data: [
{ y: [500, 750], base: [0, 250], x: [h0, h1], type: 'bar', offsetgroup: 0},
{ y: [500, 750], base: [0, 250], x: [h0, h1], type: 'bar', offsetgroup: 1},
{ y: [200, 800], x: [half, final]}
], layout: { title: 'more than one bar', bargap: 0 }, config: { responsive: true }
}
)
Right now, I have to calculate the midpoint of the date myself so I can offset the bars to the left so the dots appear at the right-edge of the bars. If I use the default dates to plot the bars and the dots, the dots will be placed at the center of the bars, but the bar on "single bar" did not disappear, as shown in Image 4 below.
I have no issue when the data length is more than one, but when the length is one; is there any way to make bars filled the canvas and the dot stays at the right edge? or how to offset the dots to the right?

Related

How to customise distance between tickers on the 2nd y-axis in BokehJS

So I'm trying to create a plot with BokehJS. This plot needs 3 axes (left, right, bottom):
The plot looks like this
As you can see, the right y-axis is pretty ugly, you can't read any data from towards the bottom as the tickers are bunched up.
This is how im creating my plot and lines
function zip(arr1, arr2, floatCast){
var out = {};
if (floatCast){
arr1.map( (val,idx)=>{ out[parseFloat(val)] = arr2[idx]; } );
}
else{
arr1.map( (val,idx)=>{ out[val] = arr2[idx]; } );
}
return out;
}
function createBokehPlot(PNVibe, staticPN, transX, transY){
//empty the previous plot
$( "#graph-div" ).empty();
//Data Source for PN under vibration vs. offset frequency
const source = new Bokeh.ColumnDataSource({
data: { x: Object.keys(PNVibe), y: Object.values(PNVibe) }
});
//Data source for Static PN vs offset frequency
const source1 = new Bokeh.ColumnDataSource({
data: { x: Object.keys(staticPN), y: Object.values(staticPN) }
});
//Data source for Transmissibility line
const source2 = new Bokeh.ColumnDataSource({
data: { x: transX, y: transY}
});
//Set plot x/y ranges
var max_offset = Math.max(Object.keys(PNVibe));
const xdr = new Bokeh.Range1d({ start: 1, end: 100000 });
const ydr = new Bokeh.Range1d({ start: -180, end: -50 });
const y2_range = new Bokeh.Range1d({start: 0.001, end: 10});
// make a plot with some tools
const plot = Bokeh.Plotting.figure({
title: 'Example of random data',
tools: "pan,wheel_zoom,box_zoom,reset,save",
toolbar_location: "right",
toolbar_sticky: false,
height: 600,
width: 700,
outerWidth: 800,
legend_location: "top_left",
x_range: xdr,
y_range: ydr,
x_axis_type:"log",
x_axis_label: "Offset Frequency (Hz)",
y_axis_type: "linear",
y_axis_label: "Phase Noise (dBc/Hz)",
extra_y_ranges: {y2_range},
major_label_standoff: 1
});
//Add the second y axis on the right
const second_y_axis = new Bokeh.LogAxis({y_range_name:"y2_range", axis_label:'Vibration Profile (g^2/Hz)', x_range: xdr, bounds:[0.0001, 10]});
second_y_axis.ticker = new Bokeh.FixedTicker({ticks: [0.0001, 0.001, 0.01, 0.1, 1, 10]})
plot.add_layout(second_y_axis, "right");
// add line for vibraiton phase noise
plot.line({ field: "x" }, { field: "y" }, {
source: source,
line_width: 2,
line_color: "red",
legend_label: "Phase Noise under Vibrations"
});
//add line for static phase noise
plot.line({ field: "x" }, { field: "y" }, {
source: source1,
line_width: 2,
line_color: "blue",
legend_label: "Static Phase Noise"
});
plot.line({ field: "x" }, { field: "y" }, {
source: source2,
line_width: 2,
line_color: "green",
y_range_name:"y2_range",
legend_label: "Transmissibillity"
});
// show the plot, appending it to the end of the current section
Bokeh.Plotting.show(plot, "#graph-div");
return;
}
//Call function
var PNVibe = zip([10, 100, 1000], [-95, -100, -105], false);
var staticPN = zip([10, 100, 1000], [-90, -105, -110], false);
var transX = [10, 100, 1000];
var transY = [0.0005, 0.003, 0.05];
createBokehPlot(PNVibe, staticPN, transX, transY);
My question is, how would I be able to make it so that the right y-axis displays better? Preferably I want each tick to be the same distance from each other (ie. space between 10^0 and 10^1 is the same as space between 10^1 and 10^2)
Thanks
I also posted this on the bokeh forums:Here
Fixed my problem:
I believe I may have had some invalid javascript in my original code which is why it wasnt correctly rendering. After hours of messing around with whatever I could think of, it's fixed.
//Define range for y2
const y2_range = new Bokeh.Range1d({start: 0.0001, end: 10}); //Cannot use //array for this
// make a plot with some tools
const plot = Bokeh.Plotting.figure({
title: 'Example of random data',
tools: "pan,wheel_zoom,box_zoom,reset,save,hover",
toolbar_location: "right",
toolbar_sticky: false,
height: 600,
width: 700,
outerWidth: 800,
legend_location: "top_left",
x_range: [1, 1000000],
y_range: [-180, -70],
x_axis_type:"log",
x_axis_label: "Offset Frequency (Hz)",
y_axis_label: "Phase Noise (dBc/Hz)",
extra_y_ranges: {"y2_range": y2_range}, //This was incorrect
extra_y_scales: {"y2_range": new Bokeh.LogScale()}, //This was incorrect
major_label_standoff: 5,
});
//Add the second y axis on the right
const second_y_axis = new Bokeh.LogAxis({
y_range_name:"y2_range",
axis_label:'Vibration Profile (g^2/Hz)',
x_range: [1, 1000000],
bounds:[0.0001, 10],
});
plot.add_layout(second_y_axis, "right");

how to add a needle or dial to gauge indicator in plotly.js?

I'm having hard time adding the dial/needle to the gauge chart from plotly.js.
gauge without needle
: As you could see in the image above it's gauge chart without any needle.
gauge with needle
: I want to build something similar to "gauge with needle", which is giving me hard time.
my code for "gauge without needle/dial" :
`https://codepen.io/vivek137/pen/rNyembX`
You will need to add an arrow annotation on top of your gauge chart. I answered a similar question and in that answer, I described how you can use polar coordinates to find out the ending position x and y for your arrow. Under the hood, the gauge chart you made has an x-range of [0,1] and a y-range of [0,1], so the starting point is ax=0.5 and ax=0 which are both parameters for your annotation. Then the ending position is given by x = 0.5 + r * cos(theta) and y = r * sin(theta) where theta is the angle taken from the right side of the chart and moving counterclockwise.
One thing you should keep in mind is that if the render area in your browser isn't a perfect square, then the r and theta values may need to be adjusted. For example, in my codepen, I used r=0.7, theta=93.5 to point to the 40.
let data = [
{
mode: "gauge",
type: "indicator",
value: 40,
gauge: {
shape: "angular",
bar: {
color: "blue",
line: {
color: "red",
width: 4
},
thickness: 0
},
bgcolor: "#388",
bordercolor: "#a89d32",
borderwidth: 3,
axis: {
range: [0,100],
visible: true,
tickmode: "array",
tickvals: [5, 10, 40, 80, 100],
ticks: "outside"
},
steps: [
{
range: [0, 40],
color: "#9032a8"
}
]
}
}
]
var theta = 93.5
var r = 0.7
var x_head = r * Math.cos(Math.PI/180*theta)
var y_head = r * Math.sin(Math.PI/180*theta)
let layout = {
xaxis: {range: [0, 1], showgrid: false, 'zeroline': false, 'visible': false},
yaxis: {range: [0, 1], showgrid: false, 'zeroline': false, 'visible': false},
showlegend: false,
annotations: [
{
ax: 0.5,
ay: 0,
axref: 'x',
ayref: 'y',
x: 0.5+x_head,
y: y_head,
xref: 'x',
yref: 'y',
showarrow: true,
arrowhead: 9,
}
]
};
Plotly.newPlot('gauge1', data, layout)

Plotly JavaScript: Customize y ticks or labels on y axis

Iam using Plotly.js https://plotly.com/javascript/. I am trying to develop a chart where I want to add a small image on each ticks on the y axis. For reference please see the image given below.
Notice the small gray discs on y axis (next to the texts "Red", "Green" and "Blue"). I am trying to achieve something like this. However on the reference document, I couldn't find anything that does this.
How can I achieve that?
[UPDATE]
After implementing the answer as suggested by #Ruben, and further making some updates, I get this little tip of the x-axis extended to the left to the negative side (ref. the screenshot of this extended tip below)
If it's really only about the dots, I've hacked together something that inserts this unicode shape as a solid, black circle at every bar using annotations. Then you can colour it if you want.
var data = [{
type: 'bar',
x: [20, 14, 23],
y: ['giraffes', 'orangutans', 'monkeys'],
orientation: 'h'
}];
var layout = {
annotations: data[0].y.map((v, i) => ({
x: -0.75,
y: i,
xref: 'x',
yref: 'y',
text: "⬤",
showarrow: false,
font: {
size: 14,
color: ['red', 'blue', 'green'][i % 3]
}
}))
};
Plotly.newPlot('myDiv', data, layout);
<script src='https://cdn.plot.ly/plotly-latest.js'></script>
<div id='myDiv'></div>
Edit: now using changed labels:
var data = [{
type: 'bar',
x: [20, 14, 23],
y: ['giraffes', 'orangutans', 'monkeys'],
orientation: 'h'
}];
data[0].y = data[0].y.map((v, i) => {
const color = ['red', 'blue', 'green'][i % 3];
return `${v} <span style="color: ${color};">⬤</span>`
})
var layout = {
xaxis: {
showline: true,
},
margin: {
l: 100,
}
};
Plotly.newPlot('myDiv', data, layout);
<script src='https://cdn.plot.ly/plotly-latest.js'></script>
<div id='myDiv'></div>

React plotly bar chart: color bars dependend on x value

I got the following code:
x: [1, 2, 3,4],
y: ['Who?', 'Where?', 'When?','What?'],
name: 'Subject',
orientation: 'h',
marker: {
color: 'rgba(55,128,191,0.6)',
width: 1
},
type: 'bar'
};
var data = [trace1];
var layout = {
title: 'Colored Bar Chart',
barmode: 'stack'
};
Plotly.newPlot('myDiv', data, layout, {showSendToCloud:true});
The label 'Who?' should be red, 'Where?' should be orange, 'When?'should be yellow and 'What?' should be green. How do I archive this?
I already looked at colorscale but couldnt make it work.
https://plot.ly/javascript/reference/#bar-marker-color
Sets themarkercolor. It accepts either a specific color or an array of
numbers that are mapped to the colorscale relative to the max and min
values of the array or relative to marker.cmin and marker.cmax if
set.
Like this:
marker: {
color: ['#ff0000', '#ff2200', 'rgba(55,128,191,0.6)', '#00ff00'],
width: 1
},
First color in array corresponds to first bar, 2nd to 2nd, etc

Charts.js - Bubble chart with two word axis

I need to create a bubble chart style chart which has two axis, both which are words rather than text.
In my example I want:
axis x to be colours, e.g. red, blue, Yellow
axis y to be cars, e.g. small car, medium car, big car
from this I want to plot how many of each car was ordered, e.g. if 2 small red cars were ordered and one big blue car was ordered there would be a bubble on small red which is twice the size of the bubble at big blue.
I have done a bit with charts.js, but none of my examples cover how to use text instead of numbers.
Any help would be greatly appreciated with this, I have looked through the documentation here.. enter link description here, but have not been able to get anything to work.
Thanks in advance.
I've recently had the same requirement for a dataset and utilised the callback function for each axis in the scale option. I populated the list of values for the labels into an array and then used the index of the point to perform a lookup to rename the tick label.
var colours = ["Red", "Blue", "Green", "Yellow"];
var carSizes = ["Small", "Medium", "Large"];
// Small Red = 10
// Small Green = 14
// Medium Yellow = 23
var dataPoints = [{x: 0, y: 0, r: 10}, {x: 2, y: 0, r: 14}, {x: 3, y: 1, r: 23}
var myBubbleChart = new Chart(bubbleCtx, {
type: 'bubble',
data: dataPoints,
options: {
title: {
display: true,
text: "Car Orders"
},
scales: {
yAxes: [{
ticks: {
stepSize: 1,
callback: function (value, index, values) {
if (index < carSizes.length) {
return carSizes[carSizes.length - (1 + index)]; //this is to reverse the ordering
}
}
},
position: 'left'
}],
xAxes: [{
ticks: {
stepSize: 1,
callback: function (value, index, values) {
if (index < colours.length) {
return colours[index];
}
}
},
position: 'bottom'
}]
}
}
});
After much trial and error, I found it necessary to set the step size to 1 otherwise the chart would get skewed with data appearing outside the gridlines.
If you are not setting the data dynamically and know the minimum and maximum values for each axis, you can set the min and max attributes for the ticks and specify the axis type as 'category'.
yAxes: [{
type: 'category',
ticks: {
stepSize: 1,
min: 'Small',
max: 'Large'
},
position: 'left'
}]
You can use line type chart with bordercolour radius 0. it will act as line chart and avoid line. It will appeared like bubble chart.

Categories