Draw multiple arrows using plotly python - plotly-python

There is an example about multiple annotations, it simply duplicate the go.layout.Annotation() to draw 2 arrows.
But I need to draw more than 100+ arrows, I don't know how.
The go.layout.Annotation() is tuple type and accepts dict() for each arrow, is there any easy way to add more dict() to tuple() ?
Thank you.

I solved my own question.
fig.layout.annotations accepts list, parameters of each arrow is a dict(). So the idea is to create a list of many dict(), and then use fig.update_layout(annotations = list) to draw multiple arrows.
the dict() for each arrow looks like this:
arrow = go.layout.Annotation(dict(
x= x_end,
y= y_end,
xref="x", yref="y",
text="",
showarrow=True,
axref = "x", ayref='y',
ax= x_start,
ay= y_start,
arrowhead = 3,
arrowwidth=1.5,
arrowcolor='rgb(255,51,0)',)
)
the list for multiple arrows can be easily created like this:
list = list + [dict()]
Then, update the fig:
fig.update_layout(
annotations= list_of_all_arrows,)
If all arrows are in time series, this is the final result:

Related

How to add text into a plot in pyqtgraph like matplotlib.plot.text()

Like the title said, I want to add a text into a graph which I used pyqtgraph to plot, but I didn't find any function like matplotlib.plot.text() which I could set the text and even position in the graph.
self.plt_1.setLabel('left', 'CDF')
self.plt_1.setLabel('bottom', 'Delay', units='ms')
self.plt_1.setXRange(0, 200)
self.plt_1.setYRange(0, 1)
self.plt_1.setWindowTitle('DL CDF Curve')
self.plt_1.setMouseEnabled(x=False, y=False)
self.plt_1.setMenuEnabled(False)
self.plt_1.setText(30, 20, str(self.x_dl_5g_flag))
I tried this, but it doesn't work in my case, does anyone know how to do it in pyqtgraph? thanks
self.text = pg.TextItem(str(self.x_dl_5g_flag))
self.plt_1.addItem(self.text)
self.text.setPos(30,20)
If you want to add text to a graph and define its position on the plot in coordinates relative to the plot canvas (not data coordinates) you can use LabelItem instead of TextItem, something along the following lines (with pyqtgraph imported as pg):
self.text_label = pg.LabelItem("Your text")
self.text_label.setParentItem(self.plt_1.graphicsItem())
self.text_label.anchor(itemPos=(0.4, 0.1), parentPos=(0.4, 0.1))

Why does get_legend_handles_labels() return empty lists when legend labels are added via ax.legend() [duplicate]

This one is blowing my mind. I'm creating a little customize legend function where you put in some text and properties and it'll make it for you. So, before this is reachable in the GUI, a figure with a legend has already been created by this point which has "run5" and "run6" in it.
I wrote something that deletes the existing legend and calls legend on that same axis again with new handles/labels. However, when I do ax.get_legend_handles_labels() right afterwards it returns the deleted legend's handle and labels, completely ignoring the legend call I just did.
I've tried removing the legend and then just recreating it. But clearly ax is holding onto the previous legend's data.
from matplotlib.lines import Line2D
ax = self.axes[ind] #just the axis handle
custom_lines, custom_strings = [], []
try:
ax.get_legend().remove()
except:
# Means no legend exists
pass
for idx, i in enumerate(self.lgndRowWidget):
if not i.isHidden():
#The below five lines are grabbing data from GUI
lineText = self.lgndStr[idx].text() # Is "test" here
lineType = self.lgndLine[idx].currentText()
lineWidth = self.lgndWidth[idx].value()
lineMrkr = self.lgndMrkr[idx].currentText()
lineClr = self.lgndClr[idx].text()
custom_lines.append(Line2D([0],[0],
lw=lineWidth,
ls=lineType,
marker=lineMrkr,
color=lineClr))
custom_strings.append(lineText)
if len(custom_lines) != 0:
print(custom_strings)
self.legList = ax.legend(custom_lines, custom_strings)
a,b = ax.get_legend_handles_labels()
print(b)
self.fig.canvas.draw()
print(custom_strings) returns whatever I input. In this case "test".
print(b) returns what was previously in the legend that I can't seem to get rid of: the initial "run5" and "run6". It SHOULD be "test".
You might have misunderstood the functionality of ax.get_legend_handles_labels().
What it does is to look for artists (like lines, collections etc.) that have a label.
It then returns those artists and their respective labels. Hence
ax.legend() is roughly equivalent to
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles=handles, labels=labels)
.get_legend_handles_labels() does not know about whether there is a legend present, because it returns what is supposed to be in the legend, not what currently is in it.

Matplotlib/Seaborn: Boxplot collapses on x axis

I am creating a series of boxplots in order to compare different cancer types with each other (based on 5 categories). For plotting I use seaborn/matplotlib. It works fine for most of the cancer types (see image right) however in some the x axis collapses slightly (see image left) or strongly (see image middle)
https://i.imgur.com/dxLR4B4.png
Looking into the code how seaborn plots a box/violin plot https://github.com/mwaskom/seaborn/blob/36964d7ffba3683de2117d25f224f8ebef015298/seaborn/categorical.py (line 961)
violin_data = remove_na(group_data[hue_mask])
I realized that this happens when there are too many nans
Is there any possibility to prevent this collapsing by code only
I do not want to modify my dataframe (replace the nans by zero)
Below you find my code:
boxp_df=pd.read_csv(pf_in,sep="\t",skip_blank_lines=False)
fig, ax = plt.subplots(figsize=(10, 10))
sns.violinplot(data=boxp_df, ax=ax)
plt.xticks(rotation=-45)
plt.ylabel("label")
plt.tight_layout()
plt.savefig(pf_out)
The output is a per cancer type differently sized plot
(depending on if there is any category completely nan)
I am expecting each plot to be in the same width.
Update
trying to use the order parameter as suggested leads to the following output:
https://i.imgur.com/uSm13Qw.png
Maybe this toy example helps ?
|Cat1|Cat2|Cat3|Cat4|Cat5
|3.93| |0.52| |6.01
|3.34| |0.89| |2.89
|3.39| |1.96| |4.63
|1.59| |3.66| |3.75
|2.73| |0.39| |2.87
|0.08| |1.25| |-0.27
Update
Apparently, the problem is not the data but the length of the title
https://github.com/matplotlib/matplotlib/issues/4413
Therefore I would close the question
#Diziet should I delete it or does my issue might help other ones?
Sorry for not including the line below in the code example:
ax.set_title("VERY LONG TITLE", fontsize=20)
It's hard to be sure without data to test it with, but I think you can pass the names of your categories/cancers to the order= parameter. This forces seaborn to use/display those, even if they are empty.
for instance:
tips = sns.load_dataset("tips")
ax = sns.violinplot(x="day", y="total_bill", data=tips, order=['Thur','Fri','Sat','Freedom Day','Sun','Durin\'s Day'])

Setting legend location in matplotlib (while using geopandas)

I have tried several different methods to change my plot's legend's position, but none of them have worked. I would like to set the position for example to upper left or upper right.
I have a GeoDataFrame (data_proj) which has polygons in it. I want to plot only one map with those polygons.
I created my plot like this:
p = data_proj.plot(column = "Level3", linewidth=0.03, legend = True)
I used these to set the title etc. for the legend:
leg = p.get_legend()
leg.set_title("Land cover")
leg.get_frame().set_alpha(0)
How can I change the location of the legend?
On geopandas master (i.e., a change made subsequent to the current 0.3.0 release), a legend_kwds argument was added to the plot method. One can then do the following:
ax = df.plot(column='values', categorical=True, legend=True, legend_kwds={'loc': 2})
In principle setting the legend should work as usual. The loc parameter can be used to define the location of the legend.
p = data_proj.plot(column = "Level3", linewidth=0.03)
leg = p.legend(loc="upper right")
leg.set_title("Land cover")
leg.get_frame().set_alpha(0)

Matplotlib - transform bbox

I printed some text into a plot. Now I want to make a copy of this text and move it to different coordinates. I guess I'll have to do this with tranform, but did not find a solution yet.
here is the code:
props = dict( facecolor='#DDDDDD', alpha=1,edgecolor='#FFFFFF',boxstyle="Square,pad=0.5")
text2=plt.text(4, 4, "text",va='top', ha='left',bbox=props)
plt.draw()
bb2=text2.get_bbox_patch().get_window_extent().transformed(ax.transData.inverted()).get_points()
To move the text to different coordinates you only need:
text2.set_position((new_x,new_y))
you could also use:
text2.set_x(new_x)
text2.set_y(new_y)