4

I'm trying to plot this but could not find any examples in stackoverflow or in plotly forum. I put the plotly js example here to reproduce the code better.But the real solution that I need in plotly python.

Thanks in advance for proving a guide or solution to this problem.

Some research but I have multi categorical x axis !!

Shiny: How to add a median line on a box plot using Plotly?

Plotly: How to add a median line on a box plot

enter image description here

Here is the code I've used. Ofcourse modified little bit to represent the actual plot that I want to have. https://plotly.com/javascript/axes/

var trace1 = {
  x: [
    
    ['giraffes', 'orangutans', 'monkeys','giraffes', 'orangutans', 'monkeys'],
    ['SF Zoo','SF Zoo','SF Zoo','SF Zoo','SF Zoo','SF Zoo']
  ],
  y: [5, 14, 23,12,13,14],
   boxpoints: 'all',
  name: 'SF Zoo',
  type: 'box',
  boxmean:true

};

var trace2 = {
  x: [
     ['giraffes', 'orangutans', 'monkeys','giraffes', 'orangutans', 'monkeys','monkeys','giraffes'],
    ['LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo']
  ],
  y: [12, 18, 29,22,11,19,12,26],
  //name: 'LA Zoo',
  type: 'box',
  boxmean:true,
  name: 'LA Zoo',

  boxpoints: 'all'
  
};

var x= [
    ['LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo'],
    ['giraffes', 'orangutans', 'monkeys','giraffes', 'orangutans', 'monkeys','monkeys','giraffes']
  ];

var y = [12, 18, 29,22,11,19,12,26];

var connecting_means = [{
  type: 'scatter',
  x: x,
  y: y,
  //mode: 'line',
  transforms: [{
    type: 'aggregate',
    groups: x,
    aggregations: [
      {target: 'y', func: 'mean', enabled: true}]}]
}];

var data = [trace1, trace2,connecting_means];
var layout = {
  showlegend: true,
  xaxis: {
    tickson: "boundaries",
    ticklen: 15,
    showdividers: true,
    dividercolor: 'grey',
    dividerwidth: 3
  }
};


Plotly.newPlot('myDiv', data, layout,connecting_means);
<head>
    <!-- Load plotly.js into the DOM -->
    <script src='https://cdn.plot.ly/plotly-2.4.2.min.js'></script>
</head>

<body>
    <div id='myDiv'><!-- Plotly chart will be drawn inside this DIV --></div>
</body>

5
  • As far as I know, we don't have that feature, so how about a way to annotate the lines Commented Nov 14, 2021 at 2:24
  • @r-beginners are you one of the developer from plotly? what do you mean by annotate lines ? Commented Nov 14, 2021 at 2:44
  • No, I am not involved in the development of plotly. Commented Nov 14, 2021 at 2:48
  • @r-beginners if so why you said ‘we dont have that feature’? Commented Nov 14, 2021 at 2:49
  • I may have chosen the wrong words. I meant that I have not seen any examples or features Commented Nov 14, 2021 at 2:51

1 Answer 1

1

As @r-beginners commented, Plotly doesn't have the ability to extract boxplot statistics (such as the median or quartiles). Therefore, you will need to manually calculate the median of each box, and draw lines between the boxes as traces.

Here is a solution in Plotly.js where we create arrays for each individual boxplot, find their medians using the median function written by @JBallin, and connect them using additional traces. I've restructured your data a bit, and used a loop to connect the boxes within each category. You can find the codepen here.

var giraffe_sf = [5,12]
var giraffe_la = [12,22,26]
var orang_sf = [13,14]
var orang_la = [18,11]
var monkeys_sf = [14,24]
var monkeys_la = [29,19,12]

sf_y = giraffe_sf.concat(orang_sf, monkeys_sf)
la_y = giraffe_la.concat(orang_la, monkeys_la)

var categories = ['giraffes', 'orangutans', 'monkeys']
var all_data = [[giraffe_sf, giraffe_la], [orang_sf, orang_la], [monkeys_sf, monkeys_la]]

function median(numbers) {
    const sorted = numbers.slice().sort((a, b) => a - b);
    const middle = Math.floor(sorted.length / 2);

    if (sorted.length % 2 === 0) {
        return (sorted[middle - 1] + sorted[middle]) / 2;
    }

    return sorted[middle];
}

// sort the arrays
var trace1 = {
  x: [
    ['giraffes', 'giraffes', 'orangutans', 'orangutans', 'monkeys', 'monkeys'],
    ['SF Zoo','SF Zoo','SF Zoo','SF Zoo','SF Zoo','SF Zoo']
  ],
  y: sf_y,
   boxpoints: 'all',
  name: 'SF Zoo',
  type: 'box',
  boxmean:true

};

var trace2 = {
  x: [
     ['giraffes', 'giraffes', 'giraffes', 'orangutans', 'orangutans', 'monkeys','monkeys', 'monkeys'],
    ['LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo','LA Zoo']
  ],
  y: la_y,
  type: 'box',
  boxmean:true,
  name: 'LA Zoo',
  boxpoints: 'all'
};

var data = [trace1, trace2];

for (let i = 0; i < categories.length; i++) {
  trace = {
    x: [
      [categories[i], categories[i]],
      ['SF Zoo','LA Zoo']
    ],
    y: [median(all_data[i][0]),median(all_data[i][1])],
    mode: 'lines',
    type: 'scatter',
    marker: {color: 'black'},
    showlegend: false
  }
  data.push(trace)
};

var layout = {
  showlegend: true,
  xaxis: {
    tickson: "boundaries",
    ticklen: 15,
    showdividers: true,
    dividercolor: 'grey',
    dividerwidth: 3
  }
};

Plotly.newPlot('myDiv', data, layout);

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

thank you Derek. I think converting this to ploly python should be straight forward. I think median function is already built in python as well.
oh that's my mistake: i didn't read your question carefully enough and thought you wanted it in plotly.js but in plotly-python there are indeed several different packages that have median so the solution should be pretty similar

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.