Matplotlib specific axis plotting - python

I'm newbie in plotting with python so can not really figure out some things, sorry. The matter is that according to documentation I could only plot images with four axis without any modification.
So, I've found couple tutorials, but still could plot only something like this:
My question is: where to find tutorials to be able plot something like this
As you can see there is no top and right axis and years text direction is changed.

It's actually (at least) two questions:
Rotating the labels can be done with setp; see answer here
This axes props demo shows how to get the grid-like effect in your graph.

Done.
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import matplotlib.pyplot as plt
import matplotlib.ticker
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
# ------------ Main Data ----------------
xlist = [x for x in xrange(2001, 2016, 1)]
ylist = [0, 1, 3, 3, 5, 7, 4, 4, 5, 10, 10, 30, 27, 43, 45]
# ---------------------------------------
# size of plot in inches
fig = plt.figure(figsize=(9.5, 5))
# init plot
plt.plot(
xlist,
ylist,
linestyle = "-",
marker = "D",
color = "#5184be",
markerfacecolor = "#5184be",
linewidth = 2)
# axes style
axes = plt.gca()
axes.yaxis.grid(b=True, color='#c0c0c0', linestyle='-', linewidth=2)
axes.set_axisbelow(True)
# Labels
axes.set_xlabel(u'Loads, pts.', fontproperties=prop)
axes.set_ylabel(u'Year, y', fontproperties=prop)
# create line style
locator = matplotlib.ticker.MultipleLocator (base=1)
# set line style
axes.xaxis.set_major_locator (locator)
# view plot
plt.show()

Related

My animated plot using matplotlib is not moving

I have an array X_trj of shape (18,101) to be plotted in 3D (they are the trajectories of three different vehicles), and I tried animating my plot by doing the following:
#animate the plot:
import matplotlib.animation as animation
# First, create a function that updates the scatter plot for each frame
def update_plot(n,X_trj,scatters):
# Set the data for each scatter plot
scatters[0].set_offsets(np.stack((X_trj[0, :n], X_trj[1, :n], X_trj[2, :n]), axis=1))
scatters[1].set_offsets(np.stack((X_trj[6, :n], X_trj[7, :n], X_trj[8, :n]), axis=1))
scatters[2].set_offsets(np.stack((X_trj[12,:n], X_trj[13, :n], X_trj[14,:n]), axis=1))
return scatters
# Create the figure and axis
fig = plt.figure()
ax = plt.axes(projection='3d')
# Create the scatter plots
scatters = []
scatters.append(ax.scatter(X_trj[0,:], X_trj[1,:], X_trj[2,:]))
scatters.append(ax.scatter(X_trj[6,:], X_trj[7,:], X_trj[8,:]))
scatters.append(ax.scatter(X_trj[12,:], X_trj[13,:], X_trj[14,:]))
# Set the title
ax.set_title('Trajectory from one-shot optimization (human + drones)')
ani = animation.FuncAnimation(fig, update_plot, frames=range(X_trj.shape[1]), fargs=(X_trj, scatters))
plt.show()
ani.save('animation.mp4')
I get the following plot after running the code:
However, when I opened up the mp4 file my animation is not moving. It's the exact same static plot I got. Any help is greatly appreciated!
It is unclear where you copied your starting code from. Most examples use ax.plot instead of ax.scatter. Old code can become obsolete with newer matplotlib versions.
Anyway, you fill the full final trajectory already at the initialization. Instead, you should create an empty plot, and manually set the x, y and z limits.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
# first, fill X_trj with some test data
n = 2000
X_trj = np.random.randn(15, n).cumsum(axis=1)
# second, create a function that updates the scatter plot for each frame
def update_plot(k, X_trj, scatters):
# Set the data for each scatter plot
scatters[0]._offsets3d = X_trj[0:3, :k]
scatters[1]._offsets3d = X_trj[6:9, :k]
scatters[2]._offsets3d = X_trj[12:15, :k]
return scatters
# Create the figure and axis
fig = plt.figure()
ax = plt.axes(projection='3d')
# Create the scatter plots
scatters = []
scatters.append(ax.scatter([], [], []))
scatters.append(ax.scatter([], [], []))
scatters.append(ax.scatter([], [], []))
# set the axis limits
ax.set_xlim3d(X_trj[[0, 6, 12], :].min(), X_trj[[0, 6, 12], :].max())
ax.set_ylim3d(X_trj[[1, 7, 13], :].min(), X_trj[[1, 7, 13], :].max())
ax.set_zlim3d(X_trj[[2, 8, 14], :].min(), X_trj[[2, 8, 14], :].max())
# Set the title
ax.set_title('Trajectory from one-shot optimization (human + drones)')
ani = animation.FuncAnimation(fig, update_plot, frames=n, fargs=(X_trj, scatters))
ani.save('animation.mp4')
plt.show()

How to add title to the plot of shap.plots.force with Matplotlib?

I want to add some modifications to my force plot (created by shap.plots.force) using Matplotlib, e.g. adding title, using tight layout etc. However, I tried to add title and the title doesn't show up. Any ideas why and how can I add the title using Matplotlib?
import numpy as np
import shap
import matplotlib.pyplot as plt
myBaseline=1.5
shap_values_0 = np.array([-1, -4, 3])
test_point_0 = np.array([11, 12, 13])
features_names = ['a1','a2','a3']
shap.plots.force(myBaseline,shap_values_0,test_point_0,features_names,matplotlib = 1)
plt.suptitle("This is my title") # It doesn't show up, why?
fig = plt.gcf()
fig.canvas.draw()
plt.close()
The last lines in force_plot are:
if show:
plt.show()
else:
return plt.gcf()
so, if you set show = False you can get prepared SHAP plot as figure object and customize it to your needs as usual:
import shap
myBaseline = 1.5
shap_values_0 = np.array([-1, -4, 3])
test_point_0 = np.array([11, 12, 13])
features_names = ["a1", "a2", "a3"]
shap.plots.force(
myBaseline, shap_values_0, test_point_0, features_names, matplotlib=True, show=False
)
plt.title("This is my title", y=1.75)
plt.show()
I had to add show=0 at shap.plots.force, i.e.
shap.plots.force(myBaseline,shap_values_0,test_point_0,features_names,matplotlib = 1, show=0)
I have no idea why it works, but it does.

How to make a bubble graph using seaborn

import matplotlib.pyplot as plt
import numpy as np
# data
x=["IEEE", "Elsevier", "Others"]
y=[7, 6, 2]
import seaborn as sns
plt.legend()
plt.scatter(x, y, s=300, c="blue", alpha=0.4, linewidth=3)
plt.ylabel("No. of Papers")
plt.figure(figsize=(10, 4))
I want to make a graph as shown in the image. I am not sure how to provide data for both journal and conference categories. (Currently, I just include one). Also, I am not sure how to add different colors for each category.
You can try this code snippet for you problem.
- I modified your Data format, I suggest you to use pandas for
data visualization.
- I added one more field to visualize the data more efficiently.
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import pandas as pd
# data
x=["IEEE", "Elsevier", "Others", "IEEE", "Elsevier", "Others"]
y=[7, 6, 2, 5, 4, 3]
z=["conference", "journal", "conference", "journal", "conference", "journal"]
# create pandas dataframe
data_list = pd.DataFrame(
{'x_axis': x,
'y_axis': y,
'category': z
})
# change size of data points
minsize = min(data_list['y_axis'])
maxsize = max(data_list['y_axis'])
# scatter plot
sns.catplot(x="x_axis", y="y_axis", kind="swarm", hue="category",sizes=(minsize*100, maxsize*100), data=data_list)
plt.grid()
How to create the graph with correct bubble sizes and with no overlap
Seaborn stripplot and swarmplot (or sns.catplot(kind=strip or kind=swarm)) provide the handy dodge argument which prevents the bubbles from overlapping. The only downside is that the size argument applies a single size to all bubbles and the sizes argument (as used in the other answer) is of no use here. They do not work like the s and size arguments of scatterplot. Therefore, the size of each bubble must be edited after generating the plot:
import numpy as np # v 1.19.2
import pandas as pd # v 1.1.3
import seaborn as sns # v 0.11.0
# Create sample data
x = ['IEEE', 'Elsevier', 'Others', 'IEEE', 'Elsevier', 'Others']
y = np.array([7, 6, 3, 7, 1, 3])
z = ['conference', 'conference', 'conference', 'journal', 'journal', 'journal']
df = pd.DataFrame(dict(organisation=x, count=y, category=z))
# Create seaborn stripplot (swarmplot can be used the same way)
ax = sns.stripplot(data=df, x='organisation', y='count', hue='category', dodge=True)
# Adjust the size of the bubbles
for coll in ax.collections[:-2]:
y = coll.get_offsets()[0][1]
coll.set_sizes([100*y])
# Format figure size, spines and grid
ax.figure.set_size_inches(7, 5)
ax.grid(axis='y', color='black', alpha=0.2)
ax.grid(axis='x', which='minor', color='black', alpha=0.2)
ax.spines['bottom'].set(position='zero', color='black', alpha=0.2)
sns.despine(left=True)
# Format ticks
ax.tick_params(axis='both', length=0, pad=10, labelsize=12)
ax.tick_params(axis='x', which='minor', length=25, width=0.8, color=[0, 0, 0, 0.2])
minor_xticks = [tick+0.5 for tick in ax.get_xticks() if tick != ax.get_xticks()[-1]]
ax.set_xticks(minor_xticks, minor=True)
ax.set_yticks(range(0, df['count'].max()+2))
# Edit labels and legend
ax.set_xlabel('Organisation', labelpad=15, size=12)
ax.set_ylabel('No. of Papers', labelpad=15, size=12)
ax.legend(bbox_to_anchor=(1.0, 0.5), loc='center left', frameon=False);
Alternatively, you can use scatterplot with the convenient s argument (or size) and then edit the space between the bubbles to reproduce the effect of the missing dodge argument (note that the x_jitter argument seems to have no effect). Here is an example using the same data as before and without all the extra formatting:
# Create seaborn scatterplot with size argument
ax = sns.scatterplot(data=df, x='organisation', y='count',
hue='category', s=100*df['count'])
ax.figure.set_size_inches(7, 5)
ax.margins(0.2)
# Dodge bubbles
bubbles = ax.collections[0].get_offsets()
signs = np.repeat([-1, 1], df['organisation'].nunique())
for bubble, sign in zip(bubbles, signs):
bubble[0] += sign*0.15
As a side note, I recommend that you consider other types of plots for this data. A grouped bar chart:
df.pivot(index='organisation', columns='category').plot.bar()
Or a balloon plot (aka categorical bubble plot):
sns.scatterplot(data=df, x='organisation', y='category', s=100*count).margins(0.4)
Why? In the bubble graph, the counts are displayed using 2 visual attributes, i) the y-coordinate location and ii) the bubble size. Only one of them is really necessary.

python violin plot regular axis

I want to to a violin plot of binned data but at the same time be able to plot a model prediction and visualize how well the model describes the main part of the individual data distributions. My problem here is, I guess, that the x-axis after the violin plot does not behave like a regular axis with numbers, but more like string-values that just accidentally happen to be numbers. Maybe not a good description, but in the example I would like to have a "normal" plot a function, e.g. f(x) = 2*x**2, and at x=1, x=5.2, x=18.3 and x=27 I would like to have the violin in the background.
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
np.random.seed(10)
collectn_1 = np.random.normal(1, 2, 200)
collectn_2 = np.random.normal(802, 30, 200)
collectn_3 = np.random.normal(90, 20, 200)
collectn_4 = np.random.normal(70, 25, 200)
ys = [collectn_1, collectn_2, collectn_3, collectn_4]
xs = [1, 5.2, 18.3, 27]
sns.violinplot(x=xs, y=ys)
xx = np.arange(0, 30, 10)
plt.plot(xx, 2*xx**2)
plt.show()
Somehow this code actually does not plot violins but only bars, this is only a problem in this example and not in the original code though. In my real code I want to have different "half-violins" on both sides, therefore I use sns.violinplot(x="..", y="..", hue="..", data=.., split=True).
I think that would be hard to do with seaborn because it does not provide an easy way to manipulate the artists that it creates, particularly if there are other things plotted on the same Axes. Matplotlib's violinplot allows setting the position of the violins, but does not provide an option for plotting only half violins. Therefore, I would suggest using statsmodels.graphics.boxplots.violinplot, which does both.
from statsmodels.graphics.boxplots import violinplot
df = sns.load_dataset('tips')
x_col = 'day'
y_col = 'total_bill'
hue_col = 'smoker'
xs = [1, 5.2, 18.3, 27]
xx = np.arange(0, 30, 1)
yy = 0.1*xx**2
cs = ['C0','C1']
fig, ax = plt.subplots()
ax.plot(xx,yy)
for (_,gr0),side,c in zip(df.groupby(hue_col),['left','right'],cs):
print(side)
data = [gr1 for (_,gr1) in gr0.groupby(x_col)[y_col]]
violinplot(ax=ax, data=data, positions=xs, side=side, show_boxplot=False, plot_opts=dict(violin_fc=c))
# violinplot above messes up which ticks are shown, the line below restores a sensible tick locator
ax.xaxis.set_major_locator(matplotlib.ticker.MaxNLocator())

How to set the xtick position for secondary axis in matplotlib?

I want to create a secondary xaxis at the top which has an inverse relation with the major xaxis at the bottom. I followed the official tutorial here and have the following codes:
def forward(x):
return 10/x
def backward(y):
return 10/y
fig, ax = plt.subplots()
ax.set_xlim([0.14, 1.4])
secax = ax.secondary_xaxis('top', functions=(forward, backward))
secax.set_xticks(np.array([10,20,40,70])) # does not work!
plt.show()
The problem is that the xticks at the top are not at the right place. They are bunched together in the left due to the inverse function applied. How do I manually set the position of the xticks? (e.g. at 10,20,40,70)
Edit:
Just to make it more clear, the ticks are at the right place, but there are too many tickss as shown in the figure. In this case, I only want the ticks at 10, 20, 40, 70 (I don't want the ticks at 30, 50 and 60 as we can't see all the tick numbers clearly)
I believe either you missed import statement for numpy or you need to update you matplotlib. Below works fine for me -
import matplotlib.pyplot as plt
import numpy as np
def forward(x):
return 10/x
def backward(y):
return 10/y
fig, ax = plt.subplots()
ax.set_xlim([0.14, 1.4])
secax = ax.secondary_xaxis('top', functions=(forward, backward))
secax.set_xticks(np.array([10,20,40,70])) # does not work!
plt.show()
Check your version -
import matplotlib
print (matplotlib.__version__)
If above doesn't print 3.2.1. try below -
pip install matplotlib==3.2.1
It is not clear what you want to achieve.
If you want a linear relationship at the top, this might be relevant:
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
ax.set_xlim([0.14, 1.4])
secax = ax.secondary_xaxis('top', functions=(lambda x: 77 - 50 * x,
lambda y: (77 - y) / 50))
secax.set_xticks(np.array([10, 20, 40, 70]))
plt.show()

Categories