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

Commit5972691

Browse files
committed
ENH: colorbar ticks adjustable to colorbar size
1 parentf96fac0 commit5972691

File tree

11 files changed

+1055
-1167
lines changed

11 files changed

+1055
-1167
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/axis.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2364,6 +2364,7 @@ def set_view_interval(self, vmin, vmax, ignore=False):
23642364
:meth:`~matplotlib.axes.Axes.set_ylim`.
23652365
23662366
"""
2367+
23672368
ifignore:
23682369
self.axes.viewLim.intervaly=vmin,vmax
23692370
else:

‎lib/matplotlib/colorbar.py

Lines changed: 184 additions & 41 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
@@ -43,6 +44,8 @@
4344

4445
frommatplotlibimportdocstring
4546

47+
_log=logging.getLogger(__name__)
48+
4649
make_axes_kw_doc='''
4750
4851
============= ====================================================
@@ -216,6 +219,65 @@ def _set_ticks_on_axis_warn(*args, **kw):
216219
warnings.warn("Use the colorbar set_ticks() method instead.")
217220

218221

222+
classColorbarAutoLocator(ticker.MaxNLocator):
223+
"""
224+
AutoLocator for Colorbar
225+
226+
This locator is just a `.MaxNLocator` except the min and max are
227+
clipped by the norm's min and max (i.e. vmin/vmax from the
228+
image/pcolor/contour object). This is necessary so ticks don't
229+
extrude into the "extend regions".
230+
"""
231+
232+
def__init__(self,colorbar):
233+
"""
234+
ColorbarAutoLocator(colorbar)
235+
236+
This ticker needs to know the *colorbar* so that it can access
237+
its *vmin* and *vmax*. Otherwise it is the same as
238+
`~.ticker.AutoLocator`.
239+
"""
240+
241+
self._colorbar=colorbar
242+
nbins='auto'
243+
steps= [1,2,2.5,5,10]
244+
ticker.MaxNLocator.__init__(self,nbins=nbins,steps=steps)
245+
246+
deftick_values(self,vmin,vmax):
247+
vmin=max(vmin,self._colorbar.norm.vmin)
248+
vmax=min(vmax,self._colorbar.norm.vmax)
249+
returnticker.MaxNLocator.tick_values(self,vmin,vmax)
250+
251+
252+
classColorbarLogLocator(ticker.LogLocator):
253+
"""
254+
LogLocator for Colorbarbar
255+
256+
This locator is just a `.LogLocator` except the min and max are
257+
clipped by the norm's min and max (i.e. vmin/vmax from the
258+
image/pcolor/contour object). This is necessary so ticks don't
259+
extrude into the "extend regions".
260+
261+
"""
262+
def__init__(self,colorbar,*args,**kwargs):
263+
"""
264+
ColorbarLogLocator(colorbar, *args, **kwargs)
265+
266+
This ticker needs to know the *colorbar* so that it can access
267+
its *vmin* and *vmax*. Otherwise it is the same as
268+
`~.ticker.LogLocator`. The ``*args`` and ``**kwargs`` are the
269+
same as `~.ticker.LogLocator`.
270+
"""
271+
self._colorbar=colorbar
272+
ticker.LogLocator.__init__(self,*args,**kwargs)
273+
274+
deftick_values(self,vmin,vmax):
275+
vmin=self._colorbar.norm.vmin
276+
vmax=self._colorbar.norm.vmax
277+
ticks=ticker.LogLocator.tick_values(self,vmin,vmax)
278+
returnticks[(ticks>=vmin)& (ticks<=vmax)]
279+
280+
219281
classColorbarBase(cm.ScalarMappable):
220282
'''
221283
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)
@@ -357,34 +426,119 @@ def draw_all(self):
357426
defconfig_axis(self):
358427
ax=self.ax
359428
ifself.orientation=='vertical':
360-
ax.xaxis.set_ticks([])
361429
# location is either one of 'bottom' or 'top'
362430
ax.yaxis.set_label_position(self.ticklocation)
363431
ax.yaxis.set_ticks_position(self.ticklocation)
432+
if (isinstance(self.norm,colors.LogNorm)
433+
andself._use_adjustable()):
434+
ax.set_xscale('log')
435+
ax.set_yscale('log')
436+
ax.xaxis.set_ticks([])
437+
ax.xaxis.set_ticks([],minor=True)
438+
364439
else:
365-
ax.yaxis.set_ticks([])
366440
# location is either one of 'left' or 'right'
367441
ax.xaxis.set_label_position(self.ticklocation)
368442
ax.xaxis.set_ticks_position(self.ticklocation)
443+
if (isinstance(self.norm,colors.LogNorm)
444+
andself._use_adjustable()):
445+
ax.set_xscale('log')
446+
ax.set_yscale('log')
447+
ax.yaxis.set_ticks([])
448+
ax.yaxis.set_ticks([],minor=True)
369449

370450
self._set_label()
371451

452+
def_get_ticker_locator_formatter(self):
453+
"""
454+
This code looks at the norm being used by the colorbar
455+
and decides what locator and formatter to use. If ``locator`` has
456+
already been set by hand, it just returns
457+
``self.locator, self.formatter``.
458+
"""
459+
locator=self.locator
460+
formatter=self.formatter
461+
iflocatorisNone:
462+
ifself.boundariesisNone:
463+
ifisinstance(self.norm,colors.NoNorm):
464+
nv=len(self._values)
465+
base=1+int(nv/10)
466+
locator=ticker.IndexLocator(base=base,offset=0)
467+
elifisinstance(self.norm,colors.BoundaryNorm):
468+
b=self.norm.boundaries
469+
locator=ticker.FixedLocator(b,nbins=10)
470+
elifisinstance(self.norm,colors.LogNorm):
471+
locator=ColorbarLogLocator(self)
472+
elifisinstance(self.norm,colors.SymLogNorm):
473+
# The subs setting here should be replaced
474+
# by logic in the locator.
475+
locator=ticker.SymmetricalLogLocator(
476+
subs=np.arange(1,10),
477+
linthresh=self.norm.linthresh,
478+
base=10)
479+
else:
480+
ifmpl.rcParams['_internal.classic_mode']:
481+
locator=ticker.MaxNLocator()
482+
else:
483+
locator=ColorbarAutoLocator(self)
484+
else:
485+
b=self._boundaries[self._inside]
486+
locator=ticker.FixedLocator(b,nbins=10)
487+
_log.debug('locator: %r',locator)
488+
returnlocator,formatter
489+
490+
def_use_adjustable(self):
491+
"""
492+
Return if we should use an adjustable tick locator or a fixed
493+
one. (check is used twice so factored out here...)
494+
"""
495+
return (self.boundariesisNone
496+
andself.valuesisNone
497+
and ((type(self.norm)==colors.Normalize)
498+
or (type(self.norm)==colors.LogNorm)))
499+
372500
defupdate_ticks(self):
373501
"""
374502
Force the update of the ticks and ticklabels. This must be
375503
called whenever the tick locator and/or tick formatter changes.
376504
"""
377505
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)
506+
# get the locator and formatter. Defaults to
507+
# self.locator if not None..
508+
locator,formatter=self._get_ticker_locator_formatter()
509+
510+
ifself._use_adjustable():
511+
_log.debug('Using adjustable locator on colorbar')
512+
_log.debug('locator: %r',locator)
513+
#self._find_range()
514+
ifself.orientation=='vertical':
515+
ax.yaxis.set_major_locator(locator)
516+
ax.yaxis.set_major_formatter(formatter)
517+
iftype(self.norm)==colors.LogNorm:
518+
ax.yaxis.set_minor_locator(ColorbarLogLocator(self,
519+
base=10.,subs='auto'))
520+
ax.yaxis.set_minor_formatter(ticker.NullFormatter())
521+
522+
else:
523+
ax.xaxis.set_major_locator(locator)
524+
ax.xaxis.set_major_formatter(formatter)
525+
iftype(self.norm)==colors.LogNorm:
526+
ax.xaxis.set_minor_locator(ColorbarLogLocator(self,
527+
base=10.,subs='auto'))
528+
ax.xaxis.set_minor_formatter(ticker.NullFormatter())
383529

384530
else:
385-
ax.xaxis.set_ticks(ticks)
386-
ax.set_xticklabels(ticklabels)
387-
ax.xaxis.get_major_formatter().set_offset_string(offset_string)
531+
_log.debug('Using fixed locator on colorbar')
532+
ticks,ticklabels,offset_string=self._ticker(locator,formatter)
533+
ifself.orientation=='vertical':
534+
ax.yaxis.set_ticks(ticks)
535+
ax.set_yticklabels(ticklabels)
536+
ax.yaxis.get_major_formatter().set_offset_string(offset_string)
537+
538+
else:
539+
ax.xaxis.set_ticks(ticks)
540+
ax.set_xticklabels(ticklabels)
541+
ax.xaxis.get_major_formatter().set_offset_string(offset_string)
388542

389543
defset_ticks(self,ticks,update_ticks=True):
390544
"""
@@ -520,6 +674,7 @@ def _add_solids(self, X, Y, C):
520674
# since the axes object should already have hold set.
521675
_hold=self.ax._hold
522676
self.ax._hold=True
677+
_log.debug('Setting pcolormesh')
523678
col=self.ax.pcolormesh(*args,**kw)
524679
self.ax._hold=_hold
525680
#self.add_observer(col) # We should observe, not be observed...
@@ -574,39 +729,11 @@ def add_lines(self, levels, colors, linewidths, erase=True):
574729
self.ax.add_collection(col)
575730
self.stale=True
576731

577-
def_ticker(self):
732+
def_ticker(self,locator,formatter):
578733
'''
579734
Return the sequence of ticks (colorbar data locations),
580735
ticklabels (strings), and the corresponding offset string.
581736
'''
582-
locator=self.locator
583-
formatter=self.formatter
584-
iflocatorisNone:
585-
ifself.boundariesisNone:
586-
ifisinstance(self.norm,colors.NoNorm):
587-
nv=len(self._values)
588-
base=1+int(nv/10)
589-
locator=ticker.IndexLocator(base=base,offset=0)
590-
elifisinstance(self.norm,colors.BoundaryNorm):
591-
b=self.norm.boundaries
592-
locator=ticker.FixedLocator(b,nbins=10)
593-
elifisinstance(self.norm,colors.LogNorm):
594-
locator=ticker.LogLocator(subs='all')
595-
elifisinstance(self.norm,colors.SymLogNorm):
596-
# The subs setting here should be replaced
597-
# by logic in the locator.
598-
locator=ticker.SymmetricalLogLocator(
599-
subs=np.arange(1,10),
600-
linthresh=self.norm.linthresh,
601-
base=10)
602-
else:
603-
ifmpl.rcParams['_internal.classic_mode']:
604-
locator=ticker.MaxNLocator()
605-
else:
606-
locator=ticker.AutoLocator()
607-
else:
608-
b=self._boundaries[self._inside]
609-
locator=ticker.FixedLocator(b,nbins=10)
610737
ifisinstance(self.norm,colors.NoNorm)andself.boundariesisNone:
611738
intv=self._values[0],self._values[-1]
612739
else:
@@ -851,12 +978,28 @@ def _mesh(self):
851978
y=self._uniform_y(self._central_N())
852979
else:
853980
y=self._proportional_y()
981+
# if boundaries and values are None, then we can go ahead and
982+
# scale this up for Auto tick location. Otherwise we
983+
# want to keep normalized between 0 and 1 and use manual tick
984+
# locations.
985+
ifself._use_adjustable():
986+
y=self.norm.inverse(y)
987+
x=self.norm.inverse(x)
988+
else:
989+
dy=1.0
854990
self._y=y
991+
855992
X,Y=np.meshgrid(x,y)
856993
ifself._extend_lower()andnotself.extendrect:
857-
X[0, :]=0.5
994+
ifself._use_adjustable():
995+
X[0, :]=self.norm.inverse(0.5)
996+
else:
997+
X[0, :]=0.5
858998
ifself._extend_upper()andnotself.extendrect:
859-
X[-1, :]=0.5
999+
ifself._use_adjustable():
1000+
X[-1, :]=self.norm.inverse(0.5)
1001+
else:
1002+
X[-1, :]=0.5
8601003
returnX,Y
8611004

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp