mouwsy
mouwsy

Reputation: 1933

inverted label text (half turn) for Chord diagram on holoviews with bokeh

In the example in https://holoviews.org/reference/elements/bokeh/Chord.html , how can I change the orientation of the label text 180° in order to avoid rotations that flip the label text upside down in the left semicircle (see pictures). The Backend is bokeh. The label text would be much more readable with this change.

Here is what I have done so far:

import numpy as np

def rotate_label(plot, element):
        angles = plot.handles['text_1_source'].data['angle']
        angles[np.where((angles < -1.5707963267949) | (angles > 1.5707963267949))] += 3.1415926535898

chord.opts(cmap='Category20b',
           edge_cmap='Category20b', 
           edge_color=dim('source').str(), 
           labels='index', 
           node_color=dim('index').str(),
           hooks=[rotate_label]
           )

First picture (current):

enter image description here

Second picture (objective):

enter image description here

Upvotes: 0

Views: 1025

Answers (2)

Peilin Huang
Peilin Huang

Reputation: 26

Thanks to @mouwsy. I make an updated version to fix the text_align problem:

import numpy as np

def rotate_label(plot, element):
    white_space = "      "
    angles = plot.handles['text_1_source'].data['angle']
    characters = np.array(plot.handles['text_1_source'].data['text'])
    text_align = []
    
    for angle in angles:
        if angle < -1.5707963267949 or angle > 1.5707963267949:
            text_align.append('right')
        else:
            text_align.append('left')
    
    # Update text with whitespace based on angle
    plot.handles['text_1_source'].data['text'] = np.array([
        x + white_space if x in characters[np.where((angles < -1.5707963267949) | (angles > 1.5707963267949))] 
        else white_space + x 
        for x in plot.handles['text_1_source'].data['text']
    ])
    
    # Rotate labels that are upside down
    angles[np.where((angles < -1.5707963267949) | (angles > 1.5707963267949))] += 3.1415926535898
    
    # Set text alignment for each label individually
    plot.handles['text_1_source'].data['text_align'] = text_align
    plot.handles['text_1_glyph'].text_align = 'text_align'

chord.opts(cmap='Category20b',
           edge_cmap='Category20b', 
           edge_color=dim('source').str(), 
           labels='index', 
           node_color=dim('index').str(),
           hooks=[rotate_label]
           )

Upvotes: 1

mouwsy
mouwsy

Reputation: 1933

This was quite difficult. If the label text is just a few characters long this solution with a hook might be appropriate. I am sure the code could be written clearer, but I have no experience with numpy.

import numpy as np

def rotate_label(plot, element):
    white_space = "      "
    angles = plot.handles['text_1_source'].data['angle']
    characters = np.array(plot.handles['text_1_source'].data['text'])
    plot.handles['text_1_source'].data['text'] = np.array([x + white_space if x in characters[np.where((angles < -1.5707963267949) | (angles > 1.5707963267949))] else x for x in plot.handles['text_1_source'].data['text']])
    plot.handles['text_1_source'].data['text'] = np.array([white_space + x if x in characters[np.where((angles > -1.5707963267949) | (angles < 1.5707963267949))] else x for x in plot.handles['text_1_source'].data['text']])
    angles[np.where((angles < -1.5707963267949) | (angles > 1.5707963267949))] += 3.1415926535898
    plot.handles['text_1_glyph'].text_align = "center"

chord.opts(cmap='Category20b',
           edge_cmap='Category20b', 
           edge_color=dim('source').str(), 
           labels='index', 
           node_color=dim('index').str(),
           hooks=[rotate_label]
           )

The variable white_space contains several whitespace characters that can be adjusted, if necessary, to position the label text.
It's not ideal with centered label text (plot.handles['text_1_glyph'].text_align = "center"). The better solution would be to align the label text of left semicirlce to right and the label text of right semicircle to left. But I don't know how to do that.

Upvotes: 1

Related Questions