I have the result of a grid search as follows.
"trial","learning_rate","batch_size","accuracy","f1","loss"
1,0.000007,70,0.789,0.862,0.467
2,0.000008,100,0.710,0.822,0.563
3,0.000008,90,0.823,0.874,0.524
4,0.000007,90,0.833,0.878,0.492
5,0.000009,110,0.715,0.825,0.509
6,0.000006,90,0.883,0.885,0.932
7,0.000009,80,0.850,0.895,0.408
8,0.000006,110,0.683,0.812,0.593
9,0.000005,90,0.769,0.848,0.468
10,0.000005,80,0.816,0.868,0.462
11,0.000003,100,0.852,0.901,0.448
12,0.000004,100,0.705,0.818,0.512
13,0.000003,110,0.708,0.818,0.567
14,0.000002,90,0.683,0.812,0.552
15,0.000008,100,0.791,0.857,0.438
16,0.000006,110,0.683,0.812,0.604
17,0.000007,70,0.693,0.816,0.592
18,0.000005,110,0.830,0.883,0.892
19,0.000004,90,0.693,0.816,0.591
20,0.000008,70,0.696,0.818,0.570
I want to create a plot more or less similar to this using matplotlib. I know this is plotted using weights and biases but I cannot use that.
Though I don't care for the inference part. I just want the plot. I've been trying to do this using twinx but have not been successful. This is what I have so far.
from csv import DictReader
import matplotlib.pyplot as plt
trials = list(DictReader(open("hparams_trials.csv")))
trials = {f"trial_{trial['trial']}": [int(trial["batch_size"]),
float(trial["f1"]),
float(trial["loss"]),
float(trial["accuracy"]),
float(trial["learning_rate"])] for trial in trials}
items = ["batch_size", "f1", "loss", "accuracy", "learning_rate"]
host_y_values_index = 0
parts_y_values_indexes = [1, 2, 3, 4]
fig, host = plt.subplots(figsize=(8, 5)) # (width, height) in inches
fig.dpi = 300. # Figure resolution
# Removing extra spines
host.spines.top.set_visible(False)
host.spines.bottom.set_visible(False)
host.spines.right.set_visible(False)
# Creating subplots which share the same x axis.
parts = {index: host.twinx() for index in parts_y_values_indexes}
# Setting the limits of the host plot
host.set_xlim(0, len(trials["trial_1"]))
host.set_ylim(min([i[host_y_values_index] for i in trials.values()]),
max([i[host_y_values_index] for i in trials.values()]))
# Removing the extra spines from the other plots and setting y limits
for part in parts_y_values_indexes:
parts[part].spines.top.set_visible(False)
parts[part].spines.bottom.set_visible(False)
parts[part].set_ylim(min([trial[part] for trial in trials.values()]),
max([trial[part] for trial in trials.values()]))
# Colors of the trials
colors = ["gold", "lightcoral", "maroon", "springgreen", "cyan", "steelblue", "darkmagenta", "fuchsia", "crimson",
"lime", "mediumblue", "cadetblue", "dodgerblue", "olivedrab", "sandybrown", "bisque", "orangered", "black",
"rosybrown", "chocolate"]
# The plots
plots = []
# Plotting the trials. This is where I'm having problems with.
for index, trial in enumerate(trials):
plots.append(host.plot(items, trials[trial], color=colors[index], label=trial)[0])
# Creating the legend
host.legend(handles=plots, fancybox=True, loc='right', facecolor="snow", bbox_to_anchor=(1.02, 0.495), framealpha=1)
# Defining the positions of the spines.
spines_positions = [-104.85 * i for i in parts_y_values_indexes]
# Repositioning the spines
for part in parts_y_values_indexes:
parts[part].spines['right'].set_position(('outward', spines_positions[-part]))
# Adjust spacings around fig
fig.tight_layout()
host.grid(True)
# This is better than the one above but it appears on top of the legend.
# plt.grid(True)
plt.draw()
plt.show()
I'm having several problems with that code. First, I cannot place each value of a single trial based on a different spine and then connect them to one another. What I mean is that each trial has a batch size, an f1, a loss, accuracy and a learning rate. Each of those need to be plotted based on their own spine while connected to each other in that order. However, I cannot plot them based their dedicated spines and then connect them to one another to have a line plot per trial. Accordingly, for now I have placed everything in the host plot but I know that is wrong and have no idea what the correct approach is. Second problem, the ticks of the learning rate change. It gets shown as a range of 2 to 9 and then a 1e-6 appears at the top. I want to keep the original value. Third problem is probably part of the second one. The 1e-6 appears at the top right above the legend rather than above the spine for some reason. I'm struggling with resolving all three of these problems and would appreciate any help anyone can provide. If what I am doing is totally wrong, please help me in finding the correct solution. I'm somewhat going in circles here and haven't been able to find any working solutions so far.
I am trying to find a way to make an Axes object passthrough for events.
For context, I have a figure with 6 small subplots. Each of them responds to mouse motion events by displaying a cursor dot and text info where the user aims. I also made it so that clicking a subplot will make it as large as the figure for better visibility. When moving the mouse over invisible axes, event.inaxes will still point to that ax despite being set to invisible and that is what I would like to avoid.
Below is the MRE:
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.set_gid("ax1")
ax2.set_gid("ax2")
fig.show()
def on_movement(event):
"""Write on the figure in which `Axes`object the event happened."""
width, height = fig.bbox.bounds[2:]
x = event.x/width
y = event.y/height
text = ax.get_gid() if (ax := event.inaxes) is not None else "None"
fig.texts[:] = []
fig.text(x, y, s=text, transform=fig.transFigure, c="white", bbox=dict(fc="#0055AA", ec="black"))
fig.canvas.draw()
fig.canvas.mpl_connect("motion_notify_event", on_movement)
As expected, as you hover the mouse over ax1, the empty gap and ax2, you will see one of those three texts appear:
ax1.set_position((1/3, 1/3, 2/3, 2/3))
Same thing as I arbitrarily resize and move ax1 so that it is partly overlaps with ax2.
ax2.set_visible(False)
Now this is my problem. Invisible axes still trigger events. Is there a way to make some axes "transparent" to events? Obviously the usual technique of sorting all the cases in the callback does not work here.
Currently envisaged solutions:
ideally, finding a setting akin to zorder so that the "highest" axes gets the event.
ugly workaround: set the position of the invisible axes to ((0, 0, 1e-10, 1e-10)).
less ugly: working with figure coordinates to convert event.x, event.y into event.xdata, event.ydata for the only ax that I know is visible. Basically xdata1, ydata1 = ax1.transAxes.inverted().transform((event.x, event.y)) if event.inaxes is not None + see if there are edge cases.
The latter is already implemented and does work, so save your time if you want to write a reply using that approach. I'm mostly interested in an amazing one-liner that I would have missed, something like ax2.set_silenced(True).
Python 3.8.5
Matplotlib 3.1.3
Well, setting the appropriate zorder does work actually.
ax1.set_zorder(2)
ax2.set_zorder(1)
...
def on_movement(event):
...
fig.text(x, y, ..., zorder=1000)
...
I am overlaying a scatter plot of points on an imshow 128 x 128 pixels. If you look closely here:
the objects do not always fall exactly on the center of the corresponding pixels. I tried different interpolations on imshow and origins for scatter, but nothing changed. So I thought I could overlay a grid to see how much this offset actually is:
and I noticed that the grid also falls exactly on the objects and not the center of the imshow pixels. The script for the above plot is:
fig = plt.figure(figsize=(15,8))
plt.imshow(counts_pre[:,:,slice_z],cmap='viridis',interpolation=None)
plt.scatter(j_index,i_index, s = 0.1, c = 'red', marker = 'o')
myInterval=1.
loc = matplotlib.ticker.MultipleLocator(base=myInterval)
plt.gca().xaxis.set_minor_locator(loc)
plt.gca().yaxis.set_minor_locator(loc)
plt.grid(which="both", linewidth=0.72,color="white",alpha=0.1)
plt.tick_params(which="minor", length=0)
plt.show()
Any ideas on why this offset exists and how I can fix it? Notice that the grid is not very homogeneous, i.e. some squares are rectangular.
Edit:
Upgrading to the newest matplotlib version did not resolve the
issue.
I created objects where the entries are non-zero, such that I know that the points should be perfectly aligned, but they still don't match up.
I am plotting a log using matplotlib and would like my x axis to be position at the top of the plot rather than bottom.
I tried xaxis.set_ticks_position('top') but it did not work. However xaxis.set_label_position('top') worked for the label.
from matplotlib import gridspec
# creating the figure
fig=plt.figure(figsize=(12,10))
# adding the title
fig.suptitle('Volume of Clay from different methods',fontsize=14)
# creating the axes
gs=gridspec.GridSpec(4,3)
ax1=fig.add_subplot(gs[:,0])
ax2=fig.add_subplot(gs[0,1])
ax3=fig.add_subplot(gs[1,1])
ax4=fig.add_subplot(gs[2,1])
ax5=fig.add_subplot(gs[3,1])
ax6=fig.add_subplot(gs[:,2],sharey=ax1)
# Plotting graph for GR,SP
ax1.invert_yaxis()
ax1.xaxis.set_label_position('top')
ax1.xaxis.set_ticks_position('top')
ax1.grid(True)
ax1.set_ylabel('DEPTH')
ax1.set_xlabel('GR[api]',color='green')
ax1.tick_params('x',colors='green')
ax1.spines['top'].set_position(('outward',0))
ax1.plot(data.GR,data.index, color='green')
ax11=ax1.twiny()
ax11.plot(data.SP,data.index,color='blue')
ax11.set_xlabel("SP[mV]",color='blue')
ax11.spines['top'].set_position(('outward',40))
plt.show()
i am expecting the x axis for the GR curve in green to be on top but it remains in the bottom instead.
I think i found out what's going on thanks to #ImportanceOfBeingErnest
ax11.ax1.twiny() is overwriting ax1
i've fix the code as below.
from matplotlib import gridspec
# creating the figure
fig=plt.figure(figsize=(12,10))
# adding the title
fig.suptitle('Volume of Clay from different methods',fontsize=14)
fig.subplots_adjust(top=0.9,wspace=0.3, hspace=0.3)
# creating the axes
gs=gridspec.GridSpec(4,3)
ax1=fig.add_subplot(gs[:,0])
ax1.get_xaxis().set_visible(False)
ax2=fig.add_subplot(gs[0,1])
ax3=fig.add_subplot(gs[1,1])
ax4=fig.add_subplot(gs[2,1])
ax5=fig.add_subplot(gs[3,1])
ax6=fig.add_subplot(gs[:,2],sharey=ax1)
# Plotting graph for GR,SP
ax10=ax1.twiny()
ax10.invert_yaxis()
ax10.xaxis.set_label_position('top')
ax10.xaxis.set_ticks_position('top')
ax10.tick_params('x',colors='green')
ax10.spines['top'].set_position(('outward',0))
ax10.grid(True)
ax10.set_ylabel('DEPTH')
ax10.set_xlabel('GR[api]',color='green')
ax10.plot(data.GR,data.index, color='green')
ax11=ax1.twiny()
ax11.plot(data.SP,data.index,color='blue')
ax11.set_xlabel("SP[mV]",color='blue')
ax11.spines['top'].set_position(('outward',40))
If there are any better way to write this please do comment.
I'm trying to write a simple program that reads in a CSV with various datasets (all of the same length) and automatically plots them all (as a Pandas Dataframe scatter plot) on the same figure. My current code does this well, but all the marker colors are the same (blue). I'd like to figure out how to make a colormap so that in the future, if I have much larger data sets (let's say, 100+ different X-Y pairings), it will automatically color each series as it plots. Eventually, I would like for this to be a quick and easy method to run from the command line. I did not have luck reading the documentation or stack exchange, hopefully this is not a duplicate!
I've tried the recommendations from these posts:
1)Setting different color for each series in scatter plot on matplotlib
2)https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.plot.scatter.html
3) https://matplotlib.org/users/colormaps.html
However, the first one essentially grouped the data points according to their position on the x-axis and made those groups of data the same color (not what I want, each series of data is roughly a linearly increasing function). The second and third links seemed to have worked, but I don't like the colormap choices (e.g. "viridis", many colors are too similar and it's hard to distinguish data points).
This is a simplified version of my code so far (took out other lines that automatically named axes, etc. to make it easier to read). I've also removed any attempts I've made to specify a colormap, for more of a blank canvas feel:
''' Importing multiple scatter data and plotting '''
import pandas as pd
import matplotlib.pyplot as plt
### Data file path (please enter Dataframe however you like)
path = r'/Users/.../test_data.csv'
### Read in data CSV
data = pd.read_csv(path)
### List of headers
header_list = list(data)
### Set data type to float so modified data frame can be plotted
data = data.astype(float)
### X-axis limits
xmin = 1e-4;
xmax = 3e-3;
## Create subplots to be plotted together after loop
fig, ax = plt.subplots()
### Since there are multiple X-axes (every other column), this loop only plots every other x-y column pair
for i in range(len(header_list)):
if i % 2 == 0:
dfplot = data.plot.scatter(x = "{}".format(header_list[i]), y = "{}".format(header_list[i + 1]), ax=ax)
dfplot.set_xlim(xmin,xmax) # Setting limits on X axis
plot.show()
The dataset can be found in the google drive link below. Thanks for your help!
https://drive.google.com/drive/folders/1DSEs8D7lIDUW4NIPBl2qW2EZiZxslGyM?usp=sharing