Issue
How to color a plot from red to green continuously (changing smoothly) based on 4 different styles along y
axis, using cmap
, where the first and the last sections are colored by constant colors red and green respectively. I want to use plt.imshow
in this regard, if it could. I wrote the following code for that, inspiring from other posts and based on my needs, but it get some overlaps or edge colors between sections. The sections must be colored such how the first section is red (the 1st color of cmap
), the 2nd section must change from that red smoothly to yellow, the 3rd one must continue from the last red to green, and the last be that green constantly:
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (19.2, 9.6)
Diam_P = 0.4
ylim = 7
plt.imshow(np.interp(np.linspace(0, 3 * Diam_P, 1), [0, 1], [0, 0]).reshape(-1, 1),
cmap='hsv', vmin=0, vmax=1, extent=[0, 180, 0, 3 * Diam_P], origin='lower',
interpolation='bilinear', aspect='auto', zorder=-1, alpha=0.7)
plt.imshow(np.interp(np.linspace(3 * Diam_P, 2, 10000), [3 * Diam_P, 2], [0, 0.15]).reshape(-1, 1),
cmap='hsv', vmin=0, vmax=1, extent=[0, 180, 3 * Diam_P, 2], origin='lower',
interpolation='bilinear', aspect='auto', zorder=-1, alpha=0.7)
plt.imshow(np.interp(np.linspace(2, 3, 20000), [2, 3], [0.15, 0.24]).reshape(-1, 1),
cmap='hsv', vmin=0, vmax=1, extent=[0, 180, 2, 3], origin='lower',
interpolation='bilinear', aspect='auto', zorder=-1, alpha=0.7)
plt.imshow(np.interp(np.linspace(3, ylim, 1), [3, ylim], [0.24, 0.24]).reshape(-1, 1),
cmap='hsv', vmin=0, vmax=1, extent=[0, 180, 3, ylim], origin='lower',
interpolation='bilinear', aspect='auto', zorder=-1, alpha=0.7)
plt.xlim(0, 70)
plt.ylim(0, ylim)
plt.savefig("test2.png", dpi=600)
plt.show()
The problem is edgelines or overlaps which are appeared on the plot and as can be seen, colors not changed continuously from yellow to green (darker green at first and then lighter green, which is not as expected):
I would be grateful for solutions solving these issues.
Solution
Where the bands overlap, the alpha blending creates a darker line. You can avoid this either by not using alpha, or by drawing the image in one go.
Using 'hsv' with a stretched image
To draw everything in one go:
- start with a linear "image" with enough subdivisions going from
0
toylim
- use
np.interp
to map the values:0
to "color"0
(red in 'hsv')3 * Diam_P
also to "color"0
2
to "color"0.15
(yellow)3
to "color"0.24
(green)ylim
also to "color"0.15
- draw the mapped image via
imshow
withvmin=0
,vmax=1
andcmap='hsv'
import matplotlib.pyplot as plt
import numpy as np
Diam_P = 0.4
ylim = 7
linear_img = np.linspace(0, ylim, 1000).reshape(-1, 1)
stretched_img = np.interp(linear_img,
[0, 3 * Diam_P, 2, 3, ylim],
[0, 0, 0.15, 0.24, 0.24])
plt.imshow(stretched_img, cmap='hsv',
vmin=0, vmax=1, extent=[0, 180, 0, ylim], origin='lower',
interpolation='bilinear', aspect='auto', zorder=-1, alpha=0.7)
plt.show()
Using a stretched colormap with a linear image
Alternatively, you can work with a LinearSegmentedColormap
that maps the boundaries to the 3 given colors. For this mapping, the boundaries first need to be transformed to the range 0
-1
. This will create a linear mapping from the given red to the given yellow to the given green, without going through the colors present in the 'hsv' colormap. (The mapping is linear is RGB space, not in hue.)
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np
Diam_P = 0.4
ylim = 7
linear_img = np.linspace(0, 1, 1000).reshape(-1, 1)
red, yellow, green = plt.get_cmap('hsv')([0, 0.15, 0.24])
cmap = LinearSegmentedColormap.from_list('',
[(0, red),
(3 * Diam_P / ylim, red),
(2 / ylim, yellow),
(3 / ylim, green),
(1, green)])
plt.imshow(linear_img, cmap=cmap,
extent=[0, 180, 0, ylim], origin='lower',
interpolation='bilinear', aspect='auto', alpha=0.7, zorder=-1)
plt.show()
Answered By - JohanC
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.