I am having trouble using Matplotlib to plot multiple series in a loop (Matplotlib 1.0.0, Python 2.6.5, ArcGIS 10.0). Forum research pointed me to application of an Axes object, in order to plot multiple series on the same plot. I see how this works well for data generated outside of a loop (sample scripts), but when I insert the same syntax and add the second series into my loop that pulls data from database, I get the following error:
": unsupported operand type(s) for -: 'NoneType' and 'NoneType' Failed to execute (ChartAge8)."
Below is my code - any suggestions or comments are much appreciated!
import arcpy
import os
import matplotlib
import matplotlib.pyplot as plt
#Variables
FC = arcpy.GetParameterAsText(0) #feature class
P1_fld = arcpy.GetParameterAsText(1) #score field to chart
P2_fld = arcpy.GetParameterAsText(2) #score field to chart
plt.subplots_adjust(hspace=0.4)
nsubp = int(arcpy.GetCount_management(FC).getOutput(0)) #pulls n subplots from FC
last_val = object()
#Sub-plot loop
cur = arcpy.SearchCursor(FC, "", "", P1_fld)
i = 0
x1 = 1 # category 1 locator along x-axis
x2 = 2 # category 2 locator along x-axis
fig = plt.figure()
for row in cur:
y1 = row.getValue(P1_fld)
y2 = row.getValue(P2_fld)
i += 1
ax1 = fig.add_subplot(nsubp, 1, i)
ax1.scatter(x1, y1, s=10, c='b', marker="s")
ax1.scatter(x2, y2, s=10, c='r', marker="o")
del row, cur
#Save plot to pdf, open
figPDf = r"path.pdf"
plt.savefig(figPDf)
os.startfile("path.pdf")
If what you want to do is plot several stuff reusing the same plot what you should do it create the figure object outside the loop and then plot to that same object everytime, something like this:
fig = plt.figure()
for row in cur:
y1 = row.getValue(P1_fld)
y2 = row.getValue(P2_fld)
i += 1
ax1 = fig.add_subplot(nsubp, 1, i)
ax1.scatter(x1, y1, s=10, c='b', marker="s")
ax1.scatter(x2, y2, s=10, c='r', marker="o")
del row, cur
Related
I want to plot 5 timetable series using nested for loop. here is my code attached and the results of the plots. I use the first loop to generate each when I put plt.show() outside the first loop, it will just plot the fifth series, and when I put the plt.show() outside the inside (second) loop, it will just plot the first series.
How can I plot all five series using the nested loop?
How can I plot all of the same y variables with the same bound (shared y) in the loop?
fig = plt.figure(figsize=(38, 55))
for i in range(len(Traj_List)): # first loop for creating subplots for each of timeseries data (Trajectory of some states like joint angle and joint speed and muscle activations)
# States.
stateNames = list(Traj_List[i].getStateNames()) # Traj_List is a list of timeseries data
numStates = len(stateNames)
dim = np.sqrt(numStates)
if dim == np.ceil(dim):
numRows = int(dim)
numCols = int(dim)
else:
numCols = int(np.min([numStates, 4]))
numRows = int(np.floor(numStates / 4))
if not numStates % 4 == 0:
numRows += 1
# color = iter(plt.rainbow(np.linspace(0, 1, 5)))
color = ['r', 'b', 'g', 'y', 'm']
lines = ["-", "--", "-.", ":", "-."]
linewidth = [3, 2.5, 3.5, 2, 3]
for j in np.arange(numStates): # the second loop plots each time series data (states) against time.
ax = fig.add_subplot(numRows, numCols, int(j + 1))
ax.plot(Traj_List[i].getTimeMat(),
Traj_List[i].getStateMat(stateNames[j]), linestyle=lines[i], color=color[i],
linewidth=linewidth[i], label=Label_List[i])
stateName = stateNames[j]
ax.set_title(stateName)
ax.set_xlabel('time (s)')
# ax.set_xlim(0, 1)
ax.legend(loc='best')
if 'value' in stateName:
ax.set_ylabel('position (rad)')
elif 'speed' in stateName:
ax.set_ylabel('speed (rad/s)')
elif 'activation' in stateName:
ax.set_ylabel('activation (-)')
ax.set_ylim(0, 1)
# plt.show()
fig.tight_layout()
plt.show()
plt.close()
Try to only make the figure once, and save the axes. In pseudo code, because I can't run your code anyway:
for i in range(N):
M, N = size(data)
if i == 0:
# only make the axes once!
fig, axs = plt.subplots(M, N)
for j in range(M*N):
axs.flat[j].plot(yourdata)
I'm sure my ranges are not correct for your data, but that is easy to sort out. The point is don't keep recreating the axes using plt.add_subplot. Just create them once, and then plot on them.
I am having a problem with preventing grid lines in 'darkgrid' from disecting a line associated with the X1 axis when plotting a twinx() plot. I can "fix" the problem by not using 'darkgrid' or by passing an empty list to X2 (and lose the axis labels to - se last line), but I do want 'darkgrid' and x2 axis labels.
#Some imports
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
sns.set_style("darkgrid")
%matplotlib inline
#Data
d = np.arange(0, 1000, 100)
x1 = d/30 #redmodel
x2 = np.sqrt(d) #bluemodel
#Figure
fig = plt.figure(figsize = (8, 12))
sy1 = 'r-' #redmodel
sy2 = 'b-' #bluemodel
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()
_ = ax1.plot(x1, d, sy1)
_ = ax1.set_ylabel('D')
_ = ax1.set_ylim(0, 1000)
_ = ax1.set_xlabel('X1')
_ = ax1.set_xlim(0, 31)
_ = ax2.plot(x2, d, sy2)
_ = ax2.set_xlabel('X2')
_ = ax2.set_xlim(0, 31)
#_ = ax2.set_xticks([]) #Empty list passed to omit_xticks, otherwise ax2 gridines disect red line
As I was looking for solutions to this problem I stumbled upon the axes_grid1 toolkit collection of helper classes which has the twin() option (in addition to twinx and twiny) which may be the solution to my problem. But if you know of a simpler one please help me out.
The intent of your question is to answer as the challenge is to draw the grid lines of the x2 axis across the red line. I think you can simply set a standard for the grid lines of the x2 axis.
_ = ax2.grid(which='major', axis='x', zorder=1.0)
I'm trying to plot an A4 PDF with the following layout:
1 chart spanning 2 columns
2 charts, each spanning 1 column
1 chart spanning 2 columns
I have the following code:
fig = plt.figure(figsize=(8.27,11.69))
ax = fig.add_subplot(311)
ax = fig.add_subplot(323)
ax = fig.add_subplot(324)
ax = fig.add_subplot(315)
but i'm getting the following error:
ValueError: num must be 1 <= num <= 3, not 5
what am i missing?
This is the correct syntax:
fig = plt.figure()
ax = fig.add_subplot(311)
ax = fig.add_subplot(323)
ax = fig.add_subplot(324)
ax = fig.add_subplot(313)
However, for this kind of thing, you will gain in readability if you use GridSpec https://matplotlib.org/3.1.1/tutorials/intermediate/gridspec.html The following code yields the exact same output, but is (at least to me) easier to understand
fig = plt.figure()
gs = fig.add_gridspec(3, 2)
fig.add_subplot(gs[0, :])
fig.add_subplot(gs[1, 0])
fig.add_subplot(gs[1, 1])
fig.add_subplot(gs[2, :])
I have a Julia DataFrame where the first 4 columns are dimensions and the 5th one contains the actual data.
I would like to plot it using a subplots approach where the two main plot axis concern the first two dimensions and each subplot then is a contour plot over the remaining two dimensions.
I am almost there with the above code:
using DataFrames,Plots
# plotlyjs() # doesn't work with plotlyjs backend
pyplot()
X = [1,2,3,4]
Y = [0.1,0.15,0.2]
I = [2,4,6,8,10,12,14]
J = [10,20,30,40,50,60]
df = DataFrame(X=Int64[], Y=Float64[], I=Float64[], J=Float64[], V=Float64[] )
[push!(df,[x,y,i,j,(5*x+20*y+2)*(0.2*i^2+0.5*j^2+3*i*j+2*i^2*j+1)]) for x in X, y in Y, i in I, j in J]
minvalue = minimum(df[:V])
maxvalue = maximum(df[:V])
function toDict(df, dimCols, valueCol)
toReturn = Dict()
for r in eachrow(df)
keyValues = []
[push!(keyValues,r[d]) for d in dimCols]
toReturn[(keyValues...)] = r[valueCol]
end
return toReturn
end
dict = toDict(df, [:X,:Y,:I,:J], :V )
M = [dict[(x,y,i,j)] for j in J, i in I, y in Y, x in X ]
yL = length(Y)
xL = length(X)
plot(contour(M[:,:,3,1], ylabel="y = $(string(Y[3]))", zlims=(minvalue,maxvalue)), contour(M[:,:,3,2]), contour(M[:,:,3,3]), contour(M[:,:,3,4]),
contour(M[:,:,2,1], ylabel="y = $(string(Y[2]))", zlims=(minvalue,maxvalue)), contour(M[:,:,2,2]), contour(M[:,:,2,3]), contour(M[:,:,2,4]),
contour(M[:,:,1,1], ylabel="y = $(string(Y[1]))", xlabel="x = $(string(X[1]))"), contour(M[:,:,1,2], xlabel="x = $(string(X[2]))"), contour(M[:,:,1,3], xlabel="x = $(string(X[3]))"), contour(M[:,:,3,4], xlabel="x = $(string(X[4]))"),
layout=(yL,xL) )
This produces:
I remain however with the following concerns:
How do I automatize the creation of each subplot in the subplot call ? Do I need to write a macro ?
I would like each subplot to have the same limits in the z axis, but zlims seems not to work. Is zlims not yet supported ?
How do I hide the legend on the z axis on each subplot and plot it instead apart (best would be on the right side of the main/total plot) ?
EDIT:
For the first point I don't need a macro, I can create the subplots in a for loop, add them in a array and pass the array to the plot() call using the ellipsis operator:
plots = []
for y in length(Y):-1:1
for x in 1:length(X)
xlabel = y == 1 ? "x = $(string(X[x]))" : ""
ylabel = x==1 ? "y = $(string(Y[y]))" : ""
println("$y - $x")
plot = contour(I,J,M[:,:,y,x], xlabel=xlabel, ylabel=ylabel, zlims=(minvalue,maxvalue))
push!(plots,plot)
end
end
plot(plots..., layout=(yL,xL))
I have created the best fit lines for the dataset using the following code:
fig, ax = plt.subplots()
for dd,KK in DATASET.groupby('Z'):
fit = polyfit(x,y,3)
fit_fn = poly1d(fit)
ax.plot(KK['x'],KK['y'],'o',KK['x'], fit_fn(KK['x']),'k',linewidth=4)
ax.set_xlabel('x')
ax.set_ylabel('y')
The graph displays the best fit line for each group of Z. I want print the equation of the best fit line on top of the line.Please suggest what can i do out here
So you need to write some function that convert a poly parameters array to a latex string, here is an example:
import pylab as pl
import numpy as np
x = np.random.randn(100)
y = 1 + 2 * x + 3 * x * x + np.random.randn(100) * 2
poly = pl.polyfit(x, y, 2)
def poly2latex(poly, variable="x", width=2):
t = ["{0:0.{width}f}"]
t.append(t[-1] + " {variable}")
t.append(t[-1] + "^{1}")
def f():
for i, v in enumerate(reversed(poly)):
idx = i if i < 2 else 2
yield t[idx].format(v, i, variable=variable, width=width)
return "${}$".format("+".join(f()))
pl.plot(x, y, "o", alpha=0.4)
x2 = np.linspace(-2, 2, 100)
y2 = np.polyval(poly, x2)
pl.plot(x2, y2, lw=2, color="r")
pl.text(x2[5], y2[5], poly2latex(poly), fontsize=16)
Here is the output:
Here's a one liner.
If fit is the poly1d object, while plotting the fitted line, just use label argument as bellow,
label='y=${}$'.format(''.join(['{}x^{}'.format(('{:.2f}'.format(j) if j<0 else '+{:.2f}'.format(j)),(len(fit.coef)-i-1)) for i,j in enumerate(fit.coef)]))