Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit52e5d81

Browse files
committed
ENH: colorbar ticks adjustable to colorbar size
1 parentfc73593 commit52e5d81

File tree

10 files changed

+1039
-1173
lines changed

10 files changed

+1039
-1173
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
The ticks for colorbar now adjust for the size of the colorbar
2+
--------------------------------------------------------------
3+
4+
Colorbar ticks now adjust for the size of the colorbar if the
5+
colorbar is made from a mappable that is not a contour or
6+
doesn't have a BoundaryNorm, or boundaries are not specified.
7+
If boundaries, etc are specified, the colorbar maintains the
8+
original behaviour.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Colorbar ticks can now be automatic
2+
-----------------------------------
3+
4+
The number of ticks on colorbars was appropriate for a large colorbar, but
5+
looked bad if the colorbar was made smaller (i.e. via the ``shrink`` kwarg).
6+
This has been changed so that the number of ticks is now responsive to how
7+
large the colorbar is.

‎lib/matplotlib/colorbar.py

Lines changed: 169 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
importsix
2525
fromsix.movesimportxrange,zip
2626

27+
importlogging
2728
importwarnings
2829

2930
importnumpyasnp
@@ -44,6 +45,8 @@
4445
importmatplotlib._constrained_layoutasconstrained_layout
4546
frommatplotlibimportdocstring
4647

48+
_log=logging.getLogger(__name__)
49+
4750
make_axes_kw_doc='''
4851
4952
============= ====================================================
@@ -217,6 +220,65 @@ def _set_ticks_on_axis_warn(*args, **kw):
217220
warnings.warn("Use the colorbar set_ticks() method instead.")
218221

219222

223+
class_ColorbarAutoLocator(ticker.MaxNLocator):
224+
"""
225+
AutoLocator for Colorbar
226+
227+
This locator is just a `.MaxNLocator` except the min and max are
228+
clipped by the norm's min and max (i.e. vmin/vmax from the
229+
image/pcolor/contour object). This is necessary so ticks don't
230+
extrude into the "extend regions".
231+
"""
232+
233+
def__init__(self,colorbar):
234+
"""
235+
_ColorbarAutoLocator(colorbar)
236+
237+
This ticker needs to know the *colorbar* so that it can access
238+
its *vmin* and *vmax*. Otherwise it is the same as
239+
`~.ticker.AutoLocator`.
240+
"""
241+
242+
self._colorbar=colorbar
243+
nbins='auto'
244+
steps= [1,2,2.5,5,10]
245+
ticker.MaxNLocator.__init__(self,nbins=nbins,steps=steps)
246+
247+
deftick_values(self,vmin,vmax):
248+
vmin=max(vmin,self._colorbar.norm.vmin)
249+
vmax=min(vmax,self._colorbar.norm.vmax)
250+
returnticker.MaxNLocator.tick_values(self,vmin,vmax)
251+
252+
253+
class_ColorbarLogLocator(ticker.LogLocator):
254+
"""
255+
LogLocator for Colorbarbar
256+
257+
This locator is just a `.LogLocator` except the min and max are
258+
clipped by the norm's min and max (i.e. vmin/vmax from the
259+
image/pcolor/contour object). This is necessary so ticks don't
260+
extrude into the "extend regions".
261+
262+
"""
263+
def__init__(self,colorbar,*args,**kwargs):
264+
"""
265+
_ColorbarLogLocator(colorbar, *args, **kwargs)
266+
267+
This ticker needs to know the *colorbar* so that it can access
268+
its *vmin* and *vmax*. Otherwise it is the same as
269+
`~.ticker.LogLocator`. The ``*args`` and ``**kwargs`` are the
270+
same as `~.ticker.LogLocator`.
271+
"""
272+
self._colorbar=colorbar
273+
ticker.LogLocator.__init__(self,*args,**kwargs)
274+
275+
deftick_values(self,vmin,vmax):
276+
vmin=self._colorbar.norm.vmin
277+
vmax=self._colorbar.norm.vmax
278+
ticks=ticker.LogLocator.tick_values(self,vmin,vmax)
279+
returnticks[(ticks>=vmin)& (ticks<=vmax)]
280+
281+
220282
classColorbarBase(cm.ScalarMappable):
221283
'''
222284
Draw a colorbar in an existing axes.
@@ -346,8 +408,15 @@ def draw_all(self):
346408
and do all the drawing.
347409
'''
348410

411+
# sets self._boundaries and self._values in real data units.
412+
# takes into account extend values:
349413
self._process_values()
414+
# sets self.vmin and vmax in data units, but just for
415+
# the part of the colorbar that is not part of the extend
416+
# patch:
350417
self._find_range()
418+
# returns the X and Y mesh, *but* this was/is in normalized
419+
# units:
351420
X,Y=self._mesh()
352421
C=self._values[:,np.newaxis]
353422
self._config_axes(X,Y)
@@ -356,35 +425,103 @@ def draw_all(self):
356425

357426
defconfig_axis(self):
358427
ax=self.ax
428+
if (isinstance(self.norm,colors.LogNorm)
429+
andself._use_auto_colorbar_locator()):
430+
# *both* axes are made log so that determining the
431+
# mid point is easier.
432+
ax.set_xscale('log')
433+
ax.set_yscale('log')
434+
359435
ifself.orientation=='vertical':
360-
ax.xaxis.set_ticks([])
361-
# location is either one of 'bottom' or 'top'
362-
ax.yaxis.set_label_position(self.ticklocation)
363-
ax.yaxis.set_ticks_position(self.ticklocation)
436+
long_axis,short_axis=ax.yaxis,ax.xaxis
364437
else:
365-
ax.yaxis.set_ticks([])
366-
# location is either one of 'left' or 'right'
367-
ax.xaxis.set_label_position(self.ticklocation)
368-
ax.xaxis.set_ticks_position(self.ticklocation)
438+
long_axis,short_axis=ax.xaxis,ax.yaxis
439+
440+
long_axis.set_label_position(self.ticklocation)
441+
long_axis.set_ticks_position(self.ticklocation)
442+
short_axis.set_ticks([])
443+
short_axis.set_ticks([],minor=True)
369444

370445
self._set_label()
371446

447+
def_get_ticker_locator_formatter(self):
448+
"""
449+
This code looks at the norm being used by the colorbar
450+
and decides what locator and formatter to use. If ``locator`` has
451+
already been set by hand, it just returns
452+
``self.locator, self.formatter``.
453+
"""
454+
locator=self.locator
455+
formatter=self.formatter
456+
iflocatorisNone:
457+
ifself.boundariesisNone:
458+
ifisinstance(self.norm,colors.NoNorm):
459+
nv=len(self._values)
460+
base=1+int(nv/10)
461+
locator=ticker.IndexLocator(base=base,offset=0)
462+
elifisinstance(self.norm,colors.BoundaryNorm):
463+
b=self.norm.boundaries
464+
locator=ticker.FixedLocator(b,nbins=10)
465+
elifisinstance(self.norm,colors.LogNorm):
466+
locator=_ColorbarLogLocator(self)
467+
elifisinstance(self.norm,colors.SymLogNorm):
468+
# The subs setting here should be replaced
469+
# by logic in the locator.
470+
locator=ticker.SymmetricalLogLocator(
471+
subs=np.arange(1,10),
472+
linthresh=self.norm.linthresh,
473+
base=10)
474+
else:
475+
ifmpl.rcParams['_internal.classic_mode']:
476+
locator=ticker.MaxNLocator()
477+
else:
478+
locator=_ColorbarAutoLocator(self)
479+
else:
480+
b=self._boundaries[self._inside]
481+
locator=ticker.FixedLocator(b,nbins=10)
482+
_log.debug('locator: %r',locator)
483+
returnlocator,formatter
484+
485+
def_use_auto_colorbar_locator(self):
486+
"""
487+
Return if we should use an adjustable tick locator or a fixed
488+
one. (check is used twice so factored out here...)
489+
"""
490+
return (self.boundariesisNone
491+
andself.valuesisNone
492+
and ((type(self.norm)==colors.Normalize)
493+
or (type(self.norm)==colors.LogNorm)))
494+
372495
defupdate_ticks(self):
373496
"""
374497
Force the update of the ticks and ticklabels. This must be
375498
called whenever the tick locator and/or tick formatter changes.
376499
"""
377500
ax=self.ax
378-
ticks,ticklabels,offset_string=self._ticker()
379-
ifself.orientation=='vertical':
380-
ax.yaxis.set_ticks(ticks)
381-
ax.set_yticklabels(ticklabels)
382-
ax.yaxis.get_major_formatter().set_offset_string(offset_string)
501+
# get the locator and formatter. Defaults to
502+
# self.locator if not None..
503+
locator,formatter=self._get_ticker_locator_formatter()
383504

505+
ifself.orientation=='vertical':
506+
long_axis,short_axis=ax.yaxis,ax.xaxis
384507
else:
385-
ax.xaxis.set_ticks(ticks)
386-
ax.set_xticklabels(ticklabels)
387-
ax.xaxis.get_major_formatter().set_offset_string(offset_string)
508+
long_axis,short_axis=ax.xaxis,ax.yaxis
509+
510+
ifself._use_auto_colorbar_locator():
511+
_log.debug('Using auto colorbar locator on colorbar')
512+
_log.debug('locator: %r',locator)
513+
long_axis.set_major_locator(locator)
514+
long_axis.set_major_formatter(formatter)
515+
iftype(self.norm)==colors.LogNorm:
516+
long_axis.set_minor_locator(_ColorbarLogLocator(self,
517+
base=10.,subs='auto'))
518+
long_axis.set_minor_formatter(ticker.NullFormatter())
519+
else:
520+
_log.debug('Using fixed locator on colorbar')
521+
ticks,ticklabels,offset_string=self._ticker(locator,formatter)
522+
long_axis.set_ticks(ticks)
523+
long_axis.set_ticklabels(ticklabels)
524+
long_axis.get_major_formatter().set_offset_string(offset_string)
388525

389526
defset_ticks(self,ticks,update_ticks=True):
390527
"""
@@ -520,6 +657,7 @@ def _add_solids(self, X, Y, C):
520657
# since the axes object should already have hold set.
521658
_hold=self.ax._hold
522659
self.ax._hold=True
660+
_log.debug('Setting pcolormesh')
523661
col=self.ax.pcolormesh(*args,**kw)
524662
self.ax._hold=_hold
525663
#self.add_observer(col) # We should observe, not be observed...
@@ -573,39 +711,11 @@ def add_lines(self, levels, colors, linewidths, erase=True):
573711
self.ax.add_collection(col)
574712
self.stale=True
575713

576-
def_ticker(self):
714+
def_ticker(self,locator,formatter):
577715
'''
578716
Return the sequence of ticks (colorbar data locations),
579717
ticklabels (strings), and the corresponding offset string.
580718
'''
581-
locator=self.locator
582-
formatter=self.formatter
583-
iflocatorisNone:
584-
ifself.boundariesisNone:
585-
ifisinstance(self.norm,colors.NoNorm):
586-
nv=len(self._values)
587-
base=1+int(nv/10)
588-
locator=ticker.IndexLocator(base=base,offset=0)
589-
elifisinstance(self.norm,colors.BoundaryNorm):
590-
b=self.norm.boundaries
591-
locator=ticker.FixedLocator(b,nbins=10)
592-
elifisinstance(self.norm,colors.LogNorm):
593-
locator=ticker.LogLocator(subs='all')
594-
elifisinstance(self.norm,colors.SymLogNorm):
595-
# The subs setting here should be replaced
596-
# by logic in the locator.
597-
locator=ticker.SymmetricalLogLocator(
598-
subs=np.arange(1,10),
599-
linthresh=self.norm.linthresh,
600-
base=10)
601-
else:
602-
ifmpl.rcParams['_internal.classic_mode']:
603-
locator=ticker.MaxNLocator()
604-
else:
605-
locator=ticker.AutoLocator()
606-
else:
607-
b=self._boundaries[self._inside]
608-
locator=ticker.FixedLocator(b,nbins=10)
609719
ifisinstance(self.norm,colors.NoNorm)andself.boundariesisNone:
610720
intv=self._values[0],self._values[-1]
611721
else:
@@ -845,17 +955,29 @@ def _mesh(self):
845955
transposition for a horizontal colorbar are done outside
846956
this function.
847957
'''
958+
# if boundaries and values are None, then we can go ahead and
959+
# scale this up for Auto tick location. Otherwise we
960+
# want to keep normalized between 0 and 1 and use manual tick
961+
# locations.
962+
848963
x=np.array([0.0,1.0])
849964
ifself.spacing=='uniform':
850965
y=self._uniform_y(self._central_N())
851966
else:
852967
y=self._proportional_y()
968+
ifself._use_auto_colorbar_locator():
969+
y=self.norm.inverse(y)
970+
x=self.norm.inverse(x)
853971
self._y=y
854972
X,Y=np.meshgrid(x,y)
973+
ifself._use_auto_colorbar_locator():
974+
xmid=self.norm.inverse(0.5)
975+
else:
976+
xmid=0.5
855977
ifself._extend_lower()andnotself.extendrect:
856-
X[0, :]=0.5
978+
X[0, :]=xmid
857979
ifself._extend_upper()andnotself.extendrect:
858-
X[-1, :]=0.5
980+
X[-1, :]=xmid
859981
returnX,Y
860982

861983
def_locate(self,x):
Binary file not shown.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp