2013-02-13 14 views
5

muszę narysować punchcard z matplotlib, które wydają się nie mieć takiego function.So mam zakodowany na następujący:Matplotlib: Jak usunąć pionową przestrzeń podczas wyświetlania okręgów na siatce?

import matplotlib.pyplot as plt 
import numpy as np 

def draw_punchcard(infos, 
       ax1=range(7), 
       ax2=range(24), 
       ax1_ticks=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], 
       ax2_ticks=range(24), 
       ax1_label='Day', 
       ax2_label='Hour'): 
    """Construct a punchcard. 
    Quick'n dirty way. 

    Parameters 
    ========== 
    - infos: Dictionary of quantities to display. 
      They are indexed by key of type (val1,val2) with 
      val1 included in ax1 and val2 included in ax2. 
    - ax1: list 
      Possible values for first axe (if different than days) 
    - ax2: list 
      Possible values for second axe (if different than hours) 
    - ax1_ticks: list 
      Value to display in ticks of first axe (if different than days) 
    - ax2_ticks: list 
      Value to display in ticks of second axe (if different than days) 
    - ax1_label: String 
      Value to give to first axis (if different than day) 
    - ax2_label: String 
      Value to give to second axis (if different than day) 

    """ 

    # build the array which contains the values 
    data = np.zeros((len(ax1),len(ax2))) 
    for key in infos: 
     data[key[0],key[1]] = infos[key] 
    data = data/float(np.max(data)) 


    # Draw the punchcard (create one circle per element) 
    # Ugly normalisation allows to obtain perfect circles instead of ovals.... 
    for y in range(data.shape[0]): 
     for x in range(data.shape[1]): 
      circle = plt.Circle((x/float(data.shape[1])*data.shape[0],y), 
           data[y][x]/float(data.shape[1])*data.shape[0]/2) 
      plt.gca().add_artist(circle) 

    plt.ylim(0-0.5, data.shape[0]-0.5) 
    plt.xlim(0, data.shape[0]) 
    plt.yticks(np.arange(len(ax1)), ax1_ticks) 
    plt.xticks(np.linspace(0,len(ax1),len(ax2))+0.5/float(data.shape[1]), ax2_ticks) 
    plt.xlabel(ax1_label) 
    plt.ylabel(ax2_label) 
    plt.gca().invert_yaxis() 

jednak nie dokładnie działa zgodnie z oczekiwaniami. Jeśli jest oceniana na poniższym przykładzie:

infos = {(6, 9): 12196, (0, 20): 22490, (1, 17): 59636, (0, 7): 14915, (2, 22): 7193, (1, 6): 11694, (0, 10): 85793, (3, 7): 17507, (2, 5): 4078, (1, 11): 83424, (5, 8): 33625, (4, 0): 1915, (6, 7): 10528, (5, 5): 3525, (4, 19): 33253, (6, 10): 12186, (5, 18): 20856, (0, 17): 61370, (0, 4): 551, (1, 1): 389, (4, 10): 94684, (3, 2): 286, (2, 6): 11845, (5, 11): 46822, (4, 5): 5215, (3, 23): 1841, (6, 0): 3441, (4, 16): 94545, (6, 23): 1285, (5, 21): 11096, (2, 17): 59928, (0, 1): 279, (3, 12): 56193, (1, 12): 59846, (4, 15): 102986, (3, 1): 371, (2, 11): 78007, (5, 14): 27711, (3, 18): 41365, (6, 13): 11994, (4, 21): 14477, (6, 16): 11669, (1, 21): 13629, (2, 18): 42399, (0, 14): 66284, (3, 11): 76402, (2, 1): 358, (1, 15): 93381, (4, 12): 67279, (2, 12): 57427, (5, 1): 509, (3, 17): 58974, (6, 14): 11383, (0, 21): 12604, (1, 16): 86199, (2, 23): 1914, (1, 5): 4002, (0, 11): 79164, (3, 6): 11434, (2, 2): 304, (1, 10): 88874, (4, 1): 420, (6, 4): 750, (5, 4): 783, (6, 11): 12886, (5, 17): 21573, (0, 18): 41842, (1, 19): 33073, (0, 5): 2777, (1, 0): 1189, (0, 8): 46486, (4, 11): 89246, (3, 5): 4105, (2, 7): 18534, (5, 10): 54826, (4, 6): 14638, (3, 22): 5043, (6, 1): 894, (5, 7): 16052, (4, 17): 66899, (6, 20): 16085, (5, 20): 18041, (0, 2): 219, (3, 15): 81526, (1, 3): 251, (4, 8): 58008, (3, 0): 1581, (2, 8): 47233, (5, 13): 23896, (3, 21): 13998, (6, 2): 540, (4, 22): 5920, (6, 17): 13856, (5, 23): 2155, (1, 20): 24386, (2, 19): 33216, (0, 15): 86664, (3, 10): 81444, (1, 14): 74440, (4, 13): 62307, (2, 13): 51784, (5, 0): 1959, (3, 16): 76742, (6, 15): 11438, (0, 22): 4055, (6, 18): 17554, (1, 23): 1681, (2, 20): 26427, (1, 4): 710, (0, 12): 59008, (3, 9): 72555, (2, 3): 372, (1, 9): 79140, (4, 2): 322, (2, 14): 68869, (6, 5): 3091, (5, 3): 392, (6, 8): 11720, (5, 16): 28663, (0, 19): 30223, (1, 18): 41624, (0, 6): 8791, (1, 7): 18280, (0, 9): 75860, (3, 4): 765, (2, 4): 834, (5, 9): 52874, (4, 7): 21830, (6, 6): 7618, (5, 6): 9935, (4, 18): 43274, (6, 21): 9836, (5, 19): 20758, (0, 16): 81458, (0, 3): 245, (3, 14): 66845, (1, 2): 291, (4, 9): 86355, (3, 3): 346, (2, 9): 71401, (5, 12): 27939, (4, 4): 987, (3, 20): 24478, (6, 3): 450, (4, 23): 2236, (6, 22): 3779, (5, 22): 4950, (2, 16): 79009, (0, 0): 1655, (3, 13): 53589, (1, 13): 55308, (4, 14): 81394, (2, 10): 80932, (5, 15): 32751, (3, 19): 32193, (6, 12): 12770, (4, 20): 24379, (0, 23): 1240, (6, 19): 18908, (1, 22): 4887, (2, 21): 16508, (0, 13): 54858, (3, 8): 47367, (2, 0): 1778, (1, 8): 50393, (4, 3): 387, (2, 15): 86256, (5, 2): 385} 
draw_punchcard(infos) 
plt.show() 

otrzymujemy następujący wynik: Generated punchard

Można zauważyć, istnieje wiele pustych przestrzeni w pionie pomiędzy kręgów, natomiast spodziewałbym dwa kręgi maksimum rozmiar do dotknięcia razem (byłby to poziomo, ale nie pionowo).

A więc, jak usunąć tę przestrzeń, zachowując współczynnik koła?

Bardzo dziękuję za pomoc.

+0

Myślę, że te kształty są nadal eliptyczny i nie okręgi. Spróbuj narysować koło obok nich w programie graficznym. –

+0

Tak, masz rację ... @Juxuxx rozwiązuje ten problem – rgiot

Odpowiedz

8

Zmieniłem pionowy odstęp okręgów na podstawie współczynnika kształtu danych (r = float(data.shape[1])/data.shape[0]). Rozmiar płótna zostanie zmieniony tak, aby pasował do wyniku, dzięki czemu nie pozostaniesz z dużym białym obszarem w domyślnym rozmiarze płótna.

Wynik:

Circle Plot with proper circle scaling

def draw_punchcard(infos, 
       ax1=range(7), 
       ax2=range(24), 
       ax1_ticks=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], 
       ax2_ticks=range(24), 
       ax1_label='Day', 
       ax2_label='Hour'): 

    # build the array which contains the values 
    data = np.zeros((len(ax1),len(ax2))) 
    for key in infos: 
     data[key[0],key[1]] = infos[key] 
    data = data/float(np.max(data)) 

    # shape ratio 
    r = float(data.shape[1])/data.shape[0] 

    # Draw the punchcard (create one circle per element) 
    # Ugly normalisation allows to obtain perfect circles instead of ovals.... 
    for y in range(data.shape[0]): 
     for x in range(data.shape[1]): 
      circle = plt.Circle((x/float(data.shape[1]-1)*(data.shape[0]-1),y/r), 
           data[y][x]/float(data.shape[1])*data.shape[0]/2) 
      plt.gca().add_artist(circle) 

    plt.ylim(0-0.5, data.shape[0]-0.5) 
    plt.xlim(0, data.shape[0]) 
    plt.yticks(np.arange(0,len(ax1)/r-.1,1/r), ax1_ticks) 
    xt = np.linspace(0, len(ax1)-1, len(ax2)) 
    plt.xticks(xt, ax2_ticks) 
    plt.xlabel(ax1_label) 
    plt.ylabel(ax2_label) 
    plt.gca().invert_yaxis() 

    # make sure the axes are equal, and resize the canvas to fit the plot 
    plt.axis('equal') 
    plt.axis([0, 7, 6/r, -.5]) 
    scale = 0.5 
    plt.gcf().set_size_inches(data.shape[1]*scale,data.shape[0]*scale, forward=True) 
+0

** Wielkie dzięki ** Tak więc moim głównym błędem było to, że zapomniałem znormalizować również na osi Y – rgiot

+0

Okręgi nie pasują do x etykiet. –

+1

@orian: Prawidłowo; niektóre nieprawidłowe błędy przeniesione z pierwotnego pytania. Naprawiono teraz! – Junuxx

Powiązane problemy