Polina Sklyarevsky
Polina Sklyarevsky

Reputation: 192

How to align trace text to center in a stacked horizontal bar chart

I have a stacked horizontal bar and I want text defined for each trace to be placed at the center of the corresponding bar. I can't find an attribute that sets this without using anotations, but I'd like to use "text" for each trace and just be able to align it.

I'm using Plotly 3.4.1 with Jupyter (Plotly offline). Couldn't find any documentation about how to do this except trying to do this with annotations, which look like a more suitable solution if I want to pinpoint an explicit coordinate. What I want is a much simpler (something like "align": "center"), but couldn't find any attribute for this under go.Bar

Just want the "80", "20" to appear at the center instead of aligned to the right

from plotly.offline import iplot, plot, init_notebook_mode
import plotly.graph_objs as go

def getStackedSentimentHbar():
    trace0 = go.Bar(
        y=["A","B"],
        x=[20,80],
        orientation = 'h',
        text=["20","80"],
        textposition="inside",
        hoverinfo = "none",
    )
    trace1 = go.Bar(
        y=["A","B"],
        x=[80,20],
        orientation = 'h',
        text=["80","20"],
        textposition="inside",
        hoverinfo = "none",
    )
    data = [trace0,trace1]
    layout = go.Layout(
        barmode='stack',
        showlegend=False,
        xaxis=dict(
            showgrid=False,
            zeroline=False,
            showline=False,
            ticks='',
            showticklabels=False
        ),
        yaxis=dict(
            showgrid=False,
            zeroline=False,
            showline=False,
            ticks='',
            showticklabels=True
        ),
        margin = dict(
            l = 200, 
            r = 50, 
            b = 50, 
            t = 50, 
            pad = 10
        ),
        font=dict(
            family='Heebo', 
            size=18, 
            color='#000000'
        )
    )
    fig = go.Figure(data=data, layout=layout)
    return fig

init_notebook_mode()
fig = getStackedSentimentHbar()
iplot(fig)

Upvotes: 3

Views: 3838

Answers (3)

rfeague
rfeague

Reputation: 423

As noted in an answer to this question, you can accomplish this much more easily by setting insidetextanchor="start" (or 'middle' or 'end')

Upvotes: 1

David Avsajanishvili
David Avsajanishvili

Reputation: 8036

A better approach - use separate annotations.

enter image description here

var x1A = 20;
var x1B = 80;
var x2A = 80;
var x2B = 20;
var trace1 = {
  y: ['A', 'B'],
  x: [x1A, x1B],
  type: 'bar',
  orientation: 'h',
};

var trace2 = {
  y: ['A', 'B'],
  x: [x2A, x2B],
  type: 'bar',
  orientation: 'h',
};

var data = [trace1, trace2];

var layout = {
  barmode: 'stack',
  annotations: [
    { x: x1A / 2, y: 'A', text: '20', showarrow: false },
    { x: x1A + x2A / 2, y: 'A', text: '80', showarrow: false },
    { x: x1B / 2, y: 'B', text: '80', showarrow: false },
    { x: x1B + x2B / 2, y: 'B', text: '20', showarrow: false },
  ],
};

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

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

Here is an example from the official Plotly documentation: https://plotly.com/python/horizontal-bar-charts/#color-palette-for-bar-chart

Upvotes: 1

Maximilian Peters
Maximilian Peters

Reputation: 31709

As far as I know there is no such parameter in Plotly but we can always hack to Plotly :)

Let's just duplicate all x- and y-values but leave the text as it is.

In the code below there are two functions, getStackedSentimentHbar and getStackedSentimentHbarCentered. The first one returns the original graph, the second returns the graph with the (almost) centered labels.

enter image description here

from plotly.offline import iplot, plot, init_notebook_mode
import plotly.graph_objs as go

LAYOUT = go.Layout(
        barmode='stack',
        showlegend=False,
        xaxis=dict(
            showgrid=False,
            zeroline=False,
            showline=False,
            ticks='',
            showticklabels=False
        ),
        yaxis=dict(
            showgrid=False,
            zeroline=False,
            showline=False,
            ticks='',
            showticklabels=True
        ),
        margin = dict(
            l = 200, 
            r = 50, 
            b = 50, 
            t = 50, 
            pad = 10
        ),
        font=dict(
            family='Heebo', 
            size=18, 
            color='#000000'
        )
    )

def getStackedSentimentHbar(values):

    data = []
    for i, x in enumerate(values['x']):
        trace = go.Bar(
            x=x,
            y=values['y'][i],
            orientation='h',
            text=x,
            textposition='inside',
            hoverinfo = 'none',
        )
        data.append(trace)

    fig = go.Figure(data=data, layout=LAYOUT)
    return fig

def getStackedSentimentHbarCentered(values):

    data = []
    for i, x in enumerate(values['x']):

        trace = go.Bar(
            x=[int(i / 2) for i in x * 2],
            y=values['y'][i] * 2,
            orientation = 'h',
            text=x,
            textposition='inside',
            hoverinfo = 'none'
        )
        data.append(trace)

    fig = go.Figure(data=data, layout=LAYOUT)
    return fig

values = {'x': [[20, 80], [80, 20]],
          'y': [['A', 'B'], ['A', 'B']]}

init_notebook_mode()
fig = getStackedSentimentHbarCentered(values)
iplot(fig)

Upvotes: 1

Related Questions