Nivo bar graph - add a shared y axis? - reactjs

I'm using nivo responsive-bar to put a plot in my app. I've been asked to add a line showing the cumulative total on the same graph. Is there any way to do this? From the documentation I'm struggling to work out how to do it.
Here's the code I have so far (I've obfuscated the axis label and function names for security reasons!)
class CChart extends React.Component {
render = () => {
return (
<div style={{ height: '40em' }}>
<h3 className='text-center'>C</h3>
<ResponsiveBar
margin={{ top: 20, right: 0, bottom: 60, left: 80 }}
data={this.props.results}
indexBy='year'
colorBy={() => '#1f77b4'}
keys={['C']}
enableLabel={false}
axisLeft={{
legend: 'C(millions)',
legendPosition: 'center',
legendOffset: -60,
tickSize: 5,
tickPadding: 15,
format: v => Math.floor(v / 1000000).toLocaleString()
}}
axisBottom={{
legend: 'Year',
legendPosition: 'center',
legendOffset: 50,
tickSize: 5,
tickPadding: 15,
tickValues: this.props.results.map(x => x.year).filter(x => x % 5 === 0)
}}
theme={{
axis: {
fontSize: '1em',
legendFontSize: '1.2em'
}
}}
tooltipFormat={value => value.toLocaleString()}
animate={false}
markers={[
{ axis: 'y', value: 0 }
]}
/>
</div>
)
}
static propTypes = {
results: PropTypes.arrayOf(PropTypes.shape({
year: PropTypes.string.isRequired,
C: PropTypes.number.isRequired
})).isRequired
}
static mapStateToProps = state => ({
results: getCResults(state)
})
}

According to the #plouc (the founder of the Nivo library), as of September, 2018 you should be able to compose graphs.
https://github.com/plouc/nivo/issues/139
(scroll down until Sept 12)

It is not possible currently (https://github.com/plouc/nivo/issues/139)

Related

How to change the image size in a reusable component?

In my React Native application, I have a 48 x 48 profile picture component that is in the header on all of the screens.
ProfilePicture.jsx
const ProfilePicture = () => {
return (
<>
<Image style={styles.profPic} source={{ uri: userObj?.avatar }} />
</>
);
};
const styles = StyleSheet.create({
profPic: {
minHeight: 48,
minWidth: 48,
borderRadius: 100,
shadowColor: "#000",
shadowOffset: {
width: 2,
height: 2,
},
shadowOpacity: 1.0,
shadowRadius: 3.84,
elevation: 5,
},
});
export default ProfilePicture;
Now, I want to use a larger version in my user settings screen where the user can change their profile image.
My thought was that by setting the style in the imported component, it would show a larger version of the image:
<ProfilePicture style={{ width: 100, height: 100 }} />
However, the image remains the same size. I know I could just create another component with the required size for this page, but since the image comes from a remote server, I don't want to call the URL multiple times.
How can I do this just using my current component?
A good way to handle this would be to pass in a style prop to your ProfilePicture component. That way any component using the ProfilePicture component would be able to overrule the default styling. Combine this with the fact that the style prop of react-native components can take in arrays as value, and the code is pretty clean
const ProfilePicture = ({ style }) => {
return (
<Image style={[styles.profPic, style]} source={{ uri: userObj?.avatar }} />
);
};
const styles = StyleSheet.create({
profPic: {
minHeight: 48,
minWidth: 48,
borderRadius: 100,
shadowColor: "#000",
shadowOffset: {
width: 2,
height: 2,
},
shadowOpacity: 1.0,
shadowRadius: 3.84,
elevation: 5,
},
});
export default ProfilePicture;
Your example code will then work as intended
<ProfilePicture style={{ width: 100, height: 100 }} />

How to create Histogram with grouped data in Victory (ReactJS)?

I'm trying to create a histogram with Value, Id and Group code. I need to group the Ids based on the group code and put the labels on top. I'm also trying to add a horizontal scroll bar. Can you help me with this?
I tried to do like in this picture but I couldn't.
My data is in the form of this object
{
id: 1,
value: 0.16882,
group_id: 'group_1',
fill: 'red',
}
const App = () => {
const sharedAxisStyles = {
tickLabels: {
fontSize: 10
},
axisLabel: {
padding: 39,
fontSize: 12,
},
grid: {
stroke: "#546E7A",
strokeWidth: 0.1,
}
};
return (
<VictoryChart
domainPadding={{
x: 20,
}}
containerComponent={(
<VictoryZoomContainer
allowZoom={false}
zoomDomain={{
x: [0, 22],
}}
/>
)}
>
<VictoryLabel
x={225}
y={30}
textAnchor="middle"
text="Group code"
/>
<VictoryBar
data={data}
x={(x) => `id_${x.id}`}
y="value"
barWidth={15.8}
style={{
data: {
fill: ({datum}) => datum.fill,
}
}}
/>
<VictoryAxis
tickCount={22}
tickLabelComponent={<VictoryLabel
angle={-90}
textAnchor="end"
style={[
{ fontSize: 3, fontWeight: 'bold', fill: '#78909C' },
]}
/>}
/>
<VictoryAxis
dependentAxis
label="Value"
tickFormat={(t) => {
return (
(t).toFixed(2)
);
}}
style={sharedAxisStyles}
/>
</VictoryChart>
);
};
When I write these codes, the output I get is like this:
you will need to use VictoryGroup : https://formidable.com/open-source/victory/docs/victory-group/
And use labels to add title for each group https://formidable.com/open-source/victory/docs/victory-group/#labels

Positioning icon in SVG in React Native

Background:
I am trying to add a tooltip to a react-native-svg chart following this tutorial.
The link to the tutorial: Link
Current Code Implementation:
import React, {useState} from 'react';
import {View, Text, Dimensions} from 'react-native';
import {LineChart} from 'react-native-chart-kit';
import {Rect, Text as TextSVG, Svg} from 'react-native-svg';
const Charts = () => {
let [tooltipPos, setTooltipPos] = useState({
x: 0,
y: 0,
visible: false,
value: 0,
});
return (
<View>
<LineChart
data={{
labels: ['January', 'February', 'March', 'April', 'May', 'June'],
datasets: [
{
data: [100, 110, 90, 130, 80, 103],
},
],
}}
width={Dimensions.get('window').width}
height={250}
yAxisLabel="$"
yAxisSuffix="k"
yAxisInterval={1}
chartConfig={{
backgroundColor: 'white',
backgroundGradientFrom: '#fbfbfb',
backgroundGradientTo: '#fbfbfb',
decimalPlaces: 2,
color: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
labelColor: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
style: {
borderRadius: 0,
},
propsForDots: {
r: '6',
strokeWidth: '0',
stroke: '#fbfbfb',
},
}}
bezier
style={{
marginVertical: 8,
borderRadius: 6,
}}
decorator={() => {
return tooltipPos.visible ? (
<View>
<Svg>
<Rect
x={tooltipPos.x - 15}
y={tooltipPos.y + 10}
width="40"
height="30"
fill="black"
/>
<MaterialCommunityIcons
name="run"
size={32}
color="rgb(67, 67, 67)"
/>
<TextSVG
x={tooltipPos.x + 5}
y={tooltipPos.y + 30}
fill="white"
fontSize="16"
fontWeight="bold"
textAnchor="middle">
{tooltipPos.value}
</TextSVG>
</Svg>
</View>
) : null;
}}
onDataPointClick={(data) => {
let isSamePoint = tooltipPos.x === data.x && tooltipPos.y === data.y;
isSamePoint
? setTooltipPos((previousState) => {
return {
...previousState,
value: data.value,
visible: !previousState.visible,
};
})
: setTooltipPos({
x: data.x,
value: data.value,
y: data.y,
visible: true,
});
}}
/>
</View>
);
};
Question:
I want to add the icon(Running icon) as seen on the image above, to be next to the tool-tip text.
The Icon, then the text inside the rectangle filled in Black. When I try to position it,, it shows up on the extreme top left for some reason. How do I position it?
You can use the ForeignObject component from react-native-svg and change your decorator to something like this:
decorator={() => {
return tooltipPos.visible ? (
<ForeignObject x={tooltipPos.x} y={tooltipPos.y}>
<View
style={{
width: 70,
flexDirection: 'row',
backgroundColor: 'black',
}}>
<MaterialCommunityIcons
name="run"
size={32}
color="rgb(67, 67, 67)"
/>
<Text
style={{
color: 'white',
fontSize: 16,
fontWeight: 'bold',
textAnchor: 'middle',
}}>
{tooltipPos.value}
</Text>
</View>
</ForeignObject>
) : null;
}}
The problem with what you had before is that the react-native-svg Text and Rect components use x and y coordinates and your icon doesn't, so the positioning will be off.
The benefit of the approach shown above is that you only have to specify the x and y props of the ForeignObject. Everything inside the ForeignObject can be regular views, positioned as you normally would (https://github.com/react-native-community/react-native-svg#foreignobject).
I've chosen the tooltipPos.x and tooltipPos.y for the x and y prop values of the ForeignObject respectively, but you could add an offset if necessary.
Be sure to import ForeignObject from react-native-svg.

react-native-picker-select not Working with Parent View {flexDirection:'row'}

I want to use <RNPickerSelect./> with a <TextInput/> in a single row. So, when I make the Parent flexDirection: row, I see only the arrow and no text. Even if I remove the <TextInput/>, I don't see any text in the Picker.
import React, { Component } from 'react';
import {
StyleSheet,
View,
} from 'react-native';
import RNPickerSelect from 'react-native-picker-select';
type Props = {}
const countryCode = [
{
label: '+91',
value: '+91',
},
{
label: '+1',
value: '+1',
},
{
label: '+2',
value: '+2',
},
];
export default class PickerTest extends Component<Props> {
constructor() {
super()
this.state = {
phoneNumber: "",
countryCode: ""
}
}
render() {
return (
<View style={{flexDirection:'row'}}>
<View paddingVertical={5}>
{/* and hiding the InputAccessoryView on iOS */}
<RNPickerSelect
placeholder={{}}
items={countryCode}
onValueChange={value => {
this.setState({
countryCode: value,
});
}}
InputAccessoryView={() => null}
style={pickerSelectStyles}
value={this.state.countryCode}
/>
</View>
</View>
);
}
}
const pickerSelectStyles = StyleSheet.create({
inputIOS: {
fontSize: 16,
paddingVertical: 12,
paddingHorizontal: 10,
borderWidth: 1,
borderColor: 'gray',
borderRadius: 4,
color: 'black',
paddingRight: 30, // to ensure the text is never behind the icon
},
inputAndroid: {
fontSize: 16,
paddingHorizontal: 10,
paddingVertical: 8,
borderWidth: 0.5,
borderColor: 'purple',
borderRadius: 8,
color: 'black',
paddingRight: 30, // to ensure the text is never behind the icon
},
});
On running the above app, I get something like this
As you can see the picker is not showing the text.
Below are the configuration I am using
react-native-picker-select version: 6.3.3
react-native version: 0.61.2
react version: 16.9.0
this is an upstream issue: https://snack.expo.io/HkygCqhsr
options:
useNativeAndroidPickerStyle prop
set width and height with inputAndroid style prop
Add the atribute "pickerProps" to the RNPickerSelect with the option overflow: 'hidden'
<RNPickerSelect style={styles.selectContainer}
...
pickerProps={{ style: { height: 214, overflow: 'hidden' } }}
...
/>

Tabs navigation bar hides elements beneath it

I'm using material-ui to write a navigation bar by using Tab. My tab navigation bar is almost the same as Master.jsx:
import React from 'react';
import {
AppCanvas,
IconButton,
EnhancedButton,
Mixins,
Styles,
Tab,
Tabs,
Paper} from 'material-ui';
const {StylePropable} = Mixins;
const {Colors, Spacing, Typography} = Styles;
const ThemeManager = Styles.ThemeManager;
const DefaultRawTheme = Styles.LightRawTheme;
const Master = React.createClass({
mixins: [StylePropable],
getInitialState() {
let muiTheme = ThemeManager.getMuiTheme(DefaultRawTheme);
// To switch to RTL...
// muiTheme.isRtl = true;
return {
muiTheme,
};
},
propTypes: {
children: React.PropTypes.node,
history: React.PropTypes.object,
location: React.PropTypes.object,
},
childContextTypes: {
muiTheme: React.PropTypes.object,
},
getChildContext() {
return {
muiTheme: this.state.muiTheme,
};
},
getStyles() {
let darkWhite = Colors.darkWhite;
return {
footer: {
backgroundColor: Colors.grey900,
textAlign: 'center',
},
a: {
color: darkWhite,
},
p: {
margin: '0 auto',
padding: 0,
color: Colors.lightWhite,
maxWidth: 335,
},
github: {
position: 'fixed',
right: Spacing.desktopGutter / 2,
top: 8,
zIndex: 5,
color: 'white',
},
iconButton: {
color: darkWhite,
},
};
},
componentWillMount() {
let newMuiTheme = this.state.muiTheme;
newMuiTheme.inkBar.backgroundColor = Colors.yellow200;
this.setState({
muiTheme: newMuiTheme,
tabIndex: this._getSelectedIndex()});
let setTabsState = function() {
this.setState({renderTabs: !(document.body.clientWidth <= 647)});
}.bind(this);
setTabsState();
window.onresize = setTabsState;
},
componentWillReceiveProps(nextProps, nextContext) {
let newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme;
this.setState({
tabIndex: this._getSelectedIndex(),
muiTheme: newMuiTheme,
});
},
render() {
let styles = this.getStyles();
let githubButton = (
<IconButton
iconStyle={styles.iconButton}
iconClassName="muidocs-icon-custom-github"
href="https://github.com/callemall/material-ui"
linkButton={true}
style={styles.github} />
);
let githubButton2 = (
<IconButton
iconStyle={styles.iconButton}
iconClassName="muidocs-icon-custom-github"
href="https://github.com/callemall/material-ui"
linkButton={true}/>
);
return (
<AppCanvas>
{githubButton}
{ this._getTabs() }
{this.props.children}
</AppCanvas>
);
},
_getTabs() {
let styles = {
root: {
backgroundColor: Colors.cyan500,
position: 'fixed',
height: 64,
top: 0,
right: 0,
zIndex: 1101,
width: '100%',
},
container: {
position: 'absolute',
right: (Spacing.desktopGutter / 2) + 48,
bottom: 0,
},
span: {
color: Colors.white,
fontWeight: Typography.fontWeightLight,
left: 45,
top: 22,
position: 'absolute',
fontSize: 26,
},
svgLogoContainer: {
position: 'fixed',
width: 300,
left: Spacing.desktopGutter,
},
svgLogo: {
width: 65,
backgroundColor: Colors.cyan500,
position: 'absolute',
top: 20,
},
tabs: {
width: 425,
bottom: 0,
},
tab: {
height: 64,
},
};
const materialIcon =
<EnhancedButton
style={styles.svgLogoContainer}
linkButton={true}
href="/#/home">
<img style={this.prepareStyles(styles.svgLogo)} src="images/material-ui-logo.svg"/>
<span style={this.prepareStyles(styles.span)}>material ui</span>
</EnhancedButton>
return (
<div>
<Paper
zDepth={0}
rounded={false}
style={styles.root}>
{materialIcon}
<div style={this.prepareStyles(styles.container)}>
<Tabs
style={styles.tabs}
value={this.state.tabIndex}
onChange={this._handleTabChange}>
<Tab
value="1"
label="GETTING STARTED"
style={styles.tab}
route="/get-started" />
<Tab
value="2"
label="CUSTOMIZATION"
style={styles.tab}
route="/customization"/>
<Tab
value="3"
label="COMPONENTS"
style={styles.tab}
route="/components"/>
</Tabs>
</div>
</Paper>
</div>
);
},
_getSelectedIndex() {
return this.props.history.isActive('/get-started') ? '1' :
this.props.history.isActive('/customization') ? '2' :
this.props.history.isActive('/components') ? '3' : '0';
},
_handleTabChange(value, e, tab) {
this.props.history.pushState(null, tab.props.route);
this.setState({tabIndex: this._getSelectedIndex()});
},
});
export default Master;
Basically I removed AppBar, AppLeftNav and FullWidthSection.
The only problem is that the Tabs hides some elements beneath it, see the picture below:
I must did something wrong, any ideas? Thanks!
Your root style is fixed. It will cause the element to stick on the top. Remove it.
OK, I found paddingTop: Spacing.desktopKeylineIncrement + 'px', in page-with-nav.jsx, which is the right solution.
The reason the elements beneath the navigation tab is covered is because fixed position elements are removed from the document flow and do not take up any space. So the elements are beginning at the top as if the header isn't there. What you have to do is use padding or margin to take up the space that would have been occupied by your header if it was in the normal flow.

Resources