Seaborn plot with second y axis - python

i wanted to know how to make a plot with two y-axis so that my plot that looks like this :
to something more like this by adding another y-axis :
i'm only using this line of code from my plot in order to get the top 10 EngineVersions from my data frame :
sns.countplot(x='EngineVersion', data=train, order=train.EngineVersion.value_counts().iloc[:10].index);

I think you are looking for something like:
import matplotlib.pyplot as plt
x = [1,2,3,4,5]
y = [1000,2000,500,8000,3000]
y1 = [1050,3000,2000,4000,6000]
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.bar(x, y)
ax2.plot(x, y1, 'o-', color="red" )
ax1.set_xlabel('X data')
ax1.set_ylabel('Counts', color='g')
ax2.set_ylabel('Detection Rates', color='b')
plt.show()
Output:

#gdubs If you want to do this with Seaborn's library, this code set up worked for me. Instead of setting the ax assignment "outside" of the plot function in matplotlib, you do it "inside" of the plot function in Seaborn, where ax is the variable that stores the plot.
import seaborn as sns # Calls in seaborn
# These lines generate the data to be plotted
x = [1,2,3,4,5]
y = [1000,2000,500,8000,3000]
y1 = [1050,3000,2000,4000,6000]
fig, ax1 = plt.subplots() # initializes figure and plots
ax2 = ax1.twinx() # applies twinx to ax2, which is the second y axis.
sns.barplot(x = x, y = y, ax = ax1, color = 'blue') # plots the first set of data, and sets it to ax1.
sns.lineplot(x = x, y = y1, marker = 'o', color = 'red', ax = ax2) # plots the second set, and sets to ax2.
# these lines add the annotations for the plot.
ax1.set_xlabel('X data')
ax1.set_ylabel('Counts', color='g')
ax2.set_ylabel('Detection Rates', color='b')
plt.show(); # shows the plot.
Output:
Seaborn output example

You could try this code to obtain a very similar image to what you originally wanted.
import seaborn as sb
from matplotlib.lines import Line2D
from matplotlib.patches import Rectangle
x = ['1.1','1.2','1.2.1','2.0','2.1(beta)']
y = [1000,2000,500,8000,3000]
y1 = [3,4,1,8,5]
g = sb.barplot(x=x, y=y, color='blue')
g2 = sb.lineplot(x=range(len(x)), y=y1, color='orange', marker='o', ax=g.axes.twinx())
g.set_xticklabels(g.get_xticklabels(), rotation=-30)
g.set_xlabel('EngineVersion')
g.set_ylabel('Counts')
g2.set_ylabel('Detections rate')
g.legend(handles=[Rectangle((0,0), 0, 0, color='blue', label='Nontouch device counts'), Line2D([], [], marker='o', color='orange', label='Detections rate for nontouch devices')], loc=(1.1,0.8))

Related

Logarithmic Ticks on Top and Right Spine

I am trying to make a visualization with logarithmic ticks on all sides of the box.
import numpy as np
import matplotlib.pyplot as plt
x = np.logspace(2, 5, 5)
y = 0.5*x**(-1/2)
y2 = 0.01*x**(-1/2)
y3 = 0.05*x**(-1/3)
fig, ax = plt.subplots()
ax.plot(x, y, 'o-', label="One")
ax.plot(x, y2, '*-', label="Two")
ax.plot(x, y3, '--', label="Three")
ax.set(
xlabel='Input',
xlim=(1e2, 1e5),
xscale='log',
ylabel='Output',
ylim=(1e-5, 1e-1),
yscale='log',
)
ax.tick_params(top=True, right=True) # <-- This didn't work how I expected.
ax.legend(loc='lower left');
I would like the associated minor tick marks on the top and right spine.
Any advice on how to make that happen?
Use the which parameter of Axes.tick_params:
ax.tick_params(which='both', top=True, right=True)
Output:

plt.gcf() doesn't show previous instance of a plot

I want to save an instance of a plot into an object so that I can display it later by just calling that object.
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 10, 0.1)
y1 = x
y2 = np.sin(x)
plt.plot(x, y1, linewidth=1, color = 'deepskyblue')
fig1 = plt.gcf()
plt.plot(x, y2, linewidth=1, color = 'red')
fig2 = plt.gcf()
In this example, I first draw a blue line (y1=x) and use plt.gcf() to save an instance of this plot in fig1. Then I add a red curve (y2=sin(x)) to the plot and use plt.gcf() again to save this plot in fig2. Now, I expect that when I call fig1 I only get the blue line, and when I call fig2 I get both lines. Like this (I'm in Jupyter):
fig1 # or fig1.show() if not in Jupyter
Only blue curve
fig2
Both curves
But, in reality, when I call fig1 and fig2, both of them show both curves (like the second picture). Can someone please help how I can correctly get an instance of each plot so that I can display each of them later whenever I want?
You need to force matplotlib to actually draw the figure by setting a plot.show() in your code:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 10, 0.1)
y1 = x
y2 = np.sin(x)
plt.plot(x, y1, linewidth=1, color = 'deepskyblue')
plt.show()
fig1 = plt.gcf()
plt.plot(x, y2, linewidth=1, color = 'red')
plt.show()
fig2 = plt.gcf()
Using the function plt.plot() always plots to the current axis (if no axis is present, a new one is created).
You can also tell matplotlib explicitly to open a new figure:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 10, 0.1)
y1 = x
y2 = np.sin(x)
# open first figure
fig1 = plt.figure()
# plot
plt.plot(x, y1, linewidth=1, color = 'deepskyblue')
# open second figure
fig2 = plt.figure()
#plot
plt.plot(x, y2, linewidth=1, color = 'red')
Although this already fixes your problem, it is considered good practice to use an object-oriented version of this like this:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 10, 0.1)
y1 = x
y2 = np.sin(x)
# open first figure, axis
fig1, ax1 = plt.subplots()
# plot
ax1.plot(x, y1, linewidth=1, color = 'deepskyblue')
# open second figure, axis
fig2, ax2 = plt.subplots()
#plot
ax2.plot(x, y2, linewidth=1, color = 'red')
In all cases, you will get:
Now, why don't you need plt.show() in the other approaches? Well, matplotlib by explicitly opening a new figure/axis, it is obvious that the previous axis is finished and can be drawn.
The last approach is the clearest as you tell exactly which figure and which axis you are considering.

Matplotlib scatter plot of unfilled squares

I would like to make a scatter plot with unfilled squares. markerfacecolor is not an option recognized by scatter. I made a MarkerStyle but the fill style seems to be ignored by the scatter plot. Is there a way to make unfilled markers in the scatterplot?
import matplotlib.markers as markers
import matplotlib.pyplot as plt
import numpy as np
def main():
size = [595, 842] # in pixels
dpi = 72. # dots per inch
figsize = [i / dpi for i in size]
fig = plt.figure(figsize=figsize)
ax = fig.add_axes([0,0,1,1])
x_max = 52
y_max = 90
ax.set_xlim([0, x_max+1])
ax.set_ylim([0, y_max + 1])
x = np.arange(1, x_max+1)
y = [np.arange(1, y_max+1) for i in range(x_max)]
marker = markers.MarkerStyle(marker='s', fillstyle='none')
for temp in zip(*y):
plt.scatter(x, temp, color='green', marker=marker)
plt.show()
main()
It would appear that if you want to use plt.scatter() then you have to use facecolors = 'none' instead of setting fillstyle = 'none' in construction of the MarkerStyle, e.g.
marker = markers.MarkerStyle(marker='s')
for temp in zip(*y):
plt.scatter(x, temp, color='green', marker=marker, facecolors='none')
plt.show()
or, use plt.plot() with fillstyle = 'none' and linestyle = 'none' but since the marker keyword in plt.plot does not support MarkerStyle objects you have to specify the style inline, i.e.
for temp in zip(*y):
plt.plot(x, temp, color='green', marker='s', fillstyle='none')
plt.show()
either of which will give you something that looks like this
Refer to: How to do a scatter plot with empty circles in Python?
Try adding facecolors='none' to your plt.scatter
plt.scatter(x, temp, color='green', marker=marker, facecolors='none')

PyPlot move alternative y axis to background

In pyplot, you can change the order of different graphs using the zorder option or by changing the order of the plot() commands. However, when you add an alternative axis via ax2 = twinx(), the new axis will always overlay the old axis (as described in the documentation).
Is it possible to change the order of the axis to move the alternative (twinned) y-axis to background?
In the example below, I would like to display the blue line on top of the histogram:
import numpy as np
import matplotlib.pyplot as plt
import random
# Data
x = np.arange(-3.0, 3.01, 0.1)
y = np.power(x,2)
y2 = 1/np.sqrt(2*np.pi) * np.exp(-y/2)
data = [random.gauss(0.0, 1.0) for i in range(1000)]
# Plot figure
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax2.hist(data, bins=40, normed=True, color='g',zorder=0)
ax2.plot(x, y2, color='r', linewidth=2, zorder=2)
ax1.plot(x, y, color='b', linewidth=2, zorder=5)
ax1.set_ylabel("Parabola")
ax2.set_ylabel("Normal distribution")
ax1.yaxis.label.set_color('b')
ax2.yaxis.label.set_color('r')
plt.show()
Edit: For some reason, I am unable to upload the image generated by this code. I will try again later.
You can set the zorder of an axes, ax.set_zorder(). One would then need to remove the background of that axes, such that the axes below is still visible.
ax2 = ax1.twinx()
ax1.set_zorder(10)
ax1.patch.set_visible(False)

Change ticks of y-axis in python

I want to change y axis ticks in python. I am using the code
import pylab as plt
y1 = [0,1,2,...10]
y2 = [90,40,65,12,....]
labels = [0.30,0.29,0.28,....]
plt.plot(y1)
plt.plot(y2,'r')
plt.yticks(y1, labels)
plt.yticks(y2, labels)
plt.show()
But all the y axis label appear at one place on top of one another
Borrowing heavily from this example, the code below demonstrates one possible way to have two plots on one figure.
import pylab as plt
fig, ax1 = plt.subplots()
y1 = [0,1,2,3,4,5,6,7,8,9,10]
labels = [0.30,0.29,0.28,0.27,0.26,0.25,0.24,0.23,0.22,0.21,0.20]
ax1.plot(labels, y1, 'b-')
ax1.set_xlabel('labels')
# Make the y-axis label, ticks and tick labels match the line color.
ax1.set_ylabel('y1', color='b', rotation="horizontal")
ax1.tick_params('y', colors='b')
ax2 = ax1.twinx()
y2 = [90,40,65,12,23,43,54,13,42,53,63]
ax2.plot(labels, y2, 'r-')
ax2.set_ylabel('y2', color='r', rotation="horizontal")
ax2.tick_params('y', colors='r')
fig.tight_layout()
plt.show()

Categories

Resources