1D plot matplotlib - python

I would like to plot in a single line ticks according to an array (up to 1000 elements). I would rather not to use something like:
plt.xticks(energies[i][j])
because each sample value is written up below tick. I have looked extensively at Matplotlib documentation but didn't find nothing besides hist(). If you guys know other way to visualize 1D arrays into a single line I would very much appreciate, especially if it involves colors representing density of values.
I'm using Spyder 2.2.5, Python 2.7.6 | 64-bit in OSX 10.7.4

Edit
As #tcaswell mentions in comments, eventplot is a good way to do this. Here is an example:
from matplotlib import pyplot as plt
import numpy as np
plt.figure()
a = [1,2,5,6,9,11,15,17,18]
plt.hlines(1,1,20) # Draw a horizontal line
plt.eventplot(a, orientation='horizontal', colors='b')
plt.axis('off')
plt.show()
Or you can use vertical line markers? The example below has the basic idea. You could change the color of the markers to represent density.
from matplotlib import pyplot as plt
import numpy as np
a = [1,2,5,6,9,11,15,17,18]
plt.hlines(1,1,20) # Draw a horizontal line
plt.xlim(0,21)
plt.ylim(0.5,1.5)
y = np.ones(np.shape(a)) # Make all y values the same
plt.plot(a,y,'|',ms = 40) # Plot a line at each location specified in a
plt.axis('off')
plt.show()

Related

Displaying minor grid lines for wide x axis ranges (log)

I noticed a 'strange' behaviour when running the following code:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import (MultipleLocator, AutoMinorLocator)
freqs = np.logspace(2,4)
freqs_ext = np.logspace(2, 10)
fig, ax = plt.subplots(1,2)
ax [0].plot(freqs , freqs**2)
#ax[0].xaxis.set_minor_locator(AutoMinorLocator(5))
ax[0].grid(which='both')
#ax[0].minorticks_on()
ax[0].set_xscale( 'log')
ax[1].plot(freqs_ext,freqs_ext**2)
#ax[l].xaxis.set_minor_locator(AutoMinorLocator(5))
ax[1].grid(which='both')
#ax[1].minorticks on()
ax[1].set_xscale('log')
The output is the following:
I have tried more variants than I care to report, (some are commented out in the code above), but I cannot get matplotlib to draw minor gridlines for the plot on the right side, as it does for the one on the left.
I think I have understood that the "problem" lies in where the ticks are located for the second plot, which has a much larger span. They are every two decades and I believe this might be the source of the minor grid lines not displaying.
I have played with xaxis.set_xticks and obtained ticks every decade, but still cannot get this to correctly produce the gridlines.
It is probably something stupid but I can't see it.
NOTE : I know that matplotlib doesn't turn the minor ticks on by default, and in this case this action is "triggered" by changing the scale to log (that's why axis.grid(which='both') actually only acts on the x axis)
OK, I have found this answer:
Matplotlib: strange double-decade axis ticks in log plot
which actually shows how the issue is a design choice for matplotlib starting with v2. Answer was given in 2017 so, not the newest issue :)
The following code correctly plots the minor grids as wanted:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import LogLocator
freqs = np.logspace(2,4)
freqs_ext = np.logspace(2, 10)
fig, ax = plt.subplots(1,2)
ax[0].plot(freqs , freqs**2)
ax[0].grid(which='both')
ax[0].set_xscale( 'log')
ax[1].plot(freqs_ext,freqs_ext**2)
ax[1].set_xscale('log')
ax[1].xaxis.set_major_locator(LogLocator(numticks=15))
ax[1].xaxis.set_minor_locator(LogLocator(numticks=15,subs=np.arange(2,10)))
ax[1].grid(which='both')

Using markevery kwarg with axhline

I was trying to plot a vertical line with markers on it using ax.axvline but the markers only show up on the bottom and top of the figure. I have played around with the markevery kwarg but it does not seem to have any effect when I change it even though it works for a normal line plot. Does anyone know if this is because no discrete values are specified along the axis or am I just doing something wrong?
I realize that I can plot a vertical line on my own and specify the markers, but I figure given the purpose of axvline I should use it.
Here is an example code of what I am talking about:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-10,10)
y = x**2-15.
fig = plt.figure(figsize=(4,4))
ax = plt.subplot(111)
ax.plot(y,x) #Test curve
ax.plot(2+np.zeros(len(x)),x,marker='X',markevery=1) #another way to plot what I want.
ax.axvline(0,c='r',marker='X',markevery=1) #markerevery doesn't seem to work
plt.show()
As mentioned by ImportanceofBeingErnest, the markereverykwarg does not apply for axvline or axhline because there are technically only 2 points used to draw the line at the boundaries.

How to ensure even spacing between labels on x axis of matplotlib graph?

I have been given a data for which I need to find a histogram. So I used pandas hist() function and plot it using matplotlib. The code runs on a remote server so I cannot directly see it and hence I save the image. Here is what the image looks like
Here is my code below
import matplotlib.pyplot as plt
df_hist = pd.DataFrame(np.array(raw_data)).hist(bins=5) // raw_data is the data supplied to me
plt.savefig('/path/to/file.png')
plt.close()
As you can see the x axis labels are overlapping. So I used this function plt.tight_layout() like so
import matplotlib.pyplot as plt
df_hist = pd.DataFrame(np.array(raw_data)).hist(bins=5)
plt.tight_layout()
plt.savefig('/path/to/file.png')
plt.close()
There is some improvement now
But still the labels are too close. Is there a way to ensure the labels do not touch each other and there is fair spacing between them? Also I want to resize the image to make it smaller.
I checked the documentation here https://matplotlib.org/api/_as_gen/matplotlib.pyplot.savefig.html but not sure which parameter to use for savefig.
Since raw_data is not already a pandas dataframe there's no need to turn it into one to do the plotting. Instead you can plot directly with matplotlib.
There are many different ways to achieve what you'd like. I'll start by setting up some data which looks similar to yours:
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gamma
raw_data = gamma.rvs(a=1, scale=1e6, size=100)
If we go ahead and use matplotlib to create the histogram we may find the xticks too close together:
fig, ax = plt.subplots(1, 1, figsize=[5, 3])
ax.hist(raw_data, bins=5)
fig.tight_layout()
The xticks are hard to read with all the zeros, regardless of spacing. So, one thing you may wish to do would be to use scientific formatting. This makes the x-axis much easier to interpret:
ax.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
Another option, without using scientific formatting would be to rotate the ticks (as mentioned in the comments):
ax.tick_params(axis='x', rotation=45)
fig.tight_layout()
Finally, you also mentioned altering the size of the image. Note that this is best done when the figure is initialised. You can set the size of the figure with the figsize argument. The following would create a figure 5" wide and 3" in height:
fig, ax = plt.subplots(1, 1, figsize=[5, 3])
I think the two best fixes were mentioned by Pam in the comments.
You can rotate the labels with
plt.xticks(rotation=45
For more information, look here: Rotate axis text in python matplotlib
The real problem is too many zeros that don't provide any extra info. Numpy arrays are pretty easy to work with, so pd.DataFrame(np.array(raw_data)/1000).hist(bins=5) should get rid of three zeros off of both axes. Then just add a 'kilo' in the axes labels.
To change the size of the graph use rcParams.
from matplotlib import rcParams
rcParams['figure.figsize'] = 7, 5.75 #the numbers are the dimensions

Using an image for tick labels in matplotlib [duplicate]

This question already has answers here:
How can I make the xtick labels of a plot be simple drawings using matplotlib?
(2 answers)
Closed 5 years ago.
I have a series of small, fixed width images and I want to replace the tick labels with them. For example, consider the following minimal working example:
import numpy as np
import pylab as plt
A = np.random.random(size=(5,5))
fig, ax = plt.subplots(1, 1)
ax.matshow(A)
plt.show()
I would like to replace the "0" with a custom image. I can turn off the labels, load an image into an array and display it just fine. However, I'm unsure of
Where the locations of the tick labels are, since they lie outside the plot.
Use imshow to display that image when it it will be "clipped" if put into an axis.
My thought were to use set_clip_on somehow or a custom artist, but I haven't made much progress.
Interesting question, and potentially has many possible solutions. Here is my approach, basically first calculate where the label '0' is, then draw a new axis there using absolute coordinates, and finally put the image there:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import pylab as pl
A = np.random.random(size=(5,5))
fig, ax = plt.subplots(1, 1)
xl, yl, xh, yh=np.array(ax.get_position()).ravel()
w=xh-xl
h=yh-yl
xp=xl+w*0.1 #if replace '0' label, can also be calculated systematically using xlim()
size=0.05
img=mpimg.imread('microblog.png')
ax.matshow(A)
ax1=fig.add_axes([xp-size*0.5, yh, size, size])
ax1.axison = False
imgplot = ax1.imshow(img,transform=ax.transAxes)
plt.savefig('temp.png')

Enlarging plot in mplot3D

I'm trying to compose an image with both 2D and 3D plot. so far I've done the following:
import idlsave
import matplotlib
from matplotlib import *
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from matplotlib import rc
rc('font',**{'family':'sans-serif','sans-serif':['Helvetica']})
fig = plt.figure(figsize=(18,5))
ax = fig.add_subplot(1,3,1, projection='3d',azim=-133,elev=14)
l = ax.plot3D(X3D,Y3D,Z3D,lw=2,color='red')
ax.set_xlim3d(-10,10)
ax.set_ylim3d(-10,10)
ax.set_zlim3d(-10,10)
ax.text(-2,-7,-11,'b$_r$ [mT]','x')
ax.text(-5,-1,-11,'b$_p$ [mT]','y')
ax.set_zlabel(r'b$_t$ [mT]')
ax.plot([bEq[0],-bEq[0]],[bEq[1],-bEq[1]],[bEq[2],-bEq[2]],'b--',lw=2)
ax.plot([pLe[0],-pLe[0]],[pLe[1],-pLe[1]],[pLe[2],-pLe[2]],color='black',lw=2)
ax.text(3,12,9.2,'(a)', fontsize=14)
ax = fig.add_subplot(1,3,2)
l = ax.plot(br,bp,'k-',lw=2)
ax.set_xlabel(r'b$_{\lambda_1}$ [mT]')
ax.set_ylabel(r'b$_{\lambda_2}$ [mT]')
ax.set_xlim(-2,6.3)
ax.set_ylim(-5.5,5.5)
ax.plot([0,0],[-5.5,5.5],'k-.')
ax.plot([-2,6.3],[0,0],'k-.')
e=Ellipse((pf[2],pf[3]),2*pf[0],2*pf[1],- pf[4]*57.2958,fc='none',lw=2,ls='dashed',ec='red')
ax.add_artist(e)
ax.text(-1,4, '(b)', fontsize=14)
ax = fig.add_subplot(1,3,3)
ax.plot(-bxDip,-byDip,'b-',lw=2,label='$\mathcal{D}$')
ax.plot(-bxMon,-byMon,'r-',lw=2,label='$\mathcal{M}$')
ax.set_xlabel(r'b$_{\lambda_1}$')
ax.set_ylabel(r'b$_{\lambda_2}$')
ax.set_xlim(-4,12)
ax.set_ylim(-6,7)
ax.plot([-4,12],[0,0],'k-.')
ax.plot([0,0],[-6,7],'k-.')
ax.legend(loc='upper right')
ax.text(-3,5.5, '(c)', fontsize=14)
plt.savefig("../pdf_box/fig3.pdf",bbox_inches='tight')
Wit the present code I was able to produce the figure reported here http://img219.imageshack.us/i/fig3e.png/
There are two question which puzzle me.
1) As you can see the 3D plot is smaller than the other two and there is enough white spaces between the subplots to increase the size. How can I do this? i.e. How can I enlarge the size of one subplot, eventually decreasing the other two?
2) I would like to exclude the grey background in the 3D plot.
Any help is very welcomed.
Change ax.dist for the 3D plot. This will cause the rendered graphic to fill more of the subplot area. Here is a similar question. You may find some more info there.
You may also want to adjust the widths of the subplots with respect to each other (increase the width of the 3d plot and shrink the 2D plots. This can be accomplished with subplots_adjust

Categories