Gráficos de Matplotlib perdem a transparência ao salvar como .ps / .eps

Eu estou tendo um problema com a tentativa de salvar alguns charts com elipsóides transparentes neles, se eu tentar salvá-los com extensões .ps / .eps.

Aqui está o gráfico salvo como um .png: png

Se eu optar por salvá-lo como .ps / .eps, aqui está o que parece: ps

Como eu cheguei em torno disso, foi usar o ImageMagick para converter o png original para um ps. O único problema é que a imagem no formato png é de cerca de 90k, e se torna pouco menos de 4M após a conversão. Isso não é bom, já que tenho muitas dessas imagens, e levarei muito tempo para compilar meu documento de látex. Alguém tem uma solução para isso?

O problema é que o eps não suporta transparências nativamente.

Existem poucas opções:

  1. rasterize a imagem e incorpore em um arquivo eps (como @Molly sugere) ou exportando para pdf e convertendo com alguma ferramenta externa (como gs) (que geralmente também depende da rasterização)

  2. ‘imitar’ a transparência, dando uma cor que se parece com a transparente em um determinado plano de fundo.

Eu discuti isso com certeza uma vez na lista de discussão do matplotlib , e recebi a sugestão de rasterizar, o que não é viável, já que você obtém números pixellized ou enormes. E eles não escalam muito bem quando colocados, por exemplo, em uma publicação.

Eu pessoalmente uso a segunda abordagem, e apesar de não ser ideal, achei bom o suficiente. Eu escrevi um pequeno script python que implementa o algoritmo a partir deste post SO para obter uma representação RGB sólida de uma cor com um dar transparência

EDITAR

No caso específico do seu enredo, tente usar a palavra-chave zorder para ordenar as partes plotadas. Tente usar zorder=10 para a elipse azul, zorder=11 para o verde e zorder=12 para as hexágoras.

Desta forma, o azul deve estar abaixo de tudo, depois a elipse verde e finalmente as hexágonas. E o enredo deve ser legível também com colors sólidas. E se você gosta dos tons de azul e verde que você tem em png, você pode tentar jogar com mimic_alpha.py .

EDIT 2

Se você tem 100% de certeza que tem que usar o eps, há algumas soluções alternativas que vêm à minha mente (e que são definitivamente mais feias que o seu enredo):

  1. Basta desenhar as bordas da elipse em cima das checkboxs hexagonais.
  2. Obter centro e amplitude de cada hexágono, (possivelmente descartar todas as checkboxs zero) e faça um gráfico de dispersão usando o mesmo mapa de colors como em hexbin e ajustando o tamanho ea forma do marcador que você gosta. Você pode querer redesenhar as bordas de elipses em cima disso

Outra alternativa seria salvá-los em pdf

 savefig('myfigure.pdf') 

Isso funciona com o pdflatex, se essa foi a razão pela qual você precisou usar eps e não svg.

Você pode rasterizar a figura antes de salvá-la para preservar a transparência no arquivo eps:

 ax.set_rasterized(True) plt.savefig('rasterized_fig.eps') 

Eu tive o mesmo problema. Para evitar a rasterização, você pode salvar a imagem como um pdf e, em seguida, executar (em sistemas unixish pelo menos) em um terminal:

pdftops -eps my.pdf my.eps

Que dá um arquivo .eps como saída.

Como mencionado acima, a melhor e mais fácil escolha (se você não quer perder a resolução) é rasterizar a figura

 f = plt.figure() f.set_rasterized(True) ax = f.add_subplot(111) ax.set_rasterized(True) f.savefig('figure_name.eps',rasterized=True,dpi=300) 

Dessa forma, você também pode gerenciar a opção de tamanho por dpi. Na verdade, você também pode brincar com o zorder abaixo para aplicar a rasterização:

 ax.set_rasterization_zorder(0) 

Nota: É importante manter f.set_rasterized (True) quando você usa as funções plt.subplot e plt.subplot2grid. Caso contrário, o label e a área de marcação não aparecerão no arquivo .eps

Eu resolvi isso: 1) adicionando um set_rasterization_zorder (1) ao definir a área da figura:

 fxsize=16 fysize=8 f = figure(num=None, figsize=(fxsize, fysize), dpi=180, facecolor='w', edgecolor='k') plt.subplots_adjust( left = (18/25.4)/fxsize, bottom = (13/25.4)/fysize, right = 1 - (8/25.4)/fxsize, top = 1 - (8/25.4)/fysize) subplots_adjust(hspace=0,wspace=0.1) #f.suptitle('An overall title', size=20) gs0 = gridspec.GridSpec(1, 2) gs11 = gridspec.GridSpecFromSubplotSpec(1, 1, subplot_spec=gs0[0]) ax110 = plt.Subplot(f, gs11[0,0]) f.add_subplot(ax110) ax110.set_rasterization_zorder(1) 

2) um zorder = 0 em cada alpha = anynumber no gráfico:

 ax110.scatter(xs1,ys1 , marker='o', color='gray' , s=1.5,zorder=0,alpha=0.3)#, label=label_bg) 

e 3) finalmente um rasterizado = True ao salvar:

 P.savefig(str(PLOTFILENAME)+'.eps', rasterized=True) 

Observe que isso pode não funcionar como esperado com a palavra-chave transparent para savefig porque uma cor RGBA com alpha <1 em fundo transparente será renderizada da mesma forma que a cor RGB com alpha = 1.

Minha solução é exportar o gráfico como .eps, carregá-lo no Inkscape por exemplo, depois Desagrupar o gráfico, selecionar o object que eu quero definir a transparência e apenas editar a Opacidade do Preenchimento na aba “Preenchimento e Traço” .

Você pode salvar o arquivo como .svg se quiser ajustá-lo mais tarde ou exportar a imagem para uma publicação.