Combining plt.plot(x,y) with plt.boxplot() - python

I'm trying to combine a normal matplotlib.pyplot plt.plot(x,y) with variable y as a function of variable x with a boxplot. However, I only want a boxplot on certain (variable) locations of x but this does not seem to work in matplotlib?

Are you wanting something like this? The positions kwarg to boxplot allows you to place the boxplots at arbitrary positions.
import matplotlib.pyplot as plt
import numpy as np
# Generate some data...
data = np.random.random((100, 5))
y = data.mean(axis=0)
x = np.random.random(y.size) * 10
x -= x.min()
x.sort()
# Plot a line between the means of each dataset
plt.plot(x, y, 'b-')
# Save the default tick positions, so we can reset them...
locs, labels = plt.xticks()
plt.boxplot(data, positions=x, notch=True)
# Reset the xtick locations.
plt.xticks(locs)
plt.show()

This is what has worked for me:
plot box-plot
get boxt-plot x-axis tick locations
use box-plot x-axis tick locations as x-axis values for the line plot
# Plot Box-plot
ax.boxplot(data, positions=x, notch=True)
# Get box-plot x-tick locations
locs=ax.get_xticks()
# Plot a line between the means of each dataset
# x-values = box-plot x-tick locations
# y-values = means
ax.plot(locs, y, 'b-')

Related

Show custom tick value in plot

Let's say I have made a plot, and in that plot there is a specific point where I draw vertical line from to the x-axis. This point has the x-value 33.55 for example. However, my tick separation is something like 10 or 20 from 0 to 100.
So basically: Is there a way in which I can add this single custom value to the tick axis, so it shows together with all the other values that where there before ?
Use np.append to add to the array of ticks:
import numpy as np
from matplotlib import pyplot as plt
x = np.random.rand(100) * 100
y = np.random.rand(100) * 100
fig, ax = plt.subplots(figsize=(8, 6))
ax.scatter(x, y)
ax.set_xticks(np.append(ax.get_xticks(), 33.55))
Note that if your plot is not big enough, the tick labels may overlap.
If you want the new tick to "clear its orbit", so to speak:
special_value = 33.55
black_hole_radius = 10
new_ticks = [value for value in ax.get_xticks() if abs(value - special_value) > black_hole_radius] + [special_value]
ax.set_xticks(new_ticks)

Remove tick labels but not tick marks but preserve distance beween ticks

I want to remove tick labels but keep the tick marks and keep my ticks consistently spaced. I have tried using both ax.tick_params(labelleft='off') and ax.set_yticks(np.arange(0,100,10), " ") but using either of these options rescales my y-axis, and I do not want this to happen.
a1 = plt.subplot(121, adjustable='box')
a1.plot(on[:,0], on[:, 1], linewidth=0, marker=markerz[i], color=kolor[i], ms=mymark)
a1.minorticks_on()
a1.set_yticks(np.arange(0,100,10))
a2 = plt.subplot(122, adjustable='box')
a2.plot(on[:,0], on[:, 1], linewidth=0, marker=markerz[i], color=kolor[i], ms=mymark)
a2.minorticks_on()
a2.tick_params(labelleft='off')
a2.set_yticks(np.arange(0,100,10))
This is what my plot actually looks like. I want certain subplots to share certain axes. I am trying to accomplish that by removing certain tick labels. I want to be able to remove tick labels without rescaling the tick spacing.
You can set empty ticks to your plots like this:
y_ind = np.arange(0,100,10)
plt.yticks(y_ind,['']*len(y_ind))
If you do not want your y-axis to be scaled again, then you can set the y-axis scale:
plt.ylim((y_ind[0],y_ind[-1]))
Here is an example:
import matplotlib.pyplot as plt
import numpy as np
d1 = np.random.rand(100)
d2 = np.random.rand(100)
plt.subplot(2,1,1)
plt.plot(d1)
plt.xticks(np.arange(0,110,10),['']*11)
plt.xlim((0,100))
plt.subplot(2,1,2)
plt.plot(d2)
plt.xticks(np.arange(0,110,10),['']*11)
plt.xlim((0,100))

Matplotlib xticks values irregular size

I am making a plot with matplotlib and I need irregular values for the xtick labels.
I know there is parameter size. However, I would like to have values on my x-axis that are two times greater than the values of the labels on the y-axis. With size parameter I can only change the font size of the values, but the actual numeric values will still be in proportion 1:1.
Is it possible to make xtick label values in proportion 2:1 with the ytick label values?
import matplotlib.pyplot as plt
x = [0,1,2,3,4,5]
fig=plt.figure()
ax = plt.subplot(111)
ax.plot(x)
y_tick_values = ax.get_yticks()
new_x_tick_values = [2 * y for y in y_tick_values]
ax.set_xticklabels(new_x_tick_values)
plt.show()

How to remove a particular grid line corresponding to a custom xtick on a log scale axis?

I'd like to remove the vertical grid line corresponding to the custom xtick (displayed at x = 71 in the below picture). I could remove a horizontal grid line corresponding to the ytick 701 in the below picture by using a hack : since I have no minor tick on the y axis, I defined the custom ytick corresponding to the line that points toward the maximum and crosses the y axis as a minor tick, and then I disabled grid lines for minor ticks on the y axis. Unfortunately I cannot use the same hack on the x axis without disabling the grid lines of the minor ticks and that's something I'd like to avoid at all costs.
Below is a not so minimal albeit still WE.
There are many things I don't understand, the 2 majors are why does
locs, labels = plt.xticks()
not return the locs and labels that are plotted and why I don't get xticks labels displayed as 10^x where x = 0, 1, 2 and 3 but that's outside the scope of the original question.
import matplotlib.pyplot as plt
plt.grid(True)
import numpy as np
# Generate data
x_data = np.arange(1, 1000 , 10)
y_data = np.random.lognormal(1e-5, 3, len(x_data))
y_max = max(y_data)
# plot
plt.xscale('log')
import math
ratio_log = math.log(x_data[np.argmax(y_data)]) / math.log(max(x_data)) # I need to do this in order to plot a horizontal red dashed line that points to the max and do not extend any further.
plt.axhline(y=y_max, xmin=0, xmax = ratio_log, color='r', linestyle='--') # horizontal line pointing to the max y value.
axes = plt.gca()
axes.set_xlim([1, max(x_data)]) # Limits for the x axis.
# custom ticks and labels
# First yticks because I'm able to achieve what I seek
axes.set_yticks([int(y_max)], minor=True) # Sets the custom ytick as a minor one.
from matplotlib.ticker import FormatStrFormatter
axes.yaxis.set_minor_formatter(FormatStrFormatter("%.0f"))
axes.yaxis.grid(False, which='minor') # Removes minor yticks grid. Since I only have my custom yticks as a minor one, this will disable only the grid line corresponding to that ytick. That's a hack.
import matplotlib.ticker as plticker
loc = plticker.MultipleLocator(base=y_max / 3.3) # this locator puts ticks at regular intervals. I ensure the y axis ticks look ok.
axes.yaxis.set_major_locator(loc)
# Now xticks. I'm having a lot of difficulty here, unable to remove the grid of a particular custom xticks.
locs, labels = plt.xticks() # Strangely, this doesn't return the locs and labels that are plotted. There are indeed 2 values that aren't displayed in the plot, here 1.00000000e-01 and 1.00000000e+04. I've got to remove them before I can append my custom loc and label.
# This means that if I do: plt.xticks(locs, labels) right here, it would enlarge both the lower and upper limits on the x axis... I fail to see how that's intuitive or useful at all. Might this be a bug?
locs = np.append(locs[1:-1], np.asarray(x_data[np.argmax(y_data)])) # One of the ugliest hack I have ever seen... to get correct ticks and labels.
labels = (str(int(loc)) for loc in locs) # Just visuals to get integers on the axis.
plt.xticks(locs, labels) # updates the xticks and labels.
plt.plot((x_data[np.argmax(y_data)], x_data[np.argmax(y_data)]), (0, y_max), 'r--') # vertical line that points to the max. Non OO way to do it, so a bad way.
plt.plot(x_data, y_data)
plt.savefig('grid_prob.png')
plt.close()
Example picture below (the code outputs a different picture each time it is executed, but the problem appears in all pictures).
Credit for the idea goes to #ImportanceOfBeingErnest to whom I am extremely grateful.
I removed the grid with
axes.xaxis.grid(False, which='both')
, then I added a grid correspond to each xtick except the custom one with the following loop:
for loc in locs[1:-1]:
if loc != x_data[np.argmax(y_data)]:
plt.axvline(x=loc, color = 'grey', linestyle = '-', linewidth = 0.4)
Insert this code just before the line
plt.xticks(locs, labels) # updates the xticks and labels.
Example of output picture below.

Plotting a second scaled y axis in matplotlib from one set of data

I have two views of the same data, which calls for the need to have another y-axis which is scaled appropriately from the first natural y-axis. So when I plot my {x,y} data, the left y-axis shows y, but the right y-axis also shows 1/y or any other function. I do not ever want to plot {x, f(x)} or {x, 1/y}.
Now to complicate matters I am using the .plt style of interaction rather than the axis method.
plt.scatter(X, Y, c=colours[count], alpha=1.0, label=chart, lw = 0)
plt.ylabel(y_lbl)
plt.xlabel(x_lbl)
Is there another way - with plt? Or is it a case of generating two overlain plots and changing the alpha appropriately?
I had to check your previous (duplicate) question and all the comments to understand what you actually want. So to just get a secondary y-axis you can still use twinx. Then you can use set_ylim make sure it has the same limits as the first. To put tick labels according to some function (in your case 1/y) you can use a custom FuncFormatter.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as mticker
fig, ax1 = plt.subplots(1,1)
ax1.set_xlabel('x')
ax1.set_ylabel('y')
# plot something
x = np.linspace(0.01, 10*np.pi, 1000)
y = np.sin(x)/x
ax1.plot(x, y)
# add a twin axes and set its limits so it matches the first
ax2 = ax1.twinx()
ax2.set_ylabel('1/y')
ax2.set_ylim(ax1.get_ylim())
# apply a function formatter
formatter = mticker.FuncFormatter(lambda x, pos: '{:.3f}'.format(1./x))
ax2.yaxis.set_major_formatter(formatter)
plt.show()
Result:

Categories