1
1
"""
2
- ============
3
- Gradient Bar
4
- ============
2
+ ========================
3
+ Bar chart with gradients
4
+ ========================
5
+
6
+ Matplotlib does not natively support gradients. However, we can emulate a
7
+ gradient-filled rectangle by an `.AxesImage` of the right size and coloring.
8
+
9
+ In particular, we use a colormap to generate the actual colors. It is then
10
+ sufficient to define the underlying values on the corners of the image and
11
+ let bicubic interpolation fill out the area. We define the gradient direction
12
+ by a unit vector *v*. The values at the corners are then obtained by the
13
+ lengths of the projections of the corner vectors on *v*.
14
+
15
+ A similar approach can be used to create a gradient background for an axes.
16
+ In that case, it is helpful to uses Axes coordinates
17
+ (`extent=(0, 1, 0, 1), transform=ax.transAxes`) to be independent of the data
18
+ coordinates.
5
19
6
20
"""
7
21
import matplotlib .pyplot as plt
10
24
np .random .seed (19680801 )
11
25
12
26
13
- def gbar (ax , x , y , width = 0.5 , bottom = 0 ):
14
- X = [[.6 , .6 ], [.7 , .7 ]]
27
+ def gradient_image (ax , extent , direction = 0.3 , cmap_range = (0 , 1 ), ** kwargs ):
28
+ """
29
+ Draw a gradient image based on a colormap.
30
+
31
+ Parameters
32
+ ----------
33
+ ax : Axes
34
+ The axes to draw on.
35
+ extent
36
+ The extent of the image as (xmin, xmax, ymin, ymax).
37
+ By default, this is in Axes coordinates but may be
38
+ changed using the *transform* kwarg.
39
+ direction : float
40
+ The direction of the gradient. This is a number in
41
+ range 0 (=vertical) to 1 (=horizontal).
42
+ cmap_range : float, float
43
+ The fraction (cmin, cmax) of the colormap that should be
44
+ used for the gradient, where the complete colormap is (0, 1).
45
+ **kwargs
46
+ Other parameters are passed on to `.Axes.imshow()`.
47
+ In particular useful is *cmap*.
48
+ """
49
+ phi = direction * np .pi / 2
50
+ v = np .array ([np .cos (phi ), np .sin (phi )])
51
+ X = np .array ([[v @ [1 , 0 ], v @ [1 , 1 ]],
52
+ [v @ [0 , 0 ], v @ [0 , 1 ]]])
53
+ a , b = cmap_range
54
+ X = a + (b - a ) / X .max () * X
55
+ im = ax .imshow (X , extent = extent , interpolation = 'bicubic' ,
56
+ vmin = 0 , vmax = 1 , ** kwargs )
57
+ return im
58
+
59
+
60
+ def gradient_bar (ax , x , y , width = 0.5 , bottom = 0 ):
15
61
for left , top in zip (x , y ):
16
62
right = left + width
17
- ax . imshow ( X , interpolation = 'bicubic' , cmap = plt . cm . Blues ,
18
- extent = ( left , right , bottom , top ), alpha = 1 )
63
+ gradient_image ( ax , extent = ( left , right , bottom , top ) ,
64
+ cmap = plt . cm . Blues_r , cmap_range = ( 0 , 0.8 ) )
19
65
20
66
21
67
xmin , xmax = xlim = 0 , 10
@@ -24,13 +70,13 @@ def gbar(ax, x, y, width=0.5, bottom=0):
24
70
fig , ax = plt .subplots ()
25
71
ax .set (xlim = xlim , ylim = ylim , autoscale_on = False )
26
72
27
- X = [[ .6 , .6 ], [ .7 , .7 ]]
28
- ax . imshow ( X , interpolation = 'bicubic' , cmap = plt . cm . copper ,
29
- extent = ( xmin , xmax , ymin , ymax ), alpha = 1 )
73
+ # background image
74
+ gradient_image ( ax , direction = 0 , extent = ( 0 , 1 , 0 , 1 ), transform = ax . transAxes ,
75
+ cmap = plt . cm . Oranges , cmap_range = ( 0.1 , 0.6 ) )
30
76
31
77
N = 10
32
- x = np .arange (N ) + 0.25
78
+ x = np .arange (N ) + 0.15
33
79
y = np .random .rand (N )
34
- gbar (ax , x , y , width = 0.7 )
80
+ gradient_bar (ax , x , y , width = 0.7 )
35
81
ax .set_aspect ('auto' )
36
82
plt .show ()
0 commit comments