jbrowse-plugin-mafviewer 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@jbrowse/core/Plugin'), require('@jbrowse/core/pluggableElementTypes'), require('@jbrowse/core/configuration'), require('@jbrowse/core/data_adapters/BaseAdapter'), require('mobx-state-tree'), require('@jbrowse/core/util'), require('@jbrowse/core/util/rxjs'), require('react'), require('mobx-react'), require('@jbrowse/core/ui'), require('@mui/material'), require('tss-react/mui')) :
3
- typeof define === 'function' && define.amd ? define(['exports', '@jbrowse/core/Plugin', '@jbrowse/core/pluggableElementTypes', '@jbrowse/core/configuration', '@jbrowse/core/data_adapters/BaseAdapter', 'mobx-state-tree', '@jbrowse/core/util', '@jbrowse/core/util/rxjs', 'react', 'mobx-react', '@jbrowse/core/ui', '@mui/material', 'tss-react/mui'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.JBrowsePluginMafViewer = {}, global.JBrowseExports["@jbrowse/core/Plugin"], global.JBrowseExports["@jbrowse/core/pluggableElementTypes"], global.JBrowseExports["@jbrowse/core/configuration"], global.JBrowseExports["@jbrowse/core/data_adapters/BaseAdapter"], global.JBrowseExports["mobx-state-tree"], global.JBrowseExports["@jbrowse/core/util"], global.JBrowseExports["@jbrowse/core/util/rxjs"], global.JBrowseExports.react, global.JBrowseExports["mobx-react"], global.JBrowseExports["@jbrowse/core/ui"], global.JBrowseExports["@mui/material"], global.JBrowseExports["tss-react/mui"]));
5
- })(this, (function (exports, Plugin, pluggableElementTypes, configuration, BaseAdapter, mobxStateTree, util, rxjs, React, mobxReact, ui, material, mui) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@jbrowse/core/Plugin'), require('@jbrowse/core/pluggableElementTypes'), require('@jbrowse/core/configuration'), require('@jbrowse/core/data_adapters/BaseAdapter'), require('mobx-state-tree'), require('@jbrowse/core/util'), require('@jbrowse/core/util/rxjs'), require('react'), require('mobx-react'), require('@mui/material'), require('@jbrowse/core/ui'), require('tss-react/mui')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', '@jbrowse/core/Plugin', '@jbrowse/core/pluggableElementTypes', '@jbrowse/core/configuration', '@jbrowse/core/data_adapters/BaseAdapter', 'mobx-state-tree', '@jbrowse/core/util', '@jbrowse/core/util/rxjs', 'react', 'mobx-react', '@mui/material', '@jbrowse/core/ui', 'tss-react/mui'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.JBrowsePluginMafViewer = {}, global.JBrowseExports["@jbrowse/core/Plugin"], global.JBrowseExports["@jbrowse/core/pluggableElementTypes"], global.JBrowseExports["@jbrowse/core/configuration"], global.JBrowseExports["@jbrowse/core/data_adapters/BaseAdapter"], global.JBrowseExports["mobx-state-tree"], global.JBrowseExports["@jbrowse/core/util"], global.JBrowseExports["@jbrowse/core/util/rxjs"], global.JBrowseExports.react, global.JBrowseExports["mobx-react"], global.JBrowseExports["@mui/material"], global.JBrowseExports["@jbrowse/core/ui"], global.JBrowseExports["tss-react/mui"]));
5
+ })(this, (function (exports, Plugin, pluggableElementTypes, configuration, BaseAdapter, mobxStateTree, util, rxjs, React, mobxReact, material, ui, mui) { 'use strict';
6
6
 
7
- var version = "1.0.2";
7
+ var version = "1.0.3";
8
8
 
9
9
  const configSchema$2 = configuration.ConfigurationSchema('BigMafAdapter', {
10
10
  /**
@@ -738,19 +738,42 @@
738
738
 
739
739
  function configSchemaF(pluginManager) {
740
740
  const LinearGenomePlugin = pluginManager.getPlugin('LinearGenomeViewPlugin');
741
- // @ts-expect-error
742
- const { linearBasicDisplayConfigSchemaFactory } = LinearGenomePlugin.exports;
741
+ const { baseLinearDisplayConfigSchema } = LinearGenomePlugin.exports;
743
742
  return configuration.ConfigurationSchema('LinearMafDisplay', {
744
743
  /**
745
744
  * #slot
746
745
  */
747
746
  renderer: pluginManager.pluggableConfigSchemaType('renderer'),
748
747
  }, {
749
- baseConfiguration: linearBasicDisplayConfigSchemaFactory(pluginManager),
748
+ baseConfiguration: baseLinearDisplayConfigSchema,
750
749
  explicitlyTyped: true,
751
750
  });
752
751
  }
753
752
 
753
+ const useStyles$1 = mui.makeStyles()({
754
+ root: {
755
+ width: 500,
756
+ },
757
+ });
758
+ const SetRowHeightDialog = mobxReact.observer(function (props) {
759
+ const { model, handleClose } = props;
760
+ const { classes } = useStyles$1();
761
+ const [rowHeight, setRowHeight] = React.useState(`${model.rowHeight}`);
762
+ const [rowProportion, setRowProportion] = React.useState(`${model.rowProportion}`);
763
+ return (React.createElement(ui.Dialog, { open: true, onClose: handleClose, title: "Filter options" },
764
+ React.createElement(material.DialogContent, { className: classes.root },
765
+ React.createElement(material.Typography, null, "Set row height and the proportion of the row height to use for drawing each row"),
766
+ React.createElement(material.TextField, { value: rowHeight, onChange: event => setRowHeight(event.target.value), placeholder: "Enter row height" }),
767
+ React.createElement(material.TextField, { value: rowProportion, onChange: event => setRowProportion(event.target.value), placeholder: "Enter row proportion" }),
768
+ React.createElement(material.DialogActions, null,
769
+ React.createElement(material.Button, { variant: "contained", color: "primary", type: "submit", autoFocus: true, onClick: () => {
770
+ model.setRowProportion(+rowProportion);
771
+ model.setRowHeight(+rowHeight);
772
+ handleClose();
773
+ } }, "Submit"),
774
+ React.createElement(material.Button, { variant: "contained", color: "secondary", onClick: () => handleClose() }, "Cancel")))));
775
+ });
776
+
754
777
  function isStrs(array) {
755
778
  return typeof array[0] === 'string';
756
779
  }
@@ -760,10 +783,9 @@
760
783
  */
761
784
  function stateModelFactory(configSchema, pluginManager) {
762
785
  const LinearGenomePlugin = pluginManager.getPlugin('LinearGenomeViewPlugin');
763
- // @ts-expect-error
764
- const { linearBasicDisplayModelFactory } = LinearGenomePlugin.exports;
786
+ const { BaseLinearDisplay } = LinearGenomePlugin.exports;
765
787
  return mobxStateTree.types
766
- .compose('LinearMafDisplay', linearBasicDisplayModelFactory(configSchema), mobxStateTree.types.model({
788
+ .compose('LinearMafDisplay', BaseLinearDisplay, mobxStateTree.types.model({
767
789
  /**
768
790
  * #property
769
791
  */
@@ -772,9 +794,31 @@
772
794
  * #property
773
795
  */
774
796
  configuration: configuration.ConfigurationReference(configSchema),
797
+ /**
798
+ * #property
799
+ */
800
+ rowHeight: 15,
801
+ /**
802
+ * #property
803
+ */
804
+ rowProportion: 0.8,
775
805
  }))
776
806
  .volatile(() => ({
777
807
  prefersOffset: true,
808
+ }))
809
+ .actions(self => ({
810
+ /**
811
+ * #action
812
+ */
813
+ setRowHeight(n) {
814
+ self.rowHeight = n;
815
+ },
816
+ /**
817
+ * #action
818
+ */
819
+ setRowProportion(n) {
820
+ self.rowProportion = n;
821
+ },
778
822
  }))
779
823
  .views(self => ({
780
824
  /**
@@ -789,12 +833,6 @@
789
833
  return r;
790
834
  }
791
835
  },
792
- /**
793
- * #getter
794
- */
795
- get rowHeight() {
796
- return 20;
797
- },
798
836
  /**
799
837
  * #getter
800
838
  */
@@ -814,7 +852,7 @@
814
852
  },
815
853
  }))
816
854
  .views(self => {
817
- const { renderProps: superRenderProps } = self;
855
+ const { trackMenuItems: superTrackMenuItems, renderProps: superRenderProps, } = self;
818
856
  return {
819
857
  /**
820
858
  * #method
@@ -822,10 +860,29 @@
822
860
  renderProps() {
823
861
  return {
824
862
  ...superRenderProps(),
863
+ config: self.rendererConfig,
825
864
  samples: self.samples,
826
865
  rowHeight: self.rowHeight,
866
+ rowProportion: self.rowProportion,
827
867
  };
828
868
  },
869
+ /**
870
+ * #method
871
+ */
872
+ trackMenuItems() {
873
+ return [
874
+ ...superTrackMenuItems(),
875
+ {
876
+ label: 'Set row height',
877
+ onClick: () => {
878
+ util.getSession(self).queueDialog(handleClose => [
879
+ SetRowHeightDialog,
880
+ { model: self, handleClose },
881
+ ]);
882
+ },
883
+ },
884
+ ];
885
+ },
829
886
  };
830
887
  })
831
888
  .actions(self => {
@@ -836,7 +893,6 @@
836
893
  */
837
894
  async renderSvg(opts) {
838
895
  const { renderSvg } = await Promise.resolve().then(function () { return renderSvg$1; });
839
- // @ts-expect-error
840
896
  return renderSvg(self, opts, superRenderSvg);
841
897
  },
842
898
  };
@@ -850,17 +906,14 @@
850
906
 
851
907
  const ColorLegend = mobxReact.observer(function ({ model, labelWidth, }) {
852
908
  const { samples, rowHeight } = model;
853
- const svgFontSize = Math.min(rowHeight, 12);
854
- const canDisplayLabel = rowHeight > 11;
855
- const colorBoxWidth = 0;
856
- const legendWidth = labelWidth + colorBoxWidth + 5;
857
- const extraOffset = 0;
858
- return samples ? (React.createElement(React.Fragment, null, samples.map((sample, idx) => {
859
- const boxHeight = Math.min(20, rowHeight);
860
- return (React.createElement(React.Fragment, { key: `${sample.id}-${idx}` },
861
- React.createElement(RectBg, { y: idx * rowHeight + 1, x: extraOffset, width: legendWidth, height: boxHeight, color: sample.color }),
862
- canDisplayLabel ? (React.createElement("text", { y: idx * rowHeight + 14, x: extraOffset + colorBoxWidth + 2, fontSize: svgFontSize }, sample.label)) : null));
863
- }))) : null;
909
+ const svgFontSize = Math.min(rowHeight, 10);
910
+ const canDisplayLabel = rowHeight >= 10;
911
+ const boxHeight = Math.min(20, rowHeight);
912
+ return samples ? (React.createElement(React.Fragment, null,
913
+ samples.map((sample, idx) => (React.createElement(RectBg, { key: `${sample.id}-${idx}`, y: idx * rowHeight + 1, x: 0, width: labelWidth + 5, height: boxHeight, color: sample.color }))),
914
+ canDisplayLabel
915
+ ? samples.map((sample, idx) => (React.createElement("text", { key: `${sample.id}-${idx}`, y: idx * rowHeight + 14, x: 2, fontSize: svgFontSize }, sample.label)))
916
+ : null)) : null;
864
917
  });
865
918
 
866
919
  const Wrapper = mobxReact.observer(function ({ children, model, exportSVG, }) {
@@ -883,7 +936,7 @@
883
936
  const { model } = props;
884
937
  const { rowHeight, samples } = model;
885
938
  const svgFontSize = Math.min(rowHeight, 12);
886
- const canDisplayLabel = rowHeight > 11;
939
+ const canDisplayLabel = rowHeight >= 10;
887
940
  const minWidth = 20;
888
941
  const labelWidth = Math.max(...(samples
889
942
  .map(s => util.measureText(s.label, svgFontSize))
@@ -925,20 +978,6 @@
925
978
  explicitlyTyped: true,
926
979
  });
927
980
 
928
- function getCorrectionFactor(scale) {
929
- if (scale >= 1) {
930
- return 0.6;
931
- }
932
- else if (scale >= 0.2) {
933
- return 0.05;
934
- }
935
- else if (scale >= 0.02) {
936
- return 0.03;
937
- }
938
- else {
939
- return 0.02;
940
- }
941
- }
942
981
  function getContrastBaseMap(theme) {
943
982
  return Object.fromEntries(Object.entries(getColorBaseMap(theme)).map(([key, value]) => [
944
983
  key,
@@ -955,7 +994,7 @@
955
994
  };
956
995
  }
957
996
  function makeImageData({ ctx, renderArgs, }) {
958
- const { regions, bpPerPx, rowHeight, theme: configTheme, samples, } = renderArgs;
997
+ const { regions, bpPerPx, rowHeight, theme: configTheme, samples, rowProportion, } = renderArgs;
959
998
  const [region] = regions;
960
999
  const features = renderArgs.features;
961
1000
  const h = rowHeight;
@@ -964,7 +1003,9 @@
964
1003
  const contrastForBase = getContrastBaseMap(theme);
965
1004
  const sampleToRowMap = new Map(samples.map((s, i) => [s.id, i]));
966
1005
  const scale = 1 / bpPerPx;
967
- const correctionFactor = getCorrectionFactor(bpPerPx);
1006
+ const f = 0.4;
1007
+ const h2 = h * rowProportion;
1008
+ const offset = h2 / 2;
968
1009
  // sample as alignments
969
1010
  ctx.font = 'bold 10px Courier New,monospace';
970
1011
  for (const feature of features.values()) {
@@ -974,63 +1015,117 @@
974
1015
  for (const [sample, val] of Object.entries(vals)) {
975
1016
  const origAlignment = val.data;
976
1017
  const alignment = origAlignment.toLowerCase();
977
- // gaps
978
- ctx.beginPath();
979
- ctx.fillStyle = 'black';
980
- const offset0 = (5 / 12) * h;
981
- const h6 = h / 6;
982
1018
  const row = sampleToRowMap.get(sample);
983
1019
  if (row === undefined) {
984
1020
  throw new Error(`unknown sample encountered: ${sample}`);
985
1021
  }
986
1022
  const t = h * row;
987
- for (let i = 0; i < alignment.length; i++) {
988
- const l = leftPx + scale * i;
989
- if (alignment[i] === '-') {
990
- ctx.rect(l, offset0 + t, scale + correctionFactor, h6);
1023
+ // gaps
1024
+ ctx.beginPath();
1025
+ ctx.fillStyle = 'black';
1026
+ for (let i = 0, o = 0; i < alignment.length; i++) {
1027
+ if (seq[i] !== '-') {
1028
+ if (alignment[i] === '-') {
1029
+ const l = leftPx + scale * o;
1030
+ ctx.moveTo(l, t + h2);
1031
+ ctx.lineTo(l + scale + f, t + h2);
1032
+ }
1033
+ o++;
991
1034
  }
992
1035
  }
993
- ctx.fill();
994
- const offset = (1 / 4) * h;
995
- const h2 = h / 2;
1036
+ ctx.stroke();
996
1037
  // matches
997
1038
  ctx.beginPath();
998
1039
  ctx.fillStyle = 'lightgrey';
999
- for (let i = 0; i < alignment.length; i++) {
1000
- const c = alignment[i];
1001
- const l = leftPx + scale * i;
1002
- if (seq[i] === c && c !== '-') {
1003
- ctx.rect(l, offset + t, scale + correctionFactor, h2);
1040
+ for (let i = 0, o = 0; i < alignment.length; i++) {
1041
+ if (seq[i] !== '-') {
1042
+ const c = alignment[i];
1043
+ const l = leftPx + scale * o;
1044
+ if (seq[i] === c && c !== '-') {
1045
+ ctx.rect(l, offset + t, scale + f, h2);
1046
+ }
1047
+ o++;
1004
1048
  }
1005
1049
  }
1006
1050
  ctx.fill();
1007
1051
  // mismatches
1008
- for (let i = 0; i < alignment.length; i++) {
1052
+ for (let i = 0, o = 0; i < alignment.length; i++) {
1009
1053
  const c = alignment[i];
1010
- if (seq[i] !== c && c !== '-') {
1011
- const l = leftPx + scale * i;
1012
- ctx.fillStyle =
1013
- colorForBase[c] ?? 'purple';
1014
- ctx.fillRect(l, offset + t, scale + correctionFactor, h2);
1054
+ if (seq[i] !== '-') {
1055
+ if (seq[i] !== c && c !== '-') {
1056
+ const l = leftPx + scale * o;
1057
+ ctx.fillStyle =
1058
+ colorForBase[c] ?? 'purple';
1059
+ ctx.fillRect(l, offset + t, scale + f, h2);
1060
+ }
1061
+ o++;
1015
1062
  }
1016
1063
  }
1017
1064
  // font
1018
1065
  const charSize = { w: 10 };
1019
1066
  if (scale >= charSize.w) {
1020
- for (let i = 0; i < alignment.length; i++) {
1021
- const l = leftPx + scale * i;
1022
- const offset = (scale - charSize.w) / 2 + 1;
1023
- const c = alignment[i];
1024
- if (seq[i] !== c && c !== '-') {
1025
- ctx.fillStyle = contrastForBase[c] ?? 'black';
1026
- ctx.fillText(origAlignment[i], l + offset, h2 + t + 3);
1067
+ for (let i = 0, o = 0; i < alignment.length; i++) {
1068
+ if (seq[i] !== '-') {
1069
+ const l = leftPx + scale * o;
1070
+ const offset = (scale - charSize.w) / 2 + 1;
1071
+ const c = alignment[i];
1072
+ if (seq[i] !== c && c !== '-') {
1073
+ ctx.fillStyle = contrastForBase[c] ?? 'black';
1074
+ ctx.fillText(origAlignment[i], l + offset, h2 + t + 3);
1075
+ }
1076
+ o++;
1027
1077
  }
1028
1078
  }
1029
1079
  }
1030
1080
  }
1031
1081
  }
1082
+ // second pass for insertions, has slightly improved look since the
1083
+ // insertions are always 'on top' of the other features
1084
+ for (const feature of features.values()) {
1085
+ const [leftPx] = util.featureSpanPx(feature, region, bpPerPx);
1086
+ const vals = feature.get('alignments');
1087
+ const seq = feature.get('seq').toLowerCase();
1088
+ for (const [sample, val] of Object.entries(vals)) {
1089
+ const origAlignment = val.data;
1090
+ const alignment = origAlignment.toLowerCase();
1091
+ const row = sampleToRowMap.get(sample);
1092
+ if (row === undefined) {
1093
+ throw new Error(`unknown sample encountered: ${sample}`);
1094
+ }
1095
+ const t = h * row;
1096
+ ctx.beginPath();
1097
+ ctx.fillStyle = 'purple';
1098
+ for (let i = 0, o = 0; i < alignment.length; i++) {
1099
+ let ins = '';
1100
+ while (seq[i] === '-') {
1101
+ if (alignment[i] !== '-') {
1102
+ ins += alignment[i];
1103
+ }
1104
+ i++;
1105
+ }
1106
+ if (ins.length) {
1107
+ const l = leftPx + scale * o - 2;
1108
+ ctx.rect(l, offset + t, 2, h2);
1109
+ ctx.rect(l - 2, offset + t, 6, 1);
1110
+ ctx.rect(l - 2, offset + t + h2, 6, 1);
1111
+ }
1112
+ o++;
1113
+ }
1114
+ ctx.fill();
1115
+ }
1116
+ }
1032
1117
  }
1033
1118
  class LinearMafRenderer extends pluggableElementTypes.FeatureRendererType {
1119
+ getExpandedRegion(region) {
1120
+ const { start, end } = region;
1121
+ const bpExpansion = 1;
1122
+ return {
1123
+ // xref https://github.com/mobxjs/mobx-state-tree/issues/1524 for Omit
1124
+ ...region,
1125
+ start: Math.floor(Math.max(start - bpExpansion, 0)),
1126
+ end: Math.ceil(end + bpExpansion),
1127
+ };
1128
+ }
1034
1129
  async render(renderProps) {
1035
1130
  const { regions, bpPerPx, samples, rowHeight } = renderProps;
1036
1131
  const [region] = regions;
@@ -1133,6 +1228,10 @@
1133
1228
  const { adapter } = await this.setup();
1134
1229
  return adapter.getRefNames();
1135
1230
  }
1231
+ async getHeader() {
1232
+ const { adapter } = await this.setup();
1233
+ return adapter.getHeader();
1234
+ }
1136
1235
  getFeatures(query) {
1137
1236
  return rxjs.ObservableCreate(async (observer) => {
1138
1237
  const { adapter } = await this.setup();
@@ -1140,31 +1239,29 @@
1140
1239
  for (const feature of features) {
1141
1240
  const data = feature.get('field5').split(',');
1142
1241
  const alignments = {};
1143
- const main = data[0];
1144
- const aln = main.split(':')[5];
1145
1242
  const alns = data.map(elt => elt.split(':')[5]);
1146
- const alns2 = data.map(() => '');
1243
+ // const aln = alns[0]
1244
+ // const alns2 = data.map(() => '')
1147
1245
  // remove extraneous data in other alignments
1148
1246
  // reason being: cannot represent missing data in main species that are in others)
1149
- for (let i = 0, o = 0; i < aln.length; i++, o++) {
1150
- if (aln[i] !== '-') {
1151
- for (let j = 0; j < data.length; j++) {
1152
- alns2[j] += alns[j][i];
1153
- }
1154
- }
1155
- }
1247
+ // for (let i = 0; i < aln.length; i++) {
1248
+ // if (aln[i] !== '-') {
1249
+ // for (let j = 0; j < data.length; j++) {
1250
+ // alns2[j] += alns[j][i]
1251
+ // }
1252
+ // }
1253
+ // }
1156
1254
  for (let j = 0; j < data.length; j++) {
1157
1255
  const elt = data[j];
1158
1256
  const ad = elt.split(':');
1159
- const org = ad[0].split('.')[0];
1160
- const chr = ad[0].split('.')[1];
1257
+ const [org, chr] = ad[0].split('.');
1161
1258
  alignments[org] = {
1162
- chr: chr,
1259
+ chr,
1163
1260
  start: +ad[1],
1164
1261
  srcSize: +ad[2],
1165
1262
  strand: ad[3] === '-' ? -1 : 1,
1166
1263
  unknown: +ad[4],
1167
- data: alns2[j],
1264
+ data: alns[j],
1168
1265
  };
1169
1266
  }
1170
1267
  observer.next(new util.SimpleFeature({
@@ -1175,8 +1272,8 @@
1175
1272
  refName: feature.get('refName'),
1176
1273
  name: feature.get('name'),
1177
1274
  score: feature.get('score'),
1178
- alignments: alignments,
1179
- seq: alns2[0],
1275
+ alignments,
1276
+ seq: alns[0],
1180
1277
  },
1181
1278
  }));
1182
1279
  }
@@ -1299,11 +1396,17 @@
1299
1396
  }
1300
1397
 
1301
1398
  async function renderSvg(self, opts, superRenderSvg) {
1302
- const { offsetPx } = util.getContainingView(self);
1399
+ const { height } = self;
1400
+ const { offsetPx, width } = util.getContainingView(self);
1401
+ const clipid = `mafclip-${self.id}`;
1303
1402
  return (React.createElement(React.Fragment, null,
1304
- React.createElement("g", { id: "snpcov" }, await superRenderSvg(opts)),
1305
- React.createElement("g", { transform: `translate(${Math.max(-offsetPx, 0)})` },
1306
- React.createElement(YScaleBars, { model: self, orientation: "left", exportSVG: true }))));
1403
+ React.createElement("defs", null,
1404
+ React.createElement("clipPath", { id: clipid },
1405
+ React.createElement("rect", { x: 0, y: 0, width: width, height: height }))),
1406
+ React.createElement("g", { clipPath: `url(#${clipid})` },
1407
+ React.createElement("g", { id: "snpcov" }, await superRenderSvg(opts)),
1408
+ React.createElement("g", { transform: `translate(${Math.max(-offsetPx, 0)})` },
1409
+ React.createElement(YScaleBars, { model: self, orientation: "left", exportSVG: true })))));
1307
1410
  }
1308
1411
 
1309
1412
  var renderSvg$1 = {