gpt4 book ai didi

python - matplotlib 图形中的视觉缺陷

转载 作者:行者123 更新时间:2023-12-05 04:26:24 24 4
gpt4 key购买 nike

<表类="s-表"><头>当前的matplotlib图它应该是什么样子<正文> enter image description here enter image description here

我想在图形低于零的部分更改图形颜色和渐变方向。用于说明的替代图像: enter image description here

我已经用这段代码试过了

def add_gradient_fill(ax: Optional[plt.Axes] = None, alpha_gradientglow: float = 1.0):
"""Add a gradient fill under each line,
i.e. faintly color the area below the line."""

if not ax:
ax = plt.gca()

lines = ax.get_lines()

for line in lines:

# don't add gradient fill for glow effect lines:
if hasattr(line, 'is_glow_line') and line.is_glow_line:
continue

fill_color = line.get_color()
zorder = line.get_zorder()
alpha = line.get_alpha()
alpha = 1.0 if alpha is None else alpha
rgb = mcolors.colorConverter.to_rgb(fill_color)
z = np.empty((100, 1, 4), dtype=float)
z[:, :, :3] = rgb
z[:, :, -1] = np.linspace(0, alpha, 100)[:, None]
x, y = line.get_data(orig=False)
x, y = np.array(x), np.array(y) # enforce x,y as numpy arrays
xmin, xmax = x.min(), x.max()
ymin, ymax = y.min(), y.max()
im = ax.imshow(z, aspect='auto',
extent=[xmin, xmax, ymin, ymax],
alpha=alpha_gradientglow,
origin='lower', zorder=zorder)
xy = np.column_stack([x, y])
xy = np.vstack([[xmin, ymin], xy, [xmax, ymin], [xmin, ymin]])
clip_path = Polygon(xy, facecolor='none', edgecolor='none', closed=True)
ax.add_patch(clip_path)
im.set_clip_path(clip_path)
ax.autoscale(True)

此代码也是名为 mplcyberpunk 的 matplotlib 主题库的一部分.

这使绘图看起来很漂亮,但如前所述,我希望图形的零以下部分具有不同的颜色,并且梯度方向相反。

这怎么可能实现?

PS:真诚的,我的问题与其他图形梯度问题不同,请不要关闭此问题。

编辑

最少的可重现代码

import matplotlib.pyplot as plt
import mplcyberpunk as mplcp

x = range(-10, 11)
y = [(i ** 2) - 50 for i in x]

plt.style.use('cyberpunk')


###### just for setting the theme, ignore these lines #########
for param in ['figure.facecolor', 'axes.facecolor', 'savefig.facecolor']:
plt.rcParams[param] = '#303030'

for param in ['text.color', 'axes.labelcolor', 'xtick.color', 'ytick.color']:
plt.rcParams[param] = '#ffffff'

plt.subplots()[1].grid(color='#404040')
##################################################################


plt.plot(x, y)

mplcp.make_lines_glow()
mplcp.add_gradient_fill()

plt.show()

更新:

好吧,我不知何故弄明白了,但是有一些视觉缺陷需要重点关注。以下是函数和输出:

from itertools import groupby
import numpy as np
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib.patches import Polygon


def add_glow_effects(n_glow_lines: int = 10,
diff_linewidth: float = 1.05,
alpha_line: float = 0.3,
change_line_color: bool = True,
color_positive: str = '#0000ff',
color_negative: str = '#ff0000',
alpha_gradientglow: float = 1.0, ):
make_lines_glow(n_glow_lines, diff_linewidth, alpha_line, change_line_color, color_positive, color_negative)
add_gradient_fill(alpha_gradientglow, color_positive, color_negative, )


def make_lines_glow(n_glow_lines: int = 10,
diff_linewidth: float = 1.05,
alpha_line: float = 0.3,
change_line_color: bool = True,
color_positive: str = '#0000ff',
color_negative: str = '#ff0000'):
ax = plt.gca()
lines = ax.get_lines()

alpha_value = alpha_line / n_glow_lines

for line_element in lines:

if not isinstance(line_element, Line2D):
continue

x, y = line_element.get_data(orig=False)
x, y = optimize_lines(list(x), list(y))
lines_list = list_form(x, y)

for line in lines_list:

if change_line_color:
y_avg = sum(line[1]) / len(line[1])
if y_avg >= 0:
color = color_positive
else:
color = color_negative
else:
color = line_element.get_color()

line = Line2D(line[0], line[1], linewidth=line_element.get_linewidth(), color=color)

data = list(line.get_data(orig=False))
linewidth = line.get_linewidth()

ax.plot(data[0], data[1], color=color, linewidth=linewidth)

for n in range(1, n_glow_lines + 1):
glow_line, = ax.plot(*data)
glow_line.update_from(line)
# line properties are copied as seen in this solution: https://stackoverflow.com/a/54688412/3240855

glow_line.set_alpha(alpha_value)
glow_line.set_linewidth(linewidth + (diff_linewidth * n))
# mark the glow lines, to disregard them in the underglow function.
glow_line.is_glow_line = True


# noinspection PyArgumentList
def add_gradient_fill(alpha_gradientglow: float = 1.0,
color_positive: str = '#00ff00',
color_negative: str = '#ff0000'):
"""Add a gradient fill under each line,
i.e. faintly color the area below the line."""

ax = plt.gca()
lines = ax.get_lines()

for line_element in lines:

if not isinstance(line_element, Line2D):
continue

x, y = line_element.get_data(orig=False)
x, y = optimize_lines(list(x), list(y))
lines_list = list_form(x, y)

for line in lines_list:

y_avg = sum(line[1]) / len(line[1])

# don't add gradient fill for glow effect lines:
if hasattr(line, 'is_glow_line') and line.is_glow_line:
continue

line = Line2D(line[0], line[1], linewidth=line_element.get_linewidth())

zorder = line.get_zorder()
alpha = line_element.get_alpha()
alpha = 1.0 if alpha is None else alpha

x, y = line.get_data(orig=False)
x, y = np.array(x), np.array(y) # enforce x,y as numpy arrays

xmin, xmax = x.min(), x.max()
ymin, ymax = y.min(), y.max()
xy = np.column_stack([x, y])

if y_avg >= 0:
fill_color = color_positive
linspace = np.linspace(0, alpha, 100)[:, None]
xy = np.vstack([[xmin, ymin], xy, [xmax, ymin], [xmin, ymin]])
else:
fill_color = color_negative
linspace = np.linspace(alpha, 0, 100)[:, None]
xy = np.vstack([[xmin, ymax], xy, [xmax, ymax], [xmin, ymax]])

rgb = mcolors.colorConverter.to_rgb(fill_color)
z = np.empty((100, 1, 4), dtype=float)
z[:, :, :3] = rgb
z[:, :, -1] = linspace

im = ax.imshow(z, aspect='auto',
extent=[xmin, xmax, ymin, ymax],
alpha=alpha_gradientglow,
origin='lower', zorder=zorder)
clip_path = Polygon(xy, facecolor='none', edgecolor='none', closed=True)
ax.add_patch(clip_path)
im.set_clip_path(clip_path)
ax.autoscale(True)


def optimize_lines(x: list, y: list):
y = [list(element) for index, element in groupby(y, lambda a: a >= 0)]

indexes = [0]
for i in y:
indexes.append(len(i) + indexes[-1])

# from https://www.geeksforgeeks.org/python-group-consecutive-elements-by-sign/
x = [x[indexes[i]:indexes[i + 1]] for i, _ in enumerate(indexes) if i != len(indexes) - 1]

for i in range(len(y) - 1):

if y[i][-1] == 0 and y[i + 1][0] == 0:
continue

a = y[i][-1]
b = y[i + 1][0]
diff = abs(a) + abs(b)
a_ = (abs(0 - a)) / diff
b_ = abs(0 - b) / diff

x[i].append(x[i][-1] + a_)
x[i + 1].insert(0, x[i + 1][0] - b_)

y[i].append(0)
y[i + 1].insert(0, 0)

x = [list(i) for i in x]
y = [list(i) for i in y]

# input: x=[1,2,3,4,5], y=[1,2,-5,0,2]
# output: x=[[1, 2, 2.2857142857142856], [2.2857142857142856, 3, 4.0], [4.0, 4, 5]],
# y=[[1, 2, 0], [0, -5, 0], [0, 0, 2]]

return list(x), list(y)


def list_form(x: list[list], y: list[list]):
lst = []
for i in range(len(x)):
lst.append([x[i], y[i]])
return lst

现在的输出是这样的: enter image description here

请注意如何在图表的左侧收集来自函数的光晕。此外,在图表的末尾,有一个紫色的小三角形,它被一个角偏移了。

出于相关性考虑,这篇文章的标题已从“远离 x 轴的 Matplotlib 图形梯度”更改为“matplotlib 图形中的视觉缺陷”,同时牢记帖子的最新更新。

最佳答案

有趣的问题。我有几个想法可以帮助你。我认为最简单的解决方案是找到一种优雅的方式,在发生过零时有条件地“拆分”数据(但您需要准确检测过零以获得干净的剪切蒙版)。

下面的解决方案还没有完成,但它解决了第一个问题,即具有双色渐变和复合路径以获得正/负剪切蒙版。现在线条颜色也需要分成 + 和 - 部分。到目前为止,我只是将零以下的线覆盖在现有线的顶部,并且这条线的辉光明显与第一条线的辉光混合在一起。

我稍后会回来;也许这会同时有所帮助。

gradient negative parts matplotlib style cyberpunk

import matplotlib.pyplot as plt
import mplcyberpunk as mplcp
import matplotlib.colors as mcolors
from matplotlib.path import Path
import numpy as np
from matplotlib.lines import Line2D

from matplotlib.patches import Polygon, PathPatch

def add_gradient_fill(ax=None, alpha_gradientglow=1.0, negative_color="C1"):
"""Add a gradient fill under each line,
i.e. faintly color the area below the line."""

if not ax:
ax = plt.gca()

lines = ax.get_lines()

for line in lines:

# don't add gradient fill for glow effect lines:
if hasattr(line, 'is_glow_line') and line.is_glow_line:
continue

fill_color = line.get_color()
zorder = line.get_zorder()
alpha = line.get_alpha()
alpha = 1.0 if alpha is None else alpha
rgb = mcolors.colorConverter.to_rgb(fill_color)

x, y = line.get_data(orig=False)
x, y = np.array(x), np.array(y) # enforce x,y as numpy arrays
xmin, xmax = np.nanmin(x), np.nanmax(x)
ymin, ymax = np.nanmin(y), np.nanmax(y)

z = np.empty((100, 1, 4), dtype=float)
z[:, :, :3] = rgb

# z[:, :, -1] = np.linspace(0, alpha, 100)[:, None]
ynorm = max(np.abs(ymin), np.abs(ymax))
ymin_norm = ymin / ynorm
ymax_norm = ymax / ynorm
ynorm = np.linspace(ymin_norm, ymax_norm, 100)
z[:, :, -1] = alpha * np.abs(ynorm[:, None])

rgb_neg = mcolors.colorConverter.to_rgb(negative_color)
z[ynorm < 0, :, :3] = rgb_neg

im = ax.imshow(z, aspect='auto',
extent=[xmin, xmax, ymin, ymax],
alpha=alpha_gradientglow,
origin='lower', zorder=zorder)

# Detect zero crossings
y_copy = y.copy()

y = y.clip(0, None)
xy = np.column_stack([x, y])
xy = np.vstack([[xmin, 0], xy, [xmax, 0], [xmin, 0]])
clip_path_1 = Polygon(xy, facecolor='none', edgecolor='none', closed=True)

y = y_copy.copy()
y = y.clip(None, 0)
xy = np.column_stack([x, y])
xy = np.vstack([[xmin, 0], xy, [xmax, 0], [xmin, 0]])
clip_path_2 = Polygon(xy, facecolor='none', edgecolor='none', closed=True)

ax.add_patch(clip_path_1)
ax.add_patch(clip_path_2)
clip_paths = clip_path_2, clip_path_1
vertices = np.concatenate([i.get_path().vertices for i in clip_paths])
codes = np.concatenate([i.get_path().codes for i in clip_paths])

clip_path = PathPatch(Path(vertices, codes), transform=ax.transData)
im.set_clip_path(clip_path)
ax.autoscale(True)

y = y_copy.copy()
y[y > 0] = np.nan
ax.plot(x, y)



def make_lines_glow(
ax=None,
n_glow_lines: int = 10,
diff_linewidth: float = 1.05,
alpha_line: float = 0.3,
lines=None,
) -> None:
"""Add a glow effect to the lines in an axis object.
Each existing line is redrawn several times with increasing width and low alpha to create the glow effect.
"""
if not ax:
ax = plt.gca()

lines = ax.get_lines() if lines is None else lines
lines = [lines] if isinstance(lines, Line2D) else lines

alpha_value = alpha_line / n_glow_lines

for line in lines:

data = line.get_data(orig=False)
linewidth = line.get_linewidth()

try:
step_type = line.get_drawstyle().split('-')[1]
except:
step_type = None

for n in range(1, n_glow_lines + 1):
if step_type:
glow_line, = ax.step(*data)
else:
glow_line, = ax.plot(*data)
glow_line.update_from(line) # line properties are copied as seen in this solution: https://stackoverflow.com/a/54688412/3240855

glow_line.set_alpha(alpha_value)
glow_line.set_linewidth(linewidth + (diff_linewidth * n))
glow_line.is_glow_line = True # mark the glow lines, to disregard them in the underglow function.

x = np.arange(-10, 11)
y = np.array([(i ** 2) - 50 for i in x])

plt.style.use('cyberpunk')

for param in ['figure.facecolor', 'axes.facecolor', 'savefig.facecolor']:
plt.rcParams[param] = '#303030'

for param in ['text.color', 'axes.labelcolor', 'xtick.color', 'ytick.color']:
plt.rcParams[param] = '#ffffff'

plt.subplots()[1].grid(color='#404040')

plt.plot(x, y)

add_gradient_fill(negative_color="C1")
make_lines_glow()

plt.show()

关于python - matplotlib 图形中的视觉缺陷,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73077026/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com