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

Commit651d609

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

File tree

10 files changed

+1045
-1174
lines changed

10 files changed

+1045
-1174
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: 175 additions & 48 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,108 @@ 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)
383-
501+
# get the locator and formatter. Defaults to
502+
# self.locator if not None..
503+
locator,formatter=self._get_ticker_locator_formatter()
504+
505+
ifself._use_auto_colorbar_locator():
506+
_log.debug('Using auto colorbar locator on colorbar')
507+
_log.debug('locator: %r',locator)
508+
ifself.orientation=='vertical':
509+
long_axis,short_axis=ax.yaxis,ax.xaxis
510+
else:
511+
long_axis,short_axis=ax.xaxis,ax.yaxis
512+
long_axis.set_major_locator(locator)
513+
long_axis.set_major_formatter(formatter)
514+
iftype(self.norm)==colors.LogNorm:
515+
long_axis.set_minor_locator(_ColorbarLogLocator(self,
516+
base=10.,subs='auto'))
517+
long_axis.set_minor_formatter(ticker.NullFormatter())
384518
else:
385-
ax.xaxis.set_ticks(ticks)
386-
ax.set_xticklabels(ticklabels)
387-
ax.xaxis.get_major_formatter().set_offset_string(offset_string)
519+
_log.debug('Using fixed locator on colorbar')
520+
ticks,ticklabels,offset_string=self._ticker(locator,formatter)
521+
ifself.orientation=='vertical':
522+
ax.yaxis.set_ticks(ticks)
523+
ax.set_yticklabels(ticklabels)
524+
ax.yaxis.get_major_formatter().set_offset_string(offset_string)
525+
526+
else:
527+
ax.xaxis.set_ticks(ticks)
528+
ax.set_xticklabels(ticklabels)
529+
ax.xaxis.get_major_formatter().set_offset_string(offset_string)
388530

389531
defset_ticks(self,ticks,update_ticks=True):
390532
"""
@@ -520,6 +662,7 @@ def _add_solids(self, X, Y, C):
520662
# since the axes object should already have hold set.
521663
_hold=self.ax._hold
522664
self.ax._hold=True
665+
_log.debug('Setting pcolormesh')
523666
col=self.ax.pcolormesh(*args,**kw)
524667
self.ax._hold=_hold
525668
#self.add_observer(col) # We should observe, not be observed...
@@ -573,39 +716,11 @@ def add_lines(self, levels, colors, linewidths, erase=True):
573716
self.ax.add_collection(col)
574717
self.stale=True
575718

576-
def_ticker(self):
719+
def_ticker(self,locator,formatter):
577720
'''
578721
Return the sequence of ticks (colorbar data locations),
579722
ticklabels (strings), and the corresponding offset string.
580723
'''
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)
609724
ifisinstance(self.norm,colors.NoNorm)andself.boundariesisNone:
610725
intv=self._values[0],self._values[-1]
611726
else:
@@ -845,17 +960,29 @@ def _mesh(self):
845960
transposition for a horizontal colorbar are done outside
846961
this function.
847962
'''
963+
# if boundaries and values are None, then we can go ahead and
964+
# scale this up for Auto tick location. Otherwise we
965+
# want to keep normalized between 0 and 1 and use manual tick
966+
# locations.
967+
848968
x=np.array([0.0,1.0])
849969
ifself.spacing=='uniform':
850970
y=self._uniform_y(self._central_N())
851971
else:
852972
y=self._proportional_y()
973+
ifself._use_auto_colorbar_locator():
974+
y=self.norm.inverse(y)
975+
x=self.norm.inverse(x)
853976
self._y=y
854977
X,Y=np.meshgrid(x,y)
978+
ifself._use_auto_colorbar_locator():
979+
xmid=self.norm.inverse(0.5)
980+
else:
981+
xmid=0.5
855982
ifself._extend_lower()andnotself.extendrect:
856-
X[0, :]=0.5
983+
X[0, :]=xmid
857984
ifself._extend_upper()andnotself.extendrect:
858-
X[-1, :]=0.5
985+
X[-1, :]=xmid
859986
returnX,Y
860987

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp