FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
matplotlib/lib/matplotlib/colorbar.py at main · matplotlib/matplotlib · GitHub
matplotlib
matplotlib
Repository navigation
Code
Issues
1.1k
(1.1k)
Pull requests
435
(435)
Actions
Projects
Wiki
Security and quality
Insights
Expand file tree
Breadcrumbs
matplotlib
/
lib
/
matplotlib
/
colorbar.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
1589 lines (1378 loc) · 60.4 KB
Breadcrumbs
matplotlib
/
lib
/
matplotlib
/
colorbar.py
Copy path
File metadata and controls
1589 lines (1378 loc) · 60.4 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
Colorbars are a visualization of the mapping from scalar values to colors.
In Matplotlib they are drawn into a dedicated `~.axes.Axes`.
.. note::
Colorbars are typically created through `.Figure.colorbar` or its pyplot
wrapper `.pyplot.colorbar`, which internally use `.Colorbar` together with
`.make_axes_gridspec` (for `.GridSpec`-positioned Axes) or `.make_axes` (for
non-`.GridSpec`-positioned Axes).
End-users most likely won't need to directly use this module's API.
"""
import
functools
import
logging
import
numpy
as
np
import
matplotlib
as
mpl
from
matplotlib
import
_api
,
cbook
,
collections
,
colors
,
contour
,
ticker
import
matplotlib
.
artist
as
martist
import
matplotlib
.
colorizer
as
mcolorizer
import
matplotlib
.
patches
as
mpatches
import
matplotlib
.
path
as
mpath
import
matplotlib
.
spines
as
mspines
import
matplotlib
.
transforms
as
mtransforms
from
matplotlib
import
_docstring
_log
=
logging
.
getLogger
(
__name__
)
_docstring
.
interpd
.
register
(
_make_axes_kw_doc
=
"""
location : None or {'left', 'right', 'top', 'bottom'}
The location, relative to the parent Axes, where the colorbar Axes
is created. It also determines the *orientation* of the colorbar
(colorbars on the left and right are vertical, colorbars at the top
and bottom are horizontal). If None, the location will come from the
*orientation* if it is set (vertical colorbars on the right, horizontal
ones at the bottom), or default to 'right' if *orientation* is unset.
orientation : None or {'vertical', 'horizontal'}
The orientation of the colorbar. It is preferable to set the *location*
of the colorbar, as that also determines the *orientation*; passing
incompatible values for *location* and *orientation* raises an exception.
fraction : float, default: 0.15
Fraction of original Axes to use for colorbar.
shrink : float, default: 1.0
Fraction by which to multiply the size of the colorbar.
aspect : float, default: 20
Ratio of long to short dimensions.
pad : float, default: 0.05 if vertical, 0.15 if horizontal
Fraction of original Axes between colorbar and new image Axes.
anchor : (float, float), optional
The anchor point of the colorbar Axes.
Defaults to (0.0, 0.5) if vertical; (0.5, 1.0) if horizontal.
panchor : (float, float), or *False*, optional
The anchor point of the colorbar parent Axes. If *False*, the parent
axes' anchor will be unchanged.
Defaults to (1.0, 0.5) if vertical; (0.5, 0.0) if horizontal."""
,
_colormap_kw_doc
=
"""
extend : {'neither', 'both', 'min', 'max'}
Make pointed end(s) for out-of-range values (unless 'neither'). These are
set for a given colormap using the colormap set_under and set_over methods.
extendfrac : {*None*, 'auto', length, lengths}
If set to *None*, both the minimum and maximum triangular colorbar
extensions will have a length of 5% of the interior colorbar length (this
is the default setting).
If set to 'auto', makes the triangular colorbar extensions the same lengths
as the interior boxes (when *spacing* is set to 'uniform') or the same
lengths as the respective adjacent interior boxes (when *spacing* is set to
'proportional').
If a scalar, indicates the length of both the minimum and maximum
triangular colorbar extensions as a fraction of the interior colorbar
length. A two-element sequence of fractions may also be given, indicating
the lengths of the minimum and maximum colorbar extensions respectively as
a fraction of the interior colorbar length.
extendrect : bool
If *False* the minimum and maximum colorbar extensions will be triangular
(the default). If *True* the extensions will be rectangular.
ticks : None or list of ticks or Locator
If None, ticks are determined automatically from the input.
format : None or str or Formatter
If None, `~.ticker.ScalarFormatter` is used.
Format strings, e.g., ``"%4.2e"`` or ``"{x:.2e}"``, are supported.
An alternative `~.ticker.Formatter` may be given instead.
drawedges : bool
Whether to draw lines at color boundaries.
label : str
The label on the colorbar's long axis.
boundaries, values : None or a sequence
If unset, the colormap will be displayed on a 0-1 scale.
If sequences, *values* must have a length 1 less than *boundaries*. For
each region delimited by adjacent entries in *boundaries*, the color mapped
to the corresponding value in *values* will be used. The size of each
region is determined by the *spacing* parameter.
Normally only useful for indexed colors (i.e. ``norm=NoNorm()``) or other
unusual circumstances.
spacing : {'uniform', 'proportional'}
For discrete colorbars (`.BoundaryNorm` or contours), 'uniform' gives each
color the same space; 'proportional' makes the space proportional to the
data interval."""
)
def
_set_ticks_on_axis_warn
(
*
args
,
**
kwargs
):
# a top level function which gets put in at the axes'
# set_xticks and set_yticks by Colorbar.__init__.
_api
.
warn_external
(
"Use the colorbar set_ticks() method instead."
)
class
_ColorbarSpine
(
mspines
.
Spine
):
def
__init__
(
self
,
axes
):
self
.
_ax
=
axes
super
().
__init__
(
axes
,
'colorbar'
,
mpath
.
Path
(
np
.
empty
((
0
,
2
))))
mpatches
.
Patch
.
set_transform
(
self
,
axes
.
transAxes
)
def
get_window_extent
(
self
,
renderer
=
None
):
# This Spine has no Axis associated with it, and doesn't need to adjust
# its location, so we can directly get the window extent from the
# super-super-class.
return
mpatches
.
Patch
.
get_window_extent
(
self
,
renderer
=
renderer
)
def
set_xy
(
self
,
xy
):
self
.
_path
=
mpath
.
Path
(
xy
,
closed
=
True
)
self
.
_xy
=
xy
self
.
stale
=
True
def
draw
(
self
,
renderer
):
ret
=
mpatches
.
Patch
.
draw
(
self
,
renderer
)
self
.
stale
=
False
return
ret
class
_ColorbarAxesLocator
:
"""
Shrink the Axes if there are triangular or rectangular extends.
"""
def
__init__
(
self
,
cbar
):
self
.
_cbar
=
cbar
self
.
_orig_locator
=
cbar
.
ax
.
_axes_locator
def
__call__
(
self
,
ax
,
renderer
):
if
self
.
_orig_locator
is
not
None
:
pos
=
self
.
_orig_locator
(
ax
,
renderer
)
else
:
pos
=
ax
.
get_position
(
original
=
True
)
if
self
.
_cbar
.
extend
==
'neither'
:
return
pos
y
,
extendlen
=
self
.
_cbar
.
_proportional_y
()
if
not
self
.
_cbar
.
_extend_lower
():
extendlen
[
0
]
=
0
if
not
self
.
_cbar
.
_extend_upper
():
extendlen
[
1
]
=
0
len
=
sum
(
extendlen
)
+
1
shrink
=
1
/
len
offset
=
extendlen
[
0
]
/
len
# we need to reset the aspect ratio of the axes to account
# of the extends...
if
hasattr
(
ax
,
'_colorbar_info'
):
aspect
=
ax
.
_colorbar_info
[
'aspect'
]
else
:
aspect
=
False
# now shrink and/or offset to take into account the
# extend tri/rectangles.
if
self
.
_cbar
.
orientation
==
'vertical'
:
if
aspect
:
self
.
_cbar
.
ax
.
set_box_aspect
(
aspect
*
shrink
)
pos
=
pos
.
shrunk
(
1
,
shrink
).
translated
(
0
,
offset
*
pos
.
height
)
else
:
if
aspect
:
self
.
_cbar
.
ax
.
set_box_aspect
(
1
/
(
aspect
*
shrink
))
pos
=
pos
.
shrunk
(
shrink
,
1
).
translated
(
offset
*
pos
.
width
,
0
)
return
pos
def
get_subplotspec
(
self
):
# make tight_layout happy..
return
(
self
.
_cbar
.
ax
.
get_subplotspec
()
or
getattr
(
self
.
_orig_locator
,
"get_subplotspec"
,
lambda
:
None
)())
def
_remove_cbar_axes
(
ax
,
cbar
):
"""
Replacement remove method for a colorbar's axes, so that the colorbar is
properly removed.
Note we define this at the module level to preserve pickling. A lambda or
local def within the Colorbar.__init__ method will not work.
"""
cbar
.
remove
()
@
_docstring
.
interpd
class
Colorbar
:
r"""
Draw a colorbar in an existing Axes.
Typically, colorbars are created using `.Figure.colorbar` or
`.pyplot.colorbar` and associated with `.ColorizingArtist`\s (such as an
`.AxesImage` generated via `~.axes.Axes.imshow`).
In order to draw a colorbar not associated with other elements in the
figure, e.g. when showing a colormap by itself, one can create an empty
`.ColorizingArtist`, or directly pass *cmap* and *norm* instead of *mappable*
to `Colorbar`.
Useful public methods are :meth:`set_label` and :meth:`add_lines`.
Attributes
----------
ax : `~matplotlib.axes.Axes`
The `~.axes.Axes` instance in which the colorbar is drawn.
lines : list
A list of `.LineCollection` (empty if no lines were drawn).
dividers : `.LineCollection`
A LineCollection (empty if *drawedges* is ``False``).
"""
n_rasterize
=
50
# rasterize solids if number of colors >= n_rasterize
def
__init__
(
self
,
ax
,
mappable
=
None
,
*
,
alpha
=
None
,
location
=
None
,
extend
=
None
,
extendfrac
=
None
,
extendrect
=
False
,
ticks
=
None
,
format
=
None
,
values
=
None
,
boundaries
=
None
,
spacing
=
'uniform'
,
drawedges
=
False
,
label
=
''
,
cmap
=
None
,
norm
=
None
,
# redundant with *mappable*
orientation
=
None
,
ticklocation
=
'auto'
,
# redundant with *location*
):
"""
Parameters
----------
ax : `~matplotlib.axes.Axes`
The `~.axes.Axes` instance in which the colorbar is drawn.
mappable : `.ColorizingArtist`
The mappable whose colormap and norm will be used.
To show the colors versus index instead of on a 0-1 scale, set the
mappable's norm to ``colors.NoNorm()``.
alpha : float
The colorbar transparency between 0 (transparent) and 1 (opaque).
location : None or {'left', 'right', 'top', 'bottom'}
Set the colorbar's *orientation* and *ticklocation*. Colorbars on
the left and right are vertical, colorbars at the top and bottom
are horizontal. The *ticklocation* is the same as *location*, so if
*location* is 'top', the ticks are on the top. *orientation* and/or
*ticklocation* can be provided as well and overrides the value set by
*location*, but there will be an error for incompatible combinations.
.. versionadded:: 3.7
%(_colormap_kw_doc)s
Other Parameters
----------------
cmap : `~matplotlib.colors.Colormap`, default: :rc:`image.cmap`
The colormap to use. This parameter is ignored, unless *mappable* is
None.
norm : `~matplotlib.colors.Normalize`
The normalization to use. This parameter is ignored, unless *mappable*
is None.
orientation : None or {'vertical', 'horizontal'}
If None, use the value determined by *location*. If both
*orientation* and *location* are None then defaults to 'vertical'.
ticklocation : {'auto', 'left', 'right', 'top', 'bottom'}
The location of the colorbar ticks. The *ticklocation* must match
*orientation*. For example, a horizontal colorbar can only have ticks
at the top or the bottom. If 'auto', the ticks will be the same as
*location*, so a colorbar to the left will have ticks to the left. If
*location* is None, the ticks will be at the bottom for a horizontal
colorbar and at the right for a vertical.
"""
if
mappable
is
None
:
colorizer
=
mcolorizer
.
Colorizer
(
norm
=
norm
,
cmap
=
cmap
)
mappable
=
mcolorizer
.
ColorizingArtist
(
colorizer
)
self
.
mappable
=
mappable
cmap
=
mappable
.
cmap
norm
=
mappable
.
norm
filled
=
True
if
isinstance
(
mappable
,
contour
.
ContourSet
):
cs
=
mappable
alpha
=
cs
.
get_alpha
()
boundaries
=
cs
.
_levels
values
=
cs
.
cvalues
extend
=
cs
.
extend
filled
=
cs
.
filled
if
ticks
is
None
:
ticks
=
ticker
.
FixedLocator
(
cs
.
levels
,
nbins
=
10
)
elif
isinstance
(
mappable
,
martist
.
Artist
):
alpha
=
mappable
.
get_alpha
()
mappable
.
colorbar
=
self
mappable
.
colorbar_cid
=
mappable
.
callbacks
.
connect
(
'changed'
,
self
.
update_normal
)
location_orientation
=
_get_orientation_from_location
(
location
)
_api
.
check_in_list
(
[
None
,
'vertical'
,
'horizontal'
],
orientation
=
orientation
)
_api
.
check_in_list
(
[
'auto'
,
'left'
,
'right'
,
'top'
,
'bottom'
],
ticklocation
=
ticklocation
)
_api
.
check_in_list
(
[
'uniform'
,
'proportional'
],
spacing
=
spacing
)
if
location_orientation
is
not
None
and
orientation
is
not
None
:
if
location_orientation
!=
orientation
:
raise
TypeError
(
"location and orientation are mutually exclusive"
)
else
:
orientation
=
orientation
or
location_orientation
or
"vertical"
self
.
ax
=
ax
self
.
ax
.
_axes_locator
=
_ColorbarAxesLocator
(
self
)
if
extend
is
None
:
if
(
not
isinstance
(
mappable
,
contour
.
ContourSet
)
and
getattr
(
cmap
,
'colorbar_extend'
,
False
)
is
not
False
):
extend
=
cmap
.
colorbar_extend
elif
hasattr
(
norm
,
'extend'
):
extend
=
norm
.
extend
else
:
extend
=
'neither'
self
.
alpha
=
None
# Call set_alpha to handle array-like alphas properly
self
.
set_alpha
(
alpha
)
self
.
cmap
=
cmap
self
.
norm
=
norm
self
.
values
=
values
self
.
boundaries
=
boundaries
self
.
extend
=
extend
self
.
_inside
=
_api
.
getitem_checked
(
{
'neither'
:
slice
(
0
,
None
),
'both'
:
slice
(
1
,
-
1
),
'min'
:
slice
(
1
,
None
),
'max'
:
slice
(
0
,
-
1
)},
extend
=
extend
)
self
.
spacing
=
spacing
self
.
orientation
=
orientation
self
.
drawedges
=
drawedges
self
.
_filled
=
filled
self
.
extendfrac
=
extendfrac
self
.
extendrect
=
extendrect
self
.
_extend_patches
=
[]
self
.
solids
=
None
self
.
solids_patches
=
[]
self
.
lines
=
[]
for
spine
in
self
.
ax
.
spines
.
values
():
spine
.
set_visible
(
False
)
self
.
outline
=
self
.
ax
.
spines
[
'outline'
]
=
_ColorbarSpine
(
self
.
ax
)
self
.
dividers
=
collections
.
LineCollection
(
[],
colors
=
[
mpl
.
rcParams
[
'axes.edgecolor'
]],
linewidths
=
[
0.5
*
mpl
.
rcParams
[
'axes.linewidth'
]],
clip_on
=
False
)
self
.
ax
.
add_collection
(
self
.
dividers
,
autolim
=
False
)
self
.
_locator
=
None
self
.
_minorlocator
=
None
self
.
_formatter
=
None
self
.
_minorformatter
=
None
if
ticklocation
==
'auto'
:
ticklocation
=
_get_ticklocation_from_orientation
(
orientation
)
if
location
is
None
else
location
self
.
ticklocation
=
ticklocation
self
.
set_label
(
label
)
self
.
_reset_locator_formatter_scale
()
if
np
.
iterable
(
ticks
):
self
.
_locator
=
ticker
.
FixedLocator
(
ticks
,
nbins
=
len
(
ticks
))
else
:
self
.
_locator
=
ticks
if
isinstance
(
format
,
str
):
# Check format between FormatStrFormatter and StrMethodFormatter
try
:
self
.
_formatter
=
ticker
.
FormatStrFormatter
(
format
)
_
=
self
.
_formatter
(
0
)
except
(
TypeError
,
ValueError
):
self
.
_formatter
=
ticker
.
StrMethodFormatter
(
format
)
else
:
self
.
_formatter
=
format
# Assume it is a Formatter or None
self
.
_draw_all
()
if
isinstance
(
mappable
,
contour
.
ContourSet
)
and
not
mappable
.
filled
:
self
.
add_lines
(
mappable
)
# Link the Axes and Colorbar for interactive use
self
.
ax
.
_colorbar
=
self
# Don't navigate on any of these types of mappables
if
(
isinstance
(
self
.
norm
, (
colors
.
BoundaryNorm
,
colors
.
NoNorm
))
or
isinstance
(
self
.
mappable
,
contour
.
ContourSet
)):
self
.
ax
.
set_navigate
(
False
)
self
.
_patch_ax_methods
()
# Callbacks for the extend calculations to handle inverting the axis
self
.
_extend_cid1
=
self
.
ax
.
callbacks
.
connect
(
"xlim_changed"
,
self
.
_do_extends
)
self
.
_extend_cid2
=
self
.
ax
.
callbacks
.
connect
(
"ylim_changed"
,
self
.
_do_extends
)
# Ensure proper cleanup when `cbar.ax.remove()` is called. We ensure
# this by overriding the Axes' remove method, so that `cbar.ax.remove()`
# actually calls `cbar.remove()`. In turn, we store the original Axes'
# remove method in `_ax_remove`, which `cbar.remove()` will eventually
# call to clean up the Axes itself.
self
.
_ax_remove
=
self
.
ax
.
_remove_method
self
.
ax
.
_remove_method
=
functools
.
partial
(
_remove_cbar_axes
,
cbar
=
self
)
def
_patch_ax_methods
(
self
):
"""Override Axes methods because colorbars behave slightly different."""
# These are the functions that set up interactivity on this colorbar
self
.
_interactive_funcs
=
[
"_get_view"
,
"_set_view"
,
"_set_view_from_bbox"
,
"drag_pan"
]
for
x
in
self
.
_interactive_funcs
:
setattr
(
self
.
ax
,
x
,
getattr
(
self
,
x
))
# Override the cla method with a cbar-specific implementation
self
.
ax
.
cla
=
self
.
_cbar_cla
def
_cbar_cla
(
self
):
"""Function to clear the interactive colorbar state."""
for
x
in
self
.
_interactive_funcs
:
delattr
(
self
.
ax
,
x
)
# We now restore the old cla() back and can call it directly
del
self
.
ax
.
cla
self
.
ax
.
cla
()
@
property
def
long_axis
(
self
):
"""Axis that has decorations (ticks, etc) on it."""
if
self
.
orientation
==
'vertical'
:
return
self
.
ax
.
yaxis
return
self
.
ax
.
xaxis
@
property
def
locator
(
self
):
"""Major tick `.Locator` for the colorbar."""
return
self
.
long_axis
.
get_major_locator
()
@
locator
.
setter
def
locator
(
self
,
loc
):
self
.
long_axis
.
set_major_locator
(
loc
)
self
.
_locator
=
loc
@
property
def
minorlocator
(
self
):
"""Minor tick `.Locator` for the colorbar."""
return
self
.
long_axis
.
get_minor_locator
()
@
minorlocator
.
setter
def
minorlocator
(
self
,
loc
):
self
.
long_axis
.
set_minor_locator
(
loc
)
self
.
_minorlocator
=
loc
@
property
def
formatter
(
self
):
"""Major tick label `.Formatter` for the colorbar."""
return
self
.
long_axis
.
get_major_formatter
()
@
formatter
.
setter
def
formatter
(
self
,
fmt
):
self
.
long_axis
.
set_major_formatter
(
fmt
)
self
.
_formatter
=
fmt
@
property
def
minorformatter
(
self
):
"""Minor tick `.Formatter` for the colorbar."""
return
self
.
long_axis
.
get_minor_formatter
()
@
minorformatter
.
setter
def
minorformatter
(
self
,
fmt
):
self
.
long_axis
.
set_minor_formatter
(
fmt
)
self
.
_minorformatter
=
fmt
def
update_normal
(
self
,
mappable
=
None
):
"""
Update solid patches, lines, etc.
This is meant to be called when the norm of the image or contour plot
to which this colorbar belongs changes.
If the norm on the mappable is different than before, this resets the
locator and formatter for the axis, so if these have been customized,
they will need to be customized again. However, if the norm only
changes values of *vmin*, *vmax* or *cmap* then the old formatter
and locator will be preserved.
"""
if
mappable
:
# The mappable keyword argument exists because
# ScalarMappable.changed() emits self.callbacks.process('changed', self)
# in contrast, ColorizingArtist (and Colorizer) does not use this keyword.
# [ColorizingArtist.changed() emits self.callbacks.process('changed')]
# Also, there is no test where self.mappable == mappable is not True
# and possibly no use case.
# Therefore, the mappable keyword can be deprecated if cm.ScalarMappable
# is removed.
self
.
mappable
=
mappable
_log
.
debug
(
'colorbar update normal %r %r'
,
self
.
mappable
.
norm
,
self
.
norm
)
self
.
set_alpha
(
self
.
mappable
.
get_alpha
())
self
.
cmap
=
self
.
mappable
.
cmap
if
self
.
mappable
.
norm
!=
self
.
norm
:
self
.
norm
=
self
.
mappable
.
norm
self
.
_reset_locator_formatter_scale
()
self
.
_draw_all
()
if
isinstance
(
self
.
mappable
,
contour
.
ContourSet
):
CS
=
self
.
mappable
if
not
CS
.
filled
:
self
.
add_lines
(
CS
)
self
.
stale
=
True
def
_draw_all
(
self
):
"""
Calculate any free parameters based on the current cmap and norm,
and do all the drawing.
"""
if
self
.
orientation
==
'vertical'
:
if
mpl
.
rcParams
[
'ytick.minor.visible'
]:
self
.
minorticks_on
()
else
:
if
mpl
.
rcParams
[
'xtick.minor.visible'
]:
self
.
minorticks_on
()
self
.
long_axis
.
set
(
label_position
=
self
.
ticklocation
,
ticks_position
=
self
.
ticklocation
)
self
.
_short_axis
().
set_ticks
([])
self
.
_short_axis
().
set_ticks
([],
minor
=
True
)
# Set self._boundaries and self._values, including extensions.
# self._boundaries are the edges of each square of color, and
# self._values are the value to map into the norm to get the
# color:
self
.
_process_values
()
# Set self.vmin and self.vmax to first and last boundary, excluding
# extensions:
self
.
vmin
,
self
.
vmax
=
self
.
_boundaries
[
self
.
_inside
][[
0
,
-
1
]]
# Compute the X/Y mesh.
X
,
Y
=
self
.
_mesh
()
# draw the extend triangles, and shrink the inner Axes to accommodate.
# also adds the outline path to self.outline spine:
self
.
_do_extends
()
lower
,
upper
=
self
.
vmin
,
self
.
vmax
if
self
.
long_axis
.
get_inverted
():
# If the axis is inverted, we need to swap the vmin/vmax
lower
,
upper
=
upper
,
lower
if
self
.
orientation
==
'vertical'
:
self
.
ax
.
set_xlim
(
0
,
1
)
self
.
ax
.
set_ylim
(
lower
,
upper
)
else
:
self
.
ax
.
set_ylim
(
0
,
1
)
self
.
ax
.
set_xlim
(
lower
,
upper
)
# set up the tick locators and formatters. A bit complicated because
# boundary norms + uniform spacing requires a manual locator.
self
.
update_ticks
()
if
self
.
_filled
:
ind
=
np
.
arange
(
len
(
self
.
_values
))
if
self
.
_extend_lower
():
ind
=
ind
[
1
:]
if
self
.
_extend_upper
():
ind
=
ind
[:
-
1
]
self
.
_add_solids
(
X
,
Y
,
self
.
_values
[
ind
,
np
.
newaxis
])
def
_add_solids
(
self
,
X
,
Y
,
C
):
"""Draw the colors; optionally add separators."""
# Cleanup previously set artists.
if
self
.
solids
is
not
None
:
self
.
solids
.
remove
()
for
solid
in
self
.
solids_patches
:
solid
.
remove
()
# Add new artist(s), based on mappable type. Use individual patches if
# hatching is needed, pcolormesh otherwise.
mappable
=
getattr
(
self
,
'mappable'
,
None
)
if
(
isinstance
(
mappable
,
contour
.
ContourSet
)
and
any
(
hatch
is
not
None
for
hatch
in
mappable
.
hatches
)):
self
.
_add_solids_patches
(
X
,
Y
,
C
,
mappable
)
else
:
self
.
solids
=
self
.
ax
.
pcolormesh
(
X
,
Y
,
C
,
cmap
=
self
.
cmap
,
norm
=
self
.
norm
,
alpha
=
self
.
alpha
,
edgecolors
=
'none'
,
shading
=
'flat'
)
if
not
self
.
drawedges
:
if
len
(
self
.
_y
)
>=
self
.
n_rasterize
:
self
.
solids
.
set_rasterized
(
True
)
self
.
_update_dividers
()
def
_update_dividers
(
self
):
if
not
self
.
drawedges
:
self
.
dividers
.
set_segments
([])
return
# Place all *internal* dividers.
if
self
.
orientation
==
'vertical'
:
lims
=
self
.
ax
.
get_ylim
()
bounds
=
(
lims
[
0
]
<
self
.
_y
)
&
(
self
.
_y
<
lims
[
1
])
else
:
lims
=
self
.
ax
.
get_xlim
()
bounds
=
(
lims
[
0
]
<
self
.
_y
)
&
(
self
.
_y
<
lims
[
1
])
y
=
self
.
_y
[
bounds
]
# And then add outer dividers if extensions are on.
if
self
.
_extend_lower
():
y
=
np
.
insert
(
y
,
0
,
lims
[
0
])
if
self
.
_extend_upper
():
y
=
np
.
append
(
y
,
lims
[
1
])
X
,
Y
=
np
.
meshgrid
([
0
,
1
],
y
)
if
self
.
orientation
==
'vertical'
:
segments
=
np
.
dstack
([
X
,
Y
])
else
:
segments
=
np
.
dstack
([
Y
,
X
])
self
.
dividers
.
set_segments
(
segments
)
def
_add_solids_patches
(
self
,
X
,
Y
,
C
,
mappable
):
hatches
=
mappable
.
hatches
*
(
len
(
C
)
+
1
)
# Have enough hatches.
if
self
.
_extend_lower
():
# remove first hatch that goes into the extend patch
hatches
=
hatches
[
1
:]
patches
=
[]
for
i
in
range
(
len
(
X
)
-
1
):
xy
=
np
.
array
([[
X
[
i
,
0
],
Y
[
i
,
1
]],
[
X
[
i
,
1
],
Y
[
i
,
0
]],
[
X
[
i
+
1
,
1
],
Y
[
i
+
1
,
0
]],
[
X
[
i
+
1
,
0
],
Y
[
i
+
1
,
1
]]])
patch
=
mpatches
.
PathPatch
(
mpath
.
Path
(
xy
),
facecolor
=
self
.
cmap
(
self
.
norm
(
C
[
i
][
0
])),
hatch
=
hatches
[
i
],
linewidth
=
0
,
antialiased
=
False
,
alpha
=
self
.
alpha
)
self
.
ax
.
add_patch
(
patch
)
patches
.
append
(
patch
)
self
.
solids_patches
=
patches
def
_do_extends
(
self
,
ax
=
None
):
"""
Add the extend tri/rectangles on the outside of the Axes.
ax is unused, but required due to the callbacks on xlim/ylim changed
"""
# Clean up any previous extend patches
for
patch
in
self
.
_extend_patches
:
patch
.
remove
()
self
.
_extend_patches
=
[]
# extend lengths are fraction of the *inner* part of colorbar,
# not the total colorbar:
_
,
extendlen
=
self
.
_proportional_y
()
bot
=
0
-
(
extendlen
[
0
]
if
self
.
_extend_lower
()
else
0
)
top
=
1
+
(
extendlen
[
1
]
if
self
.
_extend_upper
()
else
0
)
# xyout is the outline of the colorbar including the extend patches:
if
not
self
.
extendrect
:
# triangle:
xyout
=
np
.
array
([[
0
,
0
], [
0.5
,
bot
], [
1
,
0
],
[
1
,
1
], [
0.5
,
top
], [
0
,
1
], [
0
,
0
]])
else
:
# rectangle:
xyout
=
np
.
array
([[
0
,
0
], [
0
,
bot
], [
1
,
bot
], [
1
,
0
],
[
1
,
1
], [
1
,
top
], [
0
,
top
], [
0
,
1
],
[
0
,
0
]])
if
self
.
orientation
==
'horizontal'
:
xyout
=
xyout
[:, ::
-
1
]
# xyout is the path for the spine:
self
.
outline
.
set_xy
(
xyout
)
if
not
self
.
_filled
:
return
# Make extend triangles or rectangles filled patches. These are
# defined in the outer parent axes' coordinates:
mappable
=
getattr
(
self
,
'mappable'
,
None
)
if
(
isinstance
(
mappable
,
contour
.
ContourSet
)
and
any
(
hatch
is
not
None
for
hatch
in
mappable
.
hatches
)):
hatches
=
mappable
.
hatches
*
(
len
(
self
.
_y
)
+
1
)
else
:
hatches
=
[
None
]
*
(
len
(
self
.
_y
)
+
1
)
if
self
.
_extend_lower
():
if
not
self
.
extendrect
:
# triangle
xy
=
np
.
array
([[
0
,
0
], [
0.5
,
bot
], [
1
,
0
]])
else
:
# rectangle
xy
=
np
.
array
([[
0
,
0
], [
0
,
bot
], [
1.
,
bot
], [
1
,
0
]])
if
self
.
orientation
==
'horizontal'
:
xy
=
xy
[:, ::
-
1
]
# add the patch
val
=
-
1
if
self
.
long_axis
.
get_inverted
()
else
0
color
=
self
.
cmap
(
self
.
norm
(
self
.
_values
[
val
]))
patch
=
mpatches
.
PathPatch
(
mpath
.
Path
(
xy
),
facecolor
=
color
,
alpha
=
self
.
alpha
,
linewidth
=
0
,
antialiased
=
False
,
transform
=
self
.
ax
.
transAxes
,
hatch
=
hatches
[
0
],
clip_on
=
False
,
# Place it right behind the standard patches, which is
# needed if we updated the extends
zorder
=
np
.
nextafter
(
self
.
ax
.
patch
.
zorder
,
-
np
.
inf
))
self
.
ax
.
add_patch
(
patch
)
self
.
_extend_patches
.
append
(
patch
)
# remove first hatch that goes into the extend patch
hatches
=
hatches
[
1
:]
if
self
.
_extend_upper
():
if
not
self
.
extendrect
:
# triangle
xy
=
np
.
array
([[
0
,
1
], [
0.5
,
top
], [
1
,
1
]])
else
:
# rectangle
xy
=
np
.
array
([[
0
,
1
], [
0
,
top
], [
1
,
top
], [
1
,
1
]])
if
self
.
orientation
==
'horizontal'
:
xy
=
xy
[:, ::
-
1
]
# add the patch
val
=
0
if
self
.
long_axis
.
get_inverted
()
else
-
1
color
=
self
.
cmap
(
self
.
norm
(
self
.
_values
[
val
]))
hatch_idx
=
len
(
self
.
_y
)
-
1
patch
=
mpatches
.
PathPatch
(
mpath
.
Path
(
xy
),
facecolor
=
color
,
alpha
=
self
.
alpha
,
linewidth
=
0
,
antialiased
=
False
,
transform
=
self
.
ax
.
transAxes
,
hatch
=
hatches
[
hatch_idx
],
clip_on
=
False
,
# Place it right behind the standard patches, which is
# needed if we updated the extends
zorder
=
np
.
nextafter
(
self
.
ax
.
patch
.
zorder
,
-
np
.
inf
))
self
.
ax
.
add_patch
(
patch
)
self
.
_extend_patches
.
append
(
patch
)
self
.
_update_dividers
()
def
add_lines
(
self
,
*
args
,
**
kwargs
):
"""
Draw lines on the colorbar.
The lines are appended to the list :attr:`!lines`.
Parameters
----------
levels : array-like
The positions of the lines.
colors : :mpltype:`color` or list of :mpltype:`color`
Either a single color applying to all lines or one color value for
each line.
linewidths : float or array-like
Either a single linewidth applying to all lines or one linewidth
for each line.
erase : bool, default: True
Whether to remove any previously added lines.
Notes
-----
Alternatively, this method can also be called with the signature
``colorbar.add_lines(contour_set, erase=True)``, in which case
*levels*, *colors*, and *linewidths* are taken from *contour_set*.
"""
params
=
_api
.
select_matching_signature
(
[
lambda
self
,
CS
,
erase
=
True
:
locals
(),
lambda
self
,
levels
,
colors
,
linewidths
,
erase
=
True
:
locals
()],
self
,
*
args
,
**
kwargs
)
if
"CS"
in
params
:
self
,
cs
,
erase
=
params
.
values
()
if
not
isinstance
(
cs
,
contour
.
ContourSet
)
or
cs
.
filled
:
raise
ValueError
(
"If a single artist is passed to add_lines, "
"it must be a ContourSet of lines"
)
# TODO: Make colorbar lines auto-follow changes in contour lines.
return
self
.
add_lines
(
cs
.
levels
,
cs
.
to_rgba
(
cs
.
cvalues
,
cs
.
alpha
),
cs
.
get_linewidths
(),
erase
=
erase
)
else
:
self
,
levels
,
colors
,
linewidths
,
erase
=
params
.
values
()
y
=
self
.
_locate
(
levels
)
rtol
=
(
self
.
_y
[
-
1
]
-
self
.
_y
[
0
])
*
1e-10
igood
=
(
y
<
self
.
_y
[
-
1
]
+
rtol
)
&
(
y
>
self
.
_y
[
0
]
-
rtol
)
y
=
y
[
igood
]
if
np
.
iterable
(
colors
):
colors
=
np
.
asarray
(
colors
)[
igood
]
if
np
.
iterable
(
linewidths
):
linewidths
=
np
.
asarray
(
linewidths
)[
igood
]
X
,
Y
=
np
.
meshgrid
([
0
,
1
],
y
)
if
self
.
orientation
==
'vertical'
:
xy
=
np
.
stack
([
X
,
Y
],
axis
=
-
1
)
else
:
xy
=
np
.
stack
([
Y
,
X
],
axis
=
-
1
)
col
=
collections
.
LineCollection
(
xy
,
linewidths
=
linewidths
,
colors
=
colors
)
if
erase
and
self
.
lines
:
for
lc
in
self
.
lines
:
lc
.
remove
()
self
.
lines
=
[]
self
.
lines
.
append
(
col
)
# make a clip path that is just a linewidth bigger than the Axes...
fac
=
np
.
max
(
linewidths
)
/
72
xy
=
np
.
array
([[
0
,
0
], [
1
,
0
], [
1
,
1
], [
0
,
1
], [
0
,
0
]])
inches
=
self
.
ax
.
get_figure
().
dpi_scale_trans
# do in inches:
xy
=
inches
.
inverted
().
transform
(
self
.
ax
.
transAxes
.
transform
(
xy
))
xy
[[
0
,
1
,
4
],
1
]
-=
fac
xy
[[
2
,
3
],
1
]
+=
fac
# back to axes units...
xy
=
self
.
ax
.
transAxes
.
inverted
().
transform
(
inches
.
transform
(
xy
))
col
.
set_clip_path
(
mpath
.
Path
(
xy
,
closed
=
True
),
self
.
ax
.
transAxes
)
self
.
ax
.
add_collection
(
col
,
autolim
=
False
)
self
.
stale
=
True
def
update_ticks
(
self
):
"""
Set up the ticks and ticklabels. This should not be needed by users.
"""
# Get the locator and formatter; defaults to self._locator if not None.
self
.
_get_ticker_locator_formatter
()
self
.
long_axis
.
set_major_locator
(
self
.
_locator
)
self
.
long_axis
.
set_minor_locator
(
self
.
_minorlocator
)
self
.
long_axis
.
set_major_formatter
(
self
.
_formatter
)
def
_get_ticker_locator_formatter
(
self
):
"""
Return the ``locator`` and ``formatter`` of the colorbar.
If they have not been defined (i.e. are *None*), the formatter and
locator are retrieved from the axis, or from the value of the
boundaries for a boundary norm.
Called by update_ticks...
"""
locator
=
self
.
_locator
formatter
=
self
.
_formatter
minorlocator
=
self
.
_minorlocator
if
isinstance
(
self
.
norm
,
colors
.
BoundaryNorm
):
b
=
self
.
norm
.
boundaries
if
locator
is
None
:
locator
=
ticker
.
FixedLocator
(
b
,
nbins
=
10
)
if
minorlocator
is
None
:
minorlocator
=
ticker
.
FixedLocator
(
b
)
elif
isinstance
(
self
.
norm
,
colors
.
NoNorm
):
if
locator
is
None
:
# put ticks on integers between the boundaries of NoNorm
nv
=
len
(
self
.
_values
)
base
=
1
+
int
(
nv
/
10
)
locator
=
ticker
.
IndexLocator
(
base
=
base
,
offset
=
.5
)
elif
self
.
boundaries
is
not
None
:
b
=
self
.
_boundaries
[
self
.
_inside
]
if
locator
is
None
:
locator
=
ticker
.
FixedLocator
(
b
,
nbins
=
10
)
else
:
# most cases:
if
locator
is
None
:
# we haven't set the locator explicitly, so use the default
# for this axis:
locator
=
self
.
long_axis
.
get_major_locator
()
if
minorlocator
is
None
:
minorlocator
=
self
.
long_axis
.
get_minor_locator
()
if
minorlocator
is
None
:
minorlocator
=
ticker
.
NullLocator
()
if
formatter
is
None
:
formatter
=
self
.
long_axis
.
get_major_formatter
()
self
.
_locator
=
locator
self
.
_formatter
=
formatter
self
.
_minorlocator
=
minorlocator
_log
.
debug
(
'locator: %r'
,
locator
)
def
set_ticks
(
self
,
ticks
,
*
,
labels
=
None
,
minor
=
False
,
**
kwargs
):
"""
Set tick locations.
Parameters
----------
ticks : 1D array-like
List of tick locations.
labels : list of str, optional
List of tick labels. If not set, the labels show the data value.
minor : bool, default: False
If ``False``, set the major ticks; if ``True``, the minor ticks.
**kwargs
`.Text` properties for the labels. These take effect only if you
pass *labels*. In other cases, please use `~.Axes.tick_params`.
"""
if
np
.
iterable
(
ticks
):
self
.
long_axis
.
set_ticks
(
ticks
,
labels
=
labels
,
minor
=
minor
,
**
kwargs
)
self
.
_locator
=
self
.
long_axis
.
get_major_locator
()
else
:
self
.
_locator
=
ticks
self
.
long_axis
.
set_major_locator
(
self
.
_locator
)
self
.
stale
=
True
def
get_ticks
(
self
,
minor
=
False
):
"""
Return the ticks as a list of locations.
Parameters
----------
minor : boolean, default: False
if True return the minor ticks.
"""
if
minor
:
return
self
.
long_axis
.
get_minorticklocs
()
else
:
return
self
.
long_axis
.
get_majorticklocs
()
def
set_ticklabels
(
self
,
ticklabels
,
*
,
minor
=
False
,
**
kwargs
):
"""
[*Discouraged*] Set tick labels.
.. admonition:: Discouraged
The use of this method is discouraged, because of the dependency
on tick positions. In most cases, you'll want to use
``set_ticks(positions, labels=labels)`` instead.
If you are using this method, you should always fix the tick
positions before, e.g. by using `.Colorbar.set_ticks` or by
explicitly setting a `~.ticker.FixedLocator` on the long axis
of the colorbar. Otherwise, ticks are free to move and the
labels may end up in unexpected positions.
Parameters
----------
ticklabels : sequence of str or of `.Text`
Texts for labeling each tick location in the sequence set by
`.Colorbar.set_ticks`; the number of labels must match the number
of locations.
update_ticks : bool, default: True
This keyword argument is ignored and will be removed.
Deprecated
minor : bool
If True, set minor ticks instead of major ticks.
**kwargs
`.Text` properties for the labels.
"""
self
.
long_axis
.
set_ticklabels
(
ticklabels
,
minor
=
minor
,
**
kwargs
)
def
minorticks_on
(
self
):
"""
Turn on colorbar minor ticks.
"""
self
.
ax
.
minorticks_on
()
self
.
_short_axis
().
set_minor_locator
(
ticker
.
NullLocator
())
def
minorticks_off
(
self
):
"""Turn the minor ticks of the colorbar off."""
self
.
_minorlocator
=
ticker
.
NullLocator
()
self
.
long_axis
.
set_minor_locator
(
self
.
_minorlocator
)
def
set_label
(
self
,
label
,
*
,
loc
=
None
,
**
kwargs
):
"""
Add a label to the long axis of the colorbar.
Parameters
----------
label : str
The label text.
loc : str, optional
The location of the label.
- For horizontal orientation one of {'left', 'center', 'right'}
- For vertical orientation one of {'bottom', 'center', 'top'}
Defaults to :rc:`xaxis.labellocation` or :rc:`yaxis.labellocation`
depending on the orientation.
**kwargs
Keyword arguments are passed to `~.Axes.set_xlabel` /
`~.Axes.set_ylabel`.
Supported keywords are *labelpad* and `.Text` properties.
View remainder of file in raw view
Back
|
FazBrowse Home
|
New Git URL