Рисование размытых линий с помощью Matplotlib/Python

Мне интересно, можно ли сделать визуализацию, подобную приведенной ниже, с помощью Matplotlib.

введите здесь описание изображения

Другая точка зрения:

введите здесь описание изображения

Источник: http://dl.acm.org/citation.cfm?id=1961832< /а>

Что делают эти изображения, и что я хотел бы сделать, так это объединить две визуализации. Один (фон) представляет собой простой график, который можно сделать с помощью imshow, pcolor, pcolormesh, а в другом используется текстура сетка, размытие которой (фактор w) определяет некоторую характеристику, в данном случае неопределенность. Чего я не знаю, как сделать, так это построить разные линии с разным размытием. Для каждого пикселя у меня есть неопределенность, и я должен нарисовать линию в этом пикселе с неопределенностью, представленной в виде размытия линии.

Я не знаю, как это сделать (рисовать линии с размытием) с помощью Matplotlib.

Любая помощь будет оценена по достоинству. Заранее спасибо.


person pceccon    schedule 15.07.2014    source источник
comment
Я не уверен, правильно ли я понял ваш вопрос. Можно ли решить эту проблему, создав тепловую карту с использованием pcolormesh, а затем нарисовав черные линии, образующие сетку с альфа-значениями, соответствующими вашей неопределенности?   -  person Christoph    schedule 15.07.2014
comment
Я не вижу ничего, что помешало бы вам это сделать. Было бы немного запутанно, чтобы все линии совпадали, но для всего этого есть инструменты, я их использовал.   -  person will    schedule 15.07.2014
comment
Да, я уверен, что предложенное мной решение может сработать. Я менее уверен, решаю ли я правильную проблему.   -  person Christoph    schedule 15.07.2014
comment
Да, это то, чего я хочу, @Christoph. Однако не уверен, как это сделать.   -  person pceccon    schedule 15.07.2014
comment
Точнее, часть рисования линий.   -  person pceccon    schedule 15.07.2014
comment
Этого несколько сложно добиться. Вам нужно добавить каждую строку как LineCollection. Они состоят из отдельных сегментов, состоящих из начальной и конечной точек. Сегментам можно присвоить индивидуальные цвета, которые могут содержать альфа-значения.   -  person Christoph    schedule 15.07.2014
comment
@Кристоф - это выполнимо. Я работаю над примером сейчас. Вот текущий прогресс.   -  person will    schedule 15.07.2014
comment
Спасибо за ваше время, @will.   -  person pceccon    schedule 15.07.2014
comment
На заметку - посмотрев только те части арта, которые вы предоставили - какой в ​​этом смысл? Я понимаю, что рисунок ткани смешивается поверх изображения contourf, но, судя по всему, это просто образец штриховки, смешанный в соответствии со значением основного изображения. Не похоже, что он предоставляет какую-либо дополнительную информацию. Что вы хотите показать этими сюжетами?   -  person will    schedule 16.07.2014
comment
Привет, @will. Я работаю с количественной оценкой неопределенности, и мне нужно отобразить неопределенность двух скалярных полей на одном графике (они связаны, поэтому я должен предоставить комбинированную визуализацию помимо двух отдельных). Обычный подход состоит в том, чтобы показать неопределенность данных как насыщенность, а неопределенность других данных - с шаблоном (размытым в неопределенных точках) - это то, что я пытаюсь сделать с Matplotlib. Спасибо.   -  person pceccon    schedule 16.07.2014
comment
@pceccon А, хорошо. Итак, по сути, у вас есть 4 набора данных, A, B, и неопределенности для каждого? Не можете ли вы объединить их вместе, используя неопределенности как относительные непрозрачности?   -  person will    schedule 16.07.2014
comment
Привет, @will. У меня есть наборы данных, A и B, и я должен показать неопределенность обоих из них на одном и том же графике (данные о них связаны, между ними есть связь, которую я и должен предоставить способ увидеть тогда в один сюжет). Один использует непрозрачность, а другой использует какой-то узор. :С   -  person pceccon    schedule 18.07.2014
comment
@pceccon не могли бы вы прислать мне два ваших набора данных вместе с их неопределенностями? Я посмотрю, смогу ли я создать функцию для построения графика того, что вы хотите, используя материал agg_filter.   -  person will    schedule 21.07.2014
comment
Конечно, @will. Я привел пример здесь dropbox.com/sh/ped312ur604357r/AACQGloHDAy8I2C6HITFzjqza. Данные 20 х 20. Большое спасибо за ваше время и за вашу готовность помочь мне.   -  person pceccon    schedule 22.07.2014


Ответы (1)


Что ж, вот что у меня есть на данный момент — я пошел немного по касательной, копируя fig. 2.

Завтра обновлю. (первая половина предназначена только для создания некоторых данных)

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import proj3d
import numpy as np
import matplotlib.gridspec as gridspec
import matplotlib

def smooth1d(x, window_len):
    s=np.r_[2*x[0]-x[window_len:1:-1],x,2*x[-1]-x[-1:-window_len:-1]]
    w = np.hanning(window_len)
    y=np.convolve(w/w.sum(),s,mode='same')
    return y[window_len-1:-window_len+1]

def smooth2d(A, sigma=3):
    window_len = max(int(sigma), 3)*2+1
    A1 = np.array([smooth1d(x, window_len) for x in np.asarray(A)])
    A2 = np.transpose(A1)
    A3 = np.array([smooth1d(x, window_len) for x in A2])
    A4 = np.transpose(A3)

    return A4

class BaseFilter(object):
    def prepare_image(self, src_image, dpi, pad):
        ny, nx, depth = src_image.shape
        #tgt_image = np.zeros([pad*2+ny, pad*2+nx, depth], dtype="d")
        padded_src = np.zeros([pad*2+ny, pad*2+nx, depth], dtype="d")
        padded_src[pad:-pad, pad:-pad,:] = src_image[:,:,:]

        return padded_src#, tgt_image

    def get_pad(self, dpi):
        return 0

    def __call__(self, im, dpi):
        pad = self.get_pad(dpi)
        padded_src = self.prepare_image(im, dpi, pad)
        tgt_image = self.process_image(padded_src, dpi)
        return tgt_image, -pad, -pad

class GaussianFilter(BaseFilter):
    "simple gauss filter"
    def __init__(self, sigma, alpha=0.5, color=None):
        self.sigma = sigma
        self.alpha = alpha
        if color is None:
            self.color=(0, 0, 0)
        else:
            self.color=color

    def get_pad(self, dpi):
        return int(self.sigma*3/72.*dpi)


    def process_image(self, padded_src, dpi):
        #offsetx, offsety = int(self.offsets[0]), int(self.offsets[1])
        tgt_image = np.zeros_like(padded_src)
        aa = smooth2d(padded_src[:,:,-1]*self.alpha,
                      self.sigma/72.*dpi)
        tgt_image[:,:,-1] = aa
        tgt_image[:,:,:-1] = self.color
        return tgt_image


from matplotlib.artist import Artist

class FilteredArtistList(Artist):
    """
    A simple container to draw filtered artist.
    """
    def __init__(self, artist_list, filter):
        self._artist_list = artist_list
        self._filter = filter
        Artist.__init__(self)

    def draw(self, renderer):
        renderer.start_rasterizing()
        renderer.start_filter()
        for a in self._artist_list:
            a.draw(renderer)
        renderer.stop_filter(self._filter)
        renderer.stop_rasterizing()





##Create the landscape
from noise import snoise2

def boxOnSurface(rect, X,Y,Z):
  #Make rectangle of indicies to draw. Left the four loops expanded for clarity. Otherwise it's fairly ugly.
  rXs, rYs, rZs = [],[],[]

  for j in range(rect[0][1], rect[1][1]):
    i = rect[0][0]

    rXs.append(X[i][j])
    rYs.append(Y[i][j])
    rZs.append(Z[i][j])

  for i in range(rect[0][0], rect[1][0]):
    j = rect[1][1]

    rXs.append(X[i][j])
    rYs.append(Y[i][j])
    rZs.append(Z[i][j])

  for j in range(rect[1][1], rect[0][1], -1):
    i = rect[1][0]

    rXs.append(X[i][j])
    rYs.append(Y[i][j])
    rZs.append(Z[i][j])

  for i in range(rect[1][0], rect[0][0]-1, -1):
    j = rect[0][1]

    rXs.append(X[i][j])
    rYs.append(Y[i][j])
    rZs.append(Z[i][j])

  return rXs, rYs, rZs, [np.mean(rXs), np.mean(rYs), np.mean(rZs)]



octaves = 4
freq = octaves * 100


xs, ys = np.linspace(0.0, 100.0, 100), np.linspace(0.0, 100.0, 100)
X,Y = np.meshgrid(xs,ys)

Z1 = np.zeros(X.shape)


for i,x in enumerate(xs):
  for j,y in enumerate(ys):
    Z1[i][j] = int(snoise2(x/freq, y/freq, octaves) * 127.0 + 128.0)



# get some different colours for the surface.
faceValues = np.zeros(X.shape)

noise = []

for i,x in enumerate(xs):
  for j,y in enumerate(ys):
    faceValues[i][j] = snoise2(4*x/freq, 4*y/freq, octaves)

jet = cm.get_cmap("jet")
faceColours = []


for i,x in enumerate(xs):
  faceColours.append([])
  for j,y in enumerate(ys):
    normalised = (faceValues[i][j] - faceValues.min()) / (faceValues.max() - faceValues.min())
    faceColours[i].append(jet(normalised))
    faceValues[i][j] = normalised




fig = plt.figure()
miniPlotCount = 5
gs = gridspec.GridSpec(5, miniPlotCount)
ax = fig.add_subplot(gs[0:4,:], projection='3d')

miniAxes = []
for i in range(miniPlotCount):
  miniAxes.append(fig.add_subplot(gs[4,i]))

ax.plot_surface(X,Y,Z1, cmap=cm.jet, linewidth=0.2, cstride=2, rstride=2, facecolors=faceColours, vmin=0, vmax=1)


#This decides where we draw the rectangle to be inspecting.
rect = ((25,45),(65,70))

boxXs, boxYs, boxZs, middleOfBox = boxOnSurface(rect, X,Y,Z1)
ax.plot(boxXs, boxYs, boxZs)

xb, yb, zb = middleOfBox

xPoint, yPoint, _ = proj3d.proj_transform(xb, yb, zb, ax.get_proj())


labels = []
grids = []
for i in range(miniPlotCount):
  bbox = miniAxes[i].get_window_extent()
  xytext = ((bbox.min[0] + bbox.max[0])/2, (bbox.min[1] + bbox.max[1])/2)
  labels.append(ax.annotate("", xy=(xPoint,yPoint), arrowprops = {"arrowstyle":'->', "connectionstyle":'arc3,rad=0'}, textcoords="figure pixels", xytext=xytext))

#  miniAxes[i].contourf(X[rect[0][0]:rect[1][0],rect[0][1]:rect[1][1]], Y[rect[0][0]:rect[1][0],rect[0][1]:rect[1][1]], Z1[rect[0][0]:rect[1][0],rect[0][1]:rect[1][1]])#, vmin=Z1.min(), vmax=Z1.max())
  miniAxes[i].contourf(X[rect[0][0]:rect[1][0],rect[0][1]:rect[1][1]], Y[rect[0][0]:rect[1][0],rect[0][1]:rect[1][1]], faceValues[rect[0][0]:rect[1][0],rect[0][1]:rect[1][1]], vmin=faceValues.min(), vmax=faceValues.max())

# miniAxes[i].set_agg_filter(gaussFilter)
  gaussFilter = GaussianFilter(i)
  miniAxes[i].grid(linestyle="-", linewidth=2, agg_filter=gaussFilter)






def update_position(e):
    xPoint, yPoint, _ = proj3d.proj_transform(xb, yb, zb, ax.get_proj())
    for label in labels:
      label.xy = xPoint, yPoint
      label.update_positions(fig.canvas.renderer)
    fig.canvas.draw()

fig.canvas.mpl_connect('motion_notify_event', update_position)




plt.show()

Что создает это:

введите здесь описание изображения

Это размытые линии сетки. (я не уверен, почему он не размыл два из них). Похоже, вы можете установить agg_filter любого объекта, который вы рисуете в matplotlib, просто добавив в agg_filter= kwarg. Если вы отредактировали класс GaussianFilter, вы могли бы сделать так, чтобы он получал все данные неопределенности, а затем использовал их для применения размытия/непрозрачности/к различным частям изображения.

person will    schedule 15.07.2014
comment
Я только что наткнулся на эту часть древней истории, и я могу попробовать что-то подобное. Всегда нормально принять собственный ответ. Спасибо! - person uhoh; 31.03.2020