2015-11-05 10 views
9

Czy ktoś wie - w Matplotlib - jak wytworzyć dobrze wyglądającą wypełnioną linię konturu z półprzezroczystymi kolorami? Jeśli contourf() przepuszcza się colormap z półprzezroczystych kolorach, produkuje małe luki pomiędzy wypełnionych obszarach:Matplotlib: wypełniony kontur z przezroczystymi kolorami

small gaps between areas

Według docs, to nie jest błąd (”contourf() [...] nie narysuj krawędzie wielokąta "). Aby narysować krawędzie, sugeruje się "dodać kontury linii z połączeniami do contour()". Ale to nie wygląda dobrze zarówno jako krawędzie stają się zbyt nieprzezroczyste:

edges are too opaque

Możesz poeksperymentować z linewidth argument contour(), ale to nie pomaga. Jakieś pomysły?

Oto kod, który reprodukuje problemu (używam API obiektowego, ale wynik jest taki sam z pyplot):

import matplotlib 
import numpy as np 
from matplotlib.figure import Figure 
from matplotlib.backends.backend_agg import FigureCanvasAgg 

# generate some data 
shape = (100, 100) 
x_rng = np.linspace(-1, 1, shape[1]) 
y_rng = np.linspace(-1, 1, shape[0]) 
x, y = np.meshgrid(x_rng, y_rng) 
z = np.sqrt(x**2 + y**2) 

# create figure 
width_inch, height_inch = 5, 5 # results in 500x500px with dpi=100 
fig = Figure() 
fig.set_size_inches((width_inch, height_inch)) 
FigureCanvasAgg(fig) 
ax = fig.add_axes([0., 0., 1., 1.]) 
ax.set_axis_off() 

# define some colors with alpha < 1 
alpha = 0.9 
colors = [ 
    (0.1, 0.1, 0.5, alpha), # dark blue 
    (0.0, 0.7, 0.3, alpha), # green 
    (0.9, 0.2, 0.7, alpha), # pink 
    (0.0, 0.0, 0.0, alpha), # black 
    (0.1, 0.7, 0.7, alpha), # light blue 
] 
cmap = matplotlib.colors.ListedColormap(colors) 
levels = np.array(np.linspace(0, z.max(), len(colors))) 
norm = matplotlib.colors.BoundaryNorm(levels, ncolors=cmap.N) 

# contourf plot produces small gaps between filled areas 
cnt = ax.contourf(x, y, z, levels, cmap=cmap, norm=norm, 
        antialiased=True, linecolor='none') 

# this fills the gaps, but it makes them too opaque 
# ax.contour(x, y, z, levels, cmap=cmap, norm=norm, 
#   antialiased=True) 

# the same is true for this trick: 
# for c in cnt.collections: 
#  c.set_edgecolor("face") 

filename = "/tmp/contourf.png" 
fig.savefig(filename, dpi=100, transparent=True, format="png") 

PS: Taka sama fabuła wygląda dobrze z backend SVG.

PPS: pcolormesh() ma podobny problem:

ax.pcolormesh(x, y, z, cmap=cmap, norm=norm, 
       edgecolor="face", antialiased=True) 

enter image description here

+0

Uwaga: '' antialiased = True'' wydaje się mieć efekt (ale wyłączenie go również nie daje dobrego wyniku). – weatherfrog

Odpowiedz

1

ja nie wiem, czy to rozwiąże problem, jako 'przystojny' jest nieco subiektywne, ale to jedyny sposób na uzyskać obraz, który nie ma żadnych problemów z wygładzaniem krawędzi lub postrzępione krawędzie, gdy powiększony do tego poziomu byłby użycie formatu wektorowego, takiego jak SVG, EPS, itp. (jak wskazujesz).

SVG (Scalable Vector Graphics)

enter image description here

Jeśli wyłączyć antyaliasing, można pozbyć się rozmycia krawędzi i „opaqueness”, ale dostaniesz poszarpaną krawędzią wygląd do kółek przy wysokich poziomach powiększenia. Można spróbować zwiększyć dpi powiedzieć, 300 dpi i zapisywanie jako tiff:

TIFF, 300 dpi, antyaliasingu = False

enter image description here

antyaliasingu ma zamiar połączyć swój wizerunek wzdłuż Granice okręgów, więc mieszanie przezroczystego koloru różowego i zielonego powoduje powstanie ciemniejszego koloru, co może sprawiać wrażenie bardziej nieprzezroczystego, nawet jeśli przezroczystość jest teoretycznie taka sama.

mam inny wyglądające wyniki od komentowania w/z następujących sekcji kodu, ale wyniki są zbyt subiektywne powiedzieć co jest lepsze spojrzenie:

Ustaw kontury, ale nie edgecolor:

ax.contour(x, y, z, levels, cmap=cmap, norm=norm, 
      antialiased=True) 

# the same is true for this trick: 
# for c in cnt.collections: 
#  c.set_edgecolor("face") 

nie ustawiaj kontury, ale ustawić kolor krawędzi:

# ax.contour(x, y, z, levels, cmap=cmap, norm=norm, 
#   antialiased=True) 

# the same is true for this trick: 
for c in cnt.collections: 
    c.set_edgecolor("face") 

ale to zależy od interpretacji czy wyglądają dobrze. Inną rzeczą, którą odkryłem, było to, że moja przeglądarka obrazów ma wbudowaną funkcję antyaliasingu, więc możesz chcieć ją wyłączyć, próbując dokonać porównań.

+0

Dzięki za pobranie tego. Rozwiązałem problem, kreśląc bez przezroczystości - używając kolorów RGB jako "elementów zastępczych" dla kolorów RGBA - i stosując przezroczystość w etapie przetwarzania końcowego. Podtrzymałem twoją odpowiedź, ale nie zaakceptowałem jej, ponieważ nie rozwiązuje ona oryginalnego pytania. – weatherfrog