Matplotlib Two Different Colors in the Same Annotate

Matplotlib Two Different Colors in the Same Annotate

I am trying to create a figure in python and make is so that the same annonate text will have two colors, half of the annonate will be blue and the other half will be red.

I think the code explain itself. I have 3 lines 1 green with green annonate, 1 blue with blue annonate.

The 3rd is red its the summation of plot 1 and plot 2, and I want it to have half annonate blue and half green.

ipython -pylab

x=arange(0,4,0.1)

exp1 = e**(-x/5)
exp2 = e**(-x/1)
exp3 = e**(-x/5) +e**(-x/1) 

figure()
plot(x,exp1)
plot(x,exp2)
plot(x,exp1+exp2)
title('Exponential Decay')


annotate(r'$e^{-x/5}$', xy=(x[10], exp1[10]), xytext=(-20,-35), 
         textcoords='offset points', ha='center', va='bottom',color='blue',
          bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3),
          arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0.95', 
                            color='b'))

annotate(r'$e^{-x/1}$', xy=(x[10], exp2[10]), xytext=(-5,20), 
         textcoords='offset points', ha='center', va='bottom',color='green',
          bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3),
          arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=-0.5', 
                            color='g'))

annotate(r'$e^{-x/5} + e^{-x/1}$', xy=(x[10], exp2[10]+exp1[10]), xytext=(40,20), 
         textcoords='offset points', ha='center', va='bottom',
          bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3),
          arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=-0.5', 
                            color='red'))

Is it possible?

2

2 Answers

You can use r'$\textcolor{blue}{e^{-x/5}} + \textcolor{green}{e^{-x/1}}$' to make the text half blue, half green. Using your own code for example:

The image is generated by the following code. Testd with matplotlib v2.1.2 with the default matplotlibrc settings.

import matplotlib as matplotlib
matplotlib.use('pgf')
matplotlib.rc('pgf', texsystem='pdflatex')  # from running latex -v
preamble = matplotlib.rcParams.setdefault('pgf.preamble', [])
preamble.append(r'\usepackage{color}')

from numpy import *
from matplotlib.pyplot import *

x=arange(0,4,0.1)

exp1 = e**(-x/5)
exp2 = e**(-x/1)
exp3 = e**(-x/5) +e**(-x/1) 

figure()
plot(x,exp1)
plot(x,exp2)
plot(x,exp1+exp2)
title('Exponential Decay')


annotate(r'$e^{-x/5}$', xy=(x[10], exp1[10]), xytext=(-20,-25), 
         textcoords='offset points', ha='center', va='bottom',color='blue',
         bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3),
         arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0.95', 
                            color='b'))

annotate(r'$e^{-x/1}$', xy=(x[10], exp2[10]), xytext=(25,20), 
         textcoords='offset points', ha='center', va='bottom',color='green',
         bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3),
         arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=-0.5', 
                            color='g'))

annotate(r'$\textcolor{blue}{e^{-x/5}} + \textcolor[rgb]{0.0, 0.5, 0.0}{e^{-x/1}}$', 
         xy=(x[10], exp2[10]+exp1[10]), xytext=(40,20), 
         textcoords='offset points', ha='center', va='bottom',
         bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3),
         arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=-0.5', 
                            color='red'))

savefig('test.png')

It is mainly your code with the following changes:

  1. You need to use a pgf backend.
  2. Usepackage color in pgf.preamble
  3. There's some overlapping with the 1st and 2nd annotations, so xytext is changed.
  4. The color='g' in te 2nd annotation actually didn't use the pure "Green" color like (0, 255, 0) of rgb. \textcolor[rgb]{0.0, 0.5, 0.0} makes it looking alike.
6

I don't think you can have multiple colours in a single annotation, since—as far as I know—annotate only takes one text object as parameter, and text objects only support single colours. So, to my knowledge, there's no "native" or "elegant" way of automatically doing this.

There is, however, a workaround: you can have multiple text objects placed arbitrarily in the graph. So here's how I'd do it:

fig1 = figure()
# all the same until the last "annotate":
annotate(r'$e^{-x/5}$'+r'$e^{-x/1}$', xy=(x[10], exp2[10]+exp1[10]), xytext=(40,20), 
         textcoords='offset points', ha='center', va='bottom',color='white',
          bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3),
          arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=-0.5', 
                            color='r'))

fig1.text(0.365, 0.62, r'$e^{-x/5}$', ha="center", va="bottom", size="medium",color="blue")
fig1.text(0.412, 0.62, r'$e^{-x/1}$', ha="center", va="bottom", size="medium",color="green")

What I did was:

  1. I set the annotation color='black';
  2. I created the two text objects at positions 0.5, 0.5 (which means the center of fig1);
  3. I manually changed the positions until they were roughly overlapping with the black text generated by annotate (which ended up being the values you see in the two calls to text);
  4. I set the annotation color='white', so it doesn't interfere with the colour of the overlapping text.

Here's the output:

It's not very elegant, and it does require some plotting to fine-tune the positions, but it gets the job done.

If you need several plots, perhaps there's a way to automate the placement: If you don't store the fig1 object, the coordinates for text become the actual x,y coordinates in the graph—I find that a bit harder to work with, but maybe it'd enable you to generate them automatically using the annotation's xy coordinates? Doesn't sound worth the trouble for me, but if you make it happen, I'd like to see the code.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Maya Lin-Takahashi
Author

Maya Lin-Takahashi

Maya is a hardware enthusiast who tests and reviews smart home devices, smartphones, wearables, and audio gear. She focuses on practical consumer value and build quality.