Matplotlib update one plot function when multiple functions plotted on same figure - python

I have a case where I plot multiple functions on one figure but want to update one function while not having to re-plot the other function.
A very simplistic example:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
x = np.arange(0,10,0.1)
ax1 = plt.subplot(1,1,1)
ax2 = plt.subplot(1,1,1)
ax1.plot(x,1*np.sin(x),'b-')
ax2.plot(x,2*np.sin(x),'g-')
I want to clear/update the data plotted in ax2 so that the data in ax1 isn't cleared or needs to be replotted.
Using ax2.clear() or ax2.cla() both clear the entire figure.
Are there any suggestions on how I can either update just the data in ax2 or a better way to control the plotting data for multiple functions on the same plot independently?
The actual case scenario plots satellite data (ax1) on a projected map with contour lines (ax2) overlayed. So the motivation is not to replot the satellite data due to time, but to keep the satellite data and update the contour plots (ax2) and save the figure at each step in a for-loop.

You can set the data for the line in ax2:
l2, = ax2.plot(x, 2*np.sin(x),'g-')
l2.set_data((2*x, 3*np.sin(x)))
This will trigger replotting of the line in ax2, but axis scaling etc. isn't updated. Not sure if this is what you want.

Related

How to show multiple already plotted matplotlib figures side-by-side or on-top in Python without re-plotting them?

I have already plotted two figures separately in a single jupyter notebook file, and exported them.
What I want is to show them side by side, but not plot them again by using matplotlib.pyplot.subplots.
For example, in Mathematica, it's easier to do this by just saving the figures into a Variable, and displaying them afterwards.
What I tried was saving the figures, using
fig1, ax1 = plt.subplots(1,1)
... #plotting using ax1.plot()
fig2, ax2 = plt.subplots(1,1)
... #plotting using ax2.plot()
Now, those fig1 or fig2 are of type Matplotlib.figure.figure which stores the figure as an 'image-type' instance. I can even see them separately by calling just fig1 or fig2 in my notebook.
But, I can not show them together as by doing something like
plt.show(fig1, fig2)
It returns nothing since, there wasn't any figures currently being plotted.
You may look at this link or this, which is a Mathematica version of what I was talking about.
assuming u want to merge those subplots in the end.
Here is the code
import numpy as np
import matplotlib.pyplot as plt
#e.x function to plot
x = np.linspace(0, 10)
y = np.exp(x)
#almost your code
figure, axes = plt.subplots(1,1)
res_1, = axes.plot(x,y) #saving the results in a tuple
plt.show()
plt.close(figure)
figure, axes = plt.subplots(1,1)
res_2, = axes.plot(x,-y) #same before
plt.show()
#restructure to merge
figure_2, (axe_1,axe_2) = plt.subplots(1,2) #defining rows and columns
axe_1.plot(res_1.get_data()[0], res_1.get_data()[1]) #using the already generated data
axe_2.plot(res_2.get_data()[0], res_2.get_data()[1])
#if you want show them in one
plt.show()
Not quite sure what you mean with:
but not plot them again by using matplotlib.pyplot.subplots.
But you can display two figures next to each other in a jupyter notebook by using:
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0] = ... # Code for first figure
ax[1] = ... # Code for second figure
plt.show()
Or above each other:
fig, ax = plt.subplots(nrows=2, ncols=1)
ax[0] = ... # Top figure
ax[1] = ... # Bottom figure
plt.show()

Matplotlib scatter plot dual y-axis

I try to figure out how to create scatter plot in matplotlib with two different y-axis values.
Now i have one and need to add second with index column values on y.
points1 = plt.scatter(r3_load["TimeUTC"], r3_load["r3_load_MW"],
c=r3_load["r3_load_MW"], s=50, cmap="rainbow", alpha=1) #set style options
plt.rcParams['figure.figsize'] = [20,10]
#plt.colorbar(points)
plt.title("timeUTC vs Load")
#plt.xlim(0, 400)
#plt.ylim(0, 300)
plt.xlabel('timeUTC')
plt.ylabel('Load_MW')
cbar = plt.colorbar(points1)
cbar.set_label('Load')
Result i expect is like this:
So second scatter set should be for TimeUTC vs index. Colors are not the subject;) also in excel y-axes are different sites, but doesnt matter.
Appriciate your help! Thanks, Paulina
Continuing after the suggestions in the comments.
There are two ways of using matplotlib.
Via the matplotlib.pyplot interface, like you were doing in your original code snippet with .plt
The object-oriented way. This is the suggested way to use matplotlib, especially when you need more customisation like in your case. In your code, ax1 is an Axes instance.
From an Axes instance, you can plot your data using the Axes.plot and Axes.scatter methods, very similar to what you did through the pyplot interface. This means, you can write a Axes.scatter call instead of .plot and use the same parameters as in your original code:
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.scatter(r3_load["TimeUTC"], r3_load["r3_load_MW"],
c=r3_load["r3_load_MW"], s=50, cmap="rainbow", alpha=1)
ax2.plot(r3_dda249["TimeUTC"], r3_dda249.index, c='b', linestyle='-')
ax1.set_xlabel('TimeUTC')
ax1.set_ylabel('r3_load_MW', color='g')
ax2.set_ylabel('index', color='b')
plt.show()

Non-overlapping legend and axes (e.g. in matplotlib)

I need the plot legend to appear side-by-side to the plot axes, i.e. outside of the axes and non-overlapping.
The width of the axes and the legend should adjust "automatically" so that they both fill the figure w/o them to overlap or the legend to be cut, even when using tight layout. The legend should occupy a minor portion of the figure (let's say max to 1/3 of figure width so that the remaining 2/3 are dedicated to the actual plot).
Eventually, the font of the legend entries can automatically reduce to meet the requirements.
I've read a number of answers regarding legend and bbox_to_anchor in matplotlib with no luck, among which:
how to put the legend out of the plot
moving matplotlib legend outside of the axis makes it cutoff by the figure box
I tried by creating a dedicated axes in which to put the legend so that plt.tight_layout() would do its job properly but then the legend only takes a minor portion of the dedicated axes, with the result that a lot of space is wasted. Or if there isn't enough space (the figure is too small), the legend overlaps the first axes anyway.
import matplotlib.pyplot as plt
import numpy as np
# generate some data
x = np.arange(1, 100)
# create 2 side-by-side axes
fig, ax = plt.subplots(1,2)
# create a plot with a long legend
for ii in range(20):
ax[0].plot(x, x**2, label='20201110_120000')
ax[0].plot(x, x, label='20201104_110000')
# grab handles and labels from the first ax and pass it to the second
hl = ax[0].get_legend_handles_labels()
leg = ax[1].legend(*hl, ncol=2)
plt.tight_layout()
I'm open to use a package different from matplotlib.
Instead of trying to plot the legend in a separate axis, you can pass loc to legend:
# create 2 side-by-side axes
fig, ax = plt.subplots(figsize=(10,6))
# create a plot with a long legend
for ii in range(20):
ax.plot(x, x**2, label='20201110_120000')
ax.plot(x, x, label='20201104_110000')
# grab handles and labels from the first ax and pass it to the second
ax.legend(ncol=2, loc=[1,0])
plt.tight_layout()
Output:

x axis label disappearing in matplotlib and basic plotting in python

I am new to matplotlib, and I am finding it very confusing. I have spent quite a lot of time on the matplotlib tutorial website, but I still cannot really understand how to build a figure from scratch. To me, this means doing everything manually... not using the plt.plot() function, but always setting figure, axis handles.
Can anyone explain how to set up a figure from the ground up?
Right now, I have this code to generate a double y-axis plot. But my xlabels are disappearing and I dont' know why
fig, ax1 = plt.subplots()
ax1.plot(yearsTotal,timeseries_data1,'r-')
ax1.set_ylabel('Windspeed [m/s]')
ax1.tick_params('y',colors='r')
ax2 = ax1.twinx()
ax2.plot(yearsTotal,timeseries_data2,'b-')
ax2.set_xticks(np.arange(min(yearsTotal),max(yearsTotal)+1))
ax2.set_xticklabels(ax1.xaxis.get_majorticklabels(), rotation=90)
ax2.set_ylabel('Open water duration [days]')
ax2.tick_params('y',colors='b')
plt.title('My title')
fig.tight_layout()
plt.savefig('plots/my_figure.png',bbox_inches='tight')
plt.show()
Because you are using a twinx, it makes sense to operate only on the original axes (ax1).
Further, the ticklabels are not defined at the point where you call ax1.xaxis.get_majorticklabels().
If you want to set the ticks and ticklabels manually, you can use your own data to do so (although I wouldn't know why you'd prefer this over using the automatic labeling) by specifying a list or array
ticks = np.arange(min(yearsTotal),max(yearsTotal)+1)
ax1.set_xticks(ticks)
ax1.set_xticklabels(ticks)
Since the ticklabels are the same as the tickpositions here, you may also just do
ax1.set_xticks(np.arange(min(yearsTotal),max(yearsTotal)+1))
plt.setp(ax1.get_xticklabels(), rotation=70)
Complete example:
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
yearsTotal = np.arange(1977, 1999)
timeseries_data1 = np.cumsum(np.random.normal(size=len(yearsTotal)))+5
timeseries_data2 = np.cumsum(np.random.normal(size=len(yearsTotal)))+20
fig, ax1 = plt.subplots()
ax1.plot(yearsTotal,timeseries_data1,'r-')
ax1.set_ylabel('Windspeed [m/s]')
ax1.tick_params('y',colors='r')
ax1.set_xticks(np.arange(min(yearsTotal),max(yearsTotal)+1))
plt.setp(ax1.get_xticklabels(), rotation=70)
ax2 = ax1.twinx()
ax2.plot(yearsTotal,timeseries_data2,'b-')
ax2.set_ylabel('Open water duration [days]')
ax2.tick_params('y',colors='b')
plt.title('My title')
fig.tight_layout()
plt.show()
Based on your code, it is not disappear, it is set (overwrite) by these two functions:
ax2.set_xticks(np.arange(min(yearsTotal),max(yearsTotal)+1))
ax2.set_xticklabels(ax1.xaxis.get_majorticklabels(), rotation=90)
set_xticks() on the axes will set the locations and set_xticklabels() will set the xtick labels with list of strings labels.

What is the necessity of plt.figure() in matplotlib?

plt.figure(figsize=(10,8))
plt.scatter(df['attacker_size'][df['year'] == 298],
# attacker size in year 298 as the y axis
df['defender_size'][df['year'] == 298],
# the marker as
marker='x',
# the color
color='b',
# the alpha
alpha=0.7,
# with size
s = 124,
# labelled this
label='Year 298')
In the above snippet of code collected from Scatterplot in Matplotlib, what is the necessity of plt.figure()?
The purpose of using plt.figure() is to create a figure object.
The whole figure is regarded as the figure object. It is necessary to explicitly use plt.figure() when we want to tweak the size of the figure and when we want to add multiple Axes objects in a single figure.
# in order to modify the size
fig = plt.figure(figsize=(12,8))
# adding multiple Axes objects
fig, ax_lst = plt.subplots(2, 2) # a figure with a 2x2 grid of Axes
Parts of a Figure
It is not always necessary because a figure is implicitly created when you create a scatter plot; however, in the case you have shown, the figure is being created explicitly using plt.figure so that the figure will be a specific size rather than the default size.
The other option would be to use gcf to get the current figure after creating the scatter plot and set the figure size retrospectively:
# Create scatter plot here
plt.gcf().set_size_inches(10, 8)

Categories

Resources