Plotting points on one line in python. 1 dimension - python

This is the kind of graph that I would like to plot, without y axis . How can I achieve this in python using matplotlib if possible.

Sadly there is not built-in fonction in matplotlib to create such a graph.
However, You can use the following code to have a similar output. This snippet is removing unwanted spines (left, right and top) and then using scatterplot to simulate a 1d graph.
As Follows:
from matplotlib import pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(10,1))
x = [1,2,3,4,9,10]
idx = np.arange(1,len(x)+1)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_position('zero')
ax.spines['bottom'].set_alpha(0.2)
ax.get_yaxis().set_visible(False)
ax.set_xlabel('Gene 1')
ax.scatter(x, np.zeros(len(x)), s=300, c='lightgreen')
ax.set_xticks([min(x), max(x)], ['Low Values', 'High Values'])
for i in range(len(idx)):
ax.annotate(idx[i], (x[i], 0), textcoords="offset points",
xytext=(0,0), # distance from text to points (x,y)
ha='center')
plt.show()
Outputs:

Related

How to increase plottable space above a subplot in matplotlib?

I am currently making a plot on matplotlib, which looks like below.
The code for which is:
fig, ax1 = plt.subplots(figsize=(20,5))
ax2 = ax1.twinx()
# plt.subplots_adjust(top=1.4)
ax2.fill_between(dryhydro_df['Time'],dryhydro_df['Flow [m³/s]'],0,facecolor='lightgrey')
ax2.set_ylim([0,10])
AB = ax2.fill_between(dryhydro_df['Time'],[12]*len(dryhydro_df['Time']),9.25,facecolor=colors[0],alpha=0.5,clip_on=False)
ab = ax2.scatter(presence_df['Datetime'][presence_df['AB']==True],[9.5]*sum(presence_df['AB']==True),marker='X',color='black')
# tidal heights
ax1.plot(tide_df['Time'],tide_df['Tide'],color='dimgrey')
I want the blue shaded region and black scatter to be above the plot. I can move the elements above the plot by using clip_on=False but I think I need to extend the space above the plot to do visualise it. Is there a way to do this? Mock-up of what I need is below:
You can use clip_on=False to draw outside the main plot. To position the elements, an xaxis transform helps. That way, x-values can be used in the x direction, while the y-direction uses "axes coordinates". ax.transAxes() uses "axes coordinates" for both directions.
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
dates = pd.date_range('2018-07-01', '2018-07-31', freq='H')
xs = dates.to_numpy().astype(float)
ys = np.sin(xs * .091) * (np.sin(xs * .023) ** 2 + 1)
fig, ax1 = plt.subplots(figsize=(20, 5))
ax1.plot(dates, ys)
ax1.scatter(np.random.choice(dates, 10), np.repeat(1.05, 10), s=20, marker='*', transform=ax1.get_xaxis_transform(),
clip_on=False)
ax1.plot([0, 1], [1.05, 1.05], color='steelblue', lw=20, alpha=0.2, transform=ax1.transAxes, clip_on=False)
plt.tight_layout() # fit labels etc. nicely
plt.subplots_adjust(top=0.9) # make room for the additional elements
plt.show()

Change coordinates for origin in scatter plot with centred axes

I have some datasets that I'm visualizing in a scatter plot. I have a bunch of mean values, and a global mean. What I'm after, but cant really achieve,is to have a scatter plot that is centered in the plot, while also placing the origin at the global mean.
This is the code that defines the layout of the plot:
plt.figure(1)
plt.suptitle('Example')
plt.xlabel('x (pixels)')
plt.ylabel('y (pixels)')
ax = plt.gca()
ax.spines['left'].set_position('center')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('center')
ax.spines['top'].set_color('none')
ax.scatter(x_data, y_data, color=color, alpha=0.08, label=csv_file_name)
ax.plot(global_mean[0], global_mean[1], color='green',
marker='x', label='Global mean')
This produces the following plot (the ax.scatter() is called multiple times for each dataset, but it's not in the code above):
I've tried playing around with the ax.set_position() parameters but nothing have worked well so far. Is there a way to do what I'm after with matplotlib, or do I need to use some other plot library?
You can use the ax.spines() method to move them around.
import numpy as np
import random
import matplotlib.pyplot as plt
#generate some random data
x = np.linspace(1,2, 100)
y = [random.random() for _ in range(100)]
fig = plt.figure(figsize=(10,5))
# original plot
ax = fig.add_subplot(1,2,1)
ax.scatter(x, y)
# same plot, but with the spines moved
ax2 = fig.add_subplot(1,2,2)
ax2.scatter(x, y)
# move the left spine (y axis) to the right
ax2.spines['left'].set_position(('axes', 0.5))
# move the bottom spine (x axis) up
ax2.spines['bottom'].set_position(('axes', 0.5))
# turn off the right and top spines
ax2.spines['right'].set_visible(False)
ax2.spines['top'].set_visible(False)
plt.show()

Matplotlib: combination of inverted plots

I need to achieve the following effect using matplotlib:
As you can see it's a combination of plots in different quadrants.
I do know how to generate each quadrant individually. For example, for the 'x invert' quadrant's plot I would simply use:
plt.plot(x, y)
plt.gca().invert_yaxis()
plt.show()
to draw the plot. It properly inverts the x axis. However, it would only generate top-left quadrant's plot for me.
How can I generate a combination of plots described in the above picture? Each quadrant has its own plot with different inverted axises.
My best idea was to merge it in some tool like Paint.
I don't have enough reputation to add a comment to add on to ImportanceOfBeingErnest's comment, but when you create the 4 subplots you'll want to remove the space between the plots as well as have shared axes (and clean up overlapping ticks).
There are various ways to do subplots, but I prefer gridspec. You can create a 2x2 grid with gridspec and do all of this, here's an example:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
# lines to plot
x = np.arange(0, 10)
y = np.arange(0, 10)
# gridspec for 2 rows, 2 cols with no space between
grid = gridspec.GridSpec(nrows=2, ncols=2, hspace=0, wspace=0, figure=fig)
x_y = fig.add_subplot(grid[0, 1], zorder=3)
x_y.plot(x, y)
x_y.margins(0)
invx_y = fig.add_subplot(grid[0, 0], zorder=2, sharey=x_y)
invx_y.plot(-x, y)
invx_y.margins(0)
invx_invy = fig.add_subplot(grid[1, 0], zorder=0, sharex=invx_y)
invx_invy.plot(-x, -y)
invx_invy.margins(0)
x_invy = fig.add_subplot(grid[1, 1], zorder=1, sharey=invx_invy, sharex=x_y)
x_invy.plot(x, -y)
x_invy.margins(0)
# clean up overlapping ticks
invx_y.tick_params(labelleft=False, length=0)
invx_invy.tick_params(labelleft=False, labelbottom=False, length=0)
x_invy.tick_params(labelbottom=False, length=0)
x_y.set_xticks(x_y.get_xticks()[1:-1])
invx_y.set_xticks(invx_y.get_xticks()[1:-1])
x_invy.set_yticks(x_invy.get_yticks()[1:-1])
plt.show()
This yields the following figure:

Show axis at center, but keep labels on the left [duplicate]

This question already has answers here:
How to move tick labels off left spine
(2 answers)
Closed 3 years ago.
I am attempting to plot a distribution which is centred around zero, and as such I want to show the y-axis spine at 0, but I want to keep the tick labels themselves to the left of the graph (i.e. outside the plot area). I thought this might be achievable through tick_params, but the labelleft option seems to keep the labels in the centre. A short example is as follows:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
vals = np.random.normal(loc=0, scale=10, size=300)
bins = range(int(min(vals)), int(max(vals))+1)
fig, ax = plt.subplots(figsize=(15,5))
ax.hist(vals, bins=bins)
ax.spines['left'].set_position('zero')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.grid(axis='y', which='major', alpha=0.5)
plt.show()
This gives you:
I would like the labels to be at the left end of the gridlines, rather than the centre of the plot.
Probably not the best solution, but you can set left spines invisible and draw a straight line at 0:
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.plot((0,0), (0,ax.get_ylim()[-1]),color='k',linewidth=1)
ax.grid(axis='y', which='major', alpha=0.5)
plt.show()
Output:
On possibility is to instruct the tick labels to use the "Axes coordinates" for their x position, and the "Data coordinates" for their y position. This implies changing their tranform property.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.transforms as transforms
np.random.seed(1)
vals = np.random.normal(loc=0, scale=10, size=300)
bins = range(int(min(vals)), int(max(vals))+1)
fig, ax = plt.subplots()
ax.hist(vals, bins=bins)
ax.spines['left'].set_position('zero')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.grid(axis='y', which='major', alpha=0.5)
trans = transforms.blended_transform_factory(ax.transAxes,ax.transData)
plt.setp(ax.get_yticklabels(), 'transform', trans)
plt.show()

Add an x-axis at 0 to a pyplot histogram with negative bars

In the histogram produced with the following code, there's no x axis at the zero level
import matplotlib.pyplot as plt
plt.bar(left=[0,4,5],height=[-100,10,110],color=['red','green','green'],width=0.1)
plt.show()
How to put it there?
I tend to use spines to get the x-axis centered:
import matplotlib.pyplot as plt
fig = plt.figure(facecolor='white')
ax = fig.add_subplot(1,1,1)
ax.bar(left=[0,4,5],height=[-100,10,110],color=['red','green','green'],width=0.1)
ax.grid(b=True)
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
plt.show()
Which will produce the next plot:
By default matplotlib does not consider the y=0 line important. You can turn on the grid by a call such as plt.grid().
An alternative used often in the matplotlib.pylab docs is to set a horizontal line at 0. This is done by
plt.axhline(0, color='black', lw=2)

Categories