Prevent 'darkgrid' ax2 gridlines in twinx() plot from disecting ax1 curve - matplotlib

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)

Related

Matplotlib subplot using nested for loop to plot timeseries (trajectory)

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.

Print weighted color palette in matplotlib

I understand that one can print a color palette (equally weighted) with the following code:
import matplotlib.pyplot as plt
blue_red = [(0,0,255), (255, 0,0)] # or any other list of RGB tuples
plt.imshow([blue_red])
However, how could I show weighted palettes? For example if I wanted to weight 90% blue and 10% red instead of 50-50?
You can do it like this:
import matplotlib.pyplot as plt
blue = (0,0,255)
red = (255, 0,0)
weight1 = 9
weight2 = 1
blue_red = [blue for _ in range (weight1)] + [red for _ in range(weight2)]
plt.imshow([blue_red])
plt.show()
or simply:
plt.imshow([[(0,0,255) for _ in range(9)] + [(255, 0,0) for _ in range(1)]])
You can also add an extent argument to clean up your corrdinates:
plt.imshow([[(0,0,255) for _ in range(9)] + [(255, 0,0) for _ in range(1)]],extent=[0,10,0,1])

matplotlib subplot of 1:2:1

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, :])

matplotlib - plotting histogram with unique bins

I am trying to plot a histogram but the x ticks does not seem to get right.
The plot is intended to get a histogram of frequency counts ( 1 to 13 ) and total rows in 10000.
d1 = []
for i in np.arange(1, 10000):
tmp = np.random.randint(1, 13)
d1.append(tmp)
d2 = pd.DataFrame(d1)
d2.hist(width = 0.5)
plt.xticks(np.arange(1, 14, 1))
I am trying to plot frequency count of values and not ranges.
You would need to set the bin edges which should be used by the histogram.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
d1 = np.random.randint(1, 13, size=1000)
d2 = pd.DataFrame(d1)
bins = np.arange(0,13)+0.5
d2.hist(bins=bins, ec ="k")
plt.xticks(np.arange(1, 13))
plt.show()

matplotlib scatter plot using axes object in loop

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