I am playing around with Bokeh for some time now and am really amazed how easy it is to create beautiful charts.
There is one visual thing I am not able to solve, however.
If I turn of background and borders all my charts still have some kind of border / frame. Can you turn this off as well?
E.g. If I use the following code to turn off my background, border and axis I still end up with a frame around the plot figure.
p.xaxis.visible = False
p.yaxis.visible = False
p.xgrid.visible = False
p.ygrid.visible = False
p.background_fill_color = None
p.border_fill_color = None
Here is my plot example.
Any idea how to get rid of the grey frame?
Thanks for your help!
You can remove it by setting p.outline_line_color to None.
Also by the way you can set p.axis.visible and p.grid.visible you don't need to specify the x and y axes separately
Related
I am currently trying to create a debugging tool for a simulation. For this is am working with the animations of plotly express. What I want to achieve:
An animation with a different background image with different traces (also differing in number) for each frame. Any help would be very much appreciated! (Also if someone knows how to do this using any other library it'd be very much appreciated!)
Thanks!
Adding the background images work perfectly well like this:
fig = px.imshow(img,origin="upper", animation_frame=0, binary_string=True, labels=dict(animation_frame="slice"))
So I only need to figure out how to display the traces.
I tried the following first:
fig = px.imshow(img,origin="upper", animation_frame=0, binary_string=True, labels=dict(animation_frame="slice")) # img consists of |time_step| images (np.array)
## now I'm trying to add the traces
for i in range(len(img)):
time_step = df.iloc[i]
for j in range(len(time_step)):
current = time_step.iloc[j]
x, y = current["x"], current["y"]
if (not current["valid"]):
fig.add_trace(go.Scatter(x=x, y=y, name="{}".format(current["unique_id"]), text="{}".format(current["costs"]), hoverinfo='text+name', line=dict(color="black", dash="dot"), line_shape="spline"))
else:
fig.add_traces(go.Scatter(x=x_list, y=y_list, line=dict(color="black"), line_shape="spline"))
fig.show()
However, I realized that fig.add_trace always adds the trace to all frames of the animation. (When only displaying the first time step it worked though :) )
However, I'd like to add the traces for one time_step only and then the ones for the next time_step.
So I started looking into this approach:
# saving in a list instead of printing immediately
if (not current["feasible"]):
info.append([x_list, y_list, "{}".format(current["unique_id"]),
"{}".format(current["costs"]), dict(color=color, dash="dot")])
else:
info.append([x_list, y_list, "{}".format(current["unique_id"]),
"{}".format(current["costs"]),dict(color=color)])
and added the information to the single frames:
frames.append(
go.Frame(
data=[go.Scatter(
x=information[0],
y=information[1],
name=information[2],
text=information[3],
hoverinfo='text+name',
line=information[4],
line_shape="spline"
)
for information in info],
)
)
figa = go.Figure(data=fig.data, frames=frames, layout=fig.layout)
figa.show()
But it only displays the first background image and once I start the animation it disappears and only shows the first saved Scatter for each time_step.
I'm a little lost as I don't have a set number of traces I can't "hardcode" the Scatters.
I would like to use HoloViews DynamicMap with a widget to select data for two curves, and a widget to control whether the curves are shown separately or as a filled area. It almost works, but sometimes shows the wrong data, depending on the order in which the widgets are manipulated.
The code snippet below demonstrates the issue, if run in a Jupyter notebook. It creates two identical DynamicMaps to show how they get out of sync with the widgets.
For this demo, if 'fill', an Area chart is shown. Otherwise, two Curve elements show the top and bottom bounds of the same area.
If 'higher', the area or curves are shifted upwards along the vertical axis (higher y values).
First, one DynamicMap is displayed. The code snippet then toggles the widget for 'fill' followed by 'higher', in that order (alternatively, the user could manually toggle the widgets). The DynamicMap should show a filled area in the higher position, but actually shows a filled area in the lower position. The image below the code snippet shows this incorrect DynamicMap on the left.
The second DynamicMap (shown on the right) is added to the display after the widgets are toggled. It correctly displays a chart corresponding to the state of the widgets at that point.
Code snippet
import holoviews as hv
import numpy as np
import panel as pn
pn.extension()
# Make two binary widgets to control whether chart
# data is high or low, and whether chart shows
# an area fill or just a pair of lines.
check_boxes = {name: pn.widgets.Checkbox(value=False, name=name) \
for name in ["higher", "fill"]}
# Data for charts.
xvals = [0.10, 0.90]
yvals_high = [1, 1.25]
yvals_low = [0.25, 0.40]
# Declare horizontal and vertical dimensions to go on charts.
xdim = hv.Dimension("x", range=(-0.5, 1.5), label="xdim")
ydim = hv.Dimension("y", range=(0, 2), label="ydim")
def make_plot(higher, fill):
"""Make high or low, filled area or line plot"""
yvals_line1 = np.array(yvals_high if higher else yvals_low)
yvals_line2 = 1.2*yvals_line1
if fill:
# Make filled area plot with x series and two y series.
area_data = (xvals, yvals_line1, yvals_line2)
plot = hv.Area(area_data,
kdims=xdim,
vdims=[ydim, ydim.clone("y.2")])
plot = hv.Overlay([plot]) # DMap will want an overlay.
else:
# Make line plot with x series and y series.
line_data_low = (xvals, yvals_line1)
line_data_high = (xvals, yvals_line2)
plot = hv.Curve(line_data_low,
kdims=xdim,
vdims=ydim) \
* hv.Curve(line_data_high,
kdims=xdim,
vdims=ydim)
return plot
# Map combinations of higher and fill to corresponding charts.
chart_dict = {(higher, fill): make_plot(higher, fill) \
for higher in [False,True] for fill in [False,True]}
def chart_func(higher, fill):
"""Return chart from chart_dict lookup"""
return chart_dict[higher, fill]
# Make two DynamicMaps linked to the check boxes.
dmap1 = hv.DynamicMap(chart_func, kdims=["higher", "fill"], streams=check_boxes)
dmap2 = hv.DynamicMap(chart_func, kdims=["higher", "fill"], streams=check_boxes)
# Show the check boxes, and one of the DMaps.
widget_row = pn.Row(*check_boxes.values(), width=150)
dmap_row = pn.Row(dmap1, align='start')
layout = pn.Column(widget_row,
dmap_row)
display(layout)
## Optionally use following line to launch a server, then toggle widgets.
#layout.show()
# Toggle 'fill' and then 'higher', in that order.
# Both DMaps should track widgets...
check_boxes["fill"].value = True
check_boxes["higher"].value = True
# Show the other DMap, which displays correctly given the current widgets.
dmap_row.append(dmap2)
# But first dmap (left) is now showing an area in wrong location.
Notebook display
Further widget toggles
The code snippet below can be run immediately afterwards in another cell. The resulting notebook display is shown in an image below the code snippet.
The code here toggles the widgets again, 'fill' and 'higher', in that order (alternatively, the user could manually toggle the widgets).
The left DynamicMap correctly displays a chart corresponding to the state of the widgets at that point, that is, two lines in the lower position.
The right DynamicMap incorrectly shows the two lines in the higher position.
# Toggle 'fill' and then 'higher' again, in that order.
# Both DMaps should track widgets...
check_boxes["fill"].value = False
check_boxes["higher"].value = False
# But now the second DMap shows lines in wrong location.
Am I just going about this the wrong way?
Thanks for the detailed, reproducible report!
After running your example, I noticed two things:
Switching from pn.extension to hv.extension at the start seems to fix the strange behavior that I also observing when using the panel extension. Could you confirm that things work as expected when using the holoviews extension?
I was wondering why your DynamicMaps work via chart_dict and chart_func when you can just use your make_plot callback in the DynamicMaps directly, without modification.
If you can confirm that the extension used changes the behavior, could you file an issue about this? Thanks!
Been unable to figure this one out so was hoping someone here could point me in the right direction...
I am basically trying to store the color that was used from my colormap such that I can use it later on in the code.
color_map = cm.get_cmap('Spectral')
for grp,frame in x.groupby('time'):
ax.scatter(x, y, cmap=color_map)
<other code>
ax.axvline(x=magic_number, color=<???>)
plt.show()
Pretty much I want to use the same color from my map in the for loop. I believe this is pretty simple to do but I cant seem to find the right combination of things to search for to get the answer.
I couldn't completely understand what you are trying to achieve. I'm not sure that below will be helpful.... (sadly)
your code should be something like this:
ax.axvline(x=magic_number, color=color_map(float(magic_number)/float(max_magix_number) ) )
It works quite simple float(magic_number)/float(max_magix_number) gives a float number in the range from zero to one. color_map(scaled number) returns required color as a tuple of R,G,B and transparancy....
>>> c = get_cmap('Spectral')
>>> c(0.5)
(0.998077662437524, 0.9992310649750096, 0.7460207612456747, 1.0)
>>>
I plot a graph with python 2.7 by using Igraph 0.6 with the Cairo extention for plotting. All good but I would like to add a legend each time I plot.
If I could only add a background image to the plot that would be also fine, because I make a white image with the right size and with the legend already added there (with general sign explanation).
None of this I can do, nor I can find by googleing it. Maybe I'm just unable to get on the right side of Google or to find the right keyword in Igraph documentations.
gp = Graph(). It's global. Has vertex and edge sequences etc. There are some lists which contain further information about vertexes and edges (in ex.: self.gp_cities, self.road_kind) Here is how I plot:
def showitshort(self,event):
global gp
layout = gp.layout("kk")
color_dict = {"1": "red", "20": "blue"}
visual_style = {}
visual_style["vertex_size"] = 15
visual_style["vertex_color"] = ["yellow"]
visual_style["edge_color"] = [color_dict[elektro] for elektro in self.road_kind]
visual_style["vertex_label"] = self.gp_cities
visual_style["layout"] = layout
visual_style["bbox"] = (4000, 2500)
visual_style["margin"] = 100
visual_style["vertex_label_dist"] = 5
visual_style["vertex_shape"] = "triangle-up"
plot(gp,**visual_style)
The right link I think is enough. Please help a little and Thank you in advance!
The trick is that you can pass an existing Cairo surface into plot and it will simply plot the graph on that surface instead of creating a new one. So, basically, you need to construct a Cairo surface (say, an ImageSurface), draw your legend using standard Cairo calls onto that surface, then pass the surface to plot as follows:
plot(gp, target=my_surface, **visual_style)
As far as I know, plot() will not show the graph itself when invoked this way; it will simply return a Plot object. You can call the show() method of the Plot object to show it or call the save() method to save it into a PNG file.
I am using the matplotlib PatchCollection to hold a bunch of matplotlib.patches.Rectangles. But I want them to be invisible when first drawn (only turn visible when something else is clicked). This works fine when I was drawing the Rectangle's straight to the canvas with add_artist, but I want to change this to using a PatchCollection. For some reason, when I create the PatchCollection and add it with add_collection, they are all visible.
self.plotFigure = Figure()
self.plotAxes = self.plotFigure.add_subplot(111)
self.selectionPatches = []
for node in self.nodeList:
node.selectionRect = Rectangle((node.posX - node.radius*0.15 , node.posY - node.radius*0.15),
node.radius*0.3,
node.radius*0.3,
linewidth = 0,
facecolor = mpl.colors.ColorConverter.colors['k'],
zorder = z,
visible = False)
self.selectionPatches.append(node.selectionRect)
self.p3 = PatchCollection(self.selectionPatches, match_original=True)
self.plotAxes.add_collection(self.p3)
If I iterate through self.selectionPatches and print out each Rectangle's get_visible(), it returns false. But they are clearly visible when they get drawn. If anyone can help me see why this is happening, I would be very grateful.
When you create a PatchCollection it extracts a whole bunch of information from the objects you hand in (shape, location, styling(if you use match_original)), but does not keep the patch objects around for later reference (so it discards the per-patch visible). If you want all of the rectangles to be visible/invisible together you can do
self.p3 = PatchCollection(self.selectionPatches,
match_original=True,
visible=False)
other wise I think you will have to group them into the sets you want to appear together.
Look at the __init__ function of PatchCollection(here) and the rest of the cascade up through Collection and Artist.