Search code examples
javascriptpythonplotbokehbokehjs

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

Graph output

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


Solution

  • 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");