rozmiar znacznika wykresu rozproszenia pyplot

376

W dokumencie pyplot dla wykresu punktowego:

matplotlib.pyplot.scatter(x, y, s=20, c='b', marker='o', cmap=None, norm=None,
                          vmin=None, vmax=None, alpha=None, linewidths=None,
                          faceted=True, verts=None, hold=None, **kwargs)

Rozmiar znacznika

s: rozmiar w punktach ^ 2. Jest to skalar lub tablica o tej samej długości co xiy.

Co to za jednostka points^2? Co to znaczy? Ma s=100na myśli 10 pixel x 10 pixel?

Zasadniczo staram się tworzyć wykresy rozrzutu o różnych rozmiarach znaczników i chcę dowiedzieć się, co oznacza sliczba.

LWZ
źródło
całkiem pewne, że punkty są tymi samymi jednostkami, co czcionki.
tacaswell
@ tcaswell, masz na myśli s=20, że rozmiar znacznika jest równy rozmiarowi fontsize=20litery?
LWZ
nie, obszar będzie wynosił 20 punktów ^ 2, fontsize=20litera ma 20 pkt wysokości (lub cokolwiek znak odniesienia w czcionce ma wysokość 20 pkt).
tacaswell
23
matplotlib.pyplot.plot()ma msparametr ( markersize) równoważny matplotlib.pyplot.scatter()parametrowi s( size). Tylko przypomnienie ..
niekas
@neikas wydaje mi się, że nie są, ponieważ jeden jest w pikselach (rozmiar znacznika), a drugi jest w tej dziwnej kwadratowej jednostce punktów (rozmiar). To zawsze było dla mnie mylące, ale uważam, że ma to związek z rozmiarem znacznika wykresu rozrzutu używanym do oznaczania ilości w wizualnie proporcjonalny sposób.
heltonbiker

Odpowiedzi:

406

Może to być nieco mylący sposób definiowania rozmiaru, ale zasadniczo określasz obszar znacznika. Oznacza to, że aby podwoić szerokość (lub wysokość) znacznika, musisz zwiększyć sgo o współczynnik 4. [ponieważ A = W H => (2W) (2H) = 4A]

Istnieje jednak powód, dla którego wielkość markerów jest definiowana w ten sposób. Z powodu skalowania obszaru jako kwadratu szerokości, podwojenie szerokości faktycznie wydaje się zwiększać rozmiar o współczynnik większy niż 2 (w rzeczywistości zwiększa go o współczynnik 4). Aby to zobaczyć, rozważ następujące dwa przykłady i dane wyjściowe, które one generują.

# doubling the width of markers
x = [0,2,4,6,8,10]
y = [0]*len(x)
s = [20*4**n for n in range(len(x))]
plt.scatter(x,y,s=s)
plt.show()

daje

wprowadź opis zdjęcia tutaj

Zauważ, że rozmiar bardzo szybko rośnie. Jeśli zamiast tego mamy

# doubling the area of markers
x = [0,2,4,6,8,10]
y = [0]*len(x)
s = [20*2**n for n in range(len(x))]
plt.scatter(x,y,s=s)
plt.show()

daje

wprowadź opis zdjęcia tutaj

Teraz pozorny rozmiar znaczników zwiększa się mniej więcej liniowo w intuicyjny sposób.

Jeśli chodzi o dokładne znaczenie tego, czym jest „punkt”, jest dość arbitralne do celów kreślenia, możesz po prostu skalować wszystkie swoje rozmiary o stałą, aż będą wyglądać rozsądnie.

Mam nadzieję że to pomoże!

Edycja: (W odpowiedzi na komentarz @Emma)

Prawdopodobnie jest to mylące sformułowanie z mojej strony. Pytanie o podwojenie szerokości koła, więc na pierwszym obrazie dla każdego koła (gdy poruszamy się od lewej do prawej) jego szerokość jest dwa razy większa od poprzedniego, więc dla obszaru jest to wykładnicza podstawa 4. Podobnie drugi przykład każde koło ma powierzchnię dwukrotnie większą niż ostatnia, co daje wykładnik z podstawą 2.

Jednak jest to drugi przykład (w którym skalujemy obszar), że podwojenie obszaru sprawia, że ​​okrąg jest dwa razy większy dla oka. Zatem jeśli chcemy, aby okrąg wyglądał na czynnik nwiększy, zwiększalibyśmy obszar o czynnik, a nnie promień, więc pozorny rozmiar skaluje się liniowo z obszarem.

Edytuj, aby wizualizować komentarz autorstwa @TomaszGandor:

Tak to wygląda dla różnych funkcji rozmiaru znacznika:

Rozmiar wykładniczy, kwadratowy lub liniowy

x = [0,2,4,6,8,10,12,14,16,18]
s_exp = [20*2**n for n in range(len(x))]
s_square = [20*n**2 for n in range(len(x))]
s_linear = [20*n for n in range(len(x))]
plt.scatter(x,[1]*len(x),s=s_exp, label='$s=2^n$', lw=1)
plt.scatter(x,[0]*len(x),s=s_square, label='$s=n^2$')
plt.scatter(x,[-1]*len(x),s=s_linear, label='$s=n$')
plt.ylim(-1.5,1.5)
plt.legend(loc='center left', bbox_to_anchor=(1.1, 0.5), labelspacing=3)
plt.show()
Dan
źródło
2
Prawdopodobnie źle rozumiem twój punkt widzenia, ale w drugim przykładzie zwiększasz s wykładniczo (s = [20, 40, 80, 160, 320, 640]) i mówię, że to daje nam ładny wzrost wielkości liniowo. Czy nie miałoby większego sensu, gdyby zwiększenie rozmiaru liniowo (np. S = [20, 40, 60, 80, 100, 120]) dało nam wynik wyglądający liniowo?
Emma,
@Emma Twoja intuicja jest słuszna, to z mojej strony złe sformułowania (alternatywnie zły wybór skalowania osi x). Wyjaśniłem trochę więcej w edycji, ponieważ było za długo na komentarz.
Dan
1
Czy można zmienić swartość zgodnie z rozmiarem okna figury? To znaczy, jeśli zmaksymalizujemy okna figury, chciałbym mieć znaki większego rozmiaru.
Sigur,
2
Świetny przykład (tylko niezbędne rzeczy!). To nie powinno być 4 ** na 2 ** n, ale n ** 4i n ** 2. Z 2 ** ndrugiego wykresu nie skaluje się liniowo pod względem średnicy koła. Nadal idzie za szybko (po prostu nie za dużo).
Tomasz Gandor
1
Krótko mówiąc - drugi wykres pokazuje pierwiastek kwadratowy z wykładniczej - co jest kolejnym wykładniczym, tylko nieco mniej stromym.
Tomasz Gandor
217

Ponieważ inne odpowiedzi tutaj twierdzą, że soznacza obszar znacznika, dodaję tę odpowiedź, aby wyjaśnić, że niekoniecznie tak jest.

Rozmiar w punktach ^ 2

Argument sw plt.scatteroznacza markersize**2. Jak mówi dokumentacja

s: skalarny lub tablicowy, kształt (n,), opcjonalny
rozmiar w punktach ^ 2. Domyślnie jest to rcParams ['lines.markersize'] ** 2.

Można to potraktować dosłownie. Aby uzyskać znacznik, który jest duży x punktów, musisz wyprostować tę liczbę i podać ją sargumentowi.

Tak więc związek między znacznikiem wielkości wykresu liniowego a argumentem rozmiaru rozproszenia jest kwadratem. Aby wytworzyć znacznik rozproszenia o tym samym rozmiarze, co znacznik wykresu o wielkości 10 punktów, nazwałbyś go scatter( .., s=100).

wprowadź opis zdjęcia tutaj

import matplotlib.pyplot as plt

fig,ax = plt.subplots()

ax.plot([0],[0], marker="o",  markersize=10)
ax.plot([0.07,0.93],[0,0],    linewidth=10)
ax.scatter([1],[0],           s=100)

ax.plot([0],[1], marker="o",  markersize=22)
ax.plot([0.14,0.86],[1,1],    linewidth=22)
ax.scatter([1],[1],           s=22**2)

plt.show()

Połączenie z „obszarem”

Dlaczego więc inne odpowiedzi, a nawet dokumentacja mówią o „obszarze”, jeśli chodzi o sparametr?

Oczywiście jednostki punktów ** 2 to jednostki powierzchni.

  • W szczególnym przypadku znacznika kwadratowego marker="s"obszar znacznika jest rzeczywiście bezpośrednio wartością sparametru.
  • W przypadku koła jego powierzchnia to area = pi/4*s.
  • W przypadku innych markerów może nie być nawet oczywisty związek z obszarem markera.

wprowadź opis zdjęcia tutaj

We wszystkich przypadkach obszar znacznika jest jednak proporcjonalny do sparametru . Jest to motywacja, by nazwać to „obszarem”, chociaż w większości przypadków tak nie jest.

Określanie wielkości znaczników rozproszenia pod względem pewnej ilości, która jest proporcjonalna do obszaru markera, ma jak dotąd sens, ponieważ to obszar markera jest postrzegany przy porównywaniu różnych łat, a nie jego długości lub średnicy z boku. To znaczy podwojenie bazowej ilości powinno podwoić powierzchnię markera.

wprowadź opis zdjęcia tutaj

Jakie są punkty?

Jak dotąd odpowiedź na pytanie, co oznacza rozmiar znacznika rozproszenia, jest podana w jednostkach punktów. Punkty są często używane w typografii, gdzie czcionki są określone w punktach. Także szerokości linii są często określone w punktach. Standardowy rozmiar punktów w matplotlib wynosi 72 punkty na cal (ppi) - 1 punkt to zatem 1/72 cala.

Przydatne może być określenie rozmiarów w pikselach zamiast punktach. Jeśli dpi również wynosi 72, jeden punkt to jeden piksel. Jeśli rozdzielczość rysunku jest inna (domyślnie jest to Matplotlib fig.dpi=100),

1 point == fig.dpi/72. pixels

Chociaż rozmiar znacznika rozproszenia w punktach wyglądałby inaczej dla różnych dpi w postaci cyfr, można by uzyskać znacznik 10 na 10 pikseli ^ 2, który zawsze miałby taką samą liczbę pokrytych pikseli:

wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj

import matplotlib.pyplot as plt

for dpi in [72,100,144]:

    fig,ax = plt.subplots(figsize=(1.5,2), dpi=dpi)
    ax.set_title("fig.dpi={}".format(dpi))

    ax.set_ylim(-3,3)
    ax.set_xlim(-2,2)

    ax.scatter([0],[1], s=10**2, 
               marker="s", linewidth=0, label="100 points^2")
    ax.scatter([1],[1], s=(10*72./fig.dpi)**2, 
               marker="s", linewidth=0, label="100 pixels^2")

    ax.legend(loc=8,framealpha=1, fontsize=8)

    fig.savefig("fig{}.png".format(dpi), bbox_inches="tight")

plt.show() 

Jeśli jesteś zainteresowany rozproszeniem w jednostkach danych, sprawdź tę odpowiedź .

WażnośćOfBeingErnest
źródło
Zastanawiasz się, jak obliczyć, jaki parametr s dać rozproszeniu, aby uzyskać okrąg pokrywający średnicę, powiedzmy, 0,1 w rzeczywistych współrzędnych wykresu (aby wypełnić lukę między powiedzmy 0,4 i 0,5 na wykresie od (0 , 0) do (1,1)?
Anatolij Aleksiejew
@AnatolyAlekseev Na to pytanie należy odpowiedzieć .
ImportanceOfBeingErnest
21

Możesz użyć markersize, aby określić rozmiar okręgu w metodzie wydruku

import numpy as np
import matplotlib.pyplot as plt

x1 = np.random.randn(20)
x2 = np.random.randn(20)
plt.figure(1)
# you can specify the marker size two ways directly:
plt.plot(x1, 'bo', markersize=20)  # blue circle with size 10 
plt.plot(x2, 'ro', ms=10,)  # ms is just an alias for markersize
plt.show()

od tutaj

wprowadź opis zdjęcia tutaj

zhaoqing
źródło
Pytanie dotyczyło wykresu rozrzutu, aw matplotlib dwie funkcje kreślenia mają różne parametry (rozmiar markera dla wykresu i s dla rozproszenia ). Ta odpowiedź nie ma zastosowania.
Dom
3
@Dom Głosowałem, ponieważ to pytanie pojawia się jako pierwszy wynik w Google, nawet gdy szukam „rozmiaru znacznika wykresu pyplot”, więc ta odpowiedź pomaga.
Przemek D
Wiem, że metoda wykresu i metoda rozproszenia różnią się w plt, ale oba mogą zrealizować „wykres rozproszenia” i dostosować rozmiar znacznika, więc ta odpowiedź jest tylko kolejną metodą, jeśli zastosujesz metodę wykresu @Dom
zhaoqing
18

Jest to obszar znacznika. To znaczy, jeśli masz s1 = 1000czym s2 = 4000relacja między promieniem każdym okręgu jest: r_s2 = 2 * r_s1. Zobacz następujący wątek:

plt.scatter(2, 1, s=4000, c='r')
plt.scatter(2, 1, s=1000 ,c='b')
plt.scatter(2, 1, s=10, c='g')

wprowadź opis zdjęcia tutaj

Miałem te same wątpliwości, kiedy zobaczyłem słupek, więc zrobiłem ten przykład, a następnie użyłem linijki na ekranie, aby zmierzyć promienie.

Joaquin
źródło
To najczystsza i najbardziej beztłuszczowa odpowiedź. Dzięki
Ayan Mitra
6

Na początku próbowałem również użyć „rozproszenia”. Po dość marnowanym czasie zdecydowałem się na następujące rozwiązanie.

import matplotlib.pyplot as plt
input_list = [{'x':100,'y':200,'radius':50, 'color':(0.1,0.2,0.3)}]    
output_list = []   
for point in input_list:
    output_list.append(plt.Circle((point['x'], point['y']), point['radius'], color=point['color'], fill=False))
ax = plt.gca(aspect='equal')
ax.cla()
ax.set_xlim((0, 1000))
ax.set_ylim((0, 1000))
for circle in output_list:    
   ax.add_artist(circle)

wprowadź opis zdjęcia tutaj

Jest to oparte na odpowiedzi na to pytanie

Ike
źródło
bardzo pomocny. Ale po co używać dwóch pętli?
grabantot
1
@grabantot bez powodu, po prostu nie zastanawiałem się zbytnio.
Ike
2

Jeśli rozmiar okręgów odpowiada kwadratowi parametru w s=parameter, to przypisz pierwiastek kwadratowy do każdego elementu, który dołączasz do tablicy rozmiarów, w ten sposób: s=[1, 1.414, 1.73, 2.0, 2.24]tak, że gdy pobierze te wartości i zwróci je, ich względny wzrost wielkości będzie wynosić pierwiastek kwadratowy z kwadratowej progresji, która zwraca liniową progresję.

Gdybym był do kwadratu każdy robi jak wyjście do działki: output=[1, 2, 3, 4, 5]. Spróbuj interpretacji listy:s=[numpy.sqrt(i) for i in s]

użytkownik34028
źródło
1
Nie i in outputpowinno być?
Sigur