2013-10-09 3 views
16

На рисунке ниже у меня есть две диаграммы рассеяния, которые имеют разную шкалу чисел, поэтому их метки оси Y не выровнены. Есть ли способ заставить горизонтальное выравнивание по меткам оси Y?matplotlib: выравнивание меток оси Y в многоуровневых диаграммах рассеяния

import matplotlib.pylab as plt 
import random 
import matplotlib.gridspec as gridspec 

random.seed(20) 
data1 = [random.random() for i in range(10)] 
data2 = [random.random()*1000 for i in range(10)] 

gs = gridspec.GridSpec(2,1) 
fig = plt.figure() 

ax = fig.add_subplot(gs[0]) 
ax.plot(data1) 
ax.set_ylabel(r'Label One', size =16) 

ax = fig.add_subplot(gs[1]) 
ax.plot(data2) 
ax.set_ylabel(r'Label Two', size =16) 

plt.show() 

stacked scatter plots

+0

то, что вы хотите, описано здесь: http://matplotlib.org/faq/howto_faq.html # align-my-ylabels-through-multiple-subplots –

ответ

18

Вы можете использовать метод set_label_coords.

import matplotlib.pylab as plt 
import random 
import matplotlib.gridspec as gridspec 

random.seed(20) 
data1 = [random.random() for i in range(10)] 
data2 = [random.random()*1000 for i in range(10)] 

gs = gridspec.GridSpec(2,1) 
fig = plt.figure() 

ax = fig.add_subplot(gs[0]) 
ax.plot(data1) 
ax.set_ylabel(r'Label One', size =16) 
ax.get_yaxis().set_label_coords(-0.1,0.5) 

ax = fig.add_subplot(gs[1]) 
ax.plot(data2) 
ax.set_ylabel(r'Label Two', size =16) 
ax.get_yaxis().set_label_coords(-0.1,0.5) 

enter image description here

+0

спасибо! Я пытался сделать что-то вроде «ax.get_yaxis(). Get_label(). Set_ha (« left »), но это не сработало. Наверное, я не совсем понял, как работают выравнивания ярлыков. – dimka

+3

Есть ли способ * автоматически определить, какое минимальное допустимое расстояние от меток на обеих осях? То есть чтобы определить, что такое независимые автоматические позиции, а затем явно установить их равными наибольшему? – andybuckley

+3

@andybuckley, я просто играл с автоматическим выравниванием меток. Вы можете получить минимальные/максимальные значения позиций, используя 'ax.yaxis.label.get_position()', но координатное пространство не совпадает с тем, что используется в 'ax.yaxis.set_label_coords()' - у вас есть для использования 'ax.yaxis.label.set_position()' и немного взлома: 'ax.yaxis._autolabelpos = False', иначе он сбрасывает позицию, когда вы вызываете' draw() ' –

2

Как писал в комментариях, что вы ищете решается с помощью set_label_coords() в described here. В вашем случае это будет что-то вроде:

labelx = -0.5 

ax = fig.add_subplot(gs[0]) 
ax.plot(data1) 
ax.set_ylabel(r'Label One', size=16) 
ax.yaxis.set_label_coords(labelx, 0.5) 

ax = fig.add_subplot(gs[1]) 
ax.plot(data2) 
ax.set_ylabel(r'Label Two', size=16) 
ax.yaxis.set_label_coords(labelx, 0.5) 
1

Здесь функции я написал для автоматического выравнивания этикеток, но это не похоже на работу в сценарии, только в интерактивном режиме.

def align_labels(axes_list,axis='y',align=None): 
    if align is None: 
     align = 'l' if axis == 'y' else 'b' 
    yx,xy = [],[] 
    for ax in axes_list: 
     yx.append(ax.yaxis.label.get_position()[0]) 
     xy.append(ax.xaxis.label.get_position()[1]) 

    if axis == 'x': 
     if align in ('t','top'): 
      lim = max(xy) 
     elif align in ('b','bottom'): 
      lim = min(xy) 
    else: 
     if align in ('l','left'): 
      lim = min(yx) 
     elif align in ('r','right'): 
      lim = max(yx) 

    if align in ('t','b','top','bottom'): 
     for ax in axes_list: 
      t = ax.xaxis.label.get_transform() 
      x,y = ax.xaxis.label.get_position() 
      ax.xaxis.set_label_coords(x,lim,t) 
    else: 
     for ax in axes_list: 
      t = ax.yaxis.label.get_transform() 
      x,y = ax.yaxis.label.get_position() 
      ax.yaxis.set_label_coords(lim,y,t) 

И пример:

fig,ax = subplots(2,2) 
ax00,ax01 = ax[0] 
ax10,ax11 = ax[1] 
ax00.set_ylim(1000,5000) 
ax00.set_ylabel('top') 
ax10.set_ylabel('bottom') 
ax10.set_xlabel('left') 
ax11.set_xlabel('right') 
ax11.xaxis.axis_date() 
fig.autofmt_xdate() 
#we have to call draw() so that matplotlib will figure out the automatic positions 
fig.canvas.draw() 
align_labels(ax[:,0],'y') 
align_labels(ax[1],'x') 

example figure

0

Я обеспечить решение в конце, но сначала я скажу, какой путь не приводит к успеху.

Я недавно рассмотрел этот вопрос и провел довольно много времени с попытками различных решений, т. Е. Попробовал практически все возможные комбинации преобразований между различными системами координат и их связь с tight_layout(). Я экспериментировал только с backend_pdf, поэтому я не могу сказать об интерактивных медиа. Но вкратце, мой вывод заключается в том, что независимо от того, как вы пытаетесь выяснить позиции и попытаться их преобразовать, на этом уровне невозможно согласовать метки осей. Думаю, как-то это должно быть возможно, например, как-то внутренне matplotlib может выровнять оси самих подзаговоров. только с рисованием в файл в формате PDF в два раза, и делать что-то вроде ниже Inbetween, я мог бы добиться лучших позиций, но до сих пор не приведены в соответствие:

# sorry for the `self`, this is from a class 
def align_x_labels(self): 
    self.lowest_ax = min(self.axes.values(), 
         key = lambda ax: ax.xaxis.label.get_position()[1]) 
    self.lowest_xlab_dcoo = self.lowest_ax.transData.transform(
     self.lowest_ax.xaxis.label.get_position()) 
    list(
     map(
       lambda ax: \ 
        ax.xaxis.set_label_coords(
         self.fig.transFigure.inverted().transform(
          ax.transAxes.transform((0.5, 0.5)))[0], 
         self.fig.transFigure.inverted().transform(
          self.lowest_xlab_dcoo)[1], 
         transform = self.fig.transFigure 
        ), 
       self.axes.values() 
      ) 
    ) 

Стыдно такие основные функциональные возможности не могут быть достигнуты, и это неясно, как различные координатные пространства преобразуются и масштабируются на разных этапах построения. Я был бы очень рад увидеть это, потому что matplotlib webpage только описывает архитектуру, представляет простые случаи, но не объясняет подобные ситуации. Также я удивляюсь, что методы, принимающие или возвращающие координаты, не указывают в своей докштрине, какие типы координат являются таковыми. Наконец, я нашел очень полезным this tutorial.

Решение

В конце концов, вместо того, чтобы возиться с преобразованиями, я создал в GridSpec дополнительный ряд нулевой высоты и невидимых осей (то же самое можно сделать с нулевой шириной колонка у меток оси). Затем я добавил метки для этих подзаговоров, установив verticalalignment на top.

# get one of the zero height phantom subplots to `self.ax`: 
self.get_subplot(i, 1) 
# set empty ticklabels: 
self.ax.xaxis.set_ticklabels([]) 
self.ax.yaxis.set_ticklabels([]) 
# set the axis label: 
self.ax.set_xlabel(labtext, fontproperties = self.fp_axis_lab) 
# and this is matter of aesthetics 
# sometimes bottom or center might look better: 
self.ax.xaxis.label.set_verticalalignment('top') 
Смежные вопросы