问题描述
我正在尝试在 Python 中创建一个色轮,最好使用 Matplotlib.以下工作正常:
将 numpy 导入为 np将 matplotlib 导入为 mpl导入 matplotlib.pyplot 作为 pltxval = np.arange(0, 2*pi, 0.01)yval = np.ones_like(xval)colormap = plt.get_cmap('hsv')范数 = mpl.colors.Normalize(0.0, 2*np.pi)ax = plt.subplot(1, 1, 1, polar=True)ax.scatter(xval, yval, c=xval, s=300, cmap=colormap, norm=norm, linewidths=0)ax.set_yticks([])
然而,这种尝试有两个严重的缺点.
首先,将结果图保存为向量时 (
如果你想要一个环而不是一个轮子,在 plt.show()
或 plt.savefig
display_axes.set_rlim([-1,1])
这给了
根据评论中的 @EelkeSpaak - 如果您按照 OP 将图形另存为 SVG,这里是处理生成的图形的提示:生成的 SVG 图像的小元素是相互接触且不重叠的.这会导致某些渲染器(Inkscape、Adobe Reader,可能未打印)中出现微弱的灰线.一个简单的解决方案是对每个单独的梯度元素应用一个小的(例如 120%)缩放,例如使用Inkscape 或 Illustrator.请注意,您必须分别将变换应用于每个元素(上述软件提供了自动执行此操作的功能),而不是应用于整个绘图,否则它没有任何效果.
I am trying to create a color wheel in Python, preferably using Matplotlib. The following works OK:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
xval = np.arange(0, 2*pi, 0.01)
yval = np.ones_like(xval)
colormap = plt.get_cmap('hsv')
norm = mpl.colors.Normalize(0.0, 2*np.pi)
ax = plt.subplot(1, 1, 1, polar=True)
ax.scatter(xval, yval, c=xval, s=300, cmap=colormap, norm=norm, linewidths=0)
ax.set_yticks([])
However, this attempt has two serious drawbacks.
First, when saving the resulting figure as a vector (figure_1.svg), the color wheel consists (as expected) of 621 different shapes, corresponding to the different (x,y) values being plotted. Although the result looks like a circle, it isn't really. I would greatly prefer to use an actual circle, defined by a few path points and Bezier curves between them, as in e.g. matplotlib.patches.Circle
. This seems to me the 'proper' way of doing it, and the result would look nicer (no banding, better gradient, better anti-aliasing).
Second (relatedly), the final plotted markers (the last few before 2*pi
) overlap the first few. It's very hard to see in the pixel rendering, but if you zoom in on the vector-based rendering you can clearly see the last disc overlap the first few.
I tried using different markers (.
or |
), but none of them go around the second issue.
Bottom line: can I draw a circle in Python/Matplotlib which is defined in the proper vector/Bezier curve way, and which has an edge color defined according to a colormap (or, failing that, an arbitrary color gradient)?
One way I have found is to produce a colormap and then project it onto a polar axis. Here is a working example - it includes a nasty hack, though (clearly commented). I'm sure there's a way to either adjust limits or (harder) write your own Transform
to get around it, but I haven't quite managed that yet. I thought the bounds on the call to Normalize
would do that, but apparently not.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
import matplotlib as mpl
fig = plt.figure()
display_axes = fig.add_axes([0.1,0.1,0.8,0.8], projection='polar')
display_axes._direction = 2*np.pi ## This is a nasty hack - using the hidden field to
## multiply the values such that 1 become 2*pi
## this field is supposed to take values 1 or -1 only!!
norm = mpl.colors.Normalize(0.0, 2*np.pi)
# Plot the colorbar onto the polar axis
# note - use orientation horizontal so that the gradient goes around
# the wheel rather than centre out
quant_steps = 2056
cb = mpl.colorbar.ColorbarBase(display_axes, cmap=cm.get_cmap('hsv',quant_steps),
norm=norm,
orientation='horizontal')
# aesthetics - get rid of border and axis labels
cb.outline.set_visible(False)
display_axes.set_axis_off()
plt.show() # Replace with plt.savefig if you want to save a file
This produces
If you want a ring rather than a wheel, use this before plt.show()
or plt.savefig
display_axes.set_rlim([-1,1])
This gives
As per @EelkeSpaak in comments - if you save the graphic as an SVG as per the OP, here is a tip for working with the resulting graphic: The little elements of the resulting SVG image are touching and non-overlapping. This leads to faint grey lines in some renderers (Inkscape, Adobe Reader, probably not in print). A simple solution to this is to apply a small (e.g. 120%) scaling to each of the individual gradient elements, using e.g. Inkscape or Illustrator. Note you'll have to apply the transform to each element separately (the mentioned software provides functionality to do this automatically), rather than to the whole drawing, otherwise it has no effect.
这篇关于使用 Python/Matplotlib 根据颜色图绘制(极坐标)色轮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!