matplotlib – control capstyle de la colección de líneas / gran número de líneas

De manera similar a una de mis preguntas anteriores , me gustaría controlar el estilo de las líneas que se dibujan con matplotlib. Sin embargo, tengo una cantidad extremadamente grande de líneas, y dibujar con cualquier otra cosa que no sea una colección de líneas toma demasiado tiempo. ¿Existen soluciones para controlar el estilo de mayúsculas de las líneas en una colección de líneas de una manera genérica (o, alternativamente, formas súper rápidas de dibujar un gran número de líneas de Line2D ). Por ejemplo, he intentado usar la configuración de matplotlib rc a través de:

 import matplotlib as mpl mpl.rcParams['lines.solid_capstyle'] = 'round' mpl.rcParams['lines.solid_joinstyle'] = 'round' 

Pero esto no parece tener ningún efecto. De la cadena de documentación para collections.py :

Las clases no tienen la intención de ser tan flexibles como sus contrapartes de un solo elemento (por ejemplo, es posible que no pueda seleccionar todos los estilos de línea), pero deben ser rápidas para los casos de uso comunes (por ejemplo, un gran conjunto de segmentos de línea sólida)

Lo que explica por qué parece que no puedo controlar varios parámetros, ¡pero todavía quiero hacerlo! He _backend_agg.cpp un vistazo al código para el backend AGG ( _backend_agg.cpp : no es que realmente lo entienda), y parece que line_cap y line_join están controlados por gc.cap y gc.join , donde gc proviene del GCAgg clase. ¿Alguien sabe cómo se puede controlar esto desde Python? ¿Estoy haciendo la pregunta correcta aquí? ¿Quizás sean formas más fáciles de controlar estos parámetros?

Cualquier ayuda es muy apreciada … Estoy desesperado por hacer que esto funcione, ¡así que hasta los locos son bienvenidos!

Gracias,

Carson

Ya que menciona en su pregunta que no le importan las soluciones “sucias”, una opción sería la siguiente.

El “proceso de dibujo” de un LineCollection particular es manejado por el método de draw definido en la clase de Collection (la base de LineCollection ). Este método crea una instancia de GraphicsContextBase (definida en backend_bases.py ) a través de la statement gc = renderer.new_gc() . Parece ser exactamente este objeto el que gobierna, entre otras cosas, las propiedades que controlan el capstyle (propiedad _capstyle ). Por lo tanto, se podría _capstyle una subclase GraphicsContextBase , anular la propiedad _capstyle e inyectar un nuevo método new_gc en la clase RendererBase para que las llamadas consiguientes a new_gc devuelvan la instancia personalizada:

Tomando prestado el ejemplo de la respuesta por @florisvb (asumiendo Python3):

 #!/usr/bin/env python import types import numpy as np from matplotlib.backend_bases import GraphicsContextBase, RendererBase import matplotlib.pyplot as plt from matplotlib.collections import LineCollection class GC(GraphicsContextBase): def __init__(self): super().__init__() self._capstyle = 'round' def custom_new_gc(self): return GC() RendererBase.new_gc = types.MethodType(custom_new_gc, RendererBase) #---------------------------------------------------------------------- np.random.seed(42) x = np.random.random(10) y = np.random.random(10) points = np.array([x, y]).T.reshape((-1, 1, 2)) segments = np.concatenate([points[:-1], points[1:]], axis=1) fig = plt.figure() ax = fig.add_subplot(111) linewidth = 10 lc = LineCollection(segments, linewidths=linewidth) ax.add_collection(lc) fig.savefig('fig.png') 

Esto produce: introduzca la descripción de la imagen aquí

Estaba luchando con el mismo problema. Terminé trazando un diagtwig de dispersión en la parte superior de mi colección de líneas. No es perfecto, pero puede funcionar para su aplicación. Hay algunas sutilezas: a continuación hay un ejemplo de trabajo.

 import numpy as np import matplotlib.pyplot as plt from matplotlib.collections import LineCollection x = np.random.random(10) y = np.random.random(10) z = np.arange(0,10) points = np.array([x, y]).T.reshape(-1, 1, 2) segments = np.concatenate([points[:-1], points[1:]], axis=1) fig = plt.figure() ax = fig.add_subplot(111) linewidth = 10 cmap = plt.get_cmap('jet') norm = plt.Normalize(np.min(z), np.max(z)) color = cmap(norm(z)) lc = LineCollection(segments, linewidths=linewidth, cmap=cmap, norm=norm) lc.set_array(z) lc.set_zorder(z.tolist()) ax.add_collection(lc) ax.scatter(x,y,color=color,s=linewidth**2,edgecolor='none', zorder=(z+2).tolist())