2013-10-25 13 views
5

Próbuję wykreślić dwie polarne wykresy na jednej figurze. Zobacz poniższy kod:Dodaj drugą oś do wykresu polarnego

fig = super(PlotWindPowerDensity, self).get_figure() 
    rect = [0.1, 0.1, 0.8, 0.8] 
    ax = WindSpeedDirectionAxes(fig, rect) 

    self.values_dict = collections.OrderedDict(sorted(self.values_dict.items())) 
    values = self.values_dict.items() 
    di, wpd = zip(*values) 
    wpd = np.array(wpd).astype(np.double) 
    wpdmask = np.isfinite(wpd) 
    theta = self.radar_factory(int(len(wpd))) 

    # spider plot 
    ax.plot(theta[wpdmask], wpd[wpdmask], color = 'b', alpha = 0.5) 
    ax.fill(theta[wpdmask], wpd[wpdmask], facecolor = 'b', alpha = 0.5) 

    # bar plot 
    ax.plot_bar(table=self.table, sectors=self.sectors, speedbins=self.wpdbins, option='wind_power_density', colorfn=get_sequential_colors) 

    fig.add_axes(ax) 
    return fig 

Result till now

Długość paska jest baza danych (ile punktów próbkowania dla tego sektora). Kolory słupków pokazują częstotliwość niektórych przedziałów wartości (np. 2,5-5 m/s) w sektorze korespondentów (niebieski: niski, czerwony: wysoki). Niebieski wykres pajęczyny pokazuje średnią wartość dla każdego sektora.

W przedstawionej postaci, wartości każdej działki są podobne, ale jest to rzadkie. Muszę przypisać drugi wykres do innej osi i pokazać tę oś w innym kierunku.

EDIT:

Po ładnym odpowiedź Joe, i uzyskać wynik na rysunku. provisional result To prawie wszystko, co chciałem osiągnąć. Ale są pewne punkty, których nie byłem w stanie wymyślić.

  1. Fabuła jest wykonywana dla dynamicznie zmieniających się baz danych. Dlatego potrzebuję dynamicznego sposobu na uzyskanie tej samej lokalizacji kręgów. Do tej pory rozwiązać go z:

    start, end = ax2.get_ylim() 
    ax2.yaxis.set_ticks(np.arange(0, end, end/len(ax.yaxis.get_ticklocs()))) 
    

    oznacza: do drugiej osi i zmieniać kleszczy w celu dopasowania do ticklocs do jednego roku od pierwszej osi. W większości przypadków uzyskuję miejsca po przecinku, ale nie chcę tego, ponieważ to psuje czystość fabuły. Czy istnieje sposób na bardziej inteligentne rozwiązanie tego problemu?

  2. The ytics (promieniowy) w zakresie od 0 do następnego do ostatniego koła. Jak mogę osiągnąć, że wartości wahają się od pierwszego koła do ostatniego (granicy)? To samo dotyczy pierwszej osi.

+0

Proszę poprawić wcięcie. Wygląda na to, że używasz mocno spersonalizowanych zestawów klas, które upraszczają to, co jest trudne. Czy możesz pokazać, czego chcesz, używając tylko standardowego obiektu matplotlib? – tacaswell

+0

Dziękujemy za dodanie obrazu. Miałem za mało ocen reputacji, żeby zrobić to dla siebie. – fidelitas

+1

Co do drugiego pytania o to, jak wyświetlić etykietę ostatniego promienia, to tylko dlatego, że ustawiasz tyknięcia używając 'np.arange'. 'arange' zatrzymuje _przedtem punkt końcowy (np.' np.arange (0, 0.5, 0.1) 'daje' tablicę ([0.0, 0.1, 0.2, 0.3, 0.4]) '). Jeśli chcesz dołączyć punkt końcowy, użyj zamiast tego 'end + dx' (gdzie' dx' to twój interwał). –

Odpowiedz

6

Tak, jak rozumiem, chcesz wyświetlać dane o bardzo różnych jasnościach na tym samym wykresie polarnym. Zasadniczo pytasz, jak zrobić coś podobnego do twinx dla osi biegunowych.

Jako przykład do zilustrowania problemu, byłoby miło, aby wyświetlić zielony serie na poniższym wykresie w innej skali niż Blue Series, utrzymując je na tych samych osiach polarnymi dla łatwego porównania .:

import numpy as np 
import matplotlib.pyplot as plt 

numpoints = 30 
theta = np.linspace(0, 2*np.pi, numpoints) 
r1 = np.random.random(numpoints) 
r2 = 5 * np.random.random(numpoints) 

params = dict(projection='polar', theta_direction=-1, theta_offset=np.pi/2) 
fig, ax = plt.subplots(subplot_kw=params) 

ax.fill_between(theta, r2, color='blue', alpha=0.5) 
ax.fill_between(theta, r1, color='green', alpha=0.5) 

plt.show() 

enter image description here

jednak ax.twinx() nie działa na działkach polarnych.

Jest możliwość obejścia tego, ale to nie jest bardzo prosta. Oto przykład:

import numpy as np 
import matplotlib.pyplot as plt 

def main(): 
    numpoints = 30 
    theta = np.linspace(0, 2*np.pi, numpoints) 
    r1 = np.random.random(numpoints) 
    r2 = 5 * np.random.random(numpoints) 

    params = dict(projection='polar', theta_direction=-1, theta_offset=np.pi/2) 
    fig, ax = plt.subplots(subplot_kw=params) 
    ax2 = polar_twin(ax) 

    ax.fill_between(theta, r2, color='blue', alpha=0.5) 
    ax2.fill_between(theta, r1, color='green', alpha=0.5) 
    plt.show() 

def polar_twin(ax): 
    ax2 = ax.figure.add_axes(ax.get_position(), projection='polar', 
          label='twin', frameon=False, 
          theta_direction=ax.get_theta_direction(), 
          theta_offset=ax.get_theta_offset()) 
    ax2.xaxis.set_visible(False) 
    # There should be a method for this, but there isn't... Pull request? 
    ax2._r_label_position._t = (22.5 + 180, 0.0) 
    ax2._r_label_position.invalidate() 
    # Ensure that original axes tick labels are on top of plots in twinned axes 
    for label in ax.get_yticklabels(): 
     ax.figure.texts.append(label) 
    return ax2 

main() 

enter image description here

Że robi to, co chcemy, ale wygląda dość źle na początku.Jeden poprawy byłoby etykietach kleszczy odpowiadać co mamy kreślenia:

plt.setp(ax2.get_yticklabels(), color='darkgreen') 
plt.setp(ax.get_yticklabels(), color='darkblue') 

enter image description here

Jednak wciąż mamy podwójnej siatki, które są mylące. Jednym z łatwych sposobów jest ręczne ustawienie r-limitów (i/lub r-ticków) tak, aby siatki spadały jeden na drugi. Alternatywnie możesz napisać niestandardowy lokalizator, aby zrobić to automatycznie. Trzymajmy z prostym podejściem tutaj:

ax.set_rlim([0, 5]) 
ax2.set_rlim([0, 1]) 

enter image description here

Zastrzeżenie: Ponieważ wspólne osie nie działają na działkach polarnych implmentation mam powyżej będą mieć problemów z niczym, który zmienia pozycję oryginalne osie. Na przykład dodanie paska koloru do rysunku spowoduje wiele problemów. Można to obejść, ale opuściłem tę część. Jeśli potrzebujesz, daj mi znać, a dodam przykład.

W każdym razie, tutaj jest pełna, samodzielna kod, aby wygenerować ostateczny rysunek:

import numpy as np 
import matplotlib.pyplot as plt 
np.random.seed(1977) 

def main(): 
    numpoints = 30 
    theta = np.linspace(0, 2*np.pi, numpoints) 
    r1 = np.random.random(numpoints) 
    r2 = 5 * np.random.random(numpoints) 

    params = dict(projection='polar', theta_direction=-1, theta_offset=np.pi/2) 
    fig, ax = plt.subplots(subplot_kw=params) 
    ax2 = polar_twin(ax) 

    ax.fill_between(theta, r2, color='blue', alpha=0.5) 
    ax2.fill_between(theta, r1, color='green', alpha=0.5) 

    plt.setp(ax2.get_yticklabels(), color='darkgreen') 
    plt.setp(ax.get_yticklabels(), color='darkblue') 
    ax.set_ylim([0, 5]) 
    ax2.set_ylim([0, 1]) 

    plt.show() 

def polar_twin(ax): 
    ax2 = ax.figure.add_axes(ax.get_position(), projection='polar', 
          label='twin', frameon=False, 
          theta_direction=ax.get_theta_direction(), 
          theta_offset=ax.get_theta_offset()) 
    ax2.xaxis.set_visible(False) 

    # There should be a method for this, but there isn't... Pull request? 
    ax2._r_label_position._t = (22.5 + 180, 0.0) 
    ax2._r_label_position.invalidate() 

    # Bit of a hack to ensure that the original axes tick labels are on top of 
    # whatever is plotted in the twinned axes. Tick labels will be drawn twice. 
    for label in ax.get_yticklabels(): 
     ax.figure.texts.append(label) 

    return ax2 

if __name__ == '__main__': 
    main() 
+0

Ta odpowiedź była tak miła, że ​​chciałem dać jej więcej niż jeden program, ale nie mogę :(Postaram się, aby moje własne odpowiedzi były tak dobre, jak to –

+0

@GamesBrainiac - Dzięki! –

+0

Dziękuję ** bardzo wiele ** za twoją szczegółową i bardzo zrozumiałą odpowiedź, działało dobrze dla mnie.Jednakże są pewne problemy, wspomniane w moim pierwszym poście. – fidelitas

1

Wystarczy dodać na (wielki) Odpowiedź @JoeKington „s, okazało się, że„hack, aby zapewnić to, że znaczniki oryginalnych osi są na wierzchu tego, co zostało narysowane w osiach bliźniaczych "nie działa dla mnie, tak jak alternatywnie użyłem:

from matplotlib.ticker import MaxNLocator 

#Match the tick point locations by setting the same number of ticks in the 
# 2nd axis as the first  
ax2.yaxis.set_major_locator(MaxNLocator(nbins=len(ax1.get_yticks()))) 

#Set the last tick as the plot limit 
ax2.set_ylim(0, ax2.get_yticks()[-1]) 

#Remove the tick label at zero 
ax2.yaxis.get_major_ticks()[0].label1.set_visible(False) 
Powiązane problemy