The RStudio IDE Viewer is also used when running code chunks in Jupyter, Quarto, and RMD Python code chunks.
The essential CanvasXpress package, for use with the CLI or flask and similar environments, can be installed using:
This section provides general instructions on creating and customizing charts.
Click to read more
Drawing Charts
The CanvasXpress
object defines what a chart should contain and how it should be formatted, but rendering the chart is
performed by the functions graph()
and show_in_browser()
.
To use graph()
import it from canvasxpress.plot
and then call it by passing a CanvasXpress
object. For example, a
Quarto, RMD, or Jupyter Notebook code chunk could be:
from random import random
from canvasxpress.canvas import CanvasXpress
from canvasxpress.plot import graph
graph(
CanvasXpress(
data={
"y": {
"data": [
[random() % 100 for i in range(20)]
],
"vars": ["A"],
}
},
config={
"background": "rgb(255,255,255)",
"colorScheme": "CanvasXpress",
"graphOrientation": "vertical",
"graphType": "Area",
"objectBorderColor": False,
"plotBox": False,
"plotBoxColor": "rgb(204,204,204)",
"showLegend": False,
"showLegendBorder": True,
"smpLabelRotate": 90,
"smpTitle": "time",
"xAxis": ["A"],
"xAxisTickRightShow": False,
"yAxisTickTopShow": False
},
width=609,
height=609
)
)
Some application frameworks, such as Shiny for Python and Plotly Dash, expect an object to be rendered to the
framework as part of the reactive flow. In these contexts, the graph()
function creates an appropriate object and
returns it. That value can be assigned to a variable to be returned at a later point in the code, or be immediately
returned. See the Shiny for Python and Dash examples for specific usage.
show_in_browser()
is similar to graph()
except that it opens a browser window on the local system and displays the
chart. It's used to facilitate learning and debugging.
graph()
does a good job of determining the runtime context to choose how the chart should be rendered, but in the case
installed packages or runtime configurations confuse the function an environment variable can be set to override
how graph()
performs the rendering. Set CANVASXPRESS_TARGET_CONTEXT
to be one of these values as appropriate for
this situation (and don't forget to pip install the necessary package support):
- rstudio
- shiny
- jupyter
- dash
- streamlit
- browser
For example:
from os import environ
environ["CANVASXPRESS_TARGET_CONTEXT"] = "jupyter"
or via a shell (bash example provided):
export CANVASXPRESS_TARGET_CONTEXT="jupyter"
Default and Pinned CanvasXpress JavaScript Editions
CanvasXpress for Python generates JavaScript that assumes use of the latest available edition of CanvasXpress for
JavaScript, but it can be set to use a specific edition.
Review this site for available versions:
https://cdnjs.com/libraries/canvasXpress
The desired version is expressed as a str
. Prior to generating a CanvasXpress chart use the following code to set the
edition that shall be used:
from canvasxpress.canvas import CanvasXpress
CanvasXpress.set_cdn_edition("48.3")
To use the default edition once again during the runtime session set the value to None
.
This is the best way to assure a specific chart behavior for production application releases; however, once set any new
JavaScript edition features or fixes will not be available until the code is removed or a different version is set.
Customizing Charts
Generally speaking, a CanvasXpress
object accepts the following parameters:
render_to
render_to
is a str
value that identifies the chart when rendered into HTML. JavaScript functions can use this ID to
access the chart and perform CanvasXpress operations within the browser. Omitting render_to
or setting it to
None
will make the CanvasXpress
object assume an anonymous mode in which a new GUID will be generated each time
graph()
is called. If the chart will not be maniluated using JavaScript in the browser it is fine for charts to be
anonymous.
NOTE: React environments regularly destroy and rebuild objects as the page is updated. In these environments it is
possible for the timing of object destruction and JavaScript execution to cause a crash. The best defense is to either
use anonymous mode, or if an ID must be known then a unique identifier should be set each time graph()
is called. In
this manner an ID for a chart in the middle of being recreated is never referenced. For example:
chart = CanvasXpress(...)
chart.render_to = str(guid4()).replace("-", "_")
return graph(chart)
Plotly's Dash framework uses React, and Dash applications should consider using only anonymous charts or assigning
unique values as the ID similar to the above code. Shiny for Python does not seem to suffer from this challenge.
data
data
sets the chart's data and metadata. This is an involved topic, and
the introductory article
is an excellent read to understand how data should be shaped. In general, data will be a dict
(also known as an XYZ
object), Web URL, or str
.
Data dict example:
data_for_use_in_chart = {
"y": {
"data": [
[random() % 100 for i in range(20)]
],
"vars": ["A"],
}
}
CanvasXpress for Python supports Pandas DataFrame assignments to data
, plus supporting sample_annotation
and
variable_annotation
properties. If data is assigned in this manner, then on generation of the JavaScript the
CanvasXpress object will create an XYZ object using the DataFrame(s).
from canvasxpress.canvas import CanvasXpress
import pandas
import io
import requests
data_url = "https://www.canvasxpress.org/data/cX-generic-dat.txt"
data_raw = requests.get(data_url).content
data_df = pandas.read_csv(
io.StringIO(data_raw.decode('utf-8')),
sep=" ",
index_col=0,
)
sample_annot_url = "https://www.canvasxpress.org/data/cX-generic-smp.txt"
sample_annot_raw = requests.get(sample_annot_url).content
sample_annot_df = pandas.read_csv(
io.StringIO(sample_annot_raw.decode('utf-8')),
sep=" ",
index_col=0,
)
variable_annot_url = "https://www.canvasxpress.org/data/cX-generic-var.txt"
variable_annot_raw = requests.get(variable_annot_url).content
variable_annot_df = pandas.read_csv(
io.StringIO(variable_annot_raw.decode('utf-8')),
sep=" ",
index_col=0,
)
cx = CanvasXpress(
data=data_df,
sample_annotation=sample_annot_df,
variable_annotation=variable_annot_df,
config={
"graphOrientation": "vertical",
"graphType": "Dotplot",
"lineType": "spline",
"llmHeader": [
["V1", "V2", "V3", "V4", "Factor1", "Factor2", "Factor3", "Factor4", "Factor5", "Factor6"]
],
"showSmpOverlaysLegend": True,
"smpOverlayProperties": {
"Factor4": {
"color": "blue",
"thickness": 50,
"type": "Bar",
"showLegend": "True"
},
"Factor5": {
"thickness": 50,
"color": "grey",
"type": "Bar",
"showLegend": "True"
},
"Factor6": {
"showLegend": "True",
"thickness": 50,
"color": "red",
"type": "Bar"
},
"Factor1": {
"type": "Default",
"color": "rgb(10,176,219)",
"spectrum": ["rgb(69,117,180)", "rgb(145,191,219)", "rgb(224,243,248)", "rgb(255,255,191)",
"rgb(254,224,144)", "rgb(252,141,89)", "rgb(215,48,39)"],
"scheme": "CanvasXpress",
"hideName": False,
"hideValue": False,
"showLegend": True,
"legendColumns": False,
"showBox": True,
"ticksOnBottomOrLeft": True,
"rotate": False,
"invert": False,
"position": "bottom"
},
"Factor2": {
"type": "Default",
"color": "rgb(254,211,133)",
"spectrum": ["rgb(69,117,180)", "rgb(145,191,219)", "rgb(224,243,248)", "rgb(255,255,191)",
"rgb(254,224,144)", "rgb(252,141,89)", "rgb(215,48,39)"],
"scheme": "CanvasXpress",
"hideName": False,
"hideValue": False,
"showLegend": True,
"legendColumns": False,
"showBox": True,
"ticksOnBottomOrLeft": True,
"rotate": False,
"invert": False,
"position": "bottom"
},
"Factor3": {
"type": "Default",
"color": "rgb(254,105,105)",
"spectrum": ["rgb(69,117,180)", "rgb(145,191,219)", "rgb(224,243,248)", "rgb(255,255,191)",
"rgb(254,224,144)", "rgb(252,141,89)", "rgb(215,48,39)"],
"scheme": "CanvasXpress",
"hideName": False,
"hideValue": False,
"showLegend": True,
"legendColumns": False,
"showBox": True,
"ticksOnBottomOrLeft": True,
"rotate": False,
"invert": False,
"position": "bottom"
}
},
"smpOverlays": ["Factor1", "Factor2", "Factor3"],
"smpTextRotate": 45,
"smpTitle": "Collection of Samples",
"smpTitleFontStyle": "italic",
"subtitle": "Random Data",
"theme": "CanvasXpress",
"title": "Dotplot Graph",
"xAxis": ["V1", "V2", "V3", "V4"],
"xAxisTickFormat": "%.0f Mil."
},
)
If a DataFrame is assigned to data
then its index will be used for xyz["y"]["vars"]
values and its header will be
used for the xyz["y"]["smps"]
values.
If a DataFrame is assigned to sample_annotation
or variable_annotation
then the following strategy will be used to
determine how the DataFrame should be parsed to create the corresponding x
and z
properties, respectively:
- The first column is first inspected to see if all of the column values match one of the available
sample (
xyz["y"]["smps"]
aka columns) or variable (xyz["y"]["vars"]
aka rows) values. - If a match is not made within the column, then the first row is inspected for the same criteria.
- Next, the DataFrame headers will be inspected.
- Finally, the DataFrame index will be used regardless of a match.
If no DataFrame is assigned to the sample_annotation
or variable_annotation
properties then those portions of the
xyz object will simply be ommitted.
sample_annotation
and variable_annotation
can only be used if the data
property is already a DataFrame. If any
other type is used, such as a dict
or str
then an exception will be raised.
data
, sample_annotation
, and variable_annotation
can be set to None
to remove their values.
Data URL example:
data_for_use_in_chart = "https://corgis-edu.github.io/corgis/datasets/csv/state_demographics/state_demographics.csv"
Data text (CSV) example:
data_for_use_in_chart = """
"State","Population.Population Percent Change","Population.2014 Population"
"Connecticut","-10.2","3605944"
"Delaware","8.4","989948"
"""
config
config
describes the chart's formatting. It is a dict
in which properties are specified and assigned values. All of
the values must be compliant with Python's json.dumps()
function. For example:
config = {
"background": "rgb(255,255,255)",
"colorScheme": "CanvasXpress",
"graphOrientation": "vertical",
"graphType": "Area",
"objectBorderColor": False,
"plotBox": False,
"plotBoxColor": "rgb(204,204,204)",
"showLegend": False,
"showLegendBorder": True,
"smpLabelRotate": 90,
"smpTitle": "time",
"xAxis": ["A"],
"xAxisTickRightShow": False,
"yAxisTickTopShow": False
},
width and height
width
and height
specify the chart's dimensions as pixels. If ommitted the CanvasXpress edition active for the
browser will assign default values, such as 500px by 500px.
Javascript Events
CanvasXpress provides support for Javascript events via hook functions that are called when events occur, such as mouse
movement or clicks. These events are supported via the canvasxpress.js sub-package. CXEvent
objects hold the
Javascript instructions for Web events. An example event for graph clicks with popup information is:
from canvasxpress.js.function import CXEvent
CXEvent(
id="click",
script="""
var s = 'click on var ' + o.y.vars[0] + ' and smp ' + o.y.smps[0];
t.showInfoSpan(e, s);
"""
)
The general JavaScript template of a CanvasXpress Javascript hook function is:
function (o, e, t) {
};
CXEvent
objects can be provided as a single object or as a list. Here's an example of an event the provides additional
information about chart data upon a user click:
from canvasxpress.canvas import CanvasXpress
from canvasxpress.plot import graph
from canvasxpress.js.function import CXEvent
graph(
CanvasXpress(
render_to="example_chart",
data={
"y": {
"vars": ["Gene1"],
"smps": ["Smp1", "Smp2", "Smp3"],
"data": [[10, 35, 88]]
}
},
config={
"graphOrientation": "vertical",
"graphType": "Bar",
"showLegend": False,
"smpLabelRotate": 90,
"smpTitle": "Samples",
"theme": "CanvasXpress",
"title": "Bar Graph Title",
"xAxisTitle": "Value"
},
events=[
CXEvent(
id="click",
script="""
var s = 'click on var ' + o.y.vars[0] + ' and smp ' + o.y.smps[0];
t.showInfoSpan(e, s);
"""
),
]
)
)
Converting to and from Reproducible JSON
CanvasXpress for Python can also convert to and from reproducible JSONs usable with the JavaScript and R editions of the
library. convert_to_reproducible_json
takes an existing CanvasXpress object and provides a str
copy of the JSON,
which can then be logged for debugging or saved to disk for use elsewhere. convert_from_reproducible_json
does the
opposite by taking a reproducible JSON str
and providing the CanvasXpress object equivalent.
Note: Events are not currently supported for import. This will be provided in a future edition. Export supports
events.
For example, do the following to see the JSON in the Python console:
from canvasxpress.canvas import CanvasXpress
from canvasxpress.plot import convert_to_reproducible_json
from canvasxpress.js.function import CXEvent
print(
convert_to_reproducible_json(
CanvasXpress(
render_to="example_chart",
data={
"y": {
"vars": ["Gene1"],
"smps": ["Smp1", "Smp2", "Smp3"],
"data": [[10, 35, 88]]
}
},
config={
"graphOrientation": "vertical",
"graphType": "Bar",
"showLegend": False,
"smpLabelRotate": 90,
"smpTitle": "Samples",
"theme": "CanvasXpress",
"title": "Bar Graph Title",
"xAxisTitle": "Value"
},
events=[
CXEvent(
id="click",
script="""
var s = 'click on var ' + o.y.vars[0] + ' and smp ' + o.y.smps[0];
t.showInfoSpan(e, s);
"""
),
]
)
)
)
The console would display:
{
"renderTo": "example_chart",
"data": {"y": {"vars": ["Gene1"], "smps": ["Smp1", "Smp2", "Smp3"], "data": [[10, 35, 88]]}, "x": {}, "z": {}},
"config": {"graphOrientation": "vertical", "graphType": "Bar", "showLegend": false, "smpLabelRotate": 90, "smpTitle": "Samples", "theme": "CanvasXpress", "title": "Bar Graph Title", "xAxisTitle": "Value"},
"afterRender": [],
"otherParams": {},
"events": {'click': function(o, e, t){
var s = 'click on var ' + o.y.vars[0] + ' and smp ' + o.y.smps[0];
t.showInfoSpan(e, s);
}},
"width": 500,
"height": 500
}
This text could be saved to a file, such as example.json
, and then dragged onto a CanvasXpress chart in a browser
to load the equivalent chart. In fact, CanvasXpress for Python uses the core functionality producing JSON output to
make charts available in contexts such as Dash and Shiny.
The RStudio IDE's Viewer panel is now supported for rendering interactive charts in the Viewer! When the graph()
function is called it detects that RStudio is running and renders the chart in the Viewer instead of a document, such as
for Quarto code chunks. However, if the document is a Quarto or RMD file and the appropriate HTML (etc.)
generation is performed then the CanvasXpress charts will be embedded in the generated output file as normal.
Charts can be defined in scripts or a console session and then displayed using the default browser, assuming that a
graphical browser with Javascript support is available on the host system. To do so use the show_in_browser()
function instead of graph()
.
The concepts in this example equally apply to other frameworks that can serve Web pages, such as Django and Tornado.