I used pp.yscale('log') in my python script to plot a figure with y ticks shown in log scale. However, in the figure, the y axis does not appear. Is there any way to explicitly show y axis in python?
...
leg = pp.legend( series_labels, loc='upper right' )
pp.axis([-0.5, x_len-0.5, 0, max_y*1.1])
configurable_xlabel = x_label + '(unit)'
pp.xlabel(configurable_xlabel)
configurable_ylabel = metrics[metric_idx] + '(unit)'
pp.ylabel(configurable_ylabel)
configurable_scaling = 2
xticklabels = []
for idx in xrange(0,x_len):
if idx % configurable_scaling == 0:
xticklabels.append(x_data[idx])
else:
xticklabels.append('');
pp.axes().set_xticks(xrange(0,x_len));
pp.axes().set_xticklabels(xticklabels[0:len(xticklabels)])
pp.yscale('log')
...
I suggested on a duplicate of this question that it might be due to logarithmic scales having no 0 and suggested further that one might be able to move the axis to another number. I have no way to check this but Richard stated that this is a solution. I hope it is :-}
Related
I have a plot that I have made which has two different categories that is subdvided into three different groups. I have made calculations of the mean and median for each of these groups, but when I try to add annotate the figures with these numbers, they end up printing on top of each other, when I want each figure within the plot to be annotated with its respective mean and median.
So my code to make this plot currently looks like this:
fig = px.violin(CVs,
y="cv %",
x="group",
color="method",
box=True,
points=False,
hover_data=CVs.columns)
for i in CVs['method'].unique():
for j in CVs['group'].unique():
mean, median = np.round(CVs.loc[CVs['method']==i].agg({'cv %':['mean', 'median']}), 2)['cv %'].values
fig.add_annotation(x=j, y=0,
yshift=-65,
text="Mean: {}%".format(mean),
font=dict(size=10),
showarrow=False)
fig.add_annotation(x=j, y=0,
yshift=-75,
text="Median: {}%".format(median),
font=dict(size=10),
showarrow=False)
fig.update_traces(meanline_visible=True)
fig.update_layout(template='plotly_white', yaxis_zeroline=False, height=fig_height, width=fig_width)
iplot(fig)
From what I have read in the documentation (https://plotly.com/python/text-and-annotations/), it seems like you need indicate the coordinates of the added annotation using the parameters x and y.
I have tried to adhere to these parameters by setting y to 0 (since the y axis is numerical), and setting x to the pertinent group along the x axis (which is a categorical). However, as one can tell from the plot above, this doesn't seem to work. I have also tried setting x to a value that increments with each iteration of the for loop, but all the values I have tried (e.g. 1, 10, 0.1) haven't worked, the annotations keep printing on top of each other, just at different places along the x axis.
I want to have one set of annotations under each figure. Does anyone know how I can set this up?
Based on what you used (yshift) to adjust the annotation, I have done the same using xshift to move each of the labels below their respective plot. Note that you have fig_height and fig_width which was not provided, so I let plotly choose the size. You may need to adjust the offset a bit if figure is different. Hope this works.
CVs = px.data.tips() ##Used tips db
CVs.rename(columns={'sex': 'group', 'day':'method', 'total_bill': 'cv %'}, inplace=True) ##Replaced to names you have
CVs = CVs[CVs.method != 'Thur'] ##Removed one as there were 4 days in tips
fig = px.violin(CVs,
y="cv %",
x="group",
color="method",
box=True,
points=False,
hover_data=CVs.columns)
x_shift = -100 ##Start at -100 to the left of the j location
for i in CVs['method'].unique():
for j in CVs['group'].unique():
mean, median = np.round(CVs.loc[CVs['method']==i].agg({'cv %':['mean', 'median']}), 2)['cv %'].values
fig.add_annotation(x=j, y=0,
yshift=-65, xshift = x_shift,
text="Mean: {}%".format(mean),
font=dict(size=10),
showarrow=False)
fig.add_annotation(x=j, y=0,
yshift=-75, xshift = x_shift,
text="Median: {}%".format(median),
font=dict(size=10),
showarrow=False)
x_shift = x_shift + 100 ##After each entry (healthy/sick in your case), add 100
fig.update_traces(meanline_visible=True)
fig.update_layout(template='plotly_white', yaxis_zeroline=False)#, height=fig_height, width=fig_width)
#iplot(fig)
Plot
I want to visualize the Birthday Problem with different n. My aim is to plot multiple graphs in the same figure but it does not work. It only plots the last graph and ignores the others. I am using the Jupyter Notebook.
This is my Code:
from decimal import Decimal
def calc_p_distinct(n):
p_distinct = numpy.arange(0, n.size, dtype=Decimal)
for i in n:
p_distinct[i] = Decimal(1.0)
for i in n:
for person in range(i):
p_distinct[i] = Decimal(p_distinct[i]) * Decimal(((Decimal(365-person))/Decimal(365)))
return p_distinct
# n is the number of people
n = numpy.arange(0, 20)
n2 = numpy.arange(0, 50)
n3 = numpy.arange(0, 100)
# plot the probability distribution
p_distinct = calc_p_distinct(n)
pylab.plot(n, p_distinct, 'r')
p_distinct2 = calc_p_distinct(n2)
pylab.plot(n2, p_distinct2, 'g')
p_distinct3 = calc_p_distinct(n3)
pylab.plot(n3, p_distinct3, 'b')
# set the labels of the axis and title
pylab.xlabel("n", fontsize=18)
pylab.ylabel("probability", fontsize=18)
pylab.title("birthday problem", fontsize=20)
# show grid
pylab.grid(True)
# show the plot
pylab.show()
When I replace one of the calc_p_distinct() function calls with another built-in function (e.g. numpy.sin(n)), it will show me two graphs. So, I conclude that it must have something to do with my function. What am I doing wrong here?
This isn't a problem with matplotlib; all the lines are there, just on top of each other (which makes perfect sense; for 100 people, the probability for only the first 20 is the same as for a group of just 20 people).
If I quickly plot them with a different line width:
How can I use annotate() (or any other command for that matter) to add a second "ylabel" to the right of a figure which makes the text "scale" the same way as the other texts (axis x,y-label and title)? With scaling I mean that I don't want to hack text offsets manually or have a solution which fails as soon as I rescale the figure/add more plots/add a colorbar or similar. I don't want to use twinx, because I'm not plotting any additional data, and I don't need another axis.
Here's an image of what I want to achieve:
Here is my code to produce this image, I want to change the ax.annotate part:
import numpy as np
import matplotlib.pyplot as plt
numPlotsY = 3
numPlotsX = 3
f, ax_grid = plt.subplots(numPlotsY,numPlotsX,sharex=True,sharey=True)
A = np.arange(numPlotsY)+1.0 # Amplitude
phi = np.arange(numPlotsX) # Phase shift
x = np.linspace(0,2.0,100) # x
for y_i in range(0,numPlotsY):
for x_i in range(0,numPlotsX):
ax = ax_grid[y_i,x_i]
y = A[y_i]*np.sin(x*np.pi + phi[x_i])
ax.plot(x,y,lw=2.0)
# Add xlabel to the left column
if x_i == 0:
ax.set_ylabel(r'$y$')
ax.set_yticks([-4,-2,0,2,4])
# Add ylabel below bottom row
if y_i == numPlotsY-1:
ax.set_xlabel(r'$x/\pi$')
ax.set_xticks([0.5,1.0,1.5])
# Add Phi label above top row
if y_i == 0:
ax.set_title(r'$\phi=%s$' % phi[x_i])
# Add amplitude label to the right... how??
if x_i == numPlotsX-1:
ax.annotate(r'$A=%d$' % A[x_i], xy=(1.1,0.5), rotation=90,
ha='center',va='center',xycoords='axes fraction')
f.subplots_adjust(wspace=0,hspace=0)
plt.suptitle(r'$A\cdot\sin\left(2\pi x + \phi\right)$',fontsize=18)
plt.show()
I've seen this topic discussed several times without an elegant solution. There's always so much hacking involved. I really think this boils down to the way matplotlib treats the axes. Why can't there be one label for each of the four sides of the figure, that behave the same way?
Or more specifically, how can I change the [659] on the upper-right corner to '659 degrees' or something like that ?
I have checked all the threads mentioned in the following reply: matplotlib values under cursor. However, all of them seem to address the x,y location of the cursor. I am interested in changing the data-value. I could not find a reply or related documentation in the api.
I have tried both format_coord(x, y) and format_cursor_data(data) but neither of them seem to be working.
Thanks,
Sarith
PS: My code is in multiple modules and is a part of gui application. I can share relevant sections if that would be of any help in answering this.
One line solution:
ax.format_coord = lambda x, y: 'x={:.2f}, y={:.2f}, z={:.2f}'.format(x,y,data[int(y + 0.5),int(x + 0.5)])
I had the same problem (I wanted to get rid of the data and send it to somewhere else in a tkinter widget).
I figured out the ax.format_coord was'nt being called, the one you have to change is the one at matplotlib.artist.Artist
this worked for me:
def format_cursor_data(self,data):
return 'new_data'
matplotlib.artist.Artist.format_cursor_data=format_cursor_data
By modifying an example from matplotlib I got this code:
This displays x,y, and z value with a degrees after z.
You should be able to easily modify it, or copy the relevant functions to make it work on your side.
You said you already tried format_coord, maybe you forgot to set the funtion? (second last line)
"""
Show how to modify the coordinate formatter to report the image "z"
value of the nearest pixel given x and y
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
X = 10*np.random.rand(5, 3)
fig, ax = plt.subplots()
ax.imshow(X, cmap=cm.jet, interpolation='nearest')
numrows, numcols = X.shape
def format_coord(x, y):
col = int(x + 0.5)
row = int(y + 0.5)
if col >= 0 and col < numcols and row >= 0 and row < numrows:
#get z from your data, given x and y
z = X[row, col]
#this only leaves two decimal points for readability
[x,y,z]=map("{0:.2f}".format,[x,y,z])
#change return string of x,y and z to whatever you want
return 'x='+str(x)+', y='+str(y)+', z='+str(z)+" degrees"
else:
return 'x=%1.4f, y=%1.4f' % (x, y)
#Set the function as the one used for display
ax.format_coord = format_coord
plt.show()
Emmm, Sarith, I am also facing the problem but a little trick helped me out. I still used this function:
your_imshow.format_coord = lambda x, y: 'x={:.5f}, y={:.2f}, amplitude='.format(x,y)
It pretends to add label before the bracket. Yeah, it is an easy but not essential way to change the presentation form, but it works to me. I hope this could also benefit others.
I had to create a contour graph (in python) based on a formula and several other parameters. My graph came out fine. However, my axis labels will not show. I have tried changing the code several times but I am actually a little lost as how to what my real problem is. I know it deals with the command to create the labels but understand the error message
Also, this is my first post and if you have recommendations for how I should ask questions, I would appreciate the help.
def contourf_plot():
T = np.linspace(0,30,50)
P = np.linspace(600,1000,50)
X, Y = np.meshgrid(T,P)
Z = (Y/100)*np.e**((12*X)/(X+243))
Z.shape
plt.figure()
CF = plt.contourf(T,P,Z,50)
plt.colorbar(CF)
plt.set_Tlabel("Temperature[$\degree$C]")
plt.set_Plabel("Pressure[Pa]")
plt.show()
return
if __name__ == "__main__":
contourf_plot()
Error message: 'module' object has no attribute 'set_Xlabel'
All you need to do is a slight change in your code. You are currently trying to add a label to the axes T and P, though they do not exist (it is still the x and y axes). T and P are just the data that you are trying to plot.
def contourf_plot():
T = np.linspace(0,30,50)
P = np.linspace(600,1000,50)
X, Y = np.meshgrid(T,P)
Z = (Y/100)*np.e**((12*X)/(X+243))
Z.shape
fig,ax = plt.subplots() #add this line
CF = plt.contourf(T,P,Z,50)
plt.colorbar(CF)
ax.set_xlabel("Temperature[$\degree$C]") #sets the x and y label
ax.set_ylabel("Pressure[Pa]")
plt.show()
return
if __name__ == "__main__":
contourf_plot()
This gives the image