Placing datalabels at certain places of a graph in matplotlib python - list

The data set below plots a line graph and where the graphs line is blue on an incline and red on a decline. I want to add data labels to the points of change in color for the graph. I want to use the code below to add data labels to my current code. The data lables are meant to print out the x,y coordinate of the current position.
Code for adding data labels:
label = f"({x},{y})"
plt.annotate(label, # this is the text
(x,y), # this is the point to label
textcoords="offset points", # how to position the text
xytext=(0,10), # distance from text to points (x,y)
ha='center') # horizontal alignment can be left, right or center
Current code
import matplotlib.pyplot as plt
x_long = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
L_Amount_list = [100.00, 9313.38, 43601.28, 61701.69, 74331.88, 198913.81, 153054.54, 119162.10, 74382.25, 203542.82, 160774.71, 220307.19, 366459.26]
colors = ['b' if a < b else 'r' for a,b in zip(L_Amount_list,L_Amount_list[1:])]
for i in range(len(x_long)):
try:
plt.plot(x_long[i:i+2], L_Amount_list[i:i+2], color=colors[i])
except:
break
plt.show()

Related

How to fully delete plots from subplot and properly resize?

I am trying to create a corner plot for an upcoming paper, but I'm running into difficulty. I am creating an N x N array of subplots (currently, N = 6) and then deleting a bit over half of them. The issue is that the figure doesn't seem to resize itself after I delete the extraneous subplots, so when I later add a legend using a dummy subplot, it exists in the area where a full row and column of deleted subplots were, thus enlarging the figure. I've been working on this for several hours now and haven't found a solution. Here is the MWE:
import matplotlib.pyplot as plt
%matplotlib notebook
n_char = 8
# Set up the main figure.
fig, ax = plt.subplots(n_char, n_char, figsize=(n_char, n_char))
# Get rid of the axis labels unless it's on the left-most column or bottom-most row.
for i in range(0, n_char):
# For each row, loop over each column.
for j in range(0, n_char):
# If the plot isn't in the bottom-most row, get rid of the x-axis tick labels.
if i != n_char - 1:
ax[i, j].set_xticklabels([])
# If the plot isn't in the left-most column, get rid of the y-axis tick labels.
if j != 0:
ax[i, j].set_yticklabels([])
# Remove the plots that are repetitive or boring (plotting against the same characteristic).
for i in range(0, n_char):
# For each row, loop over each column.
for j in range(0, n_char):
# Delete the offending axes.
if j >= i:
ax[i, j].remove()
# Set the spacing between the plots to a much smaller value.
fig.subplots_adjust(hspace=0.00, wspace=0.00)
# Create a big plot for the legend. Have the frame hidden.
fig.add_subplot(111, frameon=False, xticks=[], yticks=[], xticklabels=[], yticklabels=[])
# Create some dummy data to serve as the source of the legend.
plt.scatter([10], [10], color="k", s=5, zorder=2, label="Targets")
# Set the x-axis limits such that the dummy data point is invisible.
fig.gca().set_xlim(-1, 1)
# Add the legend to the plot. Have it located in the upper right.
plt.legend(scatterpoints=1, loc="upper right", fontsize=5)
# Save the final plot.
fig.savefig("./../Code Output/Other Plots/Corner_Plot_Test.png", bbox_inches="tight", dpi=500)
I have looked at many different questions here on Stack Overflow. The two most promising candidates was this one, but I found the solution wasn't quite workable due to the large number of plots (and, to be frank, I didn't fully understand the solution). I thought that the first answer in this one might also work, as I thought it was a sizing issue (i.e. the figure wasn't resizing, so creating a new subplot was creating one the size of the original figure), but all it did was resize the entire figure, so that didn't work either.
To help, I will also include an image. I took the output of the code above and edited it to show what I want:
I should add that if I don't add a subplot, the output is as I expected (i.e. it's the proper size), so the issue comes in when adding the subplot, i.e. the line fig.add_subplot(111, frameon=False, xticks=[], yticks=[], xticklabels=[], yticklabels=[]).
The use of GridSpec may help.
GridSpec is used to specify array of axes to plot. You can set widths for columns and heights for rows as ratios in the option. The unneeded row should have very small height ratio, while unneeded column very small width ratio.
Here is the runnable code and output plot:-
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
#import numpy as np
fig = plt.figure(figsize=(8, 8))
nn = 6
# will create gridspec of 6 rows, 6 columns
# 1st row will occupy v small heights
# last column will occupy v small widths
sm = 0.01 # the v small width/height
wh = (1.-sm)/(nn-1.) # useful width/height
gs = gridspec.GridSpec(nn, nn, width_ratios=[*[wh]*(nn-1), sm], \
height_ratios= [sm, *[wh]*(nn-1)])
cols, rows = nn, nn
ax = [[0 for i in range(cols)] for j in range(rows)]
for ea in range(nn):
for eb in range(nn):
ax[ea][eb] = fig.add_subplot(gs[ea, eb])
ax[ea][eb].set_xticklabels([])
ax[ea][eb].set_yticklabels([])
if eb>=ea:
ax[ea][eb].remove()
# plot data on some axes
# note that axes on the first row (index=0) are gone
ax[2][0].plot([2,5,3,7])
ax[4][2].plot([2,3,7])
# make legend in upper-right axes (GridSpec's first row, last column)
# first index: 0
# second index: nn-1
rx, cx = 0, nn-1
ax[rx][cx] = fig.add_subplot(gs[rx,cx])
hdl = ax[rx][cx].scatter([10], [10], color="k", s=5, zorder=2, label="Targets")
ax[rx][cx].set_axis_off()
#ax[rx][cx].set_visible(True) # already True
ax[rx][cx].set_xticklabels([])
ax[rx][cx].set_yticklabels([])
# plot legend
plt.legend(bbox_to_anchor=(1.0, 1.0), loc='upper right', borderaxespad=0.)
fig.subplots_adjust(hspace=0.00, wspace=0.00)
plt.show

Editing Radar Charts for Labeling and Axis Limits

I have been playing with the radar chart concept for visualizing percentage-based metrics. I have followed sample code but am having trouble with a few items. Can anyone help me with changing the labels from the default degree values to something else? I also want to set the x-axis minimum to 0.9, but struggled a bit.
Any help or resources are helpful. If there is a more efficient way to solve them, I am open to starting over again.
import numpy as np
import matplotlib.pyplot as plt
availability_array = np.array([.95, .9, .99, .97, 1]) #sample inverter uptime availability numbers using site with 5 inverters
# Compute pie slices
theta = np.linspace(0.0, 2 * np.pi, len(availability_array), endpoint=False)
values = availability_array #values that are graphed
width = 1 #increase/decrease width of each bar
ax = plt.subplot(111, projection='polar') #.set_xticklabels(['N', '', 'W', '', 'S', '', 'E', '']) #111 means 1x1 grid subplot starting in cell 1
bars = ax.bar(theta, values, width=width, bottom=0.0)
# Coloring
for r, bar in zip(values, bars):
bar.set_facecolor(plt.cm.viridis(r / 1))
bar.set_alpha(0.4) #transparency of the bars
plt.show()
As you've already shown in your comments, labels around the circle are xticklabels and labels along the radius are yticklabels, i.e. y-axis is along the radius. Therefore, I think you meant to "set the y-axis minimum to 0.9".
As you would do with regular plot, you can use set_xticks in combine with set_xticklabels to change "the labels from the default degree values to something else". For example:
ax.set_xticks([np.pi/4, np.pi*3/4])
ax.set_xticklabels(['NE', 'NW'])
To "set the y-axis minimum to 0.9", you can use set_ylim like this:
ax.set_ylim(0.9, 1)

Delete vertical lines (or vertical rules) in plt.table? Let only horizontal lines as a Table not as a chart

Is there any way to remove the vertical lines in a matplotlib table?
Or even using text.usetex=True obtain a plot (using Arial for all texts and numbers) and append a table without vertical lines?
My code is this:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("ticks")
plt.rcParams.update({'xtick.labelsize' : 9,
'ytick.labelsize' : 9,
'mathtext.fontset' : 'stixsans',
'mathtext.default': 'regular'
})
plt.subplots_adjust(left=0.17, right=0.96, top=0.97, bottom=0.09)
fig = plt.figure(figsize=(5.5, 3.4))
ax = fig.add_subplot(111)
ax.plot([1, 2, 3, 4, 5, 6])
ax.set_xlabel('X Label')
ax.set_ylabel('Unit ('+u'μ'+r'velocity $\cdot$ m$^{-2}$ s$^{-1}$)',
size=10)
l1 = ["","t0", "t1", "t2", "t3 ", "t4", "t5", "t6"]
l2 = ["DLI", 35, 38, 10, 22, 25, 85, 22]
t = ax.table(
colWidths=[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],
cellText = [l1, l2],
loc="upper center",
colLoc="center",
rowLoc="center",
)
plt.savefig('mpl_table.png')
plt.show()
I tried to include some LaTeX stuff in another plot, which preserves Arial font, but does not render the table with horizontal lines Table correct. When I get the table as I want, the fonts can not be setted to Arial.
Here the codes show the plots in two steps. First generating the first plot and after running in a new session the second plot.
My main problem is to maintain the Arial font (mandatory rules in the guide for authors) and tables should be without vertical rules, as stated on first plot.
I have here three approachs and no one satisfy those recquirements (e.g. Arial font and table with no vertical lines)
Any clues?
Cheers,
Arnaldo.

Bar graph for male and female born on particular date/time

I need to draw a bar graph for the values:
male=('2', '1', '2', '6', '6', '1') # list may increase
time=('Tue_Aug_13_04:37:40_2013', 'Mon_Jul__1_02:33:11_2013','Tue_Aug_13_04:37:40_2013', 'Thu_Jul__4_01:53:32_2013', 'Mon_Jul__1_10:05:55_2013','Mon_Jul__1_04:15:25_2013')# list may increase
female=(16, 11, 16, 12, 12, 11) # list may increase
Male in green colour, female in red colour as the image attached below:
The code which I tried:
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse, Polygon
fig = plt.figure()
ax1 = fig.add_subplot(131)
ax1.bar(male, color='red', edgecolor='black')
ax1.bar(bottom=range(female), color='blue', edgecolor='black')
ax1.set_xticks(time)
plt.show()
What modifications do I need to make in order to draw the bar graph as shown in the image attached for my values?
1.) I strongly suggest that you familiarize yourself with the python syntax:
What's the difference between lists enclosed by square brackets and parentheses?
What's the difference between '2' and 2?
2.) Make use of the matplotlib documentation to figure out the correct syntaxt for the plot commands you are using.
3.) In this particular case: To get you going, change your data to:
male=[2, 1, 2, 6, 6, 1] # list may increase
time=['Tue_Aug_13_04:37:40_2013', 'Mon_Jul__1_02:33:11_2013','Tue_Aug_13_04:37:40_2013', 'Thu_Jul__4_01:53:32_2013', 'Mon_Jul__1_10:05:55_2013','Mon_Jul__1_04:15:25_2013']# list may increase
female=[16, 11, 16, 12, 12, 11] # list may increase
Please examine carefully what has changed.
4.) The bar command you try to call has not enough input arguments. With the changed data from above, try this:
ax1.bar(range(len(time)),male,width=0.5, color='red', edgecolor='black')
ax1.bar(range(len(time)),female,width=0.5,bottom=male,color='blue', edgecolor='black')
What has changed?
you need the following inputs: left, height, width=0.8
you had only one of those
due to the fact that your dates are given as strings, you need a generic counter for the x-axis, hence the range(len(time)) to provide as many tics as there are entries in time.
now, you specify the height according to the values in male and female - none of which should be strings!
define a width
in your case, you want the bars to be stacked - therefore, specify the first set of values as bottom for the second
4.) Because time is made up of strings, you cannot use it for the ticks. Instead, try:
ax1.set_xticklabels(time,rotation=90)
Here, you use the strings from time as tick-labels. The rotation=90 is a nice feature so that the long strings do not overlap.
5.) If the labels are cut off by the plot window, try this:
plt.tight_layout()
plt.show()
This should get you back on track.
Good key words for a web-search inlcude:
matplotlib stacked bar
matplotlib tick labels rotation
matplotlib ticks date

Matching dendrogram with cluster number in Python's scipy.cluster.hierarchy

The following code generates a simple hierarchical cluster dendrogram with 10 leaf nodes:
import scipy
import scipy.cluster.hierarchy as sch
import matplotlib.pylab as plt
X = scipy.randn(10,2)
d = sch.distance.pdist(X)
Z= sch.linkage(d,method='complete')
P =sch.dendrogram(Z)
plt.show()
I generate three flat clusters like so:
T = sch.fcluster(Z, 3, 'maxclust')
# array([3, 1, 1, 2, 2, 2, 2, 2, 1, 2])
However, I'd like to see the cluster labels 1,2,3 on the dendrogram. It's easy for me to visualize with just 10 leaf nodes and three clusters, but when I have 1000 nodes and 10 clusters, I can't see what's going on.
How do I show the cluster numbers on the dendrogram? I'm open to other packages. Thanks.
Here is a solution that appropriately colors the clusters and labels the leaves of the dendrogram with the appropriate cluster name (leaves are labeled: 'point number, cluster number'). These techniques can be used independently or together. I modified your original example to include both:
import scipy
import scipy.cluster.hierarchy as sch
import matplotlib.pylab as plt
n=10
k=3
X = scipy.randn(n,2)
d = sch.distance.pdist(X)
Z= sch.linkage(d,method='complete')
T = sch.fcluster(Z, k, 'maxclust')
# calculate labels
labels=list('' for i in range(n))
for i in range(n):
labels[i]=str(i)+ ',' + str(T[i])
# calculate color threshold
ct=Z[-(k-1),2]
#plot
P =sch.dendrogram(Z,labels=labels,color_threshold=ct)
plt.show()