matplotlib throws error with figure.canvas.draw() and figure.savefig(): "ValueError: Expected 2-dimensional array, got 1"
matplotlib throws error with figure.canvas.draw() and figure.savefig(): "ValueError: Expected 2-dimensional array, got 1"
我想绘制一个图形,我需要在其中比较图例和图形高度。
所需的输出如下所示:
以前它很管用,现在我无法绘制存储在变量 fig
中的图形。
为此,有必要在实际绘图之前绘制图形 canvas,因为这样才能获得真正的最终图形扩展。
fig.canvas.draw()
# Get the extensions/dimensions of the current axis and legend
ax_height = ax.get_window_extent().height
ax_width = ax.get_window_extent().width
leg_height = legend.get_window_extent().height
leg_width = legend.get_window_extent().width
至少在以前,行 fig.canvas.draw()
工作完美,但这次抛出以下错误(包括整个回溯):
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/andylu/Dokumente/Allgemeines_material/Sonstiges/Programming/Python/Scripts/General/Plotting/auxiliary_plotting_functions.py", line 1293, in compare_legend_figure_height
fig.canvas.draw()
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 407, in draw
self.figure.draw(self.renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/figure.py", line 1863, in draw
mimage._draw_list_compositing_images(
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/cbook/deprecation.py", line 411, in wrapper
return func(*inner_args, **inner_kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/axes/_base.py", line 2748, in draw
mimage._draw_list_compositing_images(renderer, self, artists)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/collections.py", line 931, in draw
Collection.draw(self, renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/collections.py", line 406, in draw
renderer.draw_path_collection(
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 172, in draw_path_collection
return self._renderer.draw_path_collection(
ValueError: Expected 2-dimensional array, got 1
在调试控制台中,可以得到额外的inside into figure变量,但并没有帮助我进一步解决问题:
fig
<Figure size 1000x750 with 6 Axes>
special variables
function variables
artists:[]
axes:[<AxesSubplot:title={...19-pos4'}>, <AxesSubplot:title={...18-pos1'}>, <AxesSubplot:title={...18-pos1'}>, <AxesSubplot:title={...19-pos4'}>, <AxesSubplot:>, <AxesSubplot:>]
bbox:<matplotlib.transforms.TransformedBbox object at 0x7fc780543310>
bbox_inches:Bbox([[0.0, 0.0], [10.0, 7.5]])
callbacks:<matplotlib.cbook.CallbackRegistry object at 0x7fc7795fa3a0>
canvas:<matplotlib.backends.backend_agg.FigureCanvasAgg object at 0x7fc7811c1850>
clipbox:None
dpi:100.0
dpi_scale_trans:<matplotlib.transforms.Affine2D object at 0x7fc780543640>
eventson:False
figure:None
frameon:True
images:[]
legends:[]
lines:[]
mouseover:False
number:1
patch:<matplotlib.patches.Rectangle object at 0x7fc780554eb0>
patches:[]
stale:False
sticky_edges:_XYPair(x=[], y=[])
subplotpars:<matplotlib.figure.SubplotParams object at 0x7fc7795fa040>
suppressComposite:None
texts:[]
transFigure:<matplotlib.transforms.BboxTransformTo object at 0x7fc7805433a0>
zorder:0
_add_axes_internal:<bound method Figure._add_axes_internal of <Figure size 1000x750 with 6 Axes>>
_agg_filter:None
_align_xlabel_grp:<matplotlib.cbook.Grouper object at 0x7fc7795fac10>
_align_ylabel_grp:<matplotlib.cbook.Grouper object at 0x7fc7795faf10>
_alpha:None
_animated:False
_axobservers:<matplotlib.cbook.CallbackRegistry object at 0x7fc7811c1b50>
_axstack:<matplotlib.figure._AxesStack object at 0x7fc7795fae20>
_cachedRenderer:<matplotlib.backends.backend_agg.RendererAgg object at 0x7fc780d235e0>
_clipon:True
_clippath:None
_constrained:False
_constrained_layout_pads:{'h_pad': 0.04167, 'hspace': 0.02, 'w_pad': 0.04167, 'wspace': 0.02}
_contains:None
_default_contains:<bound method Artist._default_contains of <Figure size 1000x750 with 6 Axes>>
_dpi:100.0
_gci:<bound method Figure._gci of <Figure size 1000x750 with 6 Axes>>
_label:''
_layoutbox:None
_make_key:<bound method Figure._make_key of <Figure size 1000x750 with 6 Axes>>
_mouseover:False
_normalize_grid_string:<function Figure._normalize_grid_string at 0x7fc7d437c3a0>
_oid:0
_path_effects:[]
_picker:None
_process_projection_requirements:<bound method Figure._process_projection_requirements of <Figure size 1000x750 with 6 Axes>>
_propobservers:{}
_rasterized:None
_remove_method:None
_repr_html_:<bound method Figure._repr_html_ of <Figure size 1000x750 with 6 Axes>>
_set_artist_props:<bound method Figure._set_artist_props of <Figure size 1000x750 with 6 Axes>>
_set_dpi:<bound method Figure._set_dpi of <Figure size 1000x750 with 6 Axes>>
_set_gc_clip:<bound method Artist._set_gc_clip of <Figure size 1000x750 with 6 Axes>>
...
满怀希望,我试着像这样简单地避免这个错误:
# NOTE on scope of drawing the figure canvas:
# Crucial in order to get real legend extent afterwards
try:
fig.canvas.draw()
except Exception as e:
tools.except_print(f"The exception thrown opon executing fig.canvas.draw was:\n{e}\nExecute the rest of this function nevertheless.")
然而,通过figure.savefig()
保存图形时出现了类似的错误,所以我无法避免解决这个问题:
fig.savefig(filename,
dpi=dpi,
bbox_inches=bbox_inches,
transparent=transparent)
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/figure.py", line 2311, in savefig
self.canvas.print_figure(fname, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backend_bases.py", line 2210, in print_figure
result = print_method(
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backend_bases.py", line 1639, in wrapper
return func(*args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 509, in print_png
FigureCanvasAgg.draw(self)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 407, in draw
self.figure.draw(self.renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/figure.py", line 1863, in draw
mimage._draw_list_compositing_images(
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/cbook/deprecation.py", line 411, in wrapper
return func(*inner_args, **inner_kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/axes/_base.py", line 2748, in draw
mimage._draw_list_compositing_images(renderer, self, artists)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/collections.py", line 931, in draw
Collection.draw(self, renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/collections.py", line 406, in draw
renderer.draw_path_collection(
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 172, in draw_path_collection
return self._renderer.draw_path_collection(
ValueError: Expected 2-dimensional array, got 1
我在这个上下文中使用的最内层的绘图函数是:
def plot_point_estimator_with_CI(
df_plot_list=None,
colname=None,
estimator="mean",
ci_color=[1, 0, 0, 0.15],
CI=0.95,
hor_line=None,
strftime_str=None,
outer_index=None,
all_outer_indexes_subplot=False,
groupby_freq=None,
ax_title_pos=None,
savepath=None,
filtered_gps=None):
# Check for existence of the savepath
if savepath is not None and not os.path.exists(savepath):
os.makedirs(savepath)
# * Create a dummy date for later combination with pure time-values (i.e. HH:MM:SS)
# NOTE on scope: this is needed for being able to be plotted on a matplotlib.ax since datetime.time()-arrays will throw errors
# NOTE on implementation: use an extra-weird date in order to make clear that this is certainly not a real date
dummy_date = datetime.date(1000, 10, 10)
if not all_outer_indexes_subplot:
loop2_list = filtered_gps
else:
loop2_list = outer_index
## ** SUBPLOTS
"""Prepare the figure dimensions:
# NOTE: the figure size should be decided according to the dimensions of the grid
# Syntax from the documentation under: https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.figure.html
# (float, float), optional, default: None
# width, height in inches. If not provided, defaults to rcParams["figure.figsize"] = [6.4, 4.8]
# -> the relation is 4:3, which will be maintained throughout this
# CAUTION: even when cols=rows, the figure needs to be wider than high."""
if cols >= rows:
width = 10
height = width * (3 / 4)
else: # cols < rows:
height = 10
width = height * (3 / 4)
# * Instantiate figure
fig, axs = plt.subplots(rows, cols, figsize=(width, height))
# * Turn off possible extant subplot axes
dim_subplot = rows * cols
if len(loop2_list) < dim_subplot and len(loop2_list) > 1:
subplot_ax_overshoot = True
# Could happen when uneven number of subplots, such as "5", is passed, and the rectangular grid
# has extant subplot axis, e.g. in the case of a 2*3 = 6 grid
for i in range(len(loop2_list), dim_subplot):
axs.ravel()[i].axis('off')
else:
subplot_ax_overshoot = False
# Adapt the fontsize of the axis title strings according to the column number of the subplot
if cols < 3: # should be the "maximum max_cols_per_row"
ax_title_fontsize = 9
if not particular_ax_label_fontsize:
particular_ax_label_fontsize = 9
legend_font_size = 8.25
# NOTE on linewidths: the more columns/subplot graphic number, the finer the lines should be
if cols < 2:
linewidth = None # standard seems ok
else:
linewidth = 1.25
else:
ax_title_fontsize = 7
if not particular_ax_label_fontsize:
particular_ax_label_fontsize = 8
linewidth = 1
legend_font_size = 7
# NOTE: this is paramount in order to display the CI-band in the end as a part of the legend, even though the last subplot didn't contain it
add_handles_labels = None
# * Loop 2 - Create the output graphics
for i, elem in enumerate(loop2_list):
if groupby_freq is not None:
if groupby_freq.lower() == "y":
# Extract the grouped-by unit of the current pd.Timestamp
coord_kw = int(elem[0].strftime(
strftime_str)) # could be year, month, ...
# Assign a time unit name to the title string of the current sub-plot axis
current_ax_title = coord_kw
elif groupby_freq.lower() == "m":
# Extract the grouped-by unit of the current pd.Timestamp
coord_kw = int(elem[0].strftime(
strftime_str)) # could be year, month, ...
# Assign a time unit name to the title string of the current sub-plot axis
current_ax_title = calendar.month_name[coord_kw]
else:
string = """\nERROR: if the time-groupingby-frequency is neither "Y" nor "M",
it hasn't been implemented yet. Won't execute the plotting code (for this iteration).\nCurrent groupby_freq: '{}'""".format(
groupby_freq)
tools.except_print(string)
break
elif all_outer_indexes_subplot:
# The current outer index / directory / location name of the given meteo or gas measuring data
current_ax_title = elem
coord_kw = elem
# Define a temporary variable for the current sub-set dataframe
sub_df = df_plot_list[i]
if type(sub_df) == pd.DataFrame:
sub_df.dropna(axis=1, how="all", inplace=True)
# Assign the row and column to the current month accordingly - from dictionary
# NOTE: it should be ordered from January upper-left to December bottom-right
row, col = row_col_coords[coord_kw]
# Pass the info to the axis-dummy variable for the following plotting commands
if len(loop2_list) > 1:
# Discerning is paramount for avoiding "IndexError: too many indices for array"
if rows > 1 and cols > 1:
ax = axs[row, col]
elif rows > 1: # cols = 1
ax = axs[row]
else: # rows = 1
ax = axs[col]
# Case of single plot: rows = cols = 1
else:
# Avoid error: "is not subscriptable" when it's not a real subplot but only 1 plot
ax = axs
# * Check for datetime.time - format of index (overlay of days or similar)
if isinstance(sub_df.index[0], datetime.time):
# NOTE on implementation:
# - Replaced df_dummy.index.time with [datetime.datetime.combine(dummy_date, t) for t in df_dummy.index.time] since datetime.time(22, 35)-objects can't be processed well with ax.plot()
# Docs:
sub_df.index = [
datetime.datetime.combine(dummy_date, t) for t in sub_df.index
]
update_ticks_to_full_fledged_datetime = True
else:
update_ticks_to_full_fledged_datetime = False
# * Create plot on the designated axis based on the current sub-df
if type(sub_df) == pd.DataFrame: # contains CI-bands
# Caution: Colnames are uppercase conventionally
# NOTE: optionally another kwarg could be added: label=str_man.uppercase(estimator)
line1, = ax.plot(
sub_df.loc[:, str_man.uppercase(estimator)],
label=str_man.uppercase(estimator),
linewidth=linewidth) # matplotlib.lines.Line2D object
# Confidence interval of fit (higher resolution due to generated fit-vals with higher density)
# NOTE: the comma "," needs to be left out, otherwise: "TypeError: cannot unpack non-iterable PolyCollection object"
line2_label = "{}% CI".format(str(round(CI * 100)))
line2 = ax.fill_between(sub_df.index,
sub_df.loc[:, "Lower_bound"],
sub_df.loc[:, "Upper_bound"],
color=ci_color,
edgecolor="",
label=line2_label)
if not hor_line or i == len(loop2_list) - 1:
# NOTE on handles: could also be without "handles=.."
legend = aux_plot.set_legend_with_sorted_labels(
fig=fig,
ax=ax,
handles=[line1, line2],
return_legend_n_its_position=True)[0]
if i == len(loop2_list) - 1:
# Set to None, as the CI-band (line2) has just been plotted in the last subplot axis
add_handles_labels = None
else:
# NOTE: this is paramount in order to display the CI-band in the end as a part of the legend, even though the last subplot didn't contain it
if not add_handles_labels:
add_handles_labels = [line2, line2_label]
# Contains only the aggregated values of the statistical summary estimator, i.e. type(df) == pd.Series
else:
# pd.Series doesn't need any other kwargs to be passed
line1, = ax.plot(sub_df,
label=str_man.uppercase(estimator),
linewidth=linewidth)
if not hor_line or i == len(loop2_list) - 1:
# NOTE on handles: could also be without "handles=.."
legend = aux_plot.set_legend_with_sorted_labels(
fig=fig,
ax=ax,
handles=[line1],
return_legend_n_its_position=True)[0]
# * SET X-TICKS and -LABELS
# Create a grid for the times on the x-axis
times_grid, time_ax_vals, ax_tick_labels, sub_ordinated_unit = dt_man.time_range_grid_and_vals(
step=step, cols=cols)
# Delete superfluous variables
del time_ax_vals
# * Set the ticks and their associated labels
if update_ticks_to_full_fledged_datetime:
# NOTE on implementation: need to adapted with the dummy-date to the current axis
# -> The date doesn't matter since the ticks will be labeled separately with the "HH:MM:SS" - strings (pure times)
ax.set_xticks(
[datetime.datetime.combine(dummy_date, t) for t in times_grid])
else:
ax.set_xticks(times_grid)
# Tick labels remain untouched by the ticks-setting above
ax.set_xticklabels(ax_tick_labels,
fontsize=particular_ax_label_fontsize)
# * SET Y-TICKS and -LABELS
y_tick_labels = [str(yt) for yt in list(ax.get_yticks())]
if decimal_formatter:
y_tick_labels = [
decimal_formatter % Decimal(float(t)) for t in y_tick_labels
]
y_tick_labels = tools.round_long_floats_with_many_zeros(
number_list=y_tick_labels,
decimal_sep=".",
undesired_char="0",
limit_consec_undesired_chars=1)
ax.set_yticklabels(y_tick_labels,
fontsize=particular_ax_label_fontsize)
ax.grid(which='both', alpha=1)
# Inserts horizontal line into plot adapted by its value in comparison to the data's values
# NOTE: only the last element, which is true in case of a subplot or a single plot
if hor_line is not None:
remove_legend_from_current_axis = i != len(loop2_list) - 1
# Loop over all horizontal lines provided
for hor in hor_line:
if hor[0].lower() in colname.lower(
): # hor[0] contains the variable name (or vice versa)
# hor[1] contains tuples (triples)
for info, val, linestyle in hor[1]:
leg_label = str_man.uppercase(info)
# Caution 1: In order to obtain pd.Datetime-vals from matplotlib's ax.get_xlim() -> conversion necessary
# Caution 2: Set vertical=False since horizontal lines are desired
# NOTE on previous implementation of other_ax_vals:
# i) time_ax_vals
# ii) [datetime.datetime.combine(dummy_date, t) for t in time_ax_vals]
ax, legend = aux_plot.add_hor_vert_line_n_legend(
ax=ax,
compare_ax_vals=ax.get_ylim(),
add_handles_labels=add_handles_labels,
other_ax_vals=ax.get_xlim(),
val=val,
alpha=1,
linewidth=linewidth,
leg_label=leg_label,
vertical=False,
linestyle=linestyle,
remove_legend_from_current_axis=
remove_legend_from_current_axis)[:2]
# * X-axis label
# NOTE: otherwise, it appears always the string "time"
ax.set_xlabel("")
# * Title of current axis
# Set title with the calendar month above every subplot
# [x_coord, y_coord] -> slightly above the top and centered
ax.set_title(current_ax_title,
position=ax_title_pos,
fontsize=ax_title_fontsize)
# * AFTER 2nd LOOP
# 0.0) Assign global axis label shifts
global_X_ax_label_shift = global_X_ax_label_shift_dict[rows]
global_Y_ax_label_shift = global_Y_ax_label_shift_dict[rows]
# 0.1) Create final and global legend object
if hor_line is not None and dim_subplot > 1:
# Obtain legend handles and labels from passed axis object
handles, labels = ax.get_legend_handles_labels()
# NOTE: sometimes it is necessary to pass former handles and labels from an already plotted axis
# TIPP: the problem is that when the current axis is accessed for retrieving the handles and labels, these added
# handles and labels won't be in there since it was nothing plotted in the current axis, but in a former one
if add_handles_labels:
# Extract the additional handles and labels from another/former axis
add_handles, add_labels = add_handles_labels
# Add these accordingly to the current axis' handles..
if type(add_handles) != list:
handles += [add_handles]
else:
handles += add_handles
# .. and labels
if type(add_labels) != list:
labels += [add_labels]
else:
labels += add_labels
# CAUTION: Prevent the legend's appearance in the last selected axis of the subplot
ax.get_legend().remove()
legend_font_size = 8.25
# NOTE on the nomenclature of this legend:
# - bbox_to_anchor = (x, y), alternatively, if a size needs to be determined: (x, y, width, height)
# - loc == 9 -> upper center, (0, 0) seems to stand for the lower/upper left corner of the legend box
# - ncol : The number of columns that the legend has. Default is 1.
# - mode: If mode is set to "expand" the legend will be horizontally expanded to fill the axes area
# (or bbox_to_anchor if defines the legend's size, which is the case if a 4-tuple was passed to bbox_to_anchor like (x, y, width, height))
if not subplot_ax_overshoot:
aux_plot.set_legend_with_sorted_labels(fig=fig,
handles=handles,
labels=labels,
loc="lower center",
ncol=5,
fontsize=legend_font_size)
global_X_ax_label_shift += 0.01 # shift higher to make room for the footnote-legend
# * OTHERWISE, use the last free axis to plot the legend
else:
legend_ax = axs[rows - 1, cols - 1]
# Set sorted legend on specific axis
aux_plot.set_legend_with_sorted_labels(ax=legend_ax,
handles=handles,
labels=labels,
loc="upper left",
ncol=1,
fontsize=legend_font_size)
# 0.2) Set global X- and Y-axis labels
xaxstr = "Time ({})".format(sub_ordinated_unit)
if yaxstr is None:
yaxstr = str_man.uppercase(estimator)
if len(df_plot_list) == 1:
ax.set_xlabel(xaxstr, fontsize=ax_label_font_size)
ax.set_ylabel(yaxstr, fontsize=ax_label_font_size)
else:
fig.text(0.5,
global_X_ax_label_shift,
xaxstr,
ha='center',
rotation='horizontal',
fontsize=ax_label_font_size) # general x-axis label
fig.text(global_Y_ax_label_shift,
0.5,
yaxstr,
va='center',
rotation='vertical',
fontsize=ax_label_font_size) # general y-axis label
# 1) Generate a unique title string
# ...
# 2) Set title
if len(df_plot_list) == 1:
# NOTE: overlapping title strings with the standard .set_title()-function can be fought via the y-kwarg
ax.set_title(titlestr,
y=1.0 + add_to_ycoord / 2,
fontsize=title_font_size,
weight="bold")
fig.tight_layout()
else:
# Now, alter the y-coord of the superior title as a function of the lines the suptitlestring comprises
y_coord_suptitle = y_coord_suptitle_dict[rows]
y_coord_suptitle += add_to_ycoord
# Finally, set the suptitle
plt.suptitle(titlestr,
x=0.5,
y=y_coord_suptitle,
fontsize=title_font_size,
weight="bold")
# NOTE: Tight layout often produces nice results, but requires the title to be spaced accordingly
fig.tight_layout()
if global_Y_ax_label_shift:
# ...
fig.subplots_adjust(top=y_coord_suptitle + sub_top_shift -
add_to_ycoord,
bottom=global_X_ax_label_shift + 0.04,
left=global_Y_ax_label_shift + add_left_shift)
else:
fig.subplots_adjust(top=y_coord_suptitle + sub_top_shift -
add_to_ycoord,
bottom=global_X_ax_label_shift + 0.1)
# NOTE: Tight layout often produces nice results but requires the title to be spaced accordingly
# CAUTION: as far as this function (windrose-subplotting) is concerned, it hasn't been necessary (status: 17-08-2019)
if len(df_plot_list) == 1:
pass
else: # in case of subplots
# * FINALLY, set legend to None due to the subplots character
legend = None
## ** Finally, either show or save the current plot/figure **
aux_plot.show_or_save_plot(fig=fig,
path=savepath,
basename=titlestr,
file_extensions=['.png', '.pdf'],
legend=legend)
我最近遇到了同样的错误信息,和你在使用 fig.savefig
时弹出的信息一样。我认为问题可能出现在代码的较早部分,而不是 savefig 函数本身。对于我的情节,我将问题追溯到 plt.scatter()
中的 now-deprecated 参数 - 我使用了 edgecolors=''
,现在应该是 edgecolors=None
,它导致了相同的错误消息'ValueError: Expected 2-dimensional array, got 1' 当我试图保存这个数字时。
例如,此代码块会引发错误,但如果将 edgecolors 参数更改为 =None,代码将正常运行。
fig = plt.figure()
a = [1,2,3,4]
plt.scatter(a,a,edgecolors='')
fig.savefig('test.png')
不知道你在策划的时候有没有用过类似的弃用参数?通过在 ipython 中做一个小测试图来追溯是最容易的,因为弃用警告以一种在简单执行 .py 文件时不会出现的方式正确引发。
编辑:刚刚发现您在底部包含了您的代码 - 我相信您确实遇到了同样的问题,您在调用 fill_between
时使用了 edgecolors=""
我想绘制一个图形,我需要在其中比较图例和图形高度。 所需的输出如下所示:
以前它很管用,现在我无法绘制存储在变量 fig
中的图形。
为此,有必要在实际绘图之前绘制图形 canvas,因为这样才能获得真正的最终图形扩展。
fig.canvas.draw()
# Get the extensions/dimensions of the current axis and legend
ax_height = ax.get_window_extent().height
ax_width = ax.get_window_extent().width
leg_height = legend.get_window_extent().height
leg_width = legend.get_window_extent().width
至少在以前,行 fig.canvas.draw()
工作完美,但这次抛出以下错误(包括整个回溯):
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/andylu/Dokumente/Allgemeines_material/Sonstiges/Programming/Python/Scripts/General/Plotting/auxiliary_plotting_functions.py", line 1293, in compare_legend_figure_height
fig.canvas.draw()
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 407, in draw
self.figure.draw(self.renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/figure.py", line 1863, in draw
mimage._draw_list_compositing_images(
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/cbook/deprecation.py", line 411, in wrapper
return func(*inner_args, **inner_kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/axes/_base.py", line 2748, in draw
mimage._draw_list_compositing_images(renderer, self, artists)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/collections.py", line 931, in draw
Collection.draw(self, renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/collections.py", line 406, in draw
renderer.draw_path_collection(
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 172, in draw_path_collection
return self._renderer.draw_path_collection(
ValueError: Expected 2-dimensional array, got 1
在调试控制台中,可以得到额外的inside into figure变量,但并没有帮助我进一步解决问题:
fig
<Figure size 1000x750 with 6 Axes>
special variables
function variables
artists:[]
axes:[<AxesSubplot:title={...19-pos4'}>, <AxesSubplot:title={...18-pos1'}>, <AxesSubplot:title={...18-pos1'}>, <AxesSubplot:title={...19-pos4'}>, <AxesSubplot:>, <AxesSubplot:>]
bbox:<matplotlib.transforms.TransformedBbox object at 0x7fc780543310>
bbox_inches:Bbox([[0.0, 0.0], [10.0, 7.5]])
callbacks:<matplotlib.cbook.CallbackRegistry object at 0x7fc7795fa3a0>
canvas:<matplotlib.backends.backend_agg.FigureCanvasAgg object at 0x7fc7811c1850>
clipbox:None
dpi:100.0
dpi_scale_trans:<matplotlib.transforms.Affine2D object at 0x7fc780543640>
eventson:False
figure:None
frameon:True
images:[]
legends:[]
lines:[]
mouseover:False
number:1
patch:<matplotlib.patches.Rectangle object at 0x7fc780554eb0>
patches:[]
stale:False
sticky_edges:_XYPair(x=[], y=[])
subplotpars:<matplotlib.figure.SubplotParams object at 0x7fc7795fa040>
suppressComposite:None
texts:[]
transFigure:<matplotlib.transforms.BboxTransformTo object at 0x7fc7805433a0>
zorder:0
_add_axes_internal:<bound method Figure._add_axes_internal of <Figure size 1000x750 with 6 Axes>>
_agg_filter:None
_align_xlabel_grp:<matplotlib.cbook.Grouper object at 0x7fc7795fac10>
_align_ylabel_grp:<matplotlib.cbook.Grouper object at 0x7fc7795faf10>
_alpha:None
_animated:False
_axobservers:<matplotlib.cbook.CallbackRegistry object at 0x7fc7811c1b50>
_axstack:<matplotlib.figure._AxesStack object at 0x7fc7795fae20>
_cachedRenderer:<matplotlib.backends.backend_agg.RendererAgg object at 0x7fc780d235e0>
_clipon:True
_clippath:None
_constrained:False
_constrained_layout_pads:{'h_pad': 0.04167, 'hspace': 0.02, 'w_pad': 0.04167, 'wspace': 0.02}
_contains:None
_default_contains:<bound method Artist._default_contains of <Figure size 1000x750 with 6 Axes>>
_dpi:100.0
_gci:<bound method Figure._gci of <Figure size 1000x750 with 6 Axes>>
_label:''
_layoutbox:None
_make_key:<bound method Figure._make_key of <Figure size 1000x750 with 6 Axes>>
_mouseover:False
_normalize_grid_string:<function Figure._normalize_grid_string at 0x7fc7d437c3a0>
_oid:0
_path_effects:[]
_picker:None
_process_projection_requirements:<bound method Figure._process_projection_requirements of <Figure size 1000x750 with 6 Axes>>
_propobservers:{}
_rasterized:None
_remove_method:None
_repr_html_:<bound method Figure._repr_html_ of <Figure size 1000x750 with 6 Axes>>
_set_artist_props:<bound method Figure._set_artist_props of <Figure size 1000x750 with 6 Axes>>
_set_dpi:<bound method Figure._set_dpi of <Figure size 1000x750 with 6 Axes>>
_set_gc_clip:<bound method Artist._set_gc_clip of <Figure size 1000x750 with 6 Axes>>
...
满怀希望,我试着像这样简单地避免这个错误:
# NOTE on scope of drawing the figure canvas:
# Crucial in order to get real legend extent afterwards
try:
fig.canvas.draw()
except Exception as e:
tools.except_print(f"The exception thrown opon executing fig.canvas.draw was:\n{e}\nExecute the rest of this function nevertheless.")
然而,通过figure.savefig()
保存图形时出现了类似的错误,所以我无法避免解决这个问题:
fig.savefig(filename,
dpi=dpi,
bbox_inches=bbox_inches,
transparent=transparent)
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/figure.py", line 2311, in savefig
self.canvas.print_figure(fname, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backend_bases.py", line 2210, in print_figure
result = print_method(
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backend_bases.py", line 1639, in wrapper
return func(*args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 509, in print_png
FigureCanvasAgg.draw(self)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 407, in draw
self.figure.draw(self.renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/figure.py", line 1863, in draw
mimage._draw_list_compositing_images(
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/cbook/deprecation.py", line 411, in wrapper
return func(*inner_args, **inner_kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/axes/_base.py", line 2748, in draw
mimage._draw_list_compositing_images(renderer, self, artists)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/collections.py", line 931, in draw
Collection.draw(self, renderer)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/collections.py", line 406, in draw
renderer.draw_path_collection(
File "/home/linuxbrew/.linuxbrew/lib/python3.8/site-packages/matplotlib/backends/backend_agg.py", line 172, in draw_path_collection
return self._renderer.draw_path_collection(
ValueError: Expected 2-dimensional array, got 1
我在这个上下文中使用的最内层的绘图函数是:
def plot_point_estimator_with_CI(
df_plot_list=None,
colname=None,
estimator="mean",
ci_color=[1, 0, 0, 0.15],
CI=0.95,
hor_line=None,
strftime_str=None,
outer_index=None,
all_outer_indexes_subplot=False,
groupby_freq=None,
ax_title_pos=None,
savepath=None,
filtered_gps=None):
# Check for existence of the savepath
if savepath is not None and not os.path.exists(savepath):
os.makedirs(savepath)
# * Create a dummy date for later combination with pure time-values (i.e. HH:MM:SS)
# NOTE on scope: this is needed for being able to be plotted on a matplotlib.ax since datetime.time()-arrays will throw errors
# NOTE on implementation: use an extra-weird date in order to make clear that this is certainly not a real date
dummy_date = datetime.date(1000, 10, 10)
if not all_outer_indexes_subplot:
loop2_list = filtered_gps
else:
loop2_list = outer_index
## ** SUBPLOTS
"""Prepare the figure dimensions:
# NOTE: the figure size should be decided according to the dimensions of the grid
# Syntax from the documentation under: https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.figure.html
# (float, float), optional, default: None
# width, height in inches. If not provided, defaults to rcParams["figure.figsize"] = [6.4, 4.8]
# -> the relation is 4:3, which will be maintained throughout this
# CAUTION: even when cols=rows, the figure needs to be wider than high."""
if cols >= rows:
width = 10
height = width * (3 / 4)
else: # cols < rows:
height = 10
width = height * (3 / 4)
# * Instantiate figure
fig, axs = plt.subplots(rows, cols, figsize=(width, height))
# * Turn off possible extant subplot axes
dim_subplot = rows * cols
if len(loop2_list) < dim_subplot and len(loop2_list) > 1:
subplot_ax_overshoot = True
# Could happen when uneven number of subplots, such as "5", is passed, and the rectangular grid
# has extant subplot axis, e.g. in the case of a 2*3 = 6 grid
for i in range(len(loop2_list), dim_subplot):
axs.ravel()[i].axis('off')
else:
subplot_ax_overshoot = False
# Adapt the fontsize of the axis title strings according to the column number of the subplot
if cols < 3: # should be the "maximum max_cols_per_row"
ax_title_fontsize = 9
if not particular_ax_label_fontsize:
particular_ax_label_fontsize = 9
legend_font_size = 8.25
# NOTE on linewidths: the more columns/subplot graphic number, the finer the lines should be
if cols < 2:
linewidth = None # standard seems ok
else:
linewidth = 1.25
else:
ax_title_fontsize = 7
if not particular_ax_label_fontsize:
particular_ax_label_fontsize = 8
linewidth = 1
legend_font_size = 7
# NOTE: this is paramount in order to display the CI-band in the end as a part of the legend, even though the last subplot didn't contain it
add_handles_labels = None
# * Loop 2 - Create the output graphics
for i, elem in enumerate(loop2_list):
if groupby_freq is not None:
if groupby_freq.lower() == "y":
# Extract the grouped-by unit of the current pd.Timestamp
coord_kw = int(elem[0].strftime(
strftime_str)) # could be year, month, ...
# Assign a time unit name to the title string of the current sub-plot axis
current_ax_title = coord_kw
elif groupby_freq.lower() == "m":
# Extract the grouped-by unit of the current pd.Timestamp
coord_kw = int(elem[0].strftime(
strftime_str)) # could be year, month, ...
# Assign a time unit name to the title string of the current sub-plot axis
current_ax_title = calendar.month_name[coord_kw]
else:
string = """\nERROR: if the time-groupingby-frequency is neither "Y" nor "M",
it hasn't been implemented yet. Won't execute the plotting code (for this iteration).\nCurrent groupby_freq: '{}'""".format(
groupby_freq)
tools.except_print(string)
break
elif all_outer_indexes_subplot:
# The current outer index / directory / location name of the given meteo or gas measuring data
current_ax_title = elem
coord_kw = elem
# Define a temporary variable for the current sub-set dataframe
sub_df = df_plot_list[i]
if type(sub_df) == pd.DataFrame:
sub_df.dropna(axis=1, how="all", inplace=True)
# Assign the row and column to the current month accordingly - from dictionary
# NOTE: it should be ordered from January upper-left to December bottom-right
row, col = row_col_coords[coord_kw]
# Pass the info to the axis-dummy variable for the following plotting commands
if len(loop2_list) > 1:
# Discerning is paramount for avoiding "IndexError: too many indices for array"
if rows > 1 and cols > 1:
ax = axs[row, col]
elif rows > 1: # cols = 1
ax = axs[row]
else: # rows = 1
ax = axs[col]
# Case of single plot: rows = cols = 1
else:
# Avoid error: "is not subscriptable" when it's not a real subplot but only 1 plot
ax = axs
# * Check for datetime.time - format of index (overlay of days or similar)
if isinstance(sub_df.index[0], datetime.time):
# NOTE on implementation:
# - Replaced df_dummy.index.time with [datetime.datetime.combine(dummy_date, t) for t in df_dummy.index.time] since datetime.time(22, 35)-objects can't be processed well with ax.plot()
# Docs:
sub_df.index = [
datetime.datetime.combine(dummy_date, t) for t in sub_df.index
]
update_ticks_to_full_fledged_datetime = True
else:
update_ticks_to_full_fledged_datetime = False
# * Create plot on the designated axis based on the current sub-df
if type(sub_df) == pd.DataFrame: # contains CI-bands
# Caution: Colnames are uppercase conventionally
# NOTE: optionally another kwarg could be added: label=str_man.uppercase(estimator)
line1, = ax.plot(
sub_df.loc[:, str_man.uppercase(estimator)],
label=str_man.uppercase(estimator),
linewidth=linewidth) # matplotlib.lines.Line2D object
# Confidence interval of fit (higher resolution due to generated fit-vals with higher density)
# NOTE: the comma "," needs to be left out, otherwise: "TypeError: cannot unpack non-iterable PolyCollection object"
line2_label = "{}% CI".format(str(round(CI * 100)))
line2 = ax.fill_between(sub_df.index,
sub_df.loc[:, "Lower_bound"],
sub_df.loc[:, "Upper_bound"],
color=ci_color,
edgecolor="",
label=line2_label)
if not hor_line or i == len(loop2_list) - 1:
# NOTE on handles: could also be without "handles=.."
legend = aux_plot.set_legend_with_sorted_labels(
fig=fig,
ax=ax,
handles=[line1, line2],
return_legend_n_its_position=True)[0]
if i == len(loop2_list) - 1:
# Set to None, as the CI-band (line2) has just been plotted in the last subplot axis
add_handles_labels = None
else:
# NOTE: this is paramount in order to display the CI-band in the end as a part of the legend, even though the last subplot didn't contain it
if not add_handles_labels:
add_handles_labels = [line2, line2_label]
# Contains only the aggregated values of the statistical summary estimator, i.e. type(df) == pd.Series
else:
# pd.Series doesn't need any other kwargs to be passed
line1, = ax.plot(sub_df,
label=str_man.uppercase(estimator),
linewidth=linewidth)
if not hor_line or i == len(loop2_list) - 1:
# NOTE on handles: could also be without "handles=.."
legend = aux_plot.set_legend_with_sorted_labels(
fig=fig,
ax=ax,
handles=[line1],
return_legend_n_its_position=True)[0]
# * SET X-TICKS and -LABELS
# Create a grid for the times on the x-axis
times_grid, time_ax_vals, ax_tick_labels, sub_ordinated_unit = dt_man.time_range_grid_and_vals(
step=step, cols=cols)
# Delete superfluous variables
del time_ax_vals
# * Set the ticks and their associated labels
if update_ticks_to_full_fledged_datetime:
# NOTE on implementation: need to adapted with the dummy-date to the current axis
# -> The date doesn't matter since the ticks will be labeled separately with the "HH:MM:SS" - strings (pure times)
ax.set_xticks(
[datetime.datetime.combine(dummy_date, t) for t in times_grid])
else:
ax.set_xticks(times_grid)
# Tick labels remain untouched by the ticks-setting above
ax.set_xticklabels(ax_tick_labels,
fontsize=particular_ax_label_fontsize)
# * SET Y-TICKS and -LABELS
y_tick_labels = [str(yt) for yt in list(ax.get_yticks())]
if decimal_formatter:
y_tick_labels = [
decimal_formatter % Decimal(float(t)) for t in y_tick_labels
]
y_tick_labels = tools.round_long_floats_with_many_zeros(
number_list=y_tick_labels,
decimal_sep=".",
undesired_char="0",
limit_consec_undesired_chars=1)
ax.set_yticklabels(y_tick_labels,
fontsize=particular_ax_label_fontsize)
ax.grid(which='both', alpha=1)
# Inserts horizontal line into plot adapted by its value in comparison to the data's values
# NOTE: only the last element, which is true in case of a subplot or a single plot
if hor_line is not None:
remove_legend_from_current_axis = i != len(loop2_list) - 1
# Loop over all horizontal lines provided
for hor in hor_line:
if hor[0].lower() in colname.lower(
): # hor[0] contains the variable name (or vice versa)
# hor[1] contains tuples (triples)
for info, val, linestyle in hor[1]:
leg_label = str_man.uppercase(info)
# Caution 1: In order to obtain pd.Datetime-vals from matplotlib's ax.get_xlim() -> conversion necessary
# Caution 2: Set vertical=False since horizontal lines are desired
# NOTE on previous implementation of other_ax_vals:
# i) time_ax_vals
# ii) [datetime.datetime.combine(dummy_date, t) for t in time_ax_vals]
ax, legend = aux_plot.add_hor_vert_line_n_legend(
ax=ax,
compare_ax_vals=ax.get_ylim(),
add_handles_labels=add_handles_labels,
other_ax_vals=ax.get_xlim(),
val=val,
alpha=1,
linewidth=linewidth,
leg_label=leg_label,
vertical=False,
linestyle=linestyle,
remove_legend_from_current_axis=
remove_legend_from_current_axis)[:2]
# * X-axis label
# NOTE: otherwise, it appears always the string "time"
ax.set_xlabel("")
# * Title of current axis
# Set title with the calendar month above every subplot
# [x_coord, y_coord] -> slightly above the top and centered
ax.set_title(current_ax_title,
position=ax_title_pos,
fontsize=ax_title_fontsize)
# * AFTER 2nd LOOP
# 0.0) Assign global axis label shifts
global_X_ax_label_shift = global_X_ax_label_shift_dict[rows]
global_Y_ax_label_shift = global_Y_ax_label_shift_dict[rows]
# 0.1) Create final and global legend object
if hor_line is not None and dim_subplot > 1:
# Obtain legend handles and labels from passed axis object
handles, labels = ax.get_legend_handles_labels()
# NOTE: sometimes it is necessary to pass former handles and labels from an already plotted axis
# TIPP: the problem is that when the current axis is accessed for retrieving the handles and labels, these added
# handles and labels won't be in there since it was nothing plotted in the current axis, but in a former one
if add_handles_labels:
# Extract the additional handles and labels from another/former axis
add_handles, add_labels = add_handles_labels
# Add these accordingly to the current axis' handles..
if type(add_handles) != list:
handles += [add_handles]
else:
handles += add_handles
# .. and labels
if type(add_labels) != list:
labels += [add_labels]
else:
labels += add_labels
# CAUTION: Prevent the legend's appearance in the last selected axis of the subplot
ax.get_legend().remove()
legend_font_size = 8.25
# NOTE on the nomenclature of this legend:
# - bbox_to_anchor = (x, y), alternatively, if a size needs to be determined: (x, y, width, height)
# - loc == 9 -> upper center, (0, 0) seems to stand for the lower/upper left corner of the legend box
# - ncol : The number of columns that the legend has. Default is 1.
# - mode: If mode is set to "expand" the legend will be horizontally expanded to fill the axes area
# (or bbox_to_anchor if defines the legend's size, which is the case if a 4-tuple was passed to bbox_to_anchor like (x, y, width, height))
if not subplot_ax_overshoot:
aux_plot.set_legend_with_sorted_labels(fig=fig,
handles=handles,
labels=labels,
loc="lower center",
ncol=5,
fontsize=legend_font_size)
global_X_ax_label_shift += 0.01 # shift higher to make room for the footnote-legend
# * OTHERWISE, use the last free axis to plot the legend
else:
legend_ax = axs[rows - 1, cols - 1]
# Set sorted legend on specific axis
aux_plot.set_legend_with_sorted_labels(ax=legend_ax,
handles=handles,
labels=labels,
loc="upper left",
ncol=1,
fontsize=legend_font_size)
# 0.2) Set global X- and Y-axis labels
xaxstr = "Time ({})".format(sub_ordinated_unit)
if yaxstr is None:
yaxstr = str_man.uppercase(estimator)
if len(df_plot_list) == 1:
ax.set_xlabel(xaxstr, fontsize=ax_label_font_size)
ax.set_ylabel(yaxstr, fontsize=ax_label_font_size)
else:
fig.text(0.5,
global_X_ax_label_shift,
xaxstr,
ha='center',
rotation='horizontal',
fontsize=ax_label_font_size) # general x-axis label
fig.text(global_Y_ax_label_shift,
0.5,
yaxstr,
va='center',
rotation='vertical',
fontsize=ax_label_font_size) # general y-axis label
# 1) Generate a unique title string
# ...
# 2) Set title
if len(df_plot_list) == 1:
# NOTE: overlapping title strings with the standard .set_title()-function can be fought via the y-kwarg
ax.set_title(titlestr,
y=1.0 + add_to_ycoord / 2,
fontsize=title_font_size,
weight="bold")
fig.tight_layout()
else:
# Now, alter the y-coord of the superior title as a function of the lines the suptitlestring comprises
y_coord_suptitle = y_coord_suptitle_dict[rows]
y_coord_suptitle += add_to_ycoord
# Finally, set the suptitle
plt.suptitle(titlestr,
x=0.5,
y=y_coord_suptitle,
fontsize=title_font_size,
weight="bold")
# NOTE: Tight layout often produces nice results, but requires the title to be spaced accordingly
fig.tight_layout()
if global_Y_ax_label_shift:
# ...
fig.subplots_adjust(top=y_coord_suptitle + sub_top_shift -
add_to_ycoord,
bottom=global_X_ax_label_shift + 0.04,
left=global_Y_ax_label_shift + add_left_shift)
else:
fig.subplots_adjust(top=y_coord_suptitle + sub_top_shift -
add_to_ycoord,
bottom=global_X_ax_label_shift + 0.1)
# NOTE: Tight layout often produces nice results but requires the title to be spaced accordingly
# CAUTION: as far as this function (windrose-subplotting) is concerned, it hasn't been necessary (status: 17-08-2019)
if len(df_plot_list) == 1:
pass
else: # in case of subplots
# * FINALLY, set legend to None due to the subplots character
legend = None
## ** Finally, either show or save the current plot/figure **
aux_plot.show_or_save_plot(fig=fig,
path=savepath,
basename=titlestr,
file_extensions=['.png', '.pdf'],
legend=legend)
我最近遇到了同样的错误信息,和你在使用 fig.savefig
时弹出的信息一样。我认为问题可能出现在代码的较早部分,而不是 savefig 函数本身。对于我的情节,我将问题追溯到 plt.scatter()
中的 now-deprecated 参数 - 我使用了 edgecolors=''
,现在应该是 edgecolors=None
,它导致了相同的错误消息'ValueError: Expected 2-dimensional array, got 1' 当我试图保存这个数字时。
例如,此代码块会引发错误,但如果将 edgecolors 参数更改为 =None,代码将正常运行。
fig = plt.figure()
a = [1,2,3,4]
plt.scatter(a,a,edgecolors='')
fig.savefig('test.png')
不知道你在策划的时候有没有用过类似的弃用参数?通过在 ipython 中做一个小测试图来追溯是最容易的,因为弃用警告以一种在简单执行 .py 文件时不会出现的方式正确引发。
编辑:刚刚发现您在底部包含了您的代码 - 我相信您确实遇到了同样的问题,您在调用 fill_between
edgecolors=""