Any thought on why this solution is not working for me?
I am trying to add some text with variables with f'strings, with .format function and with this % but nothing works. Python says:
Input In [664]
ax1.text(x=0, y=-0.3, s)
^
SyntaxError: positional argument follows keyword argument
I've tried almost all solutions in the internet and cannot figute out where I am wrong.. Appreciate your help!!
P.S. This message workd fine in all formats when I print it. Not inside the plot as a text.
The most I could get is to get the text directly as it is with {} not variables
dfplot=df.copy()
# Plotting df
fig, [ax1, ax2, ax3] = plt.subplots(1,3, figsize=(15, 5))
plt.style.use('fast')
# Temperature data
ax1.grid(visible=True, which='major', axis='both')
ax1.plot(d, t, color='red', alpha=0.7)
ax1.set_title('Temperature Forecast')
ax1.set_xticks(d)
ax1.set_xticklabels(d, rotation=90, fontsize=8)
ax1.fill_between(d, t, color='red', alpha=0.3)
# HERE IS WHERE IT GETS WRONG
s="Hello!\nNow is {city}.format() the temperature is {temp}. \nSunrise today is at {sunrisrtime}. \nSunset will be at {sunsettime}"
ax1.text(x=0, y=-0.3, s)
Related
I am writing a Python tool that needs several figures open at the same time, each one with its own widgets (sliders, for the most part). I don't need any interactions across the figures here. Each figure is independent of the other ones, with its own plot and its own sliders affecting only itself.
I can get Matplotlib sliders working fine on a single figure, but I can't get them to work on multiple figures concurrently. Only the sliders of the LAST figure to open are working. The other ones are unresponsive.
I recreated my problem with the simple code below, starting from the example in the Matplotlib.Slider doc. If I run it as-is, only the sliders for the second figure (amplitude) works. The other doesn't. If I invert the two function calls at the bottom, it's the other way around.
I've had no luck googling solutions or pointers. Any help would be much appreciated.
I'm on Python 3.9.12, btw. I can upload a requirements file if someone tries and cannot reproduce the issue. Thank you!
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
# The parametrized function to be plotted
def f(time, amplitude, frequency):
return amplitude * np.sin(2 * np.pi * frequency * time)
# Define initial parameters
init_amplitude = 5
init_frequency = 3
t = np.linspace(0, 1, 1000)
def create_first_fig():
# Create the figure and the line that we will manipulate
fig1, ax1 = plt.subplots()
line1, = ax1.plot(t, f(t, init_amplitude, init_frequency), lw=2, color='b')
ax1.title.set_text('First plot - interactive frequency')
ax1.set_xlabel('Time [s]')
# adjust the main plot to make room for the sliders
fig1.subplots_adjust(left=0.25, bottom=0.25)
# Make a horizontal slider to control the frequency.
axfreq = fig1.add_axes([0.25, 0.1, 0.65, 0.03])
freq_slider = Slider(
ax=axfreq,
label='Frequency [Hz]',
valmin=0,
valmax=30,
valinit=init_frequency,
)
# register the update function with each slider
freq_slider.on_changed(lambda val: update_first_fig(val, fig1, line1))
plt.draw()
plt.pause(0.1)
return fig1
# The function to be called anytime a slider's value changes
def update_first_fig(val, fig, line):
line.set_ydata(f(t, init_amplitude, val))
fig.canvas.draw_idle()
plt.pause(0.1)
def create_second_fig():
# Create the figure and the line that we will manipulate
fig2, ax2 = plt.subplots()
line2, = ax2.plot(t, f(t, init_amplitude, init_frequency), lw=2, color='r')
ax2.title.set_text('Second plot - interactive amplitude')
ax2.set_xlabel('Time [s]')
# adjust the main plot to make room for the sliders
fig2.subplots_adjust(left=0.25, bottom=0.25)
# Make a vertically oriented slider to control the amplitude
axamp = fig2.add_axes([0.1, 0.25, 0.0225, 0.63])
amp_slider = Slider(
ax=axamp,
label="Amplitude",
valmin=0,
valmax=10,
valinit=init_amplitude,
orientation="vertical",
)
# register the update function with each slider
amp_slider.on_changed(lambda val: update_second_fig(val, fig2, line2))
plt.draw()
plt.pause(0.1)
return fig2
# The function to be called anytime a slider's value changes
def update_second_fig(val, fig, line):
line.set_ydata(f(t, val, init_frequency))
fig.canvas.draw_idle()
plt.pause(0.1)
figure1 = create_first_fig()
figure2 = create_second_fig()
plt.show()
I would expect the slider in both figures to work the way it does when I only open the corresponding figure. So far it's only the slider in the figure that's created last that works.
Edit in case someone else looks at this: see Yulia V's answer below. It works perfectly, including in my initial application. The site doesn't let me upvote it because I am too new on here, but it's a perfect solution to my problem. Thanks Yulia V!
You need to save the references to sliders as variables to make it work. No idea why, but this is how matplotlib works.
Specifically, in your functions, you need to have
return freq_slider, fig1
...
return amp_slider, fig2
instead of
return fig1
...
return fig2
and in the main script,
freq_slider, figure1 = create_first_fig()
amp_slider, figure2 = create_second_fig()
instead of
figure1 = create_first_fig()
figure2 = create_second_fig()
Just to illustrate my comment below #Yulia V's answer, it works too if we store the sliders as an attribute of the figure instead of returning them:
def create_first_fig():
...
fig1._slider = freq_slider
...
return fig1
def create_first_fig():
...
fig2._slider = amp_slider
...
return fig2
...
figure1 = create_first_fig()
figure2 = create_second_fig()
I have the following code of a piecewise_regression:
data = data_heatmap_2017.copy()
data = data[['tre200h0_2017','Leistung:']].dropna()
xx = data['tre200h0_2017'].values.tolist()
yy = data['Leistung:'].values.tolist()
pw_fit = piecewise_regression.Fit(xx, yy, n_breakpoints=1)
pw_fit.summary()
If I do a single plot with the code below, I get a diagram piecewise_regression:
# Plot the data, fit, breakpoints and confidence intervals
pw_fit.plot_data(s=0.1)
# Pass in standard matplotlib keywords to control any of the plots
pw_fit.plot_fit(color="red", linewidth=2)
pw_fit.plot_breakpoints()
pw_fit.plot_breakpoint_confidence_intervals()
plt.xlabel("Lufttemperatur [°C]")
plt.ylabel("Leistung [kW]")
plt.show()
plt.close()
Now I would like to integrate the diagram piecewise regression within this subplots on position ax10:
fig, axs = plt.subplots(2, 5, figsize=(60,50), dpi=(100))
ax10 = axs[1,0]
ax10.set_title('2017, Signatur, Zähler: ' + Zaehler)
ax10.pw_fit.plot_data(s=0.1)
ax10.pw_fit.plot_fit(color="red", linewidth=2)
ax10.set_xlabel('Lufttemperatur [°C]')
ax10.set_ylabel('Leistung [kW]')
ax10.axis([-15, 35, min_Power, max_Power])
plt.show()
plt.close()
unfortunately the lines
ax10.pw_fit.plot_data(s=0.1)
ax10.pw_fit.plot_fit(color="red", linewidth=2)
do not work with the prefix ax10. I get an AttributeError 'AxesSubplot' object has no attribute 'pw_fit'. Any idea how to solve this? Thank you!
So I'm relatively new to coding and have recently taken the monstrous task of building a few climate models for my MSc thesis. Using this code I have adapted it and it now shows no error messages except now it doesn't show any figure as an output. Any solutions?
I input
%matplotlib notebook at the top of the code, and also put plt.show(); at the bottom of the script (as per some recommendations through some similar queries)... but still doesn't work. Prior to this it was showing <Figure Ssize 432x288 with 0 Axes> which i presumed may be the problem but i can't figure out why there are 0 axes?
Any recommendations/solutions?
Thanks!
As requested - my code:
import iris.quickplot as qplt
import iris.analysis.cartography
import matplotlib.dates as mdates
def main():
Current45 = '....X.nc'
Current45 = iris.load_cube(Current45)
lats = iris.coords.DimCoord(Current45.coords()[1].points[:,0], \
standard_name='latitude', units='degrees')
lons = Current45.coords()[2].points[0]
for i in range(len(lons)):
if lons[i]>100.:
lons[i] = lons[i]-360.
lons = iris.coords.DimCoord(lons, \
standard_name='longitude', units='degrees')
Current45.remove_coord('latitude')
Current45.remove_coord('longitude')
Current45.add_dim_coord(lats, 1)
Current45.add_dim_coord(lons, 2)
Current45.convert_units('Celsius')
Colombia = iris.Constraint(longitude=lambda v: -74.73 <= v <= -76.20, \
latitude=lambda v: 5.30 <= v <= 4.43)
Current45 = Current45.extract(Colombia)
iriscc.add_day_of_year(Current45, 'time')
Current45.coord('latitude').guess_bounds()
Current45.coord('longitude').guess_bounds()
Current45_grid_areas = iris.analysis.cartography.area_weights(Current45)
Current45 = Current45.collapsed(['latitude', 'longitude'],
iris.analysis.MEAN,
weights=Current45_grid_areas)
Histogram = Current45.data
#frq, bins, patches = plt.hist(Histogram, bins=np.arange(20,37,2))
frq, bins, patches = plt.hist(Histogram, bins=np.arange(16,45,2), color='blue')
print (frq)
thresh = 32
plt.axvline(x=thresh, color='green', linestyle='dashed', linewidth=2)
plt.xlabel("Daily Max Temperature / Celsius")
plt.ylabel("Number of days")
fig = plt.gcf()
plt.show();
My code with blank figure at the bottom
In the code, you are never calling the main function, so the figure you are showing is empty.
You should call main() at some point in your code before the plt.gcf() or plt.show.
Edit
In more detail:
You are writing your main() function in this snippet of code, and then, without indent, you are calling pyplot to get the current figure, where pyplot just gives you en empty figure back (the gcf()-call is not necessary anyways in your code) and plt.show() shows no an empty figure.
You can or cannot move the plt.show() into you main() function, but at one point you must definitely call that function otherwise none of it is executed.
Edit 2:
# function definition
def main():
...
# function call
main()
# show figure
plt.show()
The image below shows, what i want, 3 different plots in one execution but using a function
enter image description here
enter image description here
I used the following code:
def box_hist_plot(data):
sns.set()
ax, fig = plt.subplots(1,3, figsize=(20,5))
sns.boxplot(x=data, linewidth=2.5, ax=fig[0])
plt.hist(x=data, bins=50, density=True, ax = fig[1])
sns.violinplot(x = data, ax=fig[2])
and i got this error:
inner() got multiple values for argument 'ax'
Besides the fact that you should not call a Figure object ax and an array of Axes object fig, your problem comes from the line plt.hist(...,ax=...). plt.hist() should not take an ax= parameter, but is meant to act on the "current" axes. If you want to specify which Axes you want to plot, you should use Axes.hist().
def box_hist_plot(data):
sns.set()
fig, axs = plt.subplots(1,3, figsize=(20,5))
sns.boxplot(x=data, linewidth=2.5, ax=axs[0])
axs[1].hist(x=data, bins=50, density=True)
sns.violinplot(x = data, ax=axs[2])
I've managed to make a set of subplots using hist2d and ImageGrid with the code below:
from mpl_toolkits.axes_grid1 import ImageGrid
fig = figure(figsize(20, 60))
grid = ImageGrid(fig, 111, nrows_ncols=(1, 3), axes_pad=0.25)
for soa, ax in zip(soalist, grid):
# grab my data from pandas DataFrame...
samps = allsubs[allsubs['soa'] == soa]
x, y = samps['x'], samps['y']
# calls hist2d and returns the Image returned by hist2d
img = gazemap(x, y, ax, std=True, mean=True)
ax.set_title("{0} ms".format(soa * 1000))
# attempt to show a colorbar for that image
grid.cbar_axes[-1].colorbar(img)
show() # threw this in for good measure, but doesn't help!
I get no explicit error (which is good, because I passed an Image to colorbar), but my colorbar does not appear. What gives?
Okay, I fixed it!
All I had to do was pass the cbar_mode and cbar_location kwargs to ImageGrid!