problem plotting on logscale in matplotlib in python - python

I am trying to plot the following numbers on a log scale as a scatter plot in matplotlib. Both the quantities on the x and y axes have very different scales, and one of the variables has a huge dynamic range (nearly 0 to 12 million roughly) while the other is between nearly 0 and 2. I think it might be good to plot both on a log scale.
I tried the following, for a subset of the values of the two variables:
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 1, 1)
ax.set_yscale('log')
ax.set_xscale('log')
plt.scatter([1.341, 0.1034, 0.6076, 1.4278, 0.0374],
[0.37, 0.12, 0.22, 0.4, 0.08])
The x-axes appear log scaled but the points do not appear -- only two points appear. Any idea how to fix this? Also, how can I make this log scale appear on a square axes, so that the correlation between the two variables can be interpreted from the scatter plot?
thanks.

I don't know why you only get those two points. For this case, you can manually adjust the limits to make sure all your points fit. I ran:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 8)) # You were missing the =
ax = fig.add_subplot(1, 1, 1)
ax.set_yscale('log')
ax.set_xscale('log')
plt.scatter([1.341, 0.1034, 0.6076, 1.4278, 0.0374],
[0.37, 0.12, 0.22, 0.4, 0.08])
plt.xlim(0.01, 10) # Fix the x limits to fit all the points
plt.show()
I'm not sure I understand understand what "Also, how can I make this log scale appear on a square axes, so that the correlation between the two variables can be interpreted from the scatter plot?" means. Perhaps someone else will understand, or maybe you can clarify?

You can also just do,
plt.loglog([1.341, 0.1034, 0.6076, 1.4278, 0.0374],
[0.37, 0.12, 0.22, 0.4, 0.08], 'o')
This produces the plot you want with properly scaled axes, though it doesn't have all the flexibility of a true scatter plot.

Related

Tight curves in a plot in python

I have four curves to plot in Python, each one corresponds to a certain value of a parameter γ. As one may see in the figure, the four curves are really tight with almost no distinction between them. I would like to do a plot as the one in the figure and to add a subplot inside where the difference of the lines could be seen.
I tried reducing the scales but it looks impossible.
Is there a in-built way in matplotlib to see these differences?
Here is a csv file with the values of each curve!
Well, thanks to #JohanC I found a walk around solution on https://matplotlib.org/3.3.1/gallery/subplots_axes_and_figures/zoom_inset_axes.html
dataframe = pd.read_csv('z_curves.csv')
fig, ax = plt.subplots()
r=dataframe['rad']
z_2=dataframe['z_2']
z_4=dataframe['z_4']
z_6=dataframe['z_6']
z_8=dataframe['z_8']
ax.plot(r,z_2,"k")
ax.plot(r,z_4,"k--")
ax.plot(r,z_6,"k:")
ax.plot(r,z_8,"k-.")
ax.plot(r,[0.0 for i in range(len(r))],"g--")
ax.set_xlabel('$r/r_c$',fontsize=20)
ax.set_ylabel('$e^{\\nu(r)}-1$',fontsize=20)
plt.xlim(0.0,1.0)
plt.ylim(-0.000001,0.0000001)
targets = ["$\gamma=0.2$", "$\gamma=0.4$", "$\gamma=0.6$", "$\gamma=0.8$"]
legend = plt.legend(targets,loc='best', shadow=True)
legend.get_frame().set_facecolor('white')
axins = ax.inset_axes([0.4, 0.4, 0.4, 0.4])
x1, x2, y1, y2 = 0.2, 0.201, -5.5634547184309856e-08, -5.5606744002038696e-08
axins.set_xlim(x1, x2-0.0008)
axins.plot(r,z_2,"k")
axins.plot(r,z_4,"k--")
axins.plot(r,z_6,"k:")
axins.plot(r,z_8,"k-.")
axins.set_ylim(y1, y2)
axins.set_xticklabels('')
axins.set_yticklabels('')
ax.indicate_inset_zoom(axins)
plt.show()

How to reduce major tick spacing on a matplotlib logarithmic plot

I would like to change the major tick label spacing to intervals of 0.1 (base 0.1) and have minor ticks (without labels) at 0.01 spacing for the code below (output shown in 1.
x = np.array([1, 5, 10, 32])
y = np.array([0.34, 0.27, 0.25, 0.21])
yerr = np.array([0.02, 0.019, 0.019, 0.016])
fig, ax = plt.subplots()
res = ax.errorbar(x, y, yerr=yerr, fmt='.', ls='')
ax.set_xscale('log')
ax.set_yscale('log')
I've tried to do
import matplotlib.ticker as mtick
ax.yaxis.set_major_locator(mtick.LogLocator(base=0.01))
however nothing changes, which makes me think the base can not be less than 10.
SOLUTION: Thanks ImportanceOfBeingErnest for the advice. My solution is to add this:
import matplotlib.ticker as mtick
ax.yaxis.set_major_locator(mtick.LogLocator(base=10, subs=range(10)))
ax.yaxis.set_minor_locator(mtick.LogLocator(base=10, subs=range(100)))
plt.setp(ax.get_yminorticklabels(), visible=False);
EDIT: OK, the reasoning behind this is wrong ( & I misundertood the question)
This would add equidistant space between the ticks, definitely not you were asking.
plt.grid("on") # Just to see the spacing more clearly
ax.yaxis.set_major_locator(mtick.LogLocator(base=10**(1.0/1)))
ax.yaxis.set_minor_locator(mtick.LogLocator(base=10**(1.0/10)))
(asuming 10 is the base of the log scale you're using and the fraction is how many more (or less) lines you want.
I did not understand how the decimal values in the 'base' variable work when using logarithmic scale.
Well, since you're working in logarithmic values ... that 'spacing' shouldn't be 1 or less. (using 1 you get an error) if you want to reduce spacing, just use a value between less than 10 (but more than 1).
In fact, using the line:
plt.grid("on") # Just to see the spacing more clearly
ax.yaxis.set_major_locator(mtick.LogLocator(base=10**(1/10)))
you get a tenth of a spacing than before.
It's all in how the vertical axes is computed when using the logarithmic scale.

Create Square Subplots in Matplotlib

I want to create square subplots which are publication quality using Matplotlib. Currently, I have 2 subplots which are made in a figure of size 8,5 and the X limits for both plots are different.
I would want both the subplots to be of square size rather than the Y axis being taller. Any suggestions ?
Alternatively, is there a way where I can explicitly control the ratio of width and height of a subplot in matplotlib?
Below is the sample image which I have right now.
You can explicitly control the figure size, and you can explicitly set the axes' positions within a figure, as a fraction of the figure size.
fig = plt.figure(figsize=(8,4))
ax1 = fig.add_axes([0.1, 0.1, 0.4, 0.8])
ax1.plot(...)
ax2 = fig.add_axes([0.5, 0.1, 0.4, 0.8])
ax2.plot(...)
In addition, you can supply aspect='equal' to functions that create axes (add_axes, add_subplot) to force the axes shape to match the axes scales (not relevant for your linear-log plot).

Plotting ordinal data with a marker in matplotlib

I have some data for which I have experimental and simulated values, the data isn't really continuous without introducing a new definition (which I don't want to do) so I wish to display it ordinally in a scatter type plot with two markers for each set and then label each set on the X-axis.
Basically I can't figure out how to do this with matplotlib (I'd prefer to use it for consistency with how I've presented other data).
An example of the data is presented below:
1cm square: 0.501, 0.505
1cm circle: 0.450, 0.448
1cm X 2cm rect: 0.665, 0.641
I may be misunderstanding the question, but it sounds like you're wanting something along these lines:
import matplotlib.pyplot as plt
# Using this layout to make the grouping clear
data = [('apples', [0.1, 0.25]),
('oranges', [0.6, 0.35]),
('pears', [0.1, 0.18]),
('bananas', [0.7, 0.98]),
('peaches', [0.6, 0.48])]
# Reorganize our data a bit
names = [item[0] for item in data]
predicted = [item[1][0] for item in data]
observed = [item[1][1] for item in data]
# It might make more sense to use a bar chart in this case.
# You could also use `ax.scatter` to plot the data instead of `ax.plot`
fig, ax = plt.subplots()
ax.plot(predicted, color='lightblue', marker='o', linestyle='none',
markersize=12, label='Predicted')
ax.plot(observed, color='red', marker='s', linestyle='none',
markersize=12, label='Observed')
ax.margins(0.05)
ax.set(xticks=range(len(names)), xticklabels=names, ylabel='Meaningless')
ax.legend(loc='best', numpoints=1)
ax.grid(axis='x')
plt.show()
The key part is setting the xticks and xticklabels to correspond to your data "groups". You could plot the data in a few other ways (e.g. bar plots, etc), but using the xticks/labels will be the same in each case.

boxplots with not-in-scale y-axis

I have some data I want to box plot. Outliers (e.g. 20, 30) are too far away from most values (e.g. 0.0002, 0.0003) and as a consequence I can only see outliers when I plot with matplotlib.
Is there anyway to zoom in the values around the median and then let the rest of the y-axis not be in scale and display outliers too?
EDIT
Here's my code in python. I would like to use inset axes, as suggested below, for each box plot I have. How can I do this in an easy way? There seems to be way too many parameters to take care of from the examples in the documentation.
plt.figure()
ax = plt.subplot(111)
plt.boxplot(dataToPlot)
axins = zoomed_inset_axes(ax, 6, loc=1) # zoom = 6
# what follows is taken from example linked in the answer below.
# I didn't get if the first argument is indeed the data this zoomed image refers to or not.
axins.imshow(dataToPlot[1], interpolation="nearest", origin="lower")
# here I only need the y-axis to be in [0,0.1], x-axis is no of use with vertical boxplots
x1, x2, y1, y2 = -1.5, -0.9, 0.0, 0.1
axins.set_xlim(x1, x2)
axins.set_ylim(y1, y2)
plt.xticks(visible=True)
plt.yticks(visible=True)
plt.savefig( 'somewhere.jpeg', bbox_inches=0)
You could do an inset axes as described on this page, about 1/2 way down.
inset axes
Very old question, but I came across this looking for something similar. I solved this by adding sym='' (this option may have not existed 7 years ago!) which tells boxplot not to show fliers (anything past the whiskers).
So for anyone else who comes across this, you might try changing line 3 in the question to:
plt.boxplot(dataToPlot, sym='')

Categories

Resources