Matplotlib:如何在streamplot中增加色彩图/线宽质量?

时间:2016-09-02 14:36:31

标签: python numpy matplotlib

我有以下代码根据interp1d生成一个streamplot - 离散数据的插值:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
from scipy.interpolate import interp1d

# CSV Import
a1array=pd.read_csv('a1.csv', sep=',',header=None).values
rv=a1array[:,0]
a1v=a1array[:,1]
da1vM=a1array[:,2]
a1 = interp1d(rv, a1v)
da1M = interp1d(rv, da1vM)

# Bx and By vector components
def bx(x ,y):
    rad = np.sqrt(x**2+y**2)
    if rad == 0:
        return 0
    else:
        return x*y/rad**4*(-2*a1(rad)+rad*da1M(rad))/2.87445E-19*1E-12

def by(x ,y):
    rad = np.sqrt(x**2+y**2)
    if rad == 0:
        return 4.02995937E-04/2.87445E-19*1E-12
    else:
        return -1/rad**4*(2*a1(rad)*y**2+rad*da1M(rad)*x**2)/2.87445E-19*1E-12

Bx = np.vectorize(bx, otypes=[np.float])
By = np.vectorize(by, otypes=[np.float])

# Grid
num_steps = 11
Y, X = np.mgrid[-25:25:(num_steps * 1j), 0:25:(num_steps * 1j)]
Vx = Bx(X, Y)
Vy = By(X, Y)
speed = np.sqrt(Bx(X, Y)**2+By(X, Y)**2)
lw = 2*speed / speed.max()+.5

# Star Radius
circle3 = plt.Circle((0, 0), 16.3473140, color='black', fill=False)

# Plot
fig0, ax0 = plt.subplots(num=None, figsize=(11,9), dpi=80, facecolor='w', edgecolor='k')
strm = ax0.streamplot(X, Y, Vx, Vy, color=speed, linewidth=lw,density=[1,2], cmap=plt.cm.jet)
ax0.streamplot(-X, Y, -Vx, Vy, color=speed, linewidth=lw,density=[1,2], cmap=plt.cm.jet)
ax0.add_artist(circle3)
cbar=fig0.colorbar(strm.lines,fraction=0.046, pad=0.04)
cbar.set_label('B[GT]', rotation=270, labelpad=8)
cbar.set_clim(0,1500)
cbar.draw_all()
ax0.set_ylim([-25,25])
ax0.set_xlim([-25,25])
ax0.set_xlabel('x [km]')
ax0.set_ylabel('z [km]')
ax0.set_aspect(1)
plt.title('polyEos(0.05,2), M/R=0.2, B_r(0,0)=1402GT', y=1.01)
plt.savefig('MR02Br1402.pdf',bbox_inches=0)
plt.show(fig0)

如果你想尝试一些东西https://www.dropbox.com/s/4t7jixpglt0mkl5/a1.csv?dl=0,我在这里上传了csv文件。 其中生成以下图: StreamPlot

我实际上对结果非常满意,除了一个小细节,我无法弄清楚:如果仔细观察线宽和颜色变化的相当大的步骤,这在中心尤为明显:

Problem

是否有一些方法/选项可以减少这些步骤的大小,特别是使色彩图更加闷烧?

4 个答案:

答案 0 :(得分:3)

我又看了一眼,并没有像我想象的那样痛苦。

添加:

    subdiv = 15
    points = np.arange(len(t[0]))
    interp_points = np.linspace(0, len(t[0]), subdiv * len(t[0]))
    tgx = np.interp(interp_points, points, tgx)
    tgy = np.interp(interp_points, points, tgy)
    tx = np.interp(interp_points, points, tx)
    ty = np.interp(interp_points, points, ty)

在轨迹循环中初始化ty之后(我的版本中的行164)。只需替换subdiv = 15所需的任何细分数。 streamplot中的所有段都将细分为您选择的同等大小的段。通过内插数据仍然可以正确地获得每种颜色和线宽。

它不像改变积分步骤那样整洁,但确实绘制了完全相同的轨迹。

subdiv = 15

答案 1 :(得分:2)

如果您不介意更改streamplot代码(matplotlib/streamplot.py),则可以简单地减小集成步骤的大小。在_integrate_rk12()内,最大步长定义为:

maxds = min(1. / dmap.mask.nx, 1. / dmap.mask.ny, 0.1)

如果减少,请说:

maxds = 0.1 * min(1. / dmap.mask.nx, 1. / dmap.mask.ny, 0.1)

我得到了这个结果(左=新,右=原始):

enter image description here

当然,这使代码速度慢了10倍,而且我还没有对它进行彻底的测试,但是对于这个例子来说它似乎很有用(作为一个快速的黑客)。

关于密度(在评论中提到):我个人没有看到这个问题。这不像我们试图想象(例如)粒子的实际路径线;密度已经是一些任意的(可控的)选择,是的,它受到集成中选择的影响,但我并不认为它改变了(不太确定如何调用它)我们所需要的可视化。

结果(密度)看起来似乎有点缩小步长,这显示了使用因子{1,5,10,20}减少积分步骤的结果:

enter image description here

答案 2 :(得分:1)

您可以增加density参数以获得更平滑的颜色过渡, 但是然后使用start_points参数来减少整体混乱。 start_points参数允许您明确选择位置和 绘制的轨迹数量。它会覆盖默认值,即绘图 尽可能多地填补整个情节。

但首先,您需要对现有代码进行一些修复: 根据{{​​3}}文档,X和Y args应该是1d数组,而不是mgrid生成的2d数组。 看起来支持传入2d数组,但它没有文档 它目前与start_points参数不兼容。

以下是我修改你的X,Y,Vx,Vy和速度的方法:

# Grid
num_steps = 11
Y = np.linspace(-25, 25, num_steps)
X = np.linspace(0, 25, num_steps)
Ygrid, Xgrid = np.mgrid[-25:25:(num_steps * 1j), 0:25:(num_steps * 1j)]
Vx = Bx(Xgrid, Ygrid)
Vy = By(Xgrid, Ygrid)
speed = np.hypot(Vx, Vy)
lw = 3*speed / speed.max()+.5

现在您可以明确设置start_points参数。实际上是起点 "种子"点。任何给定的流轨迹都将在两个方向上增长 从种子角度来看。所以,如果你把种子点放在中心位置 在示例图中,它将上下生长以产生垂直 流线。

除了控制轨迹的数量外,使用 start_points参数还控制它们的顺序 画。在考虑轨迹如何终止时,这很重要。 他们要么会撞到情节的边界,要么就会终止 他们击中了已经有轨迹的情节。这意味着 你的第一颗种子往往会长得更长,你的后期种子也会趋向于 受以前的限制。一些后来的种子可能不会生长 一点都不默认播种策略是在每个细胞种植种子, 如果你有高密度,这是非常讨厌的。它也订购 他们首先沿着地块边界种植种子并向内螺旋。 这可能不适合您的特定情况。我发现很简单 你的例子的策略是在它们之间种植一些种子 两个零速度点,y = 0和x从-10到10.那些轨迹 充分发挥,充满了大部分情节,没有杂乱。

以下是我如何创建种子点并设置密度:

num_streams = 8
stptsy = np.zeros((num_streams,), np.float)
stptsx_left = np.linspace(0, -10.0, num_streams)
stptsx_right = np.linspace(0, 10.0, num_streams)
stpts_left = np.column_stack((stptsx_left, stptsy))
stpts_right = np.column_stack((stptsx_right, stptsy))
density = (3,6)

以下是我如何修改对streamplot的调用:

strm = ax0.streamplot(X, Y, Vx, Vy, color=speed, linewidth=lw, density=density,
                  cmap=plt.cm.jet, start_points=stpts_right)
ax0.streamplot(-X, Y, -Vx, Vy, color=speed, linewidth=lw,density=density,
                  cmap=plt.cm.jet, start_points=stpts_left)

结果基本上与原始结果相似,但颜色过渡更平滑,只有15条流线。 (抱歉没有内嵌图像的声誉)

答案 3 :(得分:0)

我认为你最好的选择是使用喷射以外的色彩图。也许是cmap=plt.cmap.plasma

The same graph with the plasma colormap

看起来很奇怪的图表模糊了对数据的理解。

对于以某种方式排序的数据,例如在这种情况下的速度矢量幅度,均匀连续的彩色图将始终看起来更平滑。连续图的亮度在颜色范围内单调变化,消除了在小范围数据上的大的颜色变化。统一图在整个范围内线性变化,这使得数据中的主要特征在视觉上更加明显。

Perceptually Uniform Sequential Color Maps http://matplotlib.org/_images/lightness_00.png

喷射色彩图在其范围内涵盖了各种各样的亮度,在中间有拐点。这是造成图表中心区域周围特别令人震惊的红色到蓝色过渡的原因。

Jet and other Non-Sequential Color Maps http://matplotlib.org/_images/lightness_05.png

The matplotlib user guide on choosing a color map有一些关于为给定数据集选择合适地图的建议。

我不认为你可以通过改变你的情节中的参数来改善这一点。

streamplot将图表划分为每个方向30*density[x,y]的单元格,每个单元格最多有一条流线。直接增加段数的唯一设置是matplotlib使用的网格密度。增加Y密度将减小段长度,使得中间区域可以更平滑地过渡。在流线是水平的区域中,这是成本的不可避免的混乱。

您还可以尝试以不同方式标准化速度,以便在中心附近人为降低变化。在一天结束时,虽然它似乎打败了图表的点。该图应提供有用的数据视图供人类理解。使用具有奇怪拐点的颜色图或使数据变形以使其看起来更好可以消除一些可以通过查看图形获得的理解。

有关像喷气机这样的色彩映射问题的更详细讨论可以在blog找到。