matplotlib chart - создание горизонтальной гистограммы - PullRequest
14 голосов
/ 09 марта 2012

Я наткнулся на следующий фрагмент кода для создания горизонтальной гистограммы с помощью matplotlib:

import matplotlib
from pylab import *

val = 3+10*rand(5)    # the bar lengths
pos = arange(5)+.5    # the bar centers on the y axis
print pos
figure(1)
barh(pos,val, align='center')
yticks(pos, ('Tom', 'Dick', 'Harry', 'Slim', 'Jim'))
xlabel('Performance')
title('horizontal bar chart using matplotlib')
grid(True)
show()

Я хочу изменить приведенный выше скрипт следующим образом:

  1. Сделать построенный графикстолбцы «менее объемные» (т. е. уменьшают высоту отображаемых горизонтальных столбцов)
  2. Отображение как отрицательных, так и положительных чисел в виде горизонтальных столбцов на одном графике

любая помощь (фрагмент кода илиссылки), чтобы помочь мне сделать вышеупомянутые модификации, было бы очень полезно.

в качестве отступления, если бы я хотел сделать горизонтальные столбцы с накоплением (скажем, у каждого ярлыка было 3 горизонтальных столбца с накоплением), как бы я изменил код вышесделать график с тремя сложенными горизонтальными столбцами?

[[Редактировать]]

Может кто-нибудь опубликовать два коротких фрагмента кода, которые показывают, как:

  1. Печать меток на противоположной стороне горизонтальных полос (например, метка для «отрицательных» полос появляется в 1-м карантине, а метки для «положительных» полос - во 2-й квадреnt

  2. Построить несколько (скажем, 2 или 3) горизонтальных полос (вместо одной).Хорошими примерами являются первые два изображения, показанные здесь

Ответы [ 3 ]

22 голосов
/ 09 марта 2012
import matplotlib
from pylab import *

val = 3-6*rand(5)    # the bar lengths        # changed your data slightly
pos = arange(5)+.5    # the bar centers on the y axis
print pos
figure(1)
barh(pos,val, align='center',height=0.1)    # notice the 'height' argument
yticks(pos, ('Tom', 'Dick', 'Harry', 'Slim', 'Jim'))

gca().axvline(0,color='k',lw=3)   # poor man's zero level

xlabel('Performance')
title('horizontal bar chart using matplotlib')
grid(True)
show()

В общем, я бы предложил не использовать from pyplot import *. Если вы не находитесь в интерактивном режиме, используйте объектно-ориентированный подход:

import matplotlib.pyplot as plt
from numpy.random import rand
from numpy import arange

val = 3-6*rand(5)    # the bar lengths
pos = arange(5)+.5    # the bar centers on the y axis
print pos

fig = plt.figure()
ax = fig.add_subplot(111)
ax.barh(pos,val, align='center',height=0.1)
ax.set_yticks(pos, ('Tom', 'Dick', 'Harry', 'Slim', 'Jim'))

ax.axvline(0,color='k',lw=3)   # poor man's zero level

ax.set_xlabel('Performance')
ax.set_title('horizontal bar chart using matplotlib')
ax.grid(True)
plt.show()

Хорошей отправной точкой для различных видов сюжетов является matplotlib галерея

9 голосов
/ 13 марта 2012

Как сказал Женя, вам придется настроить свой сюжет.

В качестве примера ниже приведена функция, которая производит настройку горизонтальной линейной диаграммы:

  • входные данные, заключенные в словарь
  • Затем он вычисляет положение тиков Y в соответствии с количеством тактов (гистограмм), которое вы имеете в каждой категории (человек), и расстоянием, которое вы хотите поместить между каждой категорией.
  • наконец, он отображает каждую меру данных (с другим цветом, если вы его указали)

По умолчанию название категорий (людей) будет отображаться справа, но вы, конечно, можете это изменить.

import numpy as np
import matplotlib.pyplot as plt

# creation of the data
name_list = ['day1', 'day2', 'day3', 'day4']
data = {name: 3+10*np.random.rand(5) for name in name_list}

colors_list = ['0.5', 'r', 'b', 'g'] #optional

def customize_barh(data, width_bar=1, width_space=0.5, colors=None):
    n_measure = len(data)                   #number of measure per people
    n_people = data[data.keys()[0]].size    # number of people

    #some calculation to determine the position of Y ticks labels
    total_space = n_people*(n_measure*width_bar)+(n_people-1)*width_space
    ind_space = n_measure*width_bar
    step = ind_space/2.
    pos = np.arange(step, total_space+width_space, ind_space+width_space)

    # create the figure and the axes to plot the data 
    fig = plt.figure(figsize=(8,6))
    ax = fig.add_axes([0.15, 0.15, 0.65, 0.7])

    # remove top and right spines and turn ticks off if no spine
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    ax.xaxis.set_ticks_position('bottom')
    ax.yaxis.set_ticks_position('right')    # ticks position on the right
    # postition of tick out
    ax.tick_params(axis='both', direction='out', width=3, length=6,
                   labelsize=24, pad=8)
    ax.spines['left'].set_linewidth(3)
    ax.spines['bottom'].set_linewidth(3)

    # plot the data
    for i,day in enumerate(data.keys()):
        if colors == None:
            ax.barh(pos-step+i*width_bar, data[day], width_bar, #facecolor='0.4',
                    edgecolor='k', linewidth=3)
        else:
            ax.barh(pos-step+i*width_bar, data[day], width_bar, facecolor=colors[i],
                    edgecolor='k', linewidth=3)


    ax.set_yticks(pos)
    # you may want to use the list of name as argument of the function to be more
    # flexible (if you have to add a people)
    ax.set_yticklabels(('Tom', 'Dick', 'Harry', 'Slim', 'Jim'))         
    ax.set_ylim((-width_space, total_space+width_space))
    ax.set_xlabel('Performance', size=26, labelpad=10)

customize_barh(data, colors=colors_list)
plt.savefig('perf.png')
plt.show()

который производит: this

1 голос
/ 17 марта 2012

Следующий фрагмент кода является примером использования текстовой функции для аннотирования текстовой метки с левой стороны для отрицательных значений и с правой стороны для положительных значений, как упоминали и gcalmettes, и Женя.

from pylab import setp
import numpy as np
import matplotlib.pyplot as plt
import math

# creation of the data
name_list = ['day1', 'day2', 'day3', 'day4']
data = {name: 3+10*np.random.rand(5) for name in name_list}

for name in name_list:
  data[name][0] = data[name][0]*-1
  data[name][2] = data[name][2]*-1

colors_list = ['0.5', 'r', 'b', 'g'] #optional

def customize_barh(data, width_bar=1, width_space=0.5, colors=None):
    n_measure = len(data)                   #number of measure per people
    n_people = data[data.keys()[0]].size    # number of people

    #some calculation to determine the position of Y ticks labels
    total_space = n_people*(n_measure*width_bar)+(n_people-1)*width_space
    ind_space = n_measure*width_bar
    step = ind_space/2.
    pos = np.arange(step, total_space+width_space, ind_space+width_space)
    # create the figure and the axes to plot the data 
    fig = plt.figure(figsize=(8,6))
    ax = fig.add_axes([0.15, 0.15, 0.65, 0.7])

    # remove top and right spines and turn ticks off if no spine
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    ax.xaxis.set_ticks_position('bottom')
    ax.yaxis.set_ticks_position('default')    # ticks position on the right
    # postition of tick out
    ax.tick_params(axis='both', direction='out', width=3, length=6,
                   labelsize=24, pad=8)
    ax.spines['left'].set_linewidth(3)
    ax.spines['bottom'].set_linewidth(3)

    # plot the data
    for i,day in enumerate(data.keys()):
        if colors == None:
            ax.barh(pos-step+i*width_bar, data[day], width_bar, #facecolor='0.4',
                    edgecolor='k', linewidth=3)
        else:
            ax.barh(pos-step+i*width_bar, data[day], width_bar, facecolor=colors[i],
                    edgecolor='k', linewidth=3)


    ax.set_yticks(pos)
    # you may want to use the list of name as argument of the function to be more
    # flexible (if you have to add a people)
    setp(ax.get_yticklabels(), visible=False)         
    ax.set_ylim((-width_space, total_space+width_space))
    ax.set_xlabel('Performance', size=26, labelpad=10)
    labels_list = ['Tom', 'Dick', 'Harry', 'Slim','Jim']

    # creation of an array of positive/negative values (based on the values
    # of the data) that will be used as x values for adding text as side labels
    side_list = []
    for index in range(len(labels_list)):
        sum = 0
        for name in name_list:
            sum+= data[name][index]
        if math.copysign(1,sum) > 0:
            side_list.append(16)
        else:
            side_list.append(-21)
    for label in labels_list:
        plt.text(side_list[labels_list.index(label)], pos[labels_list.index(label)]-0.5, label,fontsize=26) 
customize_barh(data, colors=colors_list)
plt.savefig('perf.png')
plt.show()

Это работает на основе того, что все столбцы для данного человека должны быть отрицательными или положительными, чтобы текст был аннотирован с правильной стороны.Чтобы изменить это поведение, просто измените генерацию side_list.

Например, если вы хотите, чтобы определенный порог бара определял положение метки, то посчитайте значения данных через этот порог вместо суммирования значений для данного имени..

Например, при пороговом значении 3 баров из всех, цикл for становится

for index in range(len(labels_list)):
        count = 0
            for name in name_list:
               if data[name][index] > 0:
                  count+= 1
            if count > 3:
              side_list.append(16)
            else:
              side_list.append(-21)

Поколение side_list также необходимо изменить, чтобы настроить диапазон ваших данных,В качестве примеров приведены случайные данные в указанном диапазоне.

Например, вам необходимо отрегулировать смещения меток side_list.append(16) и side_list.append(-21) в соответствии с вашими данными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...