Plot colours in custom function (matplotlib) - python

I am attempting to write a function that can plot a best fit curve and its original data points. I would ideally like to run the function for 4-5 data sets and have them all appear on the same figure. The function I have at the moment does this well for plotting the best fit curve, but when I add in the individual data points they show up as a different colour to the best fit curve.
I would like them both to be the same colour so that when I run the function 4-5 times it is not too messy with 10 or so different colours. Ideally I would like the output to be like this
My code:
def plot(k, w, lab):
popt, pcov = cf(linfunc, np.log(k), np.log(w))
yfit = linfunc(np.log(k), *popt)
plt.plot(np.log(k), yfit, '-', label = lab)
plt.plot(np.log(k), np.log(w), 'o')
plt.legend();
plot(k2ml, w2ml, '2ml')
Additionally, is there a way that I could make my function take any input for the parameter "lab" and have it automatically converted to a string so it can be used in the legend?

So what You want is to plot line and it's fit in the same colors.
To achieve Your goal, You can plot first line, get it's color and then set this color to the fit line.
Here is small code snippet doing that:
# Plot first line and get list of plotted lines
lines = plt.plot([0,1,2,3,4], [5,6,7,8,9])
# Get color of first (and only) line
line_color = lines[0].get_color()
# Plot Your fit with same color parameter
plt.plot([0,1,2,3,4], [0,1,2,3,4], color=line_color)
As for label, I would just convert it into string with str(lab).

Related

Python matplotlib: legend gives wrong result for scatter

I'm trying to visualize fashion MNIST dataset with different dimensional reduction techniques and I also want to attach the legend to resulted picture with so called real_labels which tells the real name of the label. For fashion MNIST real labels are:
real_labels = ['t-shirt','trouser','pullover','dress','coat','sandal','shirt','sneaker','bag','ankle boot']
I'm doing the plotting part inside of following fucntion:
def Draw_datasamples_to_figure(X_scaled, labels, axis):
y = ['${}$'.format(i) for i in labels]
num_cls = len(list(set(labels)))
for (X_plot, Y_plot, y1, label1) in zip(X_scaled[:,0], X_scaled[:,1], y, labels):
axis.scatter(X_plot, Y_plot, color=cm.gnuplot(int(label1)/num_cls),label=y1, marker=y1, s=60)
, where X_scaled tells x and y coordinate, labels are integer numbers (0-9) for class information and axis tells in which subplot window picture will be drawn.
The legend is drawn with following command:
ax3.legend(real_labels, loc='center left', bbox_to_anchor=(1, 0.5))
Everything seems to work pretty well until the legend is drawn to picture. As you can see from picture in below, instead of numbers goes from 0 to 9, the chosen numbers in legend are arbitrary.
I know that the problem is probably in scatter part and I should implement it in another way but I hope that there is still something simple that I miss which can fix my implementation. I don't want either to use hand-made legend in where markers and names are defined in the code because I have also other datasets with different classes and real label names. Thanks in advance!

Matplotlib 2.02 plotting within a for loop

I am having trouble with two things on a plot I am generating within a for loop, my code loads some data in, fits it to a function using curve_fit and then plots measured data and the fit on the same plot for 5 different sets of measured y value (the measured data is represent by empty circle markers and fit by a solid line as the same color as the marker)
Firstly I am struggling to reduce the linewidth of the fit (solid line) however much I reduce the float value of linewidth, I can increase the size just not decrease it by the value displayed in the output below. Secondly I would like the legend to display only circle markers not circles with lines through - I cannot seem to get this to work, any ideas?
Here is my code and attached is the output plot and data file on google drive share link (for some reason it's cutting off long lines of text on this post):
import scipy
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
#define vogel-fulcher-tamman (VFT) function
def vft(x,sigma_0,temp_vf,D):
return np.log(sigma_0)-((D*temp_vf)/(x-temp_vf))
#load and sort data
data=np.genfromtxt('data file',skip_header=3)
temp=data[:,0]
inverse_temp=data[:,1]
dc_conduct=np.log10(data[:,2:11])
only_adam=dc_conduct[:,4:9]
colors = ['b','g','r','c','m']
labels = ['50mg 2-adam','300mg 2-adam','100 mg 2-adam','150 mg 2-adam','250mg
2-adam']
for i in range(0,len(only_adam)):
#fit VTF function
y=only_adam[:,i]
popt, pcov = curve_fit(vft,temp,y)
#plotting
plt.plot(inverse_temp,y,color=colors[i],marker='o',markerfacecolor='none',
label=labels[i])
plt.plot(inverse_temp,vft(temp, *popt),linewidth=0.00001,linestyle='-
',color=colors[i])
plt.ylabel("Ionic Conductivity [Scm**2/mol]")
plt.xlabel("1000 / [T(K)]")
plt.axis('tight')
plt.legend(loc='lower left')
You are looping over the rows of only_adam, but index the columns of that array with the loop variable i. This does not make sense and leads to the error shown.
The plot that shows the data points has lines in it. Those are the lines shown. You cannot make them smaller by decreasing the other plot's linewidth. Instead you need to set the linestyle of that plot off, e.g. plot(..., ls="")

Matplotlib Color Gradient based on y-value

I would like to plot a "cut" through a heat map, i.e. apply a color gradient to my plt.plot(x,y) based on the y-values (which are in a range of -0.5,0.5.
Any suggestions? I tried to workaround by using a scatter-plot, but the colormap seemed to be applied to each line individually (and not globally).
Thanks!
EDIT
To describe it in other terms: I would like to map each y-value in the interval to an appropriate color in my colormap. (The phrase 'cut through heat map' just refers to the commonly used technique to map the z-values of a function z=f(x,y) for given x and y to a color.)
As mentioned earlier already, just applying a colormap to a scatter-plot seems to to map the maximum y-value of each line (as i am plotting multiple series) to white, as seen in the attachment. Instead, I would like to map the global y=0.5 in my plot to white and -0.5 to black for each line.
Turns out i needed to normalize my colormap by using
norm = colors.Normalize(vmin=-min, vmax=max)
and then call plt.scatter(x, y, c=y, norm=norm, …).

Matplotlib contour map colorbar

I am plotting my data into a contour map. The computations work on the translated values, so I need to put it back to its original value. On the fourth line of the code, is the re-translation process.
However, when I plotted it the colorbar shows the relative values, and just a note of the shift value at the top of the color bar. It is just weird that I checked the matrix values, and it contains the original values.
How can I show the colorbar, with the original values displayed?
fig=plt.figure()
v=np.linspace(-180,180,25)
x,y = np.meshgrid(v,v)
z = np.add(z,-shift)
z = z.reshape(25,25).T
plt.contourf(x,y,z,25)
fig.suptitle(AA(prefix)+' Input Data Contour Map')
plt.xlabel('$\phi$ (deg)')
plt.ylabel('$\psi$ (deg)')
plt.xticks(np.arange(-180, 181, 30))
plt.yticks(np.arange(-180, 181, 30))
plt.colorbar()
UPDATE: I used set_ticklabels() for a temporary fix, where labels is a list of custom labels.
But I am still looking for a better way to solve this problem.
plt.colorbar().set_ticklabels(labels)
updated contour map
Matplotlib doesn't know about your shift variable. It is choosing to plot it that way because the changes you are trying to visualize are 10^(-6) of the background value.
You can force the colorbar to have tick marks at specific locations as they do in this pylab example using:
cbar = fig.colorbar(cax, ticks=[-1, 0, 1])
cbar.ax.set_yticklabels(['< -1', '0', '> 1']) # vertically oriented colorbar
However, doing so will make the scale very difficult to read.

Matplotlib markers which plot and render fast

I'm using matplotlib to plot 5 sets of approx. 400,000 data points each. Although each set of points is plotted in a different color, I need different markers for people reading the graph on black and white print-outs. The issue I'm facing is that almost all of the possible markers available in the documentation at http://matplotlib.org/api/markers_api.html take too much time to plot and render while displaying. I could only find two markers which plot and render quickly, these are '-' and '--'. Here's my code:
plt.plot(series1,'--',label='Label 1',lw=5)
plt.plot(series2,'-',label='Label 2',lw=5)
plt.plot(series3,'^',label='Label 3',lw=5)
plt.plot(series4,'*',label='Label 4',lw=5)
plt.plot(series5,'_',label='Label 5',lw=5)
I tried multiple markers. Series 1 and series 2 plot quickly and render in no time. But series 3, 4, and 5 take forever to plot and AGES to display.
I'm not able to figure out the reason behind this. Does someone know of more markers that plot and render quickly?
The first two ('--' and '-') are linestyles not markers. Thats why they are rendered faster.
It doesn't make sense to plot ~400,000 markers. You wont be able to see all of them... However, what you could do is to only plot a subset of the points.
So add the line with all your data (even though you could probably also subsample that too) and then add a second "line" with only the markers.
for that you need an "x" vectors, which you can subsample too:
# define the number of markers you want
nrmarkers = 100
# define a x-vector
x = np.arange(len(series3))
# calculate the subsampling step size
subsample = int(len(series3) / nrmarkers)
# plot the line
plt.plot(x, series3, color='g', label='Label 3', lw=5)
# plot the markers (using every `subsample`-th data point)
plt.plot(x[::subsample], series3[::subsample], color='g',
lw=5, linestyle='', marker='*')
# similar procedure for series4 and series5
Note: The code is written from scratch and not tested

Categories