add new plot to existing figure - python

I have a script with some plots ( see example code). After some other things i want to add a new plot to an existing one. But when i try that it add the plot by the last created figure(now fig2).
I can't figure out how to change that...
import matplotlib.pylab as plt
import numpy as np
n = 10
x1 = np.arange(n)
y1 = np.arange(n)
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.plot(x1,y1)
fig1.show()
x2 = np.arange(10)
y2 = n/x2
# add new data and create new figure
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
ax2.plot(x2,y2)
fig2.show()
# do something with data to compare with new data
y1_geq = y1 >= y2
y1_a = y1**2
ax1.plot(y1_geq.nonzero()[0],y1[y1_geq],'ro')
fig1.canvas.draw

Since your code is not runnable without errors I'll provide a sample snippet showing how to plot several data in same graph/diagram:
import matplotlib.pyplot as plt
xvals = [i for i in range(0, 10)]
yvals1 = [i**2 for i in range(0, 10)]
yvals2 = [i**3 for i in range(0, 10)]
f, ax = plt.subplots(1)
ax.plot(xvals, yvals1)
ax.plot(xvals, yvals2)
So the basic idea is to call ax.plot() for all datasets you need to plot into the same plot.

Related

Multiple separated graphs on Matplotlib

I am facing a simple problem I can't figure out: I am trying to plot multiple graphs with Matplotlib, but in separated graphs. This is an example code with random numbers:
import numpy as np
import matplotlib.pyplot as plt
x1 = np.random.normal(10, 1, 100)
x2 = np.random.uniform(8, 12, 100)
fig, ax = plt.subplots()
ax.plot(np.sort(x1), label = 'Normal')
ax.plot(np.sort(x2), label = 'Uniform')
plt.legend()
plt.show()
In this way I get 1 graph with 2 lines (the ax objects). I know that I can use Subplot to get 2 graphs next to each other, but what I want is to plot two different graphs, 1 for each variable, with 1 line each, all at once without starting a new code a initializing a new graph from the beginning.
Without using subplots, I think one (quite ugly) way to do this is
x1 = np.random.normal(10, 1, 100)
x2 = np.random.uniform(8, 12, 100)
data = [x1, x2]
label_list = ['Normal', 'Uniform']
for i, x in enumerate(data):
fig = plt.figure()
plt.plot(np.sort(x), label = label_list[i])
plt.legend()
plt.show()

How to use dates in this code for y axis?

The person who made this had used dates in the second graph. I was wondering how would dates be used with the scipy.signal.argrelextrema function.
With this code it doesn't do anything it prints out an empty array for peak_x and peak_y:
data_y = np.array('2015-07-04', dtype=np.datetime64) + np.arange(25)
Here's the link for the original code:
https://openwritings.net/pg/python/python-find-peaks-and-valleys-chart-using-scipysignalargrelextrema
import matplotlib
matplotlib.use('Agg') # Bypass the need to install Tkinter GUI framework
from scipy import signal
import numpy as np
import matplotlib.pyplot as plt
# Generate random data.
data_x = np.arange(start = 0, stop = 25, step = 1, dtype='int')
data_y = np.array('2015-07-04', dtype=np.datetime64) + np.arange(25) #edited part
# Find peaks(max).
peak_indexes = signal.argrelextrema(data_y, np.greater)
peak_indexes = peak_indexes[0]
# Find valleys(min).
valley_indexes = signal.argrelextrema(data_y, np.less)
valley_indexes = valley_indexes[0]
# Plot main graph.
(fig, ax) = plt.subplots()
ax.plot(data_x, data_y)
# Plot peaks.
peak_x = peak_indexes
peak_y = data_y[peak_indexes]
ax.plot(peak_x, peak_y, marker='o', linestyle='dashed', color='green', label="Peaks")
print(peak_x,peak_y)
# Plot valleys.
valley_x = valley_indexes
valley_y = data_y[valley_indexes]
ax.plot(valley_x, valley_y, marker='o', linestyle='dashed', color='red', label="Valleys")
# Save graph to file.
plt.title('Find peaks and valleys using argrelextrema()')
plt.legend(loc='best')
plt.savefig('argrelextrema.png')
Here's the example how it would work:
You're going to want to use the xticks method. See below:
import matplotlib.pyplot as plt
names = [str(i) for i in range(20)]
x_data = [x for x in range(20)]
y_data = [x for x in range(20)]
plt.plot(x_data, y_data)
plt.xticks(x_data, label=names)
plt.show()
What this does is use an integer between 1-19 cast as a string as the label for the axis X.
Except in your case you want to swap out the names for datatime objects cast to strings. For the xticks, the x_data element prescribes where the ticks will be. You may use any interval of points so long as they are within the bounds of the xdata.
In your case, replace:
data_y = np.array('2015-07-04', dtype=np.datetime64) + np.arange(25)
with
data_y_ticks = np.array('2015-07-04', dtype=np.datetime64) + np.arange(25)
data_y = [i for i, _ in enumerate(data_y_ticks.tolist())]
then plot as follows:
plt.plot(data_y, x_data)
plt.xticks(data_y, label=data_y_ticks)
plt.show()
Just a heads-up, your X and Y axis names are flipped in your code. I did not correct this in my example, however did interchange their locations in the plot to make the plot make sense.

Dendrogram Label Overlapping

I have a 2D array of relation data with labels(first row and column).
when I created the dendrogram, my Labels overlapped.
How can I make the labels separate evenly?
file= open(fileName)
line = file.readline()
file.close()
populations=line.split('\t')
del populations[0]
data = np.loadtxt(fileName, delimiter="\t",skiprows=1,usecols=range(1,len(populations)+1 ))
fig, ax = plt.subplots()
Y1 = sch.linkage(data, method='ward',optimal_ordering=True)
Z1 = sch.dendrogram(Y1, orientation='top')
ind1= Z1['leaves']
arr = np.array(populations)
populations = arr[ind1]
ax.set_xticks([])
ax.set_xticks(np.arange(len(populations)))
ax.set_xticklabels(populations )
plt.xticks(rotation=90)
plt.show()
I think it may be easier to simply specify the labels in construction of the dendrogram, since they are known at the time of construction, something like the following
import scipy.cluster.hierarchy as sch
import numpy as np # Only needed for random sample data
np.random.seed(1) # Seeded for reproducing
populations = np.arange(10) # Create some random sample data
data = abs(np.random.randn(10))
fig, ax = plt.subplots()
Y1 = sch.linkage(data, method='ward',optimal_ordering=True)
Z1 = sch.dendrogram(Y1, orientation='top', labels=populations)
plt.show()
Would give you
    

fill_between with matplotlib and a where condition of two lists

I am trying to shade the area before the point of intersection of the two curves produced by this example code:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0,100,10)
y1 = [0,2,4,6,8,5,4,3,2,1]
y2 = [0,1,3,5,6,8,9,12,13,14]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(t_list,y1,linestyle='-')
ax.plot(t_list,y2,linestyle='--')
plt.show()
Simply using:
ax.fill_between(x,y1,y2,where=y1>=y2,color='grey',alpha='0.5')
Does no work and gives the following error: "ValueError: Argument dimensions are incompatible"
I tried to convert the lists into arrays:
z1 = np.array(y1)
z2 = np.array(y2)
Then:
ax.fill_between(x,y1,y2,where=z1>=z2,color='grey',alpha='0.5')
Not the entire area was shaded.
I know I have to find the point of intersection between the two curves by interpolating but have not seen a simple way to do it.
You are completely right, you need to interpolate. And that is ludicrously complicated, as you need to add the interpolate=True keyword argument to the call to fill_between.
ax.fill_between(x,y1,y2,where=z1>=z2,color='grey', interpolate=True)
Complete code to reproduce:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0,100,10)
y1 = [0,2,4,6,8,5,4,3,2,1]
y2 = [0,1,3,5,6,8,9,12,13,14]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x,y1,linestyle='-')
ax.plot(x,y2,linestyle='--')
z1 = np.array(y1)
z2 = np.array(y2)
ax.fill_between(x,y1,y2,where=z1>=z2,color='grey',alpha=0.5, interpolate=True)
plt.show()

How should I pass a matplotlib object through a function; as Axis, Axes or Figure?

Sorry in advance if this is a little long winded but if I cut it down too much the problem is lost. I am trying to make a module on top of pandas and matplotlib which will give me the ability to make profile plots and profile matrices analogous to scatter_matrix. I am pretty sure my problem comes down to what object I need to return from Profile() so that I can handle Axes manipulation in Profile_Matrix(). Then the question is what to return form Profile_Matrix() so I can edit subplots.
My module (ProfileModule.py) borrows a lot from https://github.com/pydata/pandas/blob/master/pandas/tools/plotting.py and looks like:
import pandas as pd
from pandas import Series, DataFrame
import numpy as np
import matplotlib.pyplot as plt
def Profile(x,y,nbins,xmin,xmax):
df = DataFrame({'x' : x , 'y' : y})
binedges = xmin + ((xmax-xmin)/nbins) * np.arange(nbins+1)
df['bin'] = np.digitize(df['x'],binedges)
bincenters = xmin + ((xmax-xmin)/nbins)*np.arange(nbins) + ((xmax-xmin)/(2*nbins))
ProfileFrame = DataFrame({'bincenters' : bincenters, 'N' : df['bin'].value_counts(sort=False)},index=range(1,nbins+1))
bins = ProfileFrame.index.values
for bin in bins:
ProfileFrame.ix[bin,'ymean'] = df.ix[df['bin']==bin,'y'].mean()
ProfileFrame.ix[bin,'yStandDev'] = df.ix[df['bin']==bin,'y'].std()
ProfileFrame.ix[bin,'yMeanError'] = ProfileFrame.ix[bin,'yStandDev'] / np.sqrt(ProfileFrame.ix[bin,'N'])
fig = plt.figure();
ax = ProfilePlot.add_subplot(1, 1, 1)
plt.errorbar(ProfileFrame['bincenters'], ProfileFrame['ymean'], yerr=ProfileFrame['yMeanError'], xerr=(xmax-xmin)/(2*nbins), fmt=None)
return ax
#or should I "return fig"
def Profile_Matrix(frame):
import pandas.core.common as com
import pandas.tools.plotting as plots
from pandas.compat import lrange
from matplotlib.artist import setp
range_padding=0.05
df = frame._get_numeric_data()
n = df.columns.size
fig, axes = plots._subplots(nrows=n, ncols=n, squeeze=False)
# no gaps between subplots
fig.subplots_adjust(wspace=0, hspace=0)
mask = com.notnull(df)
boundaries_list = []
for a in df.columns:
values = df[a].values[mask[a].values]
rmin_, rmax_ = np.min(values), np.max(values)
rdelta_ext = (rmax_ - rmin_) * range_padding / 2.
boundaries_list.append((rmin_ - rdelta_ext, rmax_+ rdelta_ext))
for i, a in zip(lrange(n), df.columns):
for j, b in zip(lrange(n), df.columns):
ax = axes[i, j]
common = (mask[a] & mask[b]).values
nbins = 100
(xmin,xmax) = boundaries_list[i]
ax=Profile(df[b][common],df[a][common],nbins,xmin,xmax)
#Profile(df[b][common].values,df[a][common].values,nbins,xmin,xmax)
ax.set_xlabel('')
ax.set_ylabel('')
plots._label_axis(ax, kind='x', label=b, position='bottom', rotate=True)
plots._label_axis(ax, kind='y', label=a, position='left')
if j!= 0:
ax.yaxis.set_visible(False)
if i != n-1:
ax.xaxis.set_visible(False)
for ax in axes.flat:
setp(ax.get_xticklabels(), fontsize=8)
setp(ax.get_yticklabels(), fontsize=8)
return axes
This will run with something like:
import pandas as pd
from pandas import Series, DataFrame
import numpy as np
import matplotlib.pyplot as plt
import ProfileModule as pm
x = np.random.uniform(0, 100, size=1000)
y = x *x + 50*x*np.random.randn(1000)
z = x *y + 50*y*np.random.randn(1000)
nbins = 25
xmax = 100
xmin = 0
ProfilePlot = pm.Profile(x,y,nbins,xmin,xmax)
plt.title("Look this works!")
#This does not work as expected
frame = DataFrame({'z' : z,'x' : x , 'y' : y})
ProfileMatrix = pm.Profile_Matrix(frame)
plt.show()
This would hopefully produce a simple profile plot and a 3x3 profile matrix but it does not. I have tried various different methods to get this to work but I imagine it is not worth explaining them all.
I should mention I am using Enthought Canopy Express on Windows 7. Sorry for the long post and thanks again for any help with the code. This is my first week using Python.
You should pass around Axes objects and break your functions up to operate on a single axes at a time. You are close, but just change
import numpy as np
import matplotlib.pyplot as plt
def _profile(ax, x, y):
ln, = ax.plot(x, y)
# return the Artist created
return ln
def profile_matrix(n, m):
fig, ax_array = plt.subplots(n, m, sharex=True, sharey=True)
for ax in np.ravel(ax_array):
_profile(ax, np.arange(50), np.random.rand(50))
profile_matrix(3, 3)

Categories

Resources