2013-04-24 2 views
11

У меня есть 2d-карта преобразования координат. Данные в каждой точке представляют собой азимутальный угол в исходной системе координат, который идет от 0 до 360. Я пытаюсь использовать pyplot.contour для построения линий постоянного угла, например. 45 градусов. Контур появляется вдоль линии 45 градусов между двумя полюсами, но есть дополнительная часть контура, который соединяет два полюса вдоль разрыва 0/360. Это делает очень зубчатую уродливую линию, поскольку она в основном просто отслеживает пиксели с числом, близким к 0 с одной стороны, а другое близко к 360 на другом.Остановить pyplot.contour от рисования контура вдоль разрыва

Примеры: Вот изображение, используя полноцветную карту: colour map with discontinuity

Вы можете увидеть разрыв вдоль синей/красной кривой на левой стороне. Одна сторона - 360 градусов, другая - 0 градусов. При построении контуров, я получаю:

contour plot with discontinuity

Обратите внимание, что все контуры соединить два полюса, но даже если я НЕ нанесен на 0 градусов контура, все остальные контуры следуют вдоль 0 степени разрыва (потому что pyplot думает, если это 0 с одной стороны, а 360 - с другой, между ними должны быть все другие углы).

Код для получения этой информации:

import numpy as np 
import matplotlib.pyplot as plt 
jgal = np.array([[-0.054875539726,-0.873437108010,-0.483834985808],\ 
       [0.494109453312,-0.444829589425, 0.746982251810],\ 
       [-0.867666135858,-0.198076386122, 0.455983795705]]) 

def s2v3(rra, rdec, r): 
    pos0 = r * np.cos(rra) * np.cos(rdec) 
    pos1 = r * np.sin(rra) * np.cos(rdec) 
    pos2 = r * np.sin(rdec) 
    return np.array([pos0, pos1, pos2]) 

def v2s3(pos): 
    x = pos[0] 
    y = pos[1] 
    z = pos[2] 
    if np.isscalar(x): x, y, z = np.array([x]), np.array([y]), np.array([z]) 
    rra = np.arctan2(y, x) 
    low = np.where(rra < 0.0) 
    high = np.where(rra > 2.0 * np.pi) 
    if len(low[0]): rra[low] = rra[low] + (2.0*np.pi) 
    if len(high[0]): rra[high] = rra[high] - (2.0*np.pi) 
    rxy = np.sqrt(x**2 + y**2) 
    rdec = np.arctan2(z, rxy) 
    r = np.sqrt(x**2 + y**2 + z**2) 
    if x.size == 1: 
     rra = rra[0] 
     rdec = rdec[0] 
     r = r[0] 
    return rra, rdec, r 


def gal2fk5(gl, gb): 
    dgl = np.array(gl) 
    dgb = np.array(gb) 
    rgl = np.deg2rad(gl) 
    rgb = np.deg2rad(gb) 
    r = 1.0 
    pos = s2v3(rgl, rgb, r) 

    pos1 = np.dot(pos.transpose(), jgal).transpose() 

    rra, rdec, r = v2s3(pos1) 

    dra = np.rad2deg(rra) 
    ddec = np.rad2deg(rdec) 

    return dra, ddec 


def make_coords(resolution=50): 
    width=9 
    height=6 
    px = width*resolution 
    py = height*resolution 
    coords = np.zeros((px,py,4)) 
    for ix in range(0,px): 
     for iy in range(0,py): 
      l = 360.0/px*ix - 180.0 
      b = 180.0/py*iy - 90.0 
      dra, ddec = gal2fk5(l,b) 
      coords[ix,iy,0] = dra 
      coords[ix,iy,1] = ddec 
      coords[ix,iy,2] = l 
      coords[ix,iy,3] = b 
    return coords 

coords = make_coords() 

# now do one of these 
#plt.imshow(coords[:,:,0],origin='lower') # color plot 
#plt.contour(coords[:,:,0],levels=[45,90,135,180,225,270,315]) # contour plot with jagged ugliness 

Как я могу либо:

  1. остановка pyplot.contour от рисования контура вдоль разрыва

  2. макияж pyplot.contour признать что разрыв 0/360 в углу не является реальным разрывом вообще.

Я могу только увеличить разрешение исходных данных, но прежде чем я получаю хорошую гладкую линию он начинает занимать очень много времени и много памяти для сюжета.

Я также хочу построить контур вдоль 0 градусов, но если я смогу выяснить, как скрыть разрыв, я могу просто сдвинуть его в другое место, не находящееся вблизи контура. Или, если я могу сделать # 2, это не проблема.

+2

Это поможет, если вы можете разместить изображение сюжетной проблемы или код примера для создания (упрощенной) версии. – askewchan

+0

Я просто добавил примерные графики, чтобы проиллюстрировать проблему. – GJP

+1

Это странное использование контуров, и я не думаю, что вы сможете заставить его работать так, как вы хотите. Я, однако, уверен, что вы можете получить сюжет, который хотите, использовать что-то другое, кроме контура. Использование 'imshow' даст вам что-то вроде вашего верхнего сюжета, а' streamplot' даст вам что-то близкое к вашему нижнему сюжету. Какой сюжет ближе к тому, чего вы в конечном итоге хотите? Не могли бы вы предоставить функцию, которая создает поле данных, чтобы мы могли что-то играть? – Paul

ответ

1

Это, безусловно, еще хак, но вы можете получить хорошие гладкие контуры с два раза подхода:

  1. земля контуры абсолютного значения фазы (идущей от -180˚ до 180˚) так что нет разрыва.
  2. земля два набора контуров в конечной области, так что численные дефекты, близкие к вершинам и днищам экстремумов не ползать в

Вот полный код для добавления к вашему примеру:.

Z = np.exp(1j*np.pi*coords[:,:,0]/180.0) 
Z *= np.exp(0.25j*np.pi/2.0) # Shift to get same contours as in your example 
X = np.arange(300) 
Y = np.arange(450) 

N = 2 
levels = 90*(0.5 + (np.arange(N) + 0.5)/N) 
c1 = plt.contour(X, Y, abs(np.angle(Z)*180/np.pi), levels=levels) 
c2 = plt.contour(X, Y, abs(np.angle(Z*np.exp(0.5j*np.pi))*180/np.pi), levels=levels) 

Smooth contour plot of phase angle

можно обобщить этот код, чтобы получить гладкие контуры для любого «периодической» функции.Остается сделать следующее: создать новый набор контуров с правильными значениями, чтобы цветовые схемы применялись правильно, метки будут применены правильно и т. Д. Однако, похоже, нет простого способа сделать это с помощью matplotlib: соответствующий класс QuadContourSet делает все, и я не вижу простого способа построения соответствующего контурного объекта из контуров c1 и c2.

Смежные вопросы